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
pull/12487/head
Simon H 4 months ago committed by GitHub
parent 48c5503b53
commit 5d82573dcd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: properly assign trailing comments

@ -104,18 +104,42 @@ function get_comment_handlers(source) {
next(); next();
if (comments[0]) { if (comments[0]) {
const parent = path.at(-1); const parent = /** @type {any} */ (path.at(-1));
if (parent === undefined || node.end !== parent.end) { if (parent === undefined || node.end !== parent.end) {
const slice = source.slice(node.end, comments[0].start); const slice = source.slice(node.end, comments[0].start);
const is_last_in_body =
if (/^[,) \t]*$/.test(slice)) { ((parent?.type === 'BlockStatement' || parent?.type === 'Program') &&
parent.body.indexOf(node) === parent.body.length - 1) ||
(parent?.type === 'ArrayExpression' &&
parent.elements.indexOf(node) === parent.elements.length - 1) ||
(parent?.type === 'ObjectExpression' &&
parent.properties.indexOf(node) === parent.properties.length - 1);
if (is_last_in_body) {
// Special case: There can be multiple trailing comments after the last node in a block,
// and they can be separated by newlines
let end = node.end;
while (comments.length) {
const comment = comments[0];
if (parent && comment.start >= parent.end) break;
(node.trailingComments ||= []).push(comment);
comments.shift();
end = comment.end;
}
} else if (node.end <= comments[0].start && /^[,) \t]*$/.test(slice)) {
node.trailingComments = [/** @type {CommentWithLocation} */ (comments.shift())]; node.trailingComments = [/** @type {CommentWithLocation} */ (comments.shift())];
} }
} }
} }
} }
}); });
if (comments.length > 0) {
// Special case: Trailing comments after the root node (which can only happen for expression tags or for Program nodes).
// Adding them ensures that we can later detect the end of the expression tag correctly.
if (comments.length > 0 && (comments[0].start >= ast.end || ast.type === 'Program')) {
(ast.trailingComments ||= []).push(...comments.splice(0)); (ast.trailingComments ||= []).push(...comments.splice(0));
} }
} }

@ -5,15 +5,37 @@
/** a comment */ /** a comment */
function asd() { function asd() {
foo; // trailing
/* leading comment 1 */
/* leading comment 2 */
/* leading comment 3 */
bar;
/* trailing comment 1 */
/* trailing comment 2 */
/* trailing comment 3 */
} }
const array = [
// leading comment 1
// leading comment 2
1, // trailing comment 1
/* trailing comment 2 */
];
const object = {
// leading comment 1
// leading comment 2
a: 1, // trailing comment 1
/* trailing comment 2 */
};
</script> </script>
<button <button
on:click={// comment on:click={// comment
() => { () => {
/* another comment */ /* another comment */
fn(); fn(); // a trailing comment
/* trailing block comment */
}} }}
> >
{/* leading block comment */ a} {/* leading block comment */ a}

