From 81ed425b5ae607c781d4a22e113940ba3c5857f7 Mon Sep 17 00:00:00 2001 From: BlueGreenMagick Date: Mon, 15 Jul 2024 17:19:06 +0900 Subject: [PATCH] fix: allow leading and trailing comments in mustache tag (#11866) Fixes #7456 --------- Co-authored-by: Rich Harris --- .changeset/fresh-wombats-learn.md | 5 + .../svelte/scripts/process-messages/index.js | 5 + .../src/compiler/phases/1-parse/acorn.js | 15 +- .../phases/1-parse/read/expression.js | 4 + .../src/compiler/phases/1-parse/state/tag.js | 7 +- .../samples/javascript-comments/input.svelte | 11 +- .../samples/javascript-comments/output.json | 312 ++++++++++++++---- 7 files changed, 292 insertions(+), 67 deletions(-) create mode 100644 .changeset/fresh-wombats-learn.md diff --git a/.changeset/fresh-wombats-learn.md b/.changeset/fresh-wombats-learn.md new file mode 100644 index 0000000000..838d3bace5 --- /dev/null +++ b/.changeset/fresh-wombats-learn.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: allow leading and trailing comments in mustache expression diff --git a/packages/svelte/scripts/process-messages/index.js b/packages/svelte/scripts/process-messages/index.js index ea0a40c496..5eea56fa04 100644 --- a/packages/svelte/scripts/process-messages/index.js +++ b/packages/svelte/scripts/process-messages/index.js @@ -129,6 +129,11 @@ function transform(name, dest) { } }); + if (comments.length > 0) { + // @ts-expect-error + (ast.trailingComments ||= []).push(...comments); + } + const category = messages[name]; // find the `export function CODE` node diff --git a/packages/svelte/src/compiler/phases/1-parse/acorn.js b/packages/svelte/src/compiler/phases/1-parse/acorn.js index 432fa8f920..071e39421f 100644 --- a/packages/svelte/src/compiler/phases/1-parse/acorn.js +++ b/packages/svelte/src/compiler/phases/1-parse/acorn.js @@ -30,6 +30,7 @@ export function parse(source, typescript) { * @param {string} source * @param {boolean} typescript * @param {number} index + * @returns {acorn.Expression & { leadingComments?: CommentWithLocation[]; trailingComments?: CommentWithLocation[]; }} */ export function parse_expression_at(source, typescript, index) { const parser = typescript ? ParserWithTS : acorn.Parser; @@ -92,7 +93,7 @@ function get_comment_handlers(source) { if (comments.length === 0) return; walk(ast, null, { - _(node, { next }) { + _(node, { next, path }) { let comment; while (comments[0] && comments[0].start < node.start) { @@ -103,14 +104,20 @@ function get_comment_handlers(source) { next(); if (comments[0]) { - const slice = source.slice(node.end, comments[0].start); + const parent = path.at(-1); + if (parent === undefined || node.end !== parent.end) { + const slice = source.slice(node.end, comments[0].start); - if (/^[,) \t]*$/.test(slice)) { - node.trailingComments = [/** @type {CommentWithLocation} */ (comments.shift())]; + if (/^[,) \t]*$/.test(slice)) { + node.trailingComments = [/** @type {CommentWithLocation} */ (comments.shift())]; + } } } } }); + if (comments.length > 0) { + (ast.trailingComments ||= []).push(...comments.splice(0)); + } } }; } diff --git a/packages/svelte/src/compiler/phases/1-parse/read/expression.js b/packages/svelte/src/compiler/phases/1-parse/read/expression.js index 506fc354fb..aa86b85008 100644 --- a/packages/svelte/src/compiler/phases/1-parse/read/expression.js +++ b/packages/svelte/src/compiler/phases/1-parse/read/expression.js @@ -17,6 +17,10 @@ export default function read_expression(parser) { } let index = /** @type {number} */ (node.end); + if (node.trailingComments !== undefined && node.trailingComments.length > 0) { + index = node.trailingComments.at(-1).end; + } + while (num_parens > 0) { const char = parser.template[index]; diff --git a/packages/svelte/src/compiler/phases/1-parse/state/tag.js b/packages/svelte/src/compiler/phases/1-parse/state/tag.js index cca01d17ad..06a5321c15 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/tag.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/tag.js @@ -15,9 +15,14 @@ export default function tag(parser) { parser.allow_whitespace(); if (parser.eat('#')) return open(parser); - if (parser.eat('/')) return close(parser); if (parser.eat(':')) return next(parser); if (parser.eat('@')) return special(parser); + if (parser.match('/')) { + if (!parser.match('/*') && !parser.match('//')) { + parser.eat('/'); + return close(parser); + } + } const expression = read_expression(parser); diff --git a/packages/svelte/tests/parser-legacy/samples/javascript-comments/input.svelte b/packages/svelte/tests/parser-legacy/samples/javascript-comments/input.svelte index ff8489ac9f..5300667984 100644 --- a/packages/svelte/tests/parser-legacy/samples/javascript-comments/input.svelte +++ b/packages/svelte/tests/parser-legacy/samples/javascript-comments/input.svelte @@ -1,6 +1,7 @@