diff --git a/.changeset/witty-lies-happen.md b/.changeset/witty-lies-happen.md new file mode 100644 index 0000000000..01f5bed7b9 --- /dev/null +++ b/.changeset/witty-lies-happen.md @@ -0,0 +1,5 @@ +--- +'svelte': minor +--- + +Add TrustedTypes support diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 2d88d2a051..18421174ed 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -166,6 +166,7 @@ "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", + "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", diff --git a/packages/svelte/src/internal/client/dom/reconciler.js b/packages/svelte/src/internal/client/dom/reconciler.js index 8d3b5c0495..2cd965e9fc 100644 --- a/packages/svelte/src/internal/client/dom/reconciler.js +++ b/packages/svelte/src/internal/client/dom/reconciler.js @@ -1,6 +1,25 @@ +/** @import { TrustedTypePolicy } from 'trusted-types' */ + +/** @type {Pick | undefined} */ +let policy; + +if (globalThis?.window?.trustedTypes) { + policy = globalThis.window.trustedTypes.createPolicy('svelte-trusted-html', { + /** @param {string} html */ + createHTML: (html) => { + return html; + } + }); +} + +/** @param {string} html */ +function create_trusted_html(html) { + return /** @type {string} */(policy?.createHTML(html) ?? html); +} + /** @param {string} html */ export function create_fragment_from_html(html) { var elem = document.createElement('template'); - elem.innerHTML = html.replaceAll('', ''); // XHTML compliance + elem.innerHTML = create_trusted_html(html.replaceAll('', '')); // XHTML compliance return elem.content; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b7fb655b2d..222f93fa1e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,6 +71,9 @@ importers: '@types/estree': specifier: ^1.0.5 version: 1.0.6 + '@types/trusted-types': + specifier: ^2.0.7 + version: 2.0.7 acorn: specifier: ^8.12.1 version: 8.14.0 @@ -797,6 +800,9 @@ packages: '@types/semver@7.5.6': resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@typescript-eslint/eslint-plugin@8.26.0': resolution: {integrity: sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3059,6 +3065,8 @@ snapshots: '@types/semver@7.5.6': {} + '@types/trusted-types@2.0.7': {} + '@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4)': dependencies: '@eslint-community/regexpp': 4.12.1