fix: `print()` multiline behaviour (#17319)

* way cleaner new line handling for base_elements

* fix

* more fixes

* use esrap preview

* changeset

* bump `esrap`

* update snapshot

* update more snapshots

* Update .changeset/rich-zoos-walk.md

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/17588/head
Manuel 8 months ago committed by GitHub
parent 9d1dd2e199
commit 82fde88780
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: properly separate multiline html blocks from each other in `print()`

@ -176,7 +176,7 @@
"clsx": "^2.1.1", "clsx": "^2.1.1",
"devalue": "^5.6.2", "devalue": "^5.6.2",
"esm-env": "^1.2.1", "esm-env": "^1.2.1",
"esrap": "^2.2.1", "esrap": "^2.2.2",
"is-reference": "^3.0.3", "is-reference": "^3.0.3",
"locate-character": "^3.0.0", "locate-character": "^3.0.0",
"magic-string": "^0.30.11", "magic-string": "^0.30.11",

@ -115,57 +115,17 @@ function base_element(node, context) {
const is_doctype_node = node.name.toLowerCase() === '!doctype'; const is_doctype_node = node.name.toLowerCase() === '!doctype';
const is_self_closing = const is_self_closing =
is_void(node.name) || (node.type === 'Component' && node.fragment.nodes.length === 0); is_void(node.name) || (node.type === 'Component' && node.fragment.nodes.length === 0);
let multiline_content = false;
if (is_doctype_node) child_context.write(`>`); if (is_doctype_node) child_context.write(`>`);
else if (is_self_closing) { else if (is_self_closing) {
child_context.write(`${multiline_attributes ? '' : ' '}/>`); child_context.write(`${multiline_attributes ? '' : ' '}/>`);
} else { } else {
child_context.write('>'); child_context.write('>');
block(child_context, node.fragment, true);
// Process the element's content in a separate context for measurement
const content_context = child_context.new();
const allow_inline_content = child_context.measure() < LINE_BREAK_THRESHOLD;
block(content_context, node.fragment, allow_inline_content);
// Determine if content should be formatted on multiple lines
multiline_content = content_context.measure() > LINE_BREAK_THRESHOLD;
if (multiline_content) {
child_context.newline();
// Only indent if attributes are inline and content itself isn't already multiline
const should_indent = !multiline_attributes && !content_context.multiline;
if (should_indent) {
child_context.indent();
}
child_context.append(content_context);
if (should_indent) {
child_context.dedent();
}
child_context.newline();
} else {
child_context.append(content_context);
}
child_context.write(`</${node.name}>`); child_context.write(`</${node.name}>`);
} }
const break_line_after = child_context.measure() > LINE_BREAK_THRESHOLD;
if ((multiline_content || multiline_attributes) && !context.empty()) {
context.newline();
}
context.append(child_context); context.append(child_context);
if (is_self_closing) return;
if (multiline_content || multiline_attributes || break_line_after) {
context.newline();
}
} }
/** @type {Visitors<AST.SvelteNode>} */ /** @type {Visitors<AST.SvelteNode>} */
@ -412,6 +372,8 @@ const svelte_visitors = {
} }
} else { } else {
sequence.push(child_node); sequence.push(child_node);
if (child_node.type === 'RegularElement') flush();
} }
} }
@ -420,18 +382,20 @@ const svelte_visitors = {
let multiline = false; let multiline = false;
let width = 0; let width = 0;
const child_contexts = items.map((sequence) => { const child_contexts = items
const child_context = context.new(); .filter((x) => x.length > 0)
.map((sequence) => {
const child_context = context.new();
for (const node of sequence) { for (const node of sequence) {
child_context.visit(node); child_context.visit(node);
multiline ||= child_context.multiline; multiline ||= child_context.multiline;
} }
width += child_context.measure(); width += child_context.measure();
return child_context; return child_context;
}); });
multiline ||= width > LINE_BREAK_THRESHOLD; multiline ||= width > LINE_BREAK_THRESHOLD;

@ -4,4 +4,4 @@
</script> </script>
<Component> <Component>
<slot name="derived" slot="derived" /> <slot name="derived" slot="derived" />
</Component> </Component>

@ -3,4 +3,4 @@
let body; let body;
</script> </script>
<slot name="body"></slot> <slot name="body"></slot>

@ -1,2 +1,2 @@
<!-- @migration-task Error while migrating Svelte code: This migration would change the name of a slot (dashed-name to dashed_name) making the component unusable --> <!-- @migration-task Error while migrating Svelte code: This migration would change the name of a slot (dashed-name to dashed_name) making the component unusable -->
<slot name="dashed-name"></slot> <slot name="dashed-name"></slot>

@ -1 +1,8 @@
<script>import { setLocale } from '$lib/paraglide/runtime';import { m } from '$lib/paraglide/messages.js';</script><h1>{m.hello_world({ name: 'SvelteKit User' })}</h1><div><button onclick={() => setLocale('en')}>en</button><button onclick={() => setLocale('es')}>es</button></div><p>If you use VSCode, install the <a href="https://marketplace.visualstudio.com/items?itemName=inlang.vs-code-extension" target="_blank">Sherlock i18n extension</a>for a better i18n experience.</p> <script>import { setLocale } from '$lib/paraglide/runtime';import { m } from '$lib/paraglide/messages.js';</script>
<h1>{m.hello_world({ name: 'SvelteKit User' })}</h1><div><button onclick={() => setLocale('en')}>en</button><button onclick={() => setLocale('es')}>es</button></div><p>If you use VSCode, install the <a href="https://marketplace.visualstudio.com/items?itemName=inlang.vs-code-extension" target="_blank">Sherlock i18n extension</a>for a better i18n experience.</p>
<Component><div><button>Hello, this is a test</button><button>Hello, this is a test</button></div></Component>
<Component><button>Hello, this is a test</button><button>Hello, this is a test</button></Component>
<button class="foo bar" aria-label="click" onclick={() => console.log("clicked")}>Click me!</button>
<button class="foo bar" aria-label="click" onclick={() => console.log("clicked")}><span>some fancy looking</span><span>really long button text</span></button>

@ -4,18 +4,46 @@
</script> </script>
<h1>{m.hello_world({ name: 'SvelteKit User' })}</h1> <h1>{m.hello_world({ name: 'SvelteKit User' })}</h1>
<div> <div>
<button onclick={() => setLocale('en')}>en</button> <button onclick={() => setLocale('en')}>en</button>
<button onclick={() => setLocale('es')}>es</button> <button onclick={() => setLocale('es')}>es</button>
</div> </div>
<p> <p>
If you use VSCode, install the If you use VSCode, install the
<a <a
href="https://marketplace.visualstudio.com/items?itemName=inlang.vs-code-extension" href="https://marketplace.visualstudio.com/items?itemName=inlang.vs-code-extension"
target="_blank" target="_blank"
> >Sherlock i18n extension</a>
Sherlock i18n extension
</a>
for a better i18n experience. for a better i18n experience.
</p> </p>
<Component>
<div>
<button>Hello, this is a test</button>
<button>Hello, this is a test</button>
</div>
</Component>
<Component>
<button>Hello, this is a test</button>
<button>Hello, this is a test</button>
</Component>
<button
class="foo bar"
aria-label="click"
onclick={() => console.log("clicked")}
>Click me!</button>
<button
class="foo bar"
aria-label="click"
onclick={() => console.log("clicked")}
>
<span>some fancy looking</span>
<span>really long button text</span>
</button>

@ -1,12 +1,16 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta <meta
name="viewport" name="viewport"
content="width=device-width, initial-scale=1.0" content="width=device-width, initial-scale=1.0"
/> />
<title>Svelte App</title> <title>Svelte App</title>
</head> </head>
<body><div>Hello World</div></body> <body><div>Hello World</div></body>
</html> </html>

@ -1,8 +1,7 @@
<div style:color="red">...</div> <div style:color="red">...</div>
<div <div
style:color style:color
style:width="12rem" style:width="12rem"
style:background-color={darkMode ? 'black' : 'white'} style:background-color={darkMode ? 'black' : 'white'}
> >...</div>
...
</div>

@ -4,6 +4,7 @@
<Widget> <Widget>
<h1 slot="header">Hello</h1> <h1 slot="header">Hello</h1>
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<p>All rights reserved.</p> <p>All rights reserved.</p>
<p>Copyright (c) 2019 Svelte Industries</p> <p>Copyright (c) 2019 Svelte Industries</p>

@ -1,5 +1,6 @@
<svelte:head> <svelte:head>
<title>Hello world!</title> <title>Hello world!</title>
<meta <meta
name="description" name="description"
content="This is where the description goes for SEO" content="This is where the description goes for SEO"

@ -10,7 +10,6 @@ export default function Async_in_derived($$anchor, $$props) {
var $$promises = $.run([ var $$promises = $.run([
async () => yes1 = await $.async_derived(() => 1), async () => yes1 = await $.async_derived(() => 1),
async () => yes2 = await $.async_derived(async () => foo(await 1)), async () => yes2 = await $.async_derived(async () => foo(await 1)),
() => no1 = $.derived(async () => { () => no1 = $.derived(async () => {
return await 1; return await 1;
}), }),
@ -33,7 +32,6 @@ export default function Async_in_derived($$anchor, $$props) {
var promises = $.run([ var promises = $.run([
async () => yes1 = (await $.save($.async_derived(async () => (await $.save(1))())))(), async () => yes1 = (await $.save($.async_derived(async () => (await $.save(1))())))(),
async () => yes2 = (await $.save($.async_derived(async () => foo((await $.save(1))()))))(), async () => yes2 = (await $.save($.async_derived(async () => foo((await $.save(1))()))))(),
() => no1 = $.derived(() => (async () => { () => no1 = $.derived(() => (async () => {
return await 1; return await 1;
})()), })()),

@ -8,7 +8,6 @@ export default function Async_in_derived($$renderer, $$props) {
var $$promises = $$renderer.run([ var $$promises = $$renderer.run([
async () => yes1 = await 1, async () => yes1 = await 1,
async () => yes2 = foo(await 1), async () => yes2 = foo(await 1),
() => no1 = (async () => { () => no1 = (async () => {
return await 1; return await 1;
})(), })(),

@ -14,7 +14,6 @@ export default function Function_prop_no_getter($$anchor) {
onmousedown: () => $.set(count, $.get(count) + 1), onmousedown: () => $.set(count, $.get(count) + 1),
onmouseup, onmouseup,
onmouseenter: () => $.set(count, plusOne($.get(count)), true), onmouseenter: () => $.set(count, plusOne($.get(count)), true),
children: ($$anchor, $$slotProps) => { children: ($$anchor, $$slotProps) => {
$.next(); $.next();
@ -23,7 +22,6 @@ export default function Function_prop_no_getter($$anchor) {
$.template_effect(() => $.set_text(text, `clicks: ${$.get(count) ?? ''}`)); $.template_effect(() => $.set_text(text, `clicks: ${$.get(count) ?? ''}`));
$.append($$anchor, text); $.append($$anchor, text);
}, },
$$slots: { default: true } $$slots: { default: true }
}); });
} }

@ -13,11 +13,9 @@ export default function Function_prop_no_getter($$renderer) {
onmousedown: () => count += 1, onmousedown: () => count += 1,
onmouseup, onmouseup,
onmouseenter: () => count = plusOne(count), onmouseenter: () => count = plusOne(count),
children: ($$renderer) => { children: ($$renderer) => {
$$renderer.push(`<!---->clicks: ${$.escape(count)}`); $$renderer.push(`<!---->clicks: ${$.escape(count)}`);
}, },
$$slots: { default: true } $$slots: { default: true }
}); });
} }

@ -6,7 +6,6 @@ var root = $.from_tree(
[ [
['h1', null, 'hello'], ['h1', null, 'hello'],
' ', ' ',
[ [
'div', 'div',
{ class: 'potato' }, { class: 'potato' },

@ -96,8 +96,8 @@ importers:
specifier: ^1.2.1 specifier: ^1.2.1
version: 1.2.1 version: 1.2.1
esrap: esrap:
specifier: ^2.2.1 specifier: ^2.2.2
version: 2.2.1 version: 2.2.2
is-reference: is-reference:
specifier: ^3.0.3 specifier: ^3.0.3
version: 3.0.3 version: 3.0.3
@ -1356,8 +1356,8 @@ packages:
resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
engines: {node: '>=0.10'} engines: {node: '>=0.10'}
esrap@2.2.1: esrap@2.2.2:
resolution: {integrity: sha512-GiYWG34AN/4CUyaWAgunGt0Rxvr1PTMlGC0vvEov/uOQYWne2bpN03Um+k8jT+q3op33mKouP2zeJ6OlM+qeUg==} resolution: {integrity: sha512-zA6497ha+qKvoWIK+WM9NAh5ni17sKZKhbS5B3PoYbBvaYHZWoS33zmFybmyqpn07RLUxSmn+RCls2/XF+d0oQ==}
esrecurse@4.3.0: esrecurse@4.3.0:
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
@ -3720,7 +3720,7 @@ snapshots:
dependencies: dependencies:
estraverse: 5.3.0 estraverse: 5.3.0
esrap@2.2.1: esrap@2.2.2:
dependencies: dependencies:
'@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/sourcemap-codec': 1.5.0

Loading…
Cancel
Save