diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index bdf70408f1..0481621ce1 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -167,7 +167,7 @@ export function client_component(analysis, options) { in_constructor: false, instance_level_snippets: [], module_level_snippets: [], - prevent_template_cloning: options.preventTemplateCloning, + is_functional_template_mode: options.templatingMode === 'functional', // these are set inside the `Fragment` visitor, and cannot be used until then init: /** @type {any} */ (null), diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-template/index.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-template/index.js index 98b830a907..f28e2cf78e 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-template/index.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-template/index.js @@ -27,7 +27,7 @@ function get_template_function(namespace, state) { : contains_script_tag ? '$.template_with_script' : '$.template' - ).concat(state.prevent_template_cloning ? '_fn' : ''); + ).concat(state.is_functional_template_mode ? '_fn' : ''); } /** @@ -75,7 +75,7 @@ export function transform_template(state, context, namespace, template_name, fla /** @type {Expression[]} */ const args = [ - state.prevent_template_cloning + state.is_functional_template_mode ? template_to_functions(state.template, namespace) : b.template([b.quasi(template_to_string(state.template), true)], []) ]; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts index a73e0e0e83..fb20ebe79f 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts +++ b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts @@ -94,7 +94,7 @@ export interface ComponentClientTransformState extends ClientTransformState { }; }; readonly preserve_whitespace: boolean; - readonly prevent_template_cloning?: boolean; + readonly is_functional_template_mode?: boolean; /** The anchor node for the current context */ readonly node: Identifier; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js index 98f8b0c2e9..12abc8e9e0 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js @@ -37,7 +37,7 @@ export function Fragment(node, context) { context.state, context.state.preserve_whitespace, context.state.options.preserveComments, - context.state.prevent_template_cloning + context.state.is_functional_template_mode ); if (hoisted.length === 0 && trimmed.length === 0) { @@ -133,7 +133,7 @@ export function Fragment(node, context) { ...context, state }, - context.state.prevent_template_cloning + context.state.is_functional_template_mode ); body.push(b.var(id, b.call('$.text'))); @@ -146,7 +146,7 @@ export function Fragment(node, context) { () => b.id('$$anchor'), false, { ...context, state }, - context.state.prevent_template_cloning + context.state.is_functional_template_mode ); } else { /** @type {(is_text: boolean) => Expression} */ @@ -157,7 +157,7 @@ export function Fragment(node, context) { expression, false, { ...context, state }, - context.state.prevent_template_cloning + context.state.is_functional_template_mode ); let flags = TEMPLATE_FRAGMENT; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js index fb2bb1da20..fd8f27bc4a 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js @@ -124,7 +124,7 @@ export function RegularElement(node, context) { kind: 'set_prop', args: [ 'is', - context.state.prevent_template_cloning + context.state.is_functional_template_mode ? value.value : escape_html(value.value, true) ] @@ -312,7 +312,7 @@ export function RegularElement(node, context) { : [ value === true ? '' - : context.state.prevent_template_cloning + : context.state.is_functional_template_mode ? value : escape_html(value, true) ] @@ -386,7 +386,7 @@ export function RegularElement(node, context) { state, node.name === 'script' || state.preserve_whitespace, state.options.preserveComments, - state.prevent_template_cloning + state.is_functional_template_mode ); /** @type {typeof state} */ @@ -438,7 +438,7 @@ export function RegularElement(node, context) { ...context, state: child_state }, - context.state.prevent_template_cloning + context.state.is_functional_template_mode ); if (needs_reset) { diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js index 6ec6b5322c..fd6f6853d0 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js @@ -15,14 +15,14 @@ import { build_template_chunk } from './utils.js'; * @param {(is_text: boolean) => Expression} initial * @param {boolean} is_element * @param {ComponentContext} context - * @param {boolean} [prevent_template_cloning] + * @param {boolean} [is_functional_template_mode] */ export function process_children( nodes, initial, is_element, { visit, state }, - prevent_template_cloning + is_functional_template_mode ) { const within_bound_contenteditable = state.metadata.bound_contenteditable; let prev = initial; @@ -73,7 +73,9 @@ export function process_children( skipped += 1; state.template.push({ kind: 'create_text', - args: [sequence.map((node) => (prevent_template_cloning ? node.data : node.raw)).join('')] + args: [ + sequence.map((node) => (is_functional_template_mode ? node.data : node.raw)).join('') + ] }); return; } diff --git a/packages/svelte/src/compiler/phases/3-transform/utils.js b/packages/svelte/src/compiler/phases/3-transform/utils.js index e1ef6ef4c9..93e4c34479 100644 --- a/packages/svelte/src/compiler/phases/3-transform/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/utils.js @@ -141,7 +141,7 @@ function sort_const_tags(nodes, state) { * @param {TransformState & { options: ValidatedCompileOptions }} state * @param {boolean} preserve_whitespace * @param {boolean} preserve_comments - * @param {boolean} [prevent_template_cloning] + * @param {boolean} [is_functional_template_mode] */ export function clean_nodes( parent, @@ -154,7 +154,7 @@ export function clean_nodes( // rather than from `ClientTransformState` and `ServerTransformState` preserve_whitespace, preserve_comments, - prevent_template_cloning + is_functional_template_mode ) { if (!state.analysis.runes) { nodes = sort_const_tags(nodes, state); @@ -276,13 +276,13 @@ export function clean_nodes( // initial newline inside a `
` is disregarded, if not followed by another newline if ( parent.type === 'RegularElement' && - (parent.name === 'pre' || (prevent_template_cloning && parent.name === 'textarea')) && + (parent.name === 'pre' || (is_functional_template_mode && parent.name === 'textarea')) && first?.type === 'Text' ) { const text = first.data.replace(regex_starts_with_newline, ''); if (text !== first.data) { const tmp = text.replace(regex_starts_with_newline, ''); - if (text === tmp || prevent_template_cloning) { + if (text === tmp || is_functional_template_mode) { first.data = text; first.raw = first.raw.replace(regex_starts_with_newline, ''); if (first.data === '') { diff --git a/packages/svelte/src/compiler/types/index.d.ts b/packages/svelte/src/compiler/types/index.d.ts index 4161c71206..4aa244ad51 100644 --- a/packages/svelte/src/compiler/types/index.d.ts +++ b/packages/svelte/src/compiler/types/index.d.ts @@ -114,11 +114,11 @@ export interface CompileOptions extends ModuleCompileOptions { */ preserveWhitespace?: boolean; /** - * If `true`, the template will get compiled to a series of `document.createElement` calls instead of using `template.innerHTML`. + * If `functional`, the template will get compiled to a series of `document.createElement` calls, if `string` it will render the template tp a string and use `template.innerHTML`. * - * @default false + * @default 'string' */ - preventTemplateCloning?: boolean; + templatingMode?: 'string' | 'functional'; /** * Set to `true` to force the compiler into runes mode, even if there are no indications of runes usage. * Set to `false` to force the compiler into ignoring runes, even if there are indications of runes usage. diff --git a/packages/svelte/src/compiler/validate-options.js b/packages/svelte/src/compiler/validate-options.js index 5e6eaf5ef6..1d67951fd8 100644 --- a/packages/svelte/src/compiler/validate-options.js +++ b/packages/svelte/src/compiler/validate-options.js @@ -110,7 +110,7 @@ export const validate_component_options = preserveComments: boolean(false), - preventTemplateCloning: boolean(false), + templatingMode: list(['string', 'functional']), preserveWhitespace: boolean(false), diff --git a/packages/svelte/tests/helpers.js b/packages/svelte/tests/helpers.js index 164d855e89..684bde3875 100644 --- a/packages/svelte/tests/helpers.js +++ b/packages/svelte/tests/helpers.js @@ -80,7 +80,7 @@ export async function compile_directory( filename: path.join(cwd, file), ...compileOptions, generate, - preventTemplateCloning: templating_mode === 'functional' + templatingMode: templating_mode }; if (file.endsWith('.js')) { diff --git a/packages/svelte/tests/runtime-browser/test.ts b/packages/svelte/tests/runtime-browser/test.ts index 0f7b259715..02823ad87b 100644 --- a/packages/svelte/tests/runtime-browser/test.ts +++ b/packages/svelte/tests/runtime-browser/test.ts @@ -106,7 +106,7 @@ async function run_test( immutable: config.immutable, customElement: test_dir.includes('custom-elements-samples'), accessors: 'accessors' in config ? config.accessors : true, - preventTemplateCloning: templating_mode === 'functional' + templatingMode: templating_mode }); write( @@ -171,7 +171,7 @@ async function run_test( immutable: config.immutable, customElement: test_dir.includes('custom-elements-samples'), accessors: 'accessors' in config ? config.accessors : true, - preventTemplateCloning: templating_mode === 'functional' + templatingMode: templating_mode }); return { diff --git a/packages/svelte/tests/runtime-legacy/shared.ts b/packages/svelte/tests/runtime-legacy/shared.ts index 8acac668f9..4630a4924c 100644 --- a/packages/svelte/tests/runtime-legacy/shared.ts +++ b/packages/svelte/tests/runtime-legacy/shared.ts @@ -168,7 +168,7 @@ async function common_setup( immutable: config.immutable, accessors: 'accessors' in config ? config.accessors : true, runes, - preventTemplateCloning: templating_mode === 'functional' + templatingMode: templating_mode }; // load_compiled can be used for debugging a test. It means the compiler will not run on the input diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index ef0179f3f1..19bb6e9279 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -845,11 +845,11 @@ declare module 'svelte/compiler' { */ preserveWhitespace?: boolean; /** - * If `true`, the template will get compiled to a series of `document.createElement` calls instead of using `template.innerHTML`. + * If `functional`, the template will get compiled to a series of `document.createElement` calls, if `string` it will render the template tp a string and use `template.innerHTML`. * - * @default false + * @default 'string' */ - preventTemplateCloning?: boolean; + templatingMode?: 'string' | 'functional'; /** * Set to `true` to force the compiler into runes mode, even if there are no indications of runes usage. * Set to `false` to force the compiler into ignoring runes, even if there are indications of runes usage. @@ -2561,11 +2561,11 @@ declare module 'svelte/types/compiler/interfaces' { */ preserveWhitespace?: boolean; /** - * If `true`, the template will get compiled to a series of `document.createElement` calls instead of using `template.innerHTML`. + * If `functional`, the template will get compiled to a series of `document.createElement` calls, if `string` it will render the template tp a string and use `template.innerHTML`. * - * @default false + * @default 'string' */ - preventTemplateCloning?: boolean; + templatingMode?: 'string' | 'functional'; /** * Set to `true` to force the compiler into runes mode, even if there are no indications of runes usage. * Set to `false` to force the compiler into ignoring runes, even if there are indications of runes usage.