Skip to content

Commit 77096a1

Browse files
authored
fix: error on invalid element name (#13057)
closes #12925
1 parent 5facd5b commit 77096a1

File tree

7 files changed

+39
-39
lines changed

7 files changed

+39
-39
lines changed

.changeset/gentle-needles-train.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: error on invalid element name

packages/svelte/messages/compile-errors/template.md

+4-8
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,6 @@
100100

101101
> This type of directive is not valid on components
102102
103-
## component_invalid_name
104-
105-
> Component name must be a valid variable name or dot notation expression
106-
107103
## const_tag_cycle
108104

109105
> Cyclical dependency detected: %cycle%
@@ -136,10 +132,6 @@
136132

137133
> `</%name%>` attempted to close element that was already automatically closed by `<%reason%>` (cannot nest `<%reason%>` inside `<%name%>`)
138134
139-
## element_invalid_tag_name
140-
141-
> Expected valid tag name
142-
143135
## element_unclosed
144136

145137
> `<%name%>` was left open
@@ -358,6 +350,10 @@ HTML restricts where certain elements can appear. In case of a violation the bro
358350

359351
> `<svelte:self>` components can only exist inside `{#if}` blocks, `{#each}` blocks, `{#snippet}` blocks or slots passed to components
360352
353+
## tag_invalid_name
354+
355+
> Expected a valid element or component name. Components must have a valid variable name or dot notation expression
356+
361357
## tag_invalid_placement
362358

363359
> {@%name% ...} tag cannot be %location%

packages/svelte/src/compiler/errors.js

+9-18
Original file line numberDiff line numberDiff line change
@@ -786,15 +786,6 @@ export function component_invalid_directive(node) {
786786
e(node, "component_invalid_directive", "This type of directive is not valid on components");
787787
}
788788

789-
/**
790-
* Component name must be a valid variable name or dot notation expression
791-
* @param {null | number | NodeLike} node
792-
* @returns {never}
793-
*/
794-
export function component_invalid_name(node) {
795-
e(node, "component_invalid_name", "Component name must be a valid variable name or dot notation expression");
796-
}
797-
798789
/**
799790
* Cyclical dependency detected: %cycle%
800791
* @param {null | number | NodeLike} node
@@ -872,15 +863,6 @@ export function element_invalid_closing_tag_autoclosed(node, name, reason) {
872863
e(node, "element_invalid_closing_tag_autoclosed", `\`</${name}>\` attempted to close element that was already automatically closed by \`<${reason}>\` (cannot nest \`<${reason}>\` inside \`<${name}>\`)`);
873864
}
874865

875-
/**
876-
* Expected valid tag name
877-
* @param {null | number | NodeLike} node
878-
* @returns {never}
879-
*/
880-
export function element_invalid_tag_name(node) {
881-
e(node, "element_invalid_tag_name", "Expected valid tag name");
882-
}
883-
884866
/**
885867
* `<%name%>` was left open
886868
* @param {null | number | NodeLike} node
@@ -1378,6 +1360,15 @@ export function svelte_self_invalid_placement(node) {
13781360
e(node, "svelte_self_invalid_placement", "`<svelte:self>` components can only exist inside `{#if}` blocks, `{#each}` blocks, `{#snippet}` blocks or slots passed to components");
13791361
}
13801362

1363+
/**
1364+
* Expected a valid element or component name. Components must have a valid variable name or dot notation expression
1365+
* @param {null | number | NodeLike} node
1366+
* @returns {never}
1367+
*/
1368+
export function tag_invalid_name(node) {
1369+
e(node, "tag_invalid_name", "Expected a valid element or component name. Components must have a valid variable name or dot notation expression");
1370+
}
1371+
13811372
/**
13821373
* {@%name% ...} tag cannot be %location%
13831374
* @param {null | number | NodeLike} node

packages/svelte/src/compiler/phases/1-parse/state/element.js

+7-11
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ import { list } from '../../../utils/string.js';
1717
const regex_invalid_unquoted_attribute_value = /^(\/>|[\s"'=<>`])/;
1818
const regex_closing_textarea_tag = /^<\/textarea(\s[^>]*)?>/i;
1919
const regex_closing_comment = /-->/;
20-
const regex_component_name = /^(?:[A-Z]|[A-Za-z][A-Za-z0-9_$]*\.)/;
21-
const regex_valid_component_name =
22-
/^(?:[A-Z][A-Za-z0-9_$.]*|[a-z][A-Za-z0-9_$]*\.[A-Za-z0-9_$])[A-Za-z0-9_$.]*$/;
2320
const regex_whitespace_or_slash_or_closing_tag = /(\s|\/|>)/;
2421
const regex_token_ending_character = /[\s=/>"']/;
2522
const regex_starts_with_quote_characters = /^["']/;
2623
const regex_attribute_value = /^(?:"([^"]*)"|'([^'])*'|([^>\s]+))/;
27-
const regex_valid_tag_name = /^!?[a-zA-Z]{1,}:?[a-zA-Z0-9-]*/;
24+
const regex_valid_element_name =
25+
/^(?:![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])$/;
26+
const regex_valid_component_name =
27+
/^(?:[A-Z][A-Za-z0-9_$.]*|[a-z][A-Za-z0-9_$]*(?:\.[A-Za-z0-9_$]+)+)$/;
2828

2929
/** @type {Map<string, Compiler.ElementLike['type']>} */
3030
const root_only_meta_tags = new Map([
@@ -107,9 +107,9 @@ export default function element(parser) {
107107
e.svelte_meta_invalid_tag(bounds, list(Array.from(meta_tags.keys())));
108108
}
109109

110-
if (!regex_valid_tag_name.test(name)) {
110+
if (!regex_valid_element_name.test(name) && !regex_valid_component_name.test(name)) {
111111
const bounds = { start: start + 1, end: start + 1 + name.length };
112-
e.element_invalid_tag_name(bounds);
112+
e.tag_invalid_name(bounds);
113113
}
114114

115115
if (root_only_meta_tags.has(name)) {
@@ -126,7 +126,7 @@ export default function element(parser) {
126126

127127
const type = meta_tags.has(name)
128128
? meta_tags.get(name)
129-
: regex_component_name.test(name)
129+
: regex_valid_component_name.test(name)
130130
? 'Component'
131131
: name === 'title' && parent_is_head(parser.stack)
132132
? 'TitleElement'
@@ -135,10 +135,6 @@ export default function element(parser) {
135135
? 'SlotElement'
136136
: 'RegularElement';
137137

138-
if (type === 'Component' && !regex_valid_component_name.test(name)) {
139-
e.component_invalid_name({ start: start + 1, end: start + name.length + 1 });
140-
}
141-
142138
/** @type {Compiler.ElementLike} */
143139
const element =
144140
type === 'RegularElement'

packages/svelte/tests/compiler-errors/samples/component-invalid-name/_config.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { test } from '../../test';
22

33
export default test({
44
error: {
5-
code: 'component_invalid_name',
6-
message: 'Component name must be a valid variable name or dot notation expression',
5+
code: 'tag_invalid_name',
6+
message:
7+
'Expected a valid element or component name. Components must have a valid variable name or dot notation expression',
78
position: [1, 14]
89
}
910
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
error: {
5+
code: 'tag_invalid_name',
6+
message:
7+
'Expected a valid element or component name. Components must have a valid variable name or dot notation expression',
8+
position: [1, 8]
9+
}
10+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<yes[no]></yes[no]>

0 commit comments

Comments
 (0)