From 6efd9d6f4433463e4b20fdd11a6f1a37dc8c7fec Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Wed, 5 Jun 2024 22:16:34 +0200 Subject: [PATCH] fix: correctly backport `svelte:element` to old AST (#11917) Both `` and `` were backported as `tag: "div"` for the old AST. That's wrong because the latter should result in `tag: { type: 'Literal', .. }`. Fixing this makes all the tests in prettier-plugin-svelte pass with Svelte 5. Also cleaned up a bit of code in the parser. --- .changeset/thin-colts-yawn.md | 5 + packages/svelte/src/compiler/legacy.js | 6 +- .../src/compiler/phases/1-parse/index.js | 1 - .../compiler/phases/1-parse/state/element.js | 15 +- .../dynamic-element-string/input.svelte | 5 + .../dynamic-element-string/output.json | 144 ++++++++++++++++-- 6 files changed, 157 insertions(+), 19 deletions(-) create mode 100644 .changeset/thin-colts-yawn.md diff --git a/.changeset/thin-colts-yawn.md b/.changeset/thin-colts-yawn.md new file mode 100644 index 0000000000..9306607124 --- /dev/null +++ b/.changeset/thin-colts-yawn.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: correctly backport `svelte:element` to old AST diff --git a/packages/svelte/src/compiler/legacy.js b/packages/svelte/src/compiler/legacy.js index 513d71452a..d5bcdc71e4 100644 --- a/packages/svelte/src/compiler/legacy.js +++ b/packages/svelte/src/compiler/legacy.js @@ -478,7 +478,11 @@ export function convert(source, ast) { SvelteElement(node, { visit }) { /** @type {import('estree').Expression | string} */ let tag = node.tag; - if (tag.type === 'Literal' && typeof tag.value === 'string') { + if ( + tag.type === 'Literal' && + typeof tag.value === 'string' && + source[/** @type {number} */ (node.tag.start) - 1] !== '{' + ) { tag = tag.value; } diff --git a/packages/svelte/src/compiler/phases/1-parse/index.js b/packages/svelte/src/compiler/phases/1-parse/index.js index 7e3b65cc9e..edbd4e5463 100644 --- a/packages/svelte/src/compiler/phases/1-parse/index.js +++ b/packages/svelte/src/compiler/phases/1-parse/index.js @@ -7,7 +7,6 @@ import full_char_code_at from './utils/full_char_code_at.js'; import * as e from '../../errors.js'; import { create_fragment } from './utils/create.js'; import read_options from './read/options.js'; -import { locator } from '../../state.js'; const regex_position_indicator = / \(\d+:\d+\)$/; diff --git a/packages/svelte/src/compiler/phases/1-parse/state/element.js b/packages/svelte/src/compiler/phases/1-parse/state/element.js index 43551c7530..1322d08065 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/element.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/element.js @@ -14,7 +14,7 @@ const valid_tag_name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/; /** Invalid attribute characters if the attribute is not surrounded by quotes */ const regex_starts_with_invalid_attr_value = /^(\/>|[\s"'=<>`])/; -/** @type {Map} */ +/** @type {Map} */ const root_only_meta_tags = new Map([ ['svelte:head', 'SvelteHead'], ['svelte:options', 'SvelteOptions'], @@ -23,7 +23,7 @@ const root_only_meta_tags = new Map([ ['svelte:body', 'SvelteBody'] ]); -/** @type {Map} */ +/** @type {Map} */ const meta_tags = new Map([ ...root_only_meta_tags, ['svelte:element', 'SvelteElement'], @@ -132,11 +132,10 @@ export default function tag(parser) { : 'RegularElement'; /** @type {import('#compiler').ElementLike} */ - // @ts-expect-error TODO can't figure out this error const element = type === 'RegularElement' ? { - type: /** @type {import('#compiler').ElementLike['type']} */ (type), + type: type, start, end: -1, name, @@ -144,12 +143,14 @@ export default function tag(parser) { fragment: create_fragment(true), metadata: { svg: false, + mathml: false, + scoped: false, has_spread: false }, parent: null } - : { - type: /** @type {import('#compiler').ElementLike['type']} */ (type), + : /** @type {import('#compiler').ElementLike} */ ({ + type, start, end: -1, name, @@ -159,7 +160,7 @@ export default function tag(parser) { metadata: { svg: false } - }; + }); parser.allow_whitespace(); diff --git a/packages/svelte/tests/parser-legacy/samples/dynamic-element-string/input.svelte b/packages/svelte/tests/parser-legacy/samples/dynamic-element-string/input.svelte index 4218f5e757..616c984f8f 100644 --- a/packages/svelte/tests/parser-legacy/samples/dynamic-element-string/input.svelte +++ b/packages/svelte/tests/parser-legacy/samples/dynamic-element-string/input.svelte @@ -1,2 +1,7 @@ + + + + + diff --git a/packages/svelte/tests/parser-legacy/samples/dynamic-element-string/output.json b/packages/svelte/tests/parser-legacy/samples/dynamic-element-string/output.json index 8ac42d71b2..9ba15d6044 100644 --- a/packages/svelte/tests/parser-legacy/samples/dynamic-element-string/output.json +++ b/packages/svelte/tests/parser-legacy/samples/dynamic-element-string/output.json @@ -2,40 +2,164 @@ "html": { "type": "Fragment", "start": 0, - "end": 105, + "end": 292, "children": [ { "type": "Element", "name": "svelte:element", "start": 0, - "end": 46, + "end": 44, "tag": "div", "attributes": [], "children": [] }, { "type": "Text", - "start": 46, - "end": 47, + "start": 44, + "end": 45, + "raw": "\n", + "data": "\n" + }, + { + "type": "Comment", + "start": 45, + "end": 69, + "data": " prettier-ignore ", + "ignores": [] + }, + { + "type": "Text", + "start": 69, + "end": 70, "raw": "\n", "data": "\n" }, { "type": "Element", "name": "svelte:element", - "start": 47, - "end": 105, + "start": 70, + "end": 114, "tag": "div", + "attributes": [], + "children": [] + }, + { + "type": "Text", + "start": 114, + "end": 115, + "raw": "\n", + "data": "\n" + }, + { + "type": "Element", + "name": "svelte:element", + "start": 115, + "end": 161, + "tag": { + "type": "Literal", + "start": 137, + "end": 142, + "loc": { + "start": { + "line": 4, + "column": 22 + }, + "end": { + "line": 4, + "column": 27 + } + }, + "value": "div", + "raw": "\"div\"" + }, + "attributes": [], + "children": [] + }, + { + "type": "Text", + "start": 161, + "end": 162, + "raw": "\n", + "data": "\n" + }, + { + "type": "Comment", + "start": 162, + "end": 186, + "data": " prettier-ignore ", + "ignores": [] + }, + { + "type": "Text", + "start": 186, + "end": 187, + "raw": "\n", + "data": "\n" + }, + { + "type": "Element", + "name": "svelte:element", + "start": 187, + "end": 233, + "tag": { + "type": "Literal", + "start": 209, + "end": 214, + "loc": { + "start": { + "line": 6, + "column": 22 + }, + "end": { + "line": 6, + "column": 27 + } + }, + "value": "div", + "raw": "'div'" + }, + "attributes": [], + "children": [] + }, + { + "type": "Text", + "start": 233, + "end": 234, + "raw": "\n", + "data": "\n" + }, + { + "type": "Element", + "name": "svelte:element", + "start": 234, + "end": 292, + "tag": { + "type": "Literal", + "start": 256, + "end": 261, + "loc": { + "start": { + "line": 7, + "column": 22 + }, + "end": { + "line": 7, + "column": 27 + } + }, + "value": "div", + "raw": "\"div\"" + }, "attributes": [ { "type": "Attribute", - "start": 76, - "end": 87, + "start": 263, + "end": 274, "name": "class", "value": [ { - "start": 83, - "end": 86, + "start": 270, + "end": 273, "type": "Text", "raw": "foo", "data": "foo"