Skip to content

Commit 657130b

Browse files
committed
svelte head, let directive, tweaks
1 parent a1965cb commit 657130b

File tree

10 files changed

+55
-30
lines changed

10 files changed

+55
-30
lines changed

packages/svelte/src/compiler/errors.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ const special_elements = {
132132
'invalid-customElement-shadow-attribute': () => '"shadow" must be either "open" or "none"',
133133
'unknown-svelte-option-attribute': /** @param {string} name */ (name) =>
134134
`<svelte:options> unknown attribute '${name}'`,
135+
'illegal-svelte-head-attribute': () => '<svelte:head> cannot have attributes nor directives',
135136
'invalid-svelte-fragment-attribute': () =>
136137
`<svelte:fragment> can only have a slot attribute and (optionally) a let: directive`,
137138
'invalid-svelte-fragment-slot': () => `<svelte:fragment> slot attribute must have a static value`,
@@ -214,8 +215,8 @@ const elements = {
214215
* @param {string} parent
215216
*/
216217
'invalid-node-placement': (node, parent) => `${node} is invalid inside <${parent}>`,
217-
'title-illegal-attribute': () => '<title> cannot have attributes',
218-
'title-invalid-content': () => '<title> can only contain text and {tags}'
218+
'illegal-title-attribute': () => '<title> cannot have attributes nor directives',
219+
'invalid-title-content': () => '<title> can only contain text and {tags}'
219220
};
220221

221222
/** @satisfies {Errors} */
@@ -265,7 +266,8 @@ const attributes = {
265266
: `An element cannot have both ${describe(directive1)} directive and ${describe(
266267
directive2
267268
)} directive`;
268-
}
269+
},
270+
'invalid-let-directive-placement': () => 'let directive at invalid position'
269271
};
270272

271273
/** @satisfies {Errors} */

packages/svelte/src/compiler/phases/2-analyze/validation.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,20 @@ export const validation = {
477477
error(node, 'invalid-const-placement');
478478
}
479479
},
480+
LetDirective(node, context) {
481+
const parent = context.path.at(-1);
482+
if (
483+
parent === undefined ||
484+
(parent.type !== 'Component' &&
485+
parent.type !== 'RegularElement' &&
486+
parent.type !== 'SvelteElement' &&
487+
parent.type !== 'SvelteComponent' &&
488+
parent.type !== 'SvelteSelf' &&
489+
parent.type !== 'SvelteFragment')
490+
) {
491+
error(node, 'invalid-let-directive-placement');
492+
}
493+
},
480494
RegularElement(node, context) {
481495
if (node.name === 'textarea' && node.fragment.nodes.length > 0) {
482496
for (const attribute of node.attributes) {
@@ -514,6 +528,12 @@ export const validation = {
514528
parent_element: node.name
515529
});
516530
},
531+
SvelteHead(node) {
532+
const attribute = node.attributes[0];
533+
if (attribute) {
534+
error(attribute, 'illegal-svelte-head-attribute');
535+
}
536+
},
517537
SvelteElement(node, context) {
518538
validate_element(node, context);
519539
context.next({
@@ -568,12 +588,12 @@ export const validation = {
568588
TitleElement(node) {
569589
const attribute = node.attributes[0];
570590
if (attribute) {
571-
error(attribute, 'title-illegal-attribute');
591+
error(attribute, 'illegal-title-attribute');
572592
}
573593

574594
const child = node.fragment.nodes.find((n) => n.type !== 'Text' && n.type !== 'ExpressionTag');
575595
if (child) {
576-
error(child, 'title-invalid-content');
596+
error(child, 'invalid-title-content');
577597
}
578598
},
579599
ExpressionTag(node, context) {

packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2753,19 +2753,9 @@ export const template_visitors = {
27532753
serialize_event_attribute(node, context);
27542754
}
27552755
},
2756-
LetDirective(node, { state, path }) {
2756+
LetDirective(node, { state }) {
27572757
// let:x --> const x = $.derived(() => $.unwrap($$slotProps).x);
27582758
// let:x={{y, z}} --> const derived_x = $.derived(() => { const { y, z } = $.unwrap($$slotProps).x; return { y, z }));
2759-
const parent = path.at(-1);
2760-
if (
2761-
parent === undefined ||
2762-
(parent.type !== 'Component' &&
2763-
parent.type !== 'RegularElement' &&
2764-
parent.type !== 'SvelteFragment')
2765-
) {
2766-
error(node, 'INTERNAL', 'let directive at invalid position');
2767-
}
2768-
27692759
if (node.expression && node.expression.type !== 'Identifier') {
27702760
const name = state.scope.generate(node.name);
27712761
const bindings = state.scope.get_bindings(node);

packages/svelte/src/compiler/phases/3-transform/server/transform-server.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,17 +1495,7 @@ const template_visitors = {
14951495
state.template.push(t_statement(call));
14961496
state.template.push(t_expression(id));
14971497
},
1498-
LetDirective(node, { state, path }) {
1499-
const parent = path.at(-1);
1500-
if (
1501-
parent === undefined ||
1502-
(parent.type !== 'Component' &&
1503-
parent.type !== 'RegularElement' &&
1504-
parent.type !== 'SvelteFragment')
1505-
) {
1506-
error(node, 'INTERNAL', 'let directive at invalid position');
1507-
}
1508-
1498+
LetDirective(node, { state }) {
15091499
if (node.expression && node.expression.type !== 'Identifier') {
15101500
const name = state.scope.generate(node.name);
15111501
const bindings = state.scope.get_bindings(node);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[
2+
{
3+
"code": "invalid-let-directive-placement",
4+
"message": "let directive at invalid position",
5+
"start": { "line": 6, "column": 15 },
6+
"end": { "line": 6, "column": 20 }
7+
}
8+
]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{#if foo}
2+
<svelte:self let:x></svelte:self>
3+
{/if}
4+
<Component let:x></Component>
5+
<div let:x></div><!-- strictly speaking this is invalid, but it was never checked in Svelte 3/4 either, and is now deprecated, so don't mind -->
6+
<svelte:window let:x></svelte:window>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[
2+
{
3+
"code": "illegal-svelte-head-attribute",
4+
"message": "<svelte:head> cannot have attributes nor directives",
5+
"start": { "line": 1, "column": 13 },
6+
"end": { "line": 1, "column": 14 }
7+
}
8+
]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<svelte:head x></svelte:head>

packages/svelte/tests/validator/samples/title-no-attributes/errors.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
22
{
3-
"code": "title-illegal-attribute",
4-
"message": "<title> cannot have attributes",
3+
"code": "illegal-title-attribute",
4+
"message": "<title> cannot have attributes nor directives",
55
"start": {
66
"line": 2,
77
"column": 8

packages/svelte/tests/validator/samples/title-no-children/errors.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[
22
{
3-
"code": "title-invalid-content",
3+
"code": "invalid-title-content",
44
"message": "<title> can only contain text and {tags}",
55
"start": {
66
"line": 2,

0 commit comments

Comments
 (0)