Skip to content

Commit 5d82573

Browse files
authored
fix: properly assign trailing comments (#12471)
* fix: properly assign trailing comments Trailing comments were added even if they started before the node end, which violates the definition of trailing comments. This fixes that, with the consequence that some comments no longer show up in the AST at all. Previously they were stuffed _somewhere_, but arguably at the wrong positions. For example the last comment in a function body got assigned as a trailing comma for the body, which is wrong, because the body ends _after_ the comma. The special case is comments at the end of an expression tag - they are added even if there are multiple, and they are added regardless of whether they are separated by newlines or not. This ensures the expression tag end is calculated correctly. Fixes #12466 * support multiple trailing comments after last statement in a body * simplify, handle object and array expressions
1 parent 48c5503 commit 5d82573

File tree

4 files changed

+513
-80
lines changed

4 files changed

+513
-80
lines changed

.changeset/fast-toes-act.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: properly assign trailing comments

packages/svelte/src/compiler/phases/1-parse/acorn.js

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,18 +104,42 @@ function get_comment_handlers(source) {
104104
next();
105105

106106
if (comments[0]) {
107-
const parent = path.at(-1);
107+
const parent = /** @type {any} */ (path.at(-1));
108+
108109
if (parent === undefined || node.end !== parent.end) {
109110
const slice = source.slice(node.end, comments[0].start);
110-
111-
if (/^[,) \t]*$/.test(slice)) {
111+
const is_last_in_body =
112+
((parent?.type === 'BlockStatement' || parent?.type === 'Program') &&
113+
parent.body.indexOf(node) === parent.body.length - 1) ||
114+
(parent?.type === 'ArrayExpression' &&
115+
parent.elements.indexOf(node) === parent.elements.length - 1) ||
116+
(parent?.type === 'ObjectExpression' &&
117+
parent.properties.indexOf(node) === parent.properties.length - 1);
118+
119+
if (is_last_in_body) {
120+
// Special case: There can be multiple trailing comments after the last node in a block,
121+
// and they can be separated by newlines
122+
let end = node.end;
123+
124+
while (comments.length) {
125+
const comment = comments[0];
126+
if (parent && comment.start >= parent.end) break;
127+
128+
(node.trailingComments ||= []).push(comment);
129+
comments.shift();
130+
end = comment.end;
131+
}
132+
} else if (node.end <= comments[0].start && /^[,) \t]*$/.test(slice)) {
112133
node.trailingComments = [/** @type {CommentWithLocation} */ (comments.shift())];
113134
}
114135
}
115136
}
116137
}
117138
});
118-
if (comments.length > 0) {
139+
140+
// Special case: Trailing comments after the root node (which can only happen for expression tags or for Program nodes).
141+
// Adding them ensures that we can later detect the end of the expression tag correctly.
142+
if (comments.length > 0 && (comments[0].start >= ast.end || ast.type === 'Program')) {
119143
(ast.trailingComments ||= []).push(...comments.splice(0));
120144
}
121145
}

packages/svelte/tests/parser-legacy/samples/javascript-comments/input.svelte

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,37 @@
55
66
/** a comment */
77
function asd() {
8-
8+
foo; // trailing
9+
/* leading comment 1 */
10+
/* leading comment 2 */
11+
/* leading comment 3 */
12+
bar;
13+
/* trailing comment 1 */
14+
/* trailing comment 2 */
15+
/* trailing comment 3 */
916
}
17+
18+
const array = [
19+
// leading comment 1
20+
// leading comment 2
21+
1, // trailing comment 1
22+
/* trailing comment 2 */
23+
];
24+
25+
const object = {
26+
// leading comment 1
27+
// leading comment 2
28+
a: 1, // trailing comment 1
29+
/* trailing comment 2 */
30+
};
1031
</script>
1132

1233
<button
1334
on:click={// comment
1435
() => {
1536
/* another comment */
16-
fn();
37+
fn(); // a trailing comment
38+
/* trailing block comment */
1739
}}
1840
>
1941
{/* leading block comment */ a}

0 commit comments

Comments
 (0)