fix: preserve whitespace after inline elements when printing (#18685)

Fixes #18683.

The printer previously trimmed leading whitespace after an inline
element and failed to replace it when the fragment stayed on one line.
Track that whitespace while grouping fragment nodes and emit a space for
inline output, while retaining newline-based separation for multiline
output.

Adds regression coverage for whitespace following an inline element and
updates existing print snapshots that exposed the same behavior.
pull/17306/merge
svelte-triage-bot[bot] 3 days ago committed by GitHub
parent 3b559bbf96
commit a6153f1d2a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: preserve whitespace after inline elements when printing

@ -587,15 +587,19 @@ const svelte_visitors = (comments, state) => ({
last?.type === 'Text' &&
/\s$/.test(last.data);
/** @type {AST.SvelteNode[][]} */
/** @type {{ nodes: AST.SvelteNode[]; leading_whitespace: boolean }[]} */
const items = [];
/** @type {AST.SvelteNode[]} */
let sequence = [];
let leading_whitespace = false;
const flush = () => {
items.push(sequence);
sequence = [];
if (sequence.length > 0) {
items.push({ nodes: sequence, leading_whitespace });
sequence = [];
leading_whitespace = false;
}
};
for (let i = 0; i < node.nodes.length; i += 1) {
@ -624,6 +628,7 @@ const svelte_visitors = (comments, state) => ({
if (child_node.data.startsWith(' ') && prev && prev.type !== 'ExpressionTag') {
flush();
leading_whitespace = true;
child_node.data = child_node.data.trimStart();
}
@ -662,20 +667,18 @@ const svelte_visitors = (comments, state) => ({
let multiline = false;
let width = 0;
const child_contexts = items
.filter((x) => x.length > 0)
.map((sequence) => {
const child_context = context.new();
const child_contexts = items.map(({ nodes, leading_whitespace }) => {
const child_context = context.new();
for (const node of sequence) {
child_context.visit(node);
multiline ||= child_context.multiline;
}
for (const node of nodes) {
child_context.visit(node);
multiline ||= child_context.multiline;
}
width += child_context.measure();
width += child_context.measure() + (leading_whitespace ? 1 : 0);
return child_context;
});
return { context: child_context, leading_whitespace };
});
multiline ||= width > LINE_BREAK_THRESHOLD;
// Normally context.newline() also makes context.multiline true, but the below loop only
@ -687,14 +690,16 @@ const svelte_visitors = (comments, state) => ({
const prev = child_contexts[i];
const next = child_contexts[i + 1];
context.append(prev);
context.append(prev.context);
if (next) {
if (prev.multiline || next.multiline) {
if (prev.context.multiline || next.context.multiline) {
context.margin();
context.newline();
} else if (multiline) {
context.newline();
} else if (next.leading_whitespace) {
context.write(' ');
}
}
}

@ -1,3 +1,3 @@
<!-- inline --><!--
<!-- inline --> <!--
multiline
-->

@ -1 +1 @@
<span>{name}</span><span>{count + 1}</span>
<span>{name}</span> <span>{count + 1}</span>

@ -1 +1 @@
<div><a href="/foo">bar</a></div><br />
<div><a href="/foo">bar</a></div> <br />

Loading…
Cancel
Save