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 <rich.harris@vercel.com>
pull/15759/head
Paolo Ricciuti 5 months ago committed by GitHub
parent 3153384928
commit fd0bc29973
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: correctly validate head snippets on the server

@ -6,7 +6,7 @@ import {
} from '../../html-tree-validation.js'; } from '../../html-tree-validation.js';
import { current_component } from './context.js'; import { current_component } from './context.js';
import { invalid_snippet_arguments } from '../shared/errors.js'; import { invalid_snippet_arguments } from '../shared/errors.js';
import { Payload } from './payload.js'; import { HeadPayload, Payload } from './payload.js';
/** /**
* @typedef {{ * @typedef {{
@ -105,7 +105,11 @@ export function pop_element() {
* @param {Payload} payload * @param {Payload} payload
*/ */
export function validate_snippet_args(payload) { export function validate_snippet_args(payload) {
if (typeof payload !== 'object' || !(payload instanceof Payload)) { if (
typeof payload !== 'object' ||
// for some reason typescript consider the type of payload as never after the first instanceof
!(payload instanceof Payload || /** @type {any} */ (payload) instanceof HeadPayload)
) {
invalid_snippet_arguments(); invalid_snippet_arguments();
} }
} }

@ -1,16 +1,25 @@
export class Payload { export class HeadPayload {
/** @type {Set<{ hash: string; code: string }>} */ /** @type {Set<{ hash: string; code: string }>} */
css = new Set(); css = new Set();
out = ''; out = '';
uid = () => ''; uid = () => '';
title = '';
head = { constructor(css = new Set(), out = '', title = '', uid = () => '') {
this.css = css;
this.out = out;
this.title = title;
this.uid = uid;
}
}
export class Payload {
/** @type {Set<{ hash: string; code: string }>} */ /** @type {Set<{ hash: string; code: string }>} */
css: new Set(), css = new Set();
title: '', out = '';
out: '', uid = () => '';
uid: () => ''
}; head = new HeadPayload();
constructor(id_prefix = '') { constructor(id_prefix = '') {
this.uid = props_id_generator(id_prefix); this.uid = props_id_generator(id_prefix);
@ -30,12 +39,11 @@ export function copy_payload({ out, css, head, uid }) {
payload.css = new Set(css); payload.css = new Set(css);
payload.uid = uid; payload.uid = uid;
payload.head = { payload.head = new HeadPayload();
title: head.title, payload.head.out = head.out;
out: head.out, payload.head.css = new Set(head.css);
css: new Set(head.css), payload.head.title = head.title;
uid: head.uid payload.head.uid = head.uid;
};
return payload; return payload;
} }

@ -0,0 +1,11 @@
import { test } from '../../test';
export default test({
compileOptions: {
dev: true
},
mode: ['server'],
async test({ errors, assert }) {
assert.equal(errors, []);
}
});

@ -0,0 +1,7 @@
{#snippet head()}
<title>Cool</title>
{/snippet}
<svelte:head>
{@render head()}
</svelte:head>
Loading…
Cancel
Save