From 3cabb525345c21185c3cca607e6605c6424694b2 Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Mon, 8 Dec 2025 17:19:29 -0500 Subject: [PATCH] fix: set Root start/end to null when fragment contains only whitespace (#17125) * fix: set Root start/end to null when fragment contains only whitespace * format * always set root.start to 0 and root.end to template.length * Update .changeset/fruity-knives-ring.md --------- Co-authored-by: Rich Harris Co-authored-by: Rich Harris --- .changeset/fruity-knives-ring.md | 5 + .../src/compiler/phases/1-parse/index.js | 17 +-- .../output.json | 2 +- .../samples/comment-before-script/output.json | 2 +- .../samples/css-nth-syntax/output.json | 2 +- .../samples/css-pseudo-classes/output.json | 4 +- .../samples/generic-snippets/output.json | 2 +- .../samples/loose-valid-each-as/output.json | 2 +- .../parser-modern/samples/options/output.json | 2 +- .../script-style-no-markup/input.svelte | 6 + .../script-style-no-markup/output.json | 112 ++++++++++++++++++ .../semicolon-inside-quotes/output.json | 2 +- .../samples/snippets/output.json | 2 +- .../typescript-in-event-handler/output.json | 2 +- 14 files changed, 136 insertions(+), 26 deletions(-) create mode 100644 .changeset/fruity-knives-ring.md create mode 100644 packages/svelte/tests/parser-modern/samples/script-style-no-markup/input.svelte create mode 100644 packages/svelte/tests/parser-modern/samples/script-style-no-markup/output.json diff --git a/.changeset/fruity-knives-ring.md b/.changeset/fruity-knives-ring.md new file mode 100644 index 0000000000..059b2df1c7 --- /dev/null +++ b/.changeset/fruity-knives-ring.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: set AST `root.start` to `0` and `root.end` to `template.length` diff --git a/packages/svelte/src/compiler/phases/1-parse/index.js b/packages/svelte/src/compiler/phases/1-parse/index.js index 7017d013da..3b5f83d58f 100644 --- a/packages/svelte/src/compiler/phases/1-parse/index.js +++ b/packages/svelte/src/compiler/phases/1-parse/index.js @@ -117,21 +117,8 @@ export class Parser { e.unexpected_eof(this.index); } - if (this.root.fragment.nodes.length) { - let start = /** @type {number} */ (this.root.fragment.nodes[0].start); - while (regex_whitespace.test(template[start])) start += 1; - - let end = /** @type {number} */ ( - this.root.fragment.nodes[this.root.fragment.nodes.length - 1].end - ); - while (regex_whitespace.test(template[end - 1])) end -= 1; - - this.root.start = start; - this.root.end = end; - } else { - // @ts-ignore - this.root.start = this.root.end = null; - } + this.root.start = 0; + this.root.end = template.length; const options_index = this.root.fragment.nodes.findIndex( /** @param {any} thing */ diff --git a/packages/svelte/tests/parser-modern/samples/comment-before-function-binding/output.json b/packages/svelte/tests/parser-modern/samples/comment-before-function-binding/output.json index b26ee2866f..13cc5fea7b 100644 --- a/packages/svelte/tests/parser-modern/samples/comment-before-function-binding/output.json +++ b/packages/svelte/tests/parser-modern/samples/comment-before-function-binding/output.json @@ -1,7 +1,7 @@ { "css": null, "js": [], - "start": 37, + "start": 0, "end": 117, "type": "Root", "fragment": { diff --git a/packages/svelte/tests/parser-modern/samples/comment-before-script/output.json b/packages/svelte/tests/parser-modern/samples/comment-before-script/output.json index 827ad85d92..8d77165297 100644 --- a/packages/svelte/tests/parser-modern/samples/comment-before-script/output.json +++ b/packages/svelte/tests/parser-modern/samples/comment-before-script/output.json @@ -2,7 +2,7 @@ "css": null, "js": [], "start": 0, - "end": 27, + "end": 76, "type": "Root", "fragment": { "type": "Fragment", diff --git a/packages/svelte/tests/parser-modern/samples/css-nth-syntax/output.json b/packages/svelte/tests/parser-modern/samples/css-nth-syntax/output.json index 26b4998587..3ce5f33d09 100644 --- a/packages/svelte/tests/parser-modern/samples/css-nth-syntax/output.json +++ b/packages/svelte/tests/parser-modern/samples/css-nth-syntax/output.json @@ -1079,7 +1079,7 @@ } }, "js": [], - "start": 808, + "start": 0, "end": 820, "type": "Root", "fragment": { diff --git a/packages/svelte/tests/parser-modern/samples/css-pseudo-classes/output.json b/packages/svelte/tests/parser-modern/samples/css-pseudo-classes/output.json index e410cf2a80..d052affe46 100644 --- a/packages/svelte/tests/parser-modern/samples/css-pseudo-classes/output.json +++ b/packages/svelte/tests/parser-modern/samples/css-pseudo-classes/output.json @@ -398,8 +398,8 @@ } }, "js": [], - "start": null, - "end": null, + "start": 0, + "end": 386, "type": "Root", "fragment": { "type": "Fragment", diff --git a/packages/svelte/tests/parser-modern/samples/generic-snippets/output.json b/packages/svelte/tests/parser-modern/samples/generic-snippets/output.json index 5a0e64894d..8e1654feed 100644 --- a/packages/svelte/tests/parser-modern/samples/generic-snippets/output.json +++ b/packages/svelte/tests/parser-modern/samples/generic-snippets/output.json @@ -1,7 +1,7 @@ { "css": null, "js": [], - "start": 30, + "start": 0, "end": 192, "type": "Root", "fragment": { diff --git a/packages/svelte/tests/parser-modern/samples/loose-valid-each-as/output.json b/packages/svelte/tests/parser-modern/samples/loose-valid-each-as/output.json index 6096907d5d..b428cff0b2 100644 --- a/packages/svelte/tests/parser-modern/samples/loose-valid-each-as/output.json +++ b/packages/svelte/tests/parser-modern/samples/loose-valid-each-as/output.json @@ -1,7 +1,7 @@ { "css": null, "js": [], - "start": 45, + "start": 0, "end": 119, "type": "Root", "fragment": { diff --git a/packages/svelte/tests/parser-modern/samples/options/output.json b/packages/svelte/tests/parser-modern/samples/options/output.json index 62c9fc1b9d..08ce8d43b7 100644 --- a/packages/svelte/tests/parser-modern/samples/options/output.json +++ b/packages/svelte/tests/parser-modern/samples/options/output.json @@ -2,7 +2,7 @@ "css": null, "js": [], "start": 0, - "end": 102, + "end": 169, "type": "Root", "fragment": { "type": "Fragment", diff --git a/packages/svelte/tests/parser-modern/samples/script-style-no-markup/input.svelte b/packages/svelte/tests/parser-modern/samples/script-style-no-markup/input.svelte new file mode 100644 index 0000000000..c4dc4d5271 --- /dev/null +++ b/packages/svelte/tests/parser-modern/samples/script-style-no-markup/input.svelte @@ -0,0 +1,6 @@ + + diff --git a/packages/svelte/tests/parser-modern/samples/script-style-no-markup/output.json b/packages/svelte/tests/parser-modern/samples/script-style-no-markup/output.json new file mode 100644 index 0000000000..b5e42e9217 --- /dev/null +++ b/packages/svelte/tests/parser-modern/samples/script-style-no-markup/output.json @@ -0,0 +1,112 @@ +{ + "css": { + "type": "StyleSheet", + "start": 54, + "end": 91, + "attributes": [], + "children": [ + { + "type": "Rule", + "prelude": { + "type": "SelectorList", + "start": 63, + "end": 66, + "children": [ + { + "type": "ComplexSelector", + "start": 63, + "end": 66, + "children": [ + { + "type": "RelativeSelector", + "combinator": null, + "selectors": [ + { + "type": "TypeSelector", + "name": "div", + "start": 63, + "end": 66 + } + ], + "start": 63, + "end": 66 + } + ] + } + ] + }, + "block": { + "type": "Block", + "start": 67, + "end": 82, + "children": [ + { + "type": "Declaration", + "start": 69, + "end": 79, + "property": "color", + "value": "red" + } + ] + }, + "start": 63, + "end": 82 + } + ], + "content": { + "start": 61, + "end": 83, + "styles": "\n\tdiv { color: red; }\n", + "comment": null + } + }, + "js": [], + "start": 0, + "end": 91, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [ + { + "type": "Text", + "start": 53, + "end": 54, + "raw": "\n", + "data": "\n" + } + ] + }, + "options": null, + "instance": { + "type": "Script", + "start": 0, + "end": 53, + "context": "default", + "content": { + "type": "Program", + "start": 8, + "end": 44, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 0 + } + }, + "body": [], + "sourceType": "module", + "trailingComments": [ + { + "type": "Line", + "value": " script and style but no markup", + "start": 10, + "end": 43 + } + ] + }, + "attributes": [] + } +} diff --git a/packages/svelte/tests/parser-modern/samples/semicolon-inside-quotes/output.json b/packages/svelte/tests/parser-modern/samples/semicolon-inside-quotes/output.json index e95ccb4094..312bd7701e 100644 --- a/packages/svelte/tests/parser-modern/samples/semicolon-inside-quotes/output.json +++ b/packages/svelte/tests/parser-modern/samples/semicolon-inside-quotes/output.json @@ -77,7 +77,7 @@ }, "js": [], "start": 0, - "end": 35, + "end": 205, "type": "Root", "fragment": { "type": "Fragment", diff --git a/packages/svelte/tests/parser-modern/samples/snippets/output.json b/packages/svelte/tests/parser-modern/samples/snippets/output.json index d760fe2e2d..c217ef94e9 100644 --- a/packages/svelte/tests/parser-modern/samples/snippets/output.json +++ b/packages/svelte/tests/parser-modern/samples/snippets/output.json @@ -1,7 +1,7 @@ { "css": null, "js": [], - "start": 29, + "start": 0, "end": 101, "type": "Root", "fragment": { diff --git a/packages/svelte/tests/parser-modern/samples/typescript-in-event-handler/output.json b/packages/svelte/tests/parser-modern/samples/typescript-in-event-handler/output.json index 4281d6fa46..a1d6ed56bf 100644 --- a/packages/svelte/tests/parser-modern/samples/typescript-in-event-handler/output.json +++ b/packages/svelte/tests/parser-modern/samples/typescript-in-event-handler/output.json @@ -1,7 +1,7 @@ { "css": null, "js": [], - "start": 54, + "start": 0, "end": 173, "type": "Root", "fragment": {