@ -1,39 +1,39 @@
{ {
"html": { "html": {
"type": "Fragment", "type": "Fragment",
"start": 133, "start": 565,
"end": 341, "end": 826,
"children": [ "children": [
{ {
"type": "Text", "type": "Text",
"start": 131, "start": 563,
"end": 133, "end": 565,
"raw": "\n\n", "raw": "\n\n",
"data": "\n\n" "data": "\n\n"
}, },
{ {
"type": "Element", "type": "Element",
"start": 133, "start": 565,
"end": 251, "end": 736,
"name": "button", "name": "button",
"attributes": [ "attributes": [
{ {
"start": 142, "start": 574,
"end": 207, "end": 692,
"type": "EventHandler", "type": "EventHandler",
"name": "click", "name": "click",
"modifiers": [], "modifiers": [],
"expression": { "expression": {
"type": "ArrowFunctionExpression", "type": "ArrowFunctionExpression",
"start": 164, "start": 596,
"end": 206, "end": 691,
"loc": { "loc": {
"start": { "start": {
"line": 14, "line": 35,
"column": 1 "column": 1
}, },
"end": { "end": {
"line": 17, "line": 39,
"column": 2 "column": 2
} }
}, },
@ -44,58 +44,58 @@
"params": [], "params": [],
"body": { "body": {
"type": "BlockStatement", "type": "BlockStatement",
"start": 170, "start": 602,
"end": 206, "end": 691,
"loc": { "loc": {
"start": { "start": {
"line": 14, "line": 35,
"column": 7 "column": 7
}, },
"end": { "end": {
"line": 17, "line": 39,
"column": 2 "column": 2
} }
}, },
"body": [ "body": [
{ {
"type": "ExpressionStatement", "type": "ExpressionStatement",
"start": 198, "start": 630,
"end": 203, "end": 635,
"loc": { "loc": {
"start": { "start": {
"line": 16, "line": 37,
"column": 2 "column": 2
}, },
"end": { "end": {
"line": 16, "line": 37,
"column": 7 "column": 7
} }
}, },
"expression": { "expression": {
"type": "CallExpression", "type": "CallExpression",
"start": 198, "start": 630,
"end": 202, "end": 634,
"loc": { "loc": {
"start": { "start": {
"line": 16, "line": 37,
"column": 2 "column": 2
}, },
"end": { "end": {
"line": 16, "line": 37,
"column": 6 "column": 6
} }
}, },
"callee": { "callee": {
"type": "Identifier", "type": "Identifier",
"start": 198, "start": 630,
"end": 200, "end": 632,
"loc": { "loc": {
"start": { "start": {
"line": 16, "line": 37,
"column": 2 "column": 2
}, },
"end": { "end": {
"line": 16, "line": 37,
"column": 4 "column": 4
} }
}, },
@ -108,8 +108,22 @@
{ {
"type": "Block", "type": "Block",
"value": " another comment ", "value": " another comment ",
"start": 174, "start": 606,
"end": 195 "end": 627
}
],
"trailingComments": [
{
"type": "Line",
"value": " a trailing comment",
"start": 636,
"end": 657
},
{
"type": "Block",
"value": " trailing block comment ",
"start": 660,
"end": 688
} }
] ]
} }
@ -119,8 +133,8 @@
{ {
"type": "Line", "type": "Line",
"value": " comment", "value": " comment",
"start": 152, "start": 584,
"end": 162 "end": 594
} }
] ]
} }
@ -129,26 +143,26 @@
"children": [ "children": [
{ {
"type": "Text", "type": "Text",
"start": 209, "start": 694,
"end": 210, "end": 695,
"raw": "\n", "raw": "\n",
"data": "\n" "data": "\n"
}, },
{ {
"type": "MustacheTag", "type": "MustacheTag",
"start": 210, "start": 695,
"end": 241, "end": 726,
"expression": { "expression": {
"type": "Identifier", "type": "Identifier",
"start": 239, "start": 724,
"end": 240, "end": 725,
"loc": { "loc": {
"start": { "start": {
"line": 19, "line": 41,
"column": 29 "column": 29
}, },
"end": { "end": {
"line": 19, "line": 41,
"column": 30 "column": 30
} }
}, },
@ -157,16 +171,16 @@
{ {
"type": "Block", "type": "Block",
"value": " leading block comment ", "value": " leading block comment ",
"start": 211, "start": 696,
"end": 238 "end": 723
} }
] ]
} }
}, },
{ {
"type": "Text", "type": "Text",
"start": 241, "start": 726,
"end": 242, "end": 727,
"raw": "\n", "raw": "\n",
"data": "\n" "data": "\n"
} }
@ -174,40 +188,40 @@
}, },
{ {
"type": "Text", "type": "Text",
"start": 251, "start": 736,
"end": 252, "end": 737,
"raw": "\n", "raw": "\n",
"data": "\n" "data": "\n"
}, },
{ {
"type": "MustacheTag", "type": "MustacheTag",
"start": 252, "start": 737,
"end": 341, "end": 826,
"expression": { "expression": {
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 279, "start": 764,
"end": 284, "end": 769,
"loc": { "loc": {
"start": { "start": {
"line": 22, "line": 44,
"column": 1 "column": 1
}, },
"end": { "end": {
"line": 22, "line": 44,
"column": 6 "column": 6
} }
}, },
"left": { "left": {
"type": "Identifier", "type": "Identifier",
"start": 279, "start": 764,
"end": 280, "end": 765,
"loc": { "loc": {
"start": { "start": {
"line": 22, "line": 44,
"column": 1 "column": 1
}, },
"end": { "end": {
"line": 22, "line": 44,
"column": 2 "column": 2
} }
}, },
@ -216,15 +230,15 @@
"operator": "+", "operator": "+",
"right": { "right": {
"type": "Identifier", "type": "Identifier",
"start": 283, "start": 768,
"end": 284, "end": 769,
"loc": { "loc": {
"start": { "start": {
"line": 22, "line": 44,
"column": 5 "column": 5
}, },
"end": { "end": {
"line": 22, "line": 44,
"column": 6 "column": 6
} }
}, },
@ -234,22 +248,22 @@
{ {
"type": "Line", "type": "Line",
"value": " leading line comment", "value": " leading line comment",
"start": 254, "start": 739,
"end": 277 "end": 762
} }
], ],
"trailingComments": [ "trailingComments": [
{ {
"type": "Line", "type": "Line",
"value": " trailing line comment", "value": " trailing line comment",
"start": 285, "start": 770,
"end": 309 "end": 794
}, },
{ {
"type": "Block", "type": "Block",
"value": " trailing block comment ", "value": " trailing block comment ",
"start": 311, "start": 796,
"end": 339 "end": 824
} }
] ]
} }
@ -259,19 +273,19 @@
"instance": { "instance": {
"type": "Script", "type": "Script",
"start": 0, "start": 0,
"end": 131, "end": 563,
"context": "default", "context": "default",
"content": { "content": {
"type": "Program", "type": "Program",
"start": 8, "start": 8,
"end": 122, "end": 554,
"loc": { "loc": {
"start": { "start": {
"line": 1, "line": 1,
"column": 0 "column": 0
}, },
"end": { "end": {
"line": 10, "line": 31,
"column": 0 "column": 0
} }
}, },
@ -427,14 +441,14 @@
{ {
"type": "FunctionDeclaration", "type": "FunctionDeclaration",
"start": 101, "start": 101,
"end": 121, "end": 305,
"loc": { "loc": {
"start": { "start": {
"line": 7, "line": 7,
"column": 1 "column": 1
}, },
"end": { "end": {
"line": 9, "line": 16,
"column": 2 "column": 2
} }
}, },
@ -461,18 +475,129 @@
"body": { "body": {
"type": "BlockStatement", "type": "BlockStatement",
"start": 116, "start": 116,
"end": 121, "end": 305,
"loc": { "loc": {
"start": { "start": {
"line": 7, "line": 7,
"column": 16 "column": 16
}, },
"end": { "end": {
"line": 9, "line": 16,
"column": 2 "column": 2
} }
}, },
"body": [] "body": [
{
"type": "ExpressionStatement",
"start": 120,
"end": 124,
"loc": {
"start": {
"line": 8,
"column": 2
},
"end": {
"line": 8,
"column": 6
}
},
"expression": {
"type": "Identifier",
"start": 120,
"end": 123,
"loc": {
"start": {
"line": 8,
"column": 2
},
"end": {
"line": 8,
"column": 5
}
},
"name": "foo"
},
"trailingComments": [
{
"type": "Line",
"value": " trailing",
"start": 125,
"end": 136
}
]
},
{
"type": "ExpressionStatement",
"start": 217,
"end": 221,
"loc": {
"start": {
"line": 12,
"column": 2
},
"end": {
"line": 12,
"column": 6
}
},
"expression": {
"type": "Identifier",
"start": 217,
"end": 220,
"loc": {
"start": {
"line": 12,
"column": 2
},
"end": {
"line": 12,
"column": 5
}
},
"name": "bar"
},
"leadingComments": [
{
"type": "Block",
"value": " leading comment 1 ",
"start": 139,
"end": 162
},
{
"type": "Block",
"value": " leading comment 2 ",
"start": 165,
"end": 188
},
{
"type": "Block",
"value": " leading comment 3 ",
"start": 191,
"end": 214
}
],
"trailingComments": [
{
"type": "Block",
"value": " trailing comment 1 ",
"start": 224,
"end": 248
},
{
"type": "Block",
"value": " trailing comment 2 ",
"start": 251,
"end": 275
},
{
"type": "Block",
"value": " trailing comment 3 ",
"start": 278,
"end": 302
}
]
}
]
}, },
"leadingComments": [ "leadingComments": [
{ {
@ -482,6 +607,263 @@
"end": 99 "end": 99
} }
] ]
},
{
"type": "VariableDeclaration",
"start": 308,
"end": 427,
"loc": {
"start": {
"line": 18,
"column": 1
},
"end": {
"line": 23,
"column": 3
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 314,
"end": 426,
"loc": {
"start": {
"line": 18,
"column": 7
},
"end": {
"line": 23,
"column": 2
}
},
"id": {
"type": "Identifier",
"start": 314,
"end": 319,
"loc": {
"start": {
"line": 18,
"column": 7
},
"end": {
"line": 18,
"column": 12
}
},
"name": "array"
},
"init": {
"type": "ArrayExpression",
"start": 322,
"end": 426,
"loc": {
"start": {
"line": 18,
"column": 15
},
"end": {
"line": 23,
"column": 2
}
},
"elements": [
{
"type": "Literal",
"start": 372,
"end": 373,
"loc": {
"start": {
"line": 21,
"column": 2
},
"end": {
"line": 21,
"column": 3
}
},
"value": 1,
"raw": "1",
"leadingComments": [
{
"type": "Line",
"value": " leading comment 1",
"start": 326,
"end": 346
},
{
"type": "Line",
"value": " leading comment 2",
"start": 349,
"end": 369
}
],
"trailingComments": [
{
"type": "Line",
"value": " trailing comment 1",
"start": 375,
"end": 396
},
{
"type": "Block",
"value": " trailing comment 2 ",
"start": 399,
"end": 423
}
]
}
]
}
}
],
"kind": "const"
},
{
"type": "VariableDeclaration",
"start": 430,
"end": 553,
"loc": {
"start": {
"line": 25,
"column": 1
},
"end": {
"line": 30,
"column": 3
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 436,
"end": 552,
"loc": {
"start": {
"line": 25,
"column": 7
},
"end": {
"line": 30,
"column": 2
}
},
"id": {
"type": "Identifier",
"start": 436,
"end": 442,
"loc": {
"start": {
"line": 25,
"column": 7
},
"end": {
"line": 25,
"column": 13
}
},
"name": "object"
},
"init": {
"type": "ObjectExpression",
"start": 445,
"end": 552,
"loc": {
"start": {
"line": 25,
"column": 16
},
"end": {
"line": 30,
"column": 2
}
},
"properties": [
{
"type": "Property",
"start": 495,
"end": 499,
"loc": {
"start": {
"line": 28,
"column": 2
},
"end": {
"line": 28,
"column": 6
}
},
"method": false,
"shorthand": false,
"computed": false,
"key": {
"type": "Identifier",
"start": 495,
"end": 496,
"loc": {
"start": {
"line": 28,
"column": 2
},
"end": {
"line": 28,
"column": 3
}
},
"name": "a"
},
"value": {
"type": "Literal",
"start": 498,
"end": 499,
"loc": {
"start": {
"line": 28,
"column": 5
},
"end": {
"line": 28,
"column": 6
}
},
"value": 1,
"raw": "1"
},
"kind": "init",
"leadingComments": [
{
"type": "Line",
"value": " leading comment 1",
"start": 449,
"end": 469
},
{
"type": "Line",
"value": " leading comment 2",
"start": 472,
"end": 492
}
],
"trailingComments": [
{
"type": "Line",
"value": " trailing comment 1",
"start": 501,
"end": 522
},
{
"type": "Block",
"value": " trailing comment 2 ",
"start": 525,
"end": 549
}
]
}
]
}
}
],
"kind": "const"
} }
], ],
"sourceType": "module" "sourceType": "module"

Loading…
Cancel
Save