Skip to content

Commit fd0bc29

Browse files
fix: correctly validate head snippets on the server (#15755)
* fix: correctly validate head snippets on the server * put the logic in copy_payload so it gets treeshaken in most cases --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 3153384 commit fd0bc29

File tree

5 files changed

+50
-15
lines changed

5 files changed

+50
-15
lines changed

.changeset/dirty-zebras-do.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: correctly validate head snippets on the server

packages/svelte/src/internal/server/dev.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
} from '../../html-tree-validation.js';
77
import { current_component } from './context.js';
88
import { invalid_snippet_arguments } from '../shared/errors.js';
9-
import { Payload } from './payload.js';
9+
import { HeadPayload, Payload } from './payload.js';
1010

1111
/**
1212
* @typedef {{
@@ -105,7 +105,11 @@ export function pop_element() {
105105
* @param {Payload} payload
106106
*/
107107
export function validate_snippet_args(payload) {
108-
if (typeof payload !== 'object' || !(payload instanceof Payload)) {
108+
if (
109+
typeof payload !== 'object' ||
110+
// for some reason typescript consider the type of payload as never after the first instanceof
111+
!(payload instanceof Payload || /** @type {any} */ (payload) instanceof HeadPayload)
112+
) {
109113
invalid_snippet_arguments();
110114
}
111115
}

packages/svelte/src/internal/server/payload.js

+21-13
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
1+
export class HeadPayload {
2+
/** @type {Set<{ hash: string; code: string }>} */
3+
css = new Set();
4+
out = '';
5+
uid = () => '';
6+
title = '';
7+
8+
constructor(css = new Set(), out = '', title = '', uid = () => '') {
9+
this.css = css;
10+
this.out = out;
11+
this.title = title;
12+
this.uid = uid;
13+
}
14+
}
15+
116
export class Payload {
217
/** @type {Set<{ hash: string; code: string }>} */
318
css = new Set();
419
out = '';
520
uid = () => '';
621

7-
head = {
8-
/** @type {Set<{ hash: string; code: string }>} */
9-
css: new Set(),
10-
title: '',
11-
out: '',
12-
uid: () => ''
13-
};
22+
head = new HeadPayload();
1423

1524
constructor(id_prefix = '') {
1625
this.uid = props_id_generator(id_prefix);
@@ -30,12 +39,11 @@ export function copy_payload({ out, css, head, uid }) {
3039
payload.css = new Set(css);
3140
payload.uid = uid;
3241

33-
payload.head = {
34-
title: head.title,
35-
out: head.out,
36-
css: new Set(head.css),
37-
uid: head.uid
38-
};
42+
payload.head = new HeadPayload();
43+
payload.head.out = head.out;
44+
payload.head.css = new Set(head.css);
45+
payload.head.title = head.title;
46+
payload.head.uid = head.uid;
3947

4048
return payload;
4149
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
compileOptions: {
5+
dev: true
6+
},
7+
mode: ['server'],
8+
async test({ errors, assert }) {
9+
assert.equal(errors, []);
10+
}
11+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{#snippet head()}
2+
<title>Cool</title>
3+
{/snippet}
4+
5+
<svelte:head>
6+
{@render head()}
7+
</svelte:head>

0 commit comments

Comments
 (0)