slightly nicer printing

print
Rich Harris 3 months ago
parent 80370e3a26
commit 4538f80259

@ -16,6 +16,29 @@ export function print(ast) {
}); });
} }
/**
* @param {Context} context
* @param {AST.SvelteNode} node
*/
function block(context, node, allow_inline = false) {
const child_context = context.new();
child_context.visit(node);
if (child_context.empty()) {
return;
}
if (allow_inline && !child_context.multiline) {
context.append(child_context);
} else {
context.indent();
context.newline();
context.append(child_context);
context.dedent();
context.newline();
}
}
/** @type {Visitors<AST.SvelteNode>} */ /** @type {Visitors<AST.SvelteNode>} */
const visitors = { const visitors = {
Root(node, context) { Root(node, context) {
@ -54,81 +77,100 @@ const visitors = {
} }
context.write('>'); context.write('>');
block(context, node.content);
context.indent();
context.newline();
context.visit(node.content);
context.dedent();
context.newline();
context.write('</script>'); context.write('</script>');
}, },
Fragment(node, context) { Fragment(node, context) {
const join = context.new(); /** @type {AST.SvelteNode[][]} */
const items = [];
/** @type {Context[]} */ /** @type {AST.SvelteNode[]} */
const contexts = []; let sequence = [];
let sequence = context.new(); const flush = () => {
items.push(sequence);
let multiline = false; sequence = [];
};
function flush() {
if (sequence.empty()) {
return;
}
contexts.push(sequence);
sequence = context.new();
}
for (let i = 0; i < node.nodes.length; i += 1) { for (let i = 0; i < node.nodes.length; i += 1) {
const child_node = node.nodes[i]; let child_node = node.nodes[i];
const prev = node.nodes[i - 1]; const prev = node.nodes[i - 1];
const next = node.nodes[i + 1]; const next = node.nodes[i + 1];
const prev_is_text = prev && (prev.type === 'Text' || prev.type === 'ExpressionTag'); if (child_node.type === 'Text') {
const next_is_text = next && (next.type === 'Text' || next.type === 'ExpressionTag'); child_node = { ...child_node }; // always clone, so we can safely mutate
child_node.data = child_node.data.replace(/[^\S]+/g, ' ');
// trim fragment
if (i === 0) {
child_node.data = child_node.data.trimStart();
}
if (i === node.nodes.length - 1) {
child_node.data = child_node.data.trimEnd();
}
if (child_node.type === 'Text' || child_node.type === 'ExpressionTag') { if (child_node.data === '') {
if (child_node.type === 'Text') { continue;
let { data } = child_node; }
if (child_node.data.startsWith(' ') && prev && prev.type !== 'ExpressionTag') {
flush();
child_node.data = child_node.data.trimStart();
}
let a = !prev_is_text && data !== (data = data.trimStart()); if (child_node.data !== '') {
let b = !next_is_text && data !== (data = data.trimEnd()); sequence.push({ ...child_node, data: child_node.data });
if (data === '') { if (child_node.data.endsWith(' ') && next && next.type !== 'ExpressionTag') {
if (prev && next) sequence.append(join); flush();
} else { child_node.data = child_node.data.trimStart();
if (a && prev) sequence.append(join);
sequence.write(data);
if (b && next) sequence.append(join);
} }
} else {
sequence.visit(child_node);
} }
} else { } else {
flush(); sequence.push(child_node);
const child_context = context.new(); }
child_context.visit(child_node); }
flush();
let multiline = false;
let width = 0;
contexts.push(child_context); const child_contexts = items.map((sequence) => {
const child_context = context.new();
for (const node of sequence) {
child_context.visit(node);
multiline ||= child_context.multiline; multiline ||= child_context.multiline;
} }
}
flush(); width += child_context.measure();
if (multiline) { return child_context;
join.newline(); });
} else {
join.write(' '); multiline ||= width > 30;
}
for (let i = 0; i < child_contexts.length; i += 1) {
const prev = child_contexts[i];
const next = child_contexts[i + 1];
context.append(prev);
for (const child_context of contexts) { if (next) {
context.append(child_context); if (prev.multiline || next.multiline) {
context.margin();
context.newline();
} else if (multiline) {
context.newline();
} else {
context.write(' ');
}
}
} }
}, },
@ -192,7 +234,7 @@ const visitors = {
if (node.pending) { if (node.pending) {
context.write('}'); context.write('}');
context.visit(node.pending); block(context, node.pending);
context.write('{:'); context.write('{:');
} else { } else {
context.write(' '); context.write(' ');
@ -202,7 +244,8 @@ const visitors = {
context.write(node.value ? 'then ' : 'then'); context.write(node.value ? 'then ' : 'then');
if (node.value) context.visit(node.value); if (node.value) context.visit(node.value);
context.write('}'); context.write('}');
context.visit(node.then);
block(context, node.then);
if (node.catch) { if (node.catch) {
context.write('{:'); context.write('{:');
@ -213,7 +256,8 @@ const visitors = {
context.write(node.value ? 'catch ' : 'catch'); context.write(node.value ? 'catch ' : 'catch');
if (node.error) context.visit(node.error); if (node.error) context.visit(node.error);
context.write('}'); context.write('}');
context.visit(node.catch);
block(context, node.catch);
} }
context.write('{/await}'); context.write('{/await}');
@ -303,7 +347,7 @@ const visitors = {
if (node.fragment.nodes.length > 0) { if (node.fragment.nodes.length > 0) {
context.write('>'); context.write('>');
context.visit(node.fragment); block(context, node.fragment, true);
context.write(`</${node.name}>`); context.write(`</${node.name}>`);
} else { } else {
context.write(' />'); context.write(' />');
@ -353,7 +397,8 @@ const visitors = {
} }
context.write('}'); context.write('}');
context.visit(node.body);
block(context, node.body);
if (node.fallback) { if (node.fallback) {
context.write('{:else}'); context.write('{:else}');
@ -381,21 +426,13 @@ const visitors = {
context.visit(node.test); context.visit(node.test);
context.write('}'); context.write('}');
context.indent(); block(context, node.consequent);
context.newline();
context.visit(node.consequent);
context.dedent();
context.newline();
} else { } else {
context.write('{#if '); context.write('{#if ');
context.visit(node.test); context.visit(node.test);
context.write('}'); context.write('}');
context.indent(); block(context, node.consequent);
context.newline();
context.visit(node.consequent);
context.dedent();
context.newline();
} }
if (node.alternate !== null) { if (node.alternate !== null) {
@ -409,11 +446,7 @@ const visitors = {
context.write('{:else}'); context.write('{:else}');
} }
context.indent(); block(context, node.alternate);
context.newline();
context.visit(node.alternate);
context.dedent();
context.newline();
} }
if (!node.elseif) { if (!node.elseif) {
@ -425,7 +458,7 @@ const visitors = {
context.write('{#key '); context.write('{#key ');
context.visit(node.expression); context.visit(node.expression);
context.write('}'); context.write('}');
context.visit(node.fragment); block(context, node.fragment);
context.write('{/key}'); context.write('{/key}');
}, },
@ -487,24 +520,28 @@ const visitors = {
}, },
RegularElement(node, context) { RegularElement(node, context) {
context.write('<' + node.name); const child_context = context.new();
child_context.write('<' + node.name);
for (const attribute of node.attributes) { for (const attribute of node.attributes) {
// TODO handle multiline // TODO handle multiline
context.write(' '); child_context.write(' ');
context.visit(attribute); child_context.visit(attribute);
} }
if (is_void(node.name)) { if (is_void(node.name)) {
context.write(' />'); child_context.write(' />');
} else { } else {
context.write('>'); child_context.write('>');
if (node.fragment) { if (node.fragment) {
context.visit(node.fragment); block(child_context, node.fragment, child_context.measure() < 30);
context.write(`</${node.name}>`); child_context.write(`</${node.name}>`);
} }
} }
context.append(child_context);
}, },
RelativeSelector(node, context) { RelativeSelector(node, context) {
@ -566,7 +603,7 @@ const visitors = {
if (node.fragment.nodes.length > 0) { if (node.fragment.nodes.length > 0) {
context.write('>'); context.write('>');
context.visit(node.fragment); context.visit(node.fragment); // TODO block/inline
context.write('</slot>'); context.write('</slot>');
} else { } else {
context.write(' />'); context.write(' />');
@ -589,7 +626,7 @@ const visitors = {
} }
context.write(')}'); context.write(')}');
context.visit(node.body); block(context, node.body);
context.write('{/snippet}'); context.write('{/snippet}');
}, },
@ -658,7 +695,7 @@ const visitors = {
if (node.fragment) { if (node.fragment) {
context.write('>'); context.write('>');
context.visit(node.fragment); block(context, node.fragment, true);
context.write(`</svelte:boundary>`); context.write(`</svelte:boundary>`);
} else { } else {
context.write('/>'); context.write('/>');
@ -680,7 +717,7 @@ const visitors = {
if (node.fragment) { if (node.fragment) {
context.write('>'); context.write('>');
context.visit(node.fragment); block(context, node.fragment, true);
context.write(`</svelte:component>`); context.write(`</svelte:component>`);
} else { } else {
context.write('/>'); context.write('/>');
@ -698,7 +735,7 @@ const visitors = {
if (node.fragment) { if (node.fragment) {
context.write('>'); context.write('>');
context.visit(node.fragment); block(context, node.fragment, true);
context.write(`</svelte:document>`); context.write(`</svelte:document>`);
} else { } else {
context.write('/>'); context.write('/>');
@ -720,7 +757,7 @@ const visitors = {
if (node.fragment) { if (node.fragment) {
context.write('>'); context.write('>');
context.visit(node.fragment); block(context, node.fragment, true);
context.write(`</svelte:element>`); context.write(`</svelte:element>`);
} else { } else {
context.write('/>'); context.write('/>');
@ -738,7 +775,7 @@ const visitors = {
if (node.fragment) { if (node.fragment) {
context.write('>'); context.write('>');
context.visit(node.fragment); block(context, node.fragment, true);
context.write(`</svelte:fragment>`); context.write(`</svelte:fragment>`);
} else { } else {
context.write('/>'); context.write('/>');
@ -756,7 +793,7 @@ const visitors = {
if (node.fragment) { if (node.fragment) {
context.write('>'); context.write('>');
context.visit(node.fragment); block(context, node.fragment, true);
context.write(`</svelte:head>`); context.write(`</svelte:head>`);
} else { } else {
context.write('/>'); context.write('/>');
@ -774,7 +811,7 @@ const visitors = {
if (node.fragment) { if (node.fragment) {
context.write('>'); context.write('>');
context.visit(node.fragment); block(context, node.fragment, true);
context.write(`</svelte:self>`); context.write(`</svelte:self>`);
} else { } else {
context.write('/>'); context.write('/>');
@ -792,7 +829,7 @@ const visitors = {
if (node.fragment) { if (node.fragment) {
context.write('>'); context.write('>');
context.visit(node.fragment); block(context, node.fragment, true);
context.write(`</svelte:window>`); context.write(`</svelte:window>`);
} else { } else {
context.write('/>'); context.write('/>');

@ -87,23 +87,23 @@ function clean(ast: AST.SvelteNode) {
let child = node.nodes[i]; let child = node.nodes[i];
if (child.type === 'Text') { if (child.type === 'Text') {
child = {
...child,
data: child.data.replace(/[^\S]+/g, ' '),
raw: child.raw.replace(/[^\S]+/g, ' ')
};
if (i === 0) { if (i === 0) {
child = { child.data = child.data.trimStart();
...child, child.raw = child.raw.trimStart();
data: child.data.trimStart(),
raw: child.raw.trimStart()
};
} }
if (i === node.nodes.length - 1) { if (i === node.nodes.length - 1) {
child = { child.data = child.data.trimEnd();
...child, child.raw = child.raw.trimEnd();
data: child.data.trimEnd(),
raw: child.raw.trimEnd()
};
} }
if (!child.data) continue; if (child.data === '') continue;
} }
nodes.push(context.visit(child)); nodes.push(context.visit(child));

Loading…
Cancel
Save