diff --git a/.changeset/tender-bats-switch.md b/.changeset/tender-bats-switch.md new file mode 100644 index 0000000000..84467f43fe --- /dev/null +++ b/.changeset/tender-bats-switch.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: error on invalid component name diff --git a/packages/svelte/messages/compile-errors/template.md b/packages/svelte/messages/compile-errors/template.md index affd44e943..95e60c0cf5 100644 --- a/packages/svelte/messages/compile-errors/template.md +++ b/packages/svelte/messages/compile-errors/template.md @@ -100,6 +100,10 @@ > 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% diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index b174f69c20..f0fca61e9a 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -786,6 +786,15 @@ 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 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 12e75400be..99d3aeff10 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/element.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/element.js @@ -75,6 +75,8 @@ function parent_is_shadowroot_template(stack) { 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_$.]*$/; /** @param {Parser} parser */ export default function element(parser) { @@ -136,6 +138,10 @@ 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 new file mode 100644 index 0000000000..df78a691df --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/component-invalid-name/_config.js @@ -0,0 +1,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', + position: [1, 14] + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/component-invalid-name/main.svelte b/packages/svelte/tests/compiler-errors/samples/component-invalid-name/main.svelte new file mode 100644 index 0000000000..5c7ec3188a --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/component-invalid-name/main.svelte @@ -0,0 +1 @@ +