diff --git a/.changeset/gentle-needles-train.md b/.changeset/gentle-needles-train.md new file mode 100644 index 0000000000..578d495062 --- /dev/null +++ b/.changeset/gentle-needles-train.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: error on invalid element name diff --git a/packages/svelte/messages/compile-errors/template.md b/packages/svelte/messages/compile-errors/template.md index 29f4d7c38b..f27ed90fb4 100644 --- a/packages/svelte/messages/compile-errors/template.md +++ b/packages/svelte/messages/compile-errors/template.md @@ -100,10 +100,6 @@ > This type of directive is not valid on components -## component_invalid_name - -> Component name must be a valid variable name or dot notation expression - ## const_tag_cycle > Cyclical dependency detected: %cycle% @@ -136,10 +132,6 @@ > `` attempted to close element that was already automatically closed by `<%reason%>` (cannot nest `<%reason%>` inside `<%name%>`) -## element_invalid_tag_name - -> Expected valid tag name - ## element_unclosed > `<%name%>` was left open @@ -358,6 +350,10 @@ HTML restricts where certain elements can appear. In case of a violation the bro > `` components can only exist inside `{#if}` blocks, `{#each}` blocks, `{#snippet}` blocks or slots passed to components +## tag_invalid_name + +> Expected a valid element or component name. Components must have a valid variable name or dot notation expression + ## tag_invalid_placement > {@%name% ...} tag cannot be %location% diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index 5b7622226b..dd70be6435 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -786,15 +786,6 @@ export function component_invalid_directive(node) { e(node, "component_invalid_directive", "This type of directive is not valid on components"); } -/** - * Component name must be a valid variable name or dot notation expression - * @param {null | number | NodeLike} node - * @returns {never} - */ -export function component_invalid_name(node) { - e(node, "component_invalid_name", "Component name must be a valid variable name or dot notation expression"); -} - /** * Cyclical dependency detected: %cycle% * @param {null | number | NodeLike} node @@ -872,15 +863,6 @@ export function element_invalid_closing_tag_autoclosed(node, name, reason) { e(node, "element_invalid_closing_tag_autoclosed", `\`\` attempted to close element that was already automatically closed by \`<${reason}>\` (cannot nest \`<${reason}>\` inside \`<${name}>\`)`); } -/** - * Expected valid tag name - * @param {null | number | NodeLike} node - * @returns {never} - */ -export function element_invalid_tag_name(node) { - e(node, "element_invalid_tag_name", "Expected valid tag name"); -} - /** * `<%name%>` was left open * @param {null | number | NodeLike} node @@ -1378,6 +1360,15 @@ export function svelte_self_invalid_placement(node) { e(node, "svelte_self_invalid_placement", "`` components can only exist inside `{#if}` blocks, `{#each}` blocks, `{#snippet}` blocks or slots passed to components"); } +/** + * Expected a valid element or component name. Components must have a valid variable name or dot notation expression + * @param {null | number | NodeLike} node + * @returns {never} + */ +export function tag_invalid_name(node) { + e(node, "tag_invalid_name", "Expected a valid element or component name. Components must have a valid variable name or dot notation expression"); +} + /** * {@%name% ...} tag cannot be %location% * @param {null | number | NodeLike} node 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 6a5be676aa..07af4c8d98 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/element.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/element.js @@ -17,14 +17,14 @@ import { list } from '../../../utils/string.js'; const regex_invalid_unquoted_attribute_value = /^(\/>|[\s"'=<>`])/; const regex_closing_textarea_tag = /^<\/textarea(\s[^>]*)?>/i; const regex_closing_comment = /-->/; -const regex_component_name = /^(?:[A-Z]|[A-Za-z][A-Za-z0-9_$]*\.)/; -const regex_valid_component_name = - /^(?:[A-Z][A-Za-z0-9_$.]*|[a-z][A-Za-z0-9_$]*\.[A-Za-z0-9_$])[A-Za-z0-9_$.]*$/; const regex_whitespace_or_slash_or_closing_tag = /(\s|\/|>)/; const regex_token_ending_character = /[\s=/>"']/; const regex_starts_with_quote_characters = /^["']/; const regex_attribute_value = /^(?:"([^"]*)"|'([^'])*'|([^>\s]+))/; -const regex_valid_tag_name = /^!?[a-zA-Z]{1,}:?[a-zA-Z0-9-]*/; +const regex_valid_element_name = + /^(?:![a-zA-Z]+|[a-zA-Z](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?|[a-zA-Z][a-zA-Z0-9]*:[a-zA-Z][a-zA-Z0-9-]*[a-zA-Z0-9])$/; +const regex_valid_component_name = + /^(?:[A-Z][A-Za-z0-9_$.]*|[a-z][A-Za-z0-9_$]*(?:\.[A-Za-z0-9_$]+)+)$/; /** @type {Map} */ const root_only_meta_tags = new Map([ @@ -107,9 +107,9 @@ export default function element(parser) { e.svelte_meta_invalid_tag(bounds, list(Array.from(meta_tags.keys()))); } - if (!regex_valid_tag_name.test(name)) { + if (!regex_valid_element_name.test(name) && !regex_valid_component_name.test(name)) { const bounds = { start: start + 1, end: start + 1 + name.length }; - e.element_invalid_tag_name(bounds); + e.tag_invalid_name(bounds); } if (root_only_meta_tags.has(name)) { @@ -126,7 +126,7 @@ export default function element(parser) { const type = meta_tags.has(name) ? meta_tags.get(name) - : regex_component_name.test(name) + : regex_valid_component_name.test(name) ? 'Component' : name === 'title' && parent_is_head(parser.stack) ? 'TitleElement' @@ -135,10 +135,6 @@ export default function element(parser) { ? 'SlotElement' : 'RegularElement'; - if (type === 'Component' && !regex_valid_component_name.test(name)) { - e.component_invalid_name({ start: start + 1, end: start + name.length + 1 }); - } - /** @type {Compiler.ElementLike} */ const element = type === 'RegularElement' diff --git a/packages/svelte/tests/compiler-errors/samples/component-invalid-name/_config.js b/packages/svelte/tests/compiler-errors/samples/component-invalid-name/_config.js index df78a691df..436503ebfb 100644 --- a/packages/svelte/tests/compiler-errors/samples/component-invalid-name/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/component-invalid-name/_config.js @@ -2,8 +2,9 @@ import { test } from '../../test'; export default test({ error: { - code: 'component_invalid_name', - message: 'Component name must be a valid variable name or dot notation expression', + code: 'tag_invalid_name', + message: + 'Expected a valid element or component name. Components must have a valid variable name or dot notation expression', position: [1, 14] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/element-invalid-name/_config.js b/packages/svelte/tests/compiler-errors/samples/element-invalid-name/_config.js new file mode 100644 index 0000000000..c84f7f4d19 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/element-invalid-name/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + error: { + code: 'tag_invalid_name', + message: + 'Expected a valid element or component name. Components must have a valid variable name or dot notation expression', + position: [1, 8] + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/element-invalid-name/main.svelte b/packages/svelte/tests/compiler-errors/samples/element-invalid-name/main.svelte new file mode 100644 index 0000000000..4a5ba9be1e --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/element-invalid-name/main.svelte @@ -0,0 +1 @@ +