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 f28e2cf78ec3..becf987be915 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 @@ -76,7 +76,7 @@ export function transform_template(state, context, namespace, template_name, fla /** @type {Expression[]} */ const args = [ state.is_functional_template_mode - ? template_to_functions(state.template, namespace) + ? template_to_functions(state.template) : b.template([b.quasi(template_to_string(state.template), true)], []) ]; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-template/to-functions.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-template/to-functions.js index b109ea334ff6..ecf8151836ae 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-template/to-functions.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-template/to-functions.js @@ -1,56 +1,24 @@ /** * @import { TemplateOperations } from "../types.js" * @import { Namespace } from "#compiler" - * @import { CallExpression, Statement } from "estree" + * @import { CallExpression, Statement, ObjectExpression, Identifier, ArrayExpression, Property, Expression, Literal } from "estree" */ import { NAMESPACE_SVG, NAMESPACE_MATHML } from '../../../../../constants.js'; import * as b from '../../../../utils/builders.js'; +import { regex_is_valid_identifier } from '../../../patterns.js'; import fix_attribute_casing from './fix-attribute-casing.js'; -class Scope { - declared = new Map(); - - /** - * @param {string} _name - */ - generate(_name) { - let name = _name.replace(/[^a-zA-Z0-9_$]/g, '_').replace(/^[0-9]/, '_'); - if (!this.declared.has(name)) { - this.declared.set(name, 1); - return name; - } - let count = this.declared.get(name); - this.declared.set(name, count + 1); - return `${name}_${count}`; - } -} - /** * @param {TemplateOperations} items - * @param {Namespace} namespace */ -export function template_to_functions(items, namespace) { - let elements = []; - - let body = []; - - let scope = new Scope(); +export function template_to_functions(items) { + let elements = b.array([]); /** * @type {Array} */ let elements_stack = []; - /** - * @type {Array} - */ - let namespace_stack = []; - - /** - * @type {number} - */ - let foreign_object_count = 0; - /** * @type {Element | undefined} */ @@ -71,89 +39,48 @@ export function template_to_functions(items, namespace) { // we closed one element, we remove it from the stack and eventually revert back // the namespace to the previous one if (instruction.kind === 'pop_element') { - const removed = elements_stack.pop(); - if (removed?.namespaced) { - namespace_stack.pop(); - } - if (removed?.element === 'foreignObject') { - foreign_object_count--; - } + elements_stack.pop(); continue; } - // if the inserted node is in the svg/mathml we push the namespace to the stack because we need to - // create with createElementNS - if (instruction.metadata?.svg || instruction.metadata?.mathml) { - namespace_stack.push(instruction.metadata.svg ? NAMESPACE_SVG : NAMESPACE_MATHML); - } - // @ts-expect-error we can't be here if `swap_current_element` but TS doesn't know that const value = map[instruction.kind]( ...[ - // for set prop we need to send the last element (not the one in the stack since - // it get's added to the stack only after the push_element instruction)...for all the rest - // the first prop is a the scope to generate the name of the variable - ...(instruction.kind === 'set_prop' ? [last_current_element] : [scope]), - // for create element we also need to add the namespace...namespaces in the stack get's precedence over - // the "global" namespace (and if we are in a foreignObject we default to html) ...(instruction.kind === 'create_element' - ? [ - foreign_object_count > 0 - ? undefined - : namespace_stack.at(-1) ?? - (namespace === 'svg' - ? NAMESPACE_SVG - : namespace === 'mathml' - ? NAMESPACE_MATHML - : undefined) - ] - : []), + ? [] + : [instruction.kind === 'set_prop' ? last_current_element : elements_stack.at(-1)]), ...(instruction.args ?? []) ] ); - if (value) { - // this will compose the body of the function - body.push(value.call); - } - // with set_prop we don't need to do anything else, in all other cases we also need to // append the element/node/anchor to the current active element or push it in the elements array if (instruction.kind !== 'set_prop') { - if (elements_stack.length >= 1 && value) { - const { call } = map.insert(/** @type {Element} */ (elements_stack.at(-1)), value); - body.push(call); - } else if (value) { - elements.push(b.id(value.name)); + if (elements_stack.length >= 1 && value !== undefined) { + map.insert(/** @type {Element} */ (elements_stack.at(-1)), value); + } else if (value !== undefined) { + elements.elements.push(value); } // keep track of the last created element (it will be pushed to the stack after the props are set) if (instruction.kind === 'create_element') { last_current_element = /** @type {Element} */ (value); - if (last_current_element.element === 'foreignObject') { - foreign_object_count++; - } } } } - // every function needs to return a fragment so we create one and push all the elements there - const fragment = scope.generate('fragment'); - body.push(b.var(fragment, b.call('document.createDocumentFragment'))); - body.push(b.call(fragment + '.append', ...elements)); - body.push(b.return(b.id(fragment))); - return b.arrow([], b.block(body)); + return elements; } /** - * @typedef {{ call: Statement, name: string, add_is: (value: string)=>void, namespaced: boolean; element: string; }} Element + * @typedef {ObjectExpression} Element */ /** - * @typedef {{ call: Statement, name: string }} Anchor + * @typedef {void | null | ArrayExpression} Anchor */ /** - * @typedef {{ call: Statement, name: string }} Text + * @typedef {void | Literal} Text */ /** @@ -161,109 +88,89 @@ export function template_to_functions(items, namespace) { */ /** - * @param {Scope} scope - * @param {Namespace} namespace * @param {string} element * @returns {Element} */ -function create_element(scope, namespace, element) { - const name = scope.generate(element); - let fn = namespace != null ? 'document.createElementNS' : 'document.createElement'; - let args = [b.literal(element)]; - if (namespace != null) { - args.unshift(b.literal(namespace)); - } - const call = b.var(name, b.call(fn, ...args)); - /** - * if there's an "is" attribute we can't just add it as a property, it needs to be - * specified on creation like this `document.createElement('button', { is: 'my-button' })` - * - * Since the props are appended after the creation we change the generated call arguments and we push - * the is attribute later on on `set_prop` - * @param {string} value - */ - function add_is(value) { - /** @type {CallExpression} */ (call.declarations[0].init).arguments.push( - b.object([b.prop('init', b.literal('is'), b.literal(value))]) - ); +function create_element(element) { + return b.object([b.prop('init', b.id('e'), b.literal(element))]); +} + +/** + * + * @param {Element} element + * @param {string} name + * @param {Expression} init + * @returns {Property} + */ +function get_or_create_prop(element, name, init) { + let prop = element.properties.find( + (prop) => prop.type === 'Property' && /** @type {Identifier} */ (prop.key).name === name + ); + if (!prop) { + prop = b.prop('init', b.id(name), init); + element.properties.push(prop); } - return { - call, - name, - element, - add_is, - namespaced: namespace != null - }; + return /** @type {Property} */ (prop); } /** - * @param {Scope} scope + * @param {Element} element * @param {string} data * @returns {Anchor} */ -function create_anchor(scope, data = '') { - const name = scope.generate('comment'); - return { - call: b.var(name, b.call('document.createComment', b.literal(data))), - name - }; +function create_anchor(element, data = '') { + if (!element) return data ? b.array([b.literal(data)]) : null; + const c = get_or_create_prop(element, 'c', b.array([])); + /** @type {ArrayExpression} */ (c.value).elements.push(data ? b.array([b.literal(data)]) : null); } /** - * @param {Scope} scope + * @param {Element} element * @param {string} value * @returns {Text} */ -function create_text(scope, value) { - const name = scope.generate('text'); - return { - call: b.var(name, b.call('document.createTextNode', b.literal(value))), - name - }; +function create_text(element, value) { + if (!element) return b.literal(value); + const c = get_or_create_prop(element, 'c', b.array([])); + /** @type {ArrayExpression} */ (c.value).elements.push(b.literal(value)); } /** * - * @param {Element} el + * @param {Element} element * @param {string} prop * @param {string} value */ -function set_prop(el, prop, value) { - // see comment above about the "is" attribute +function set_prop(element, prop, value) { + const p = get_or_create_prop(element, 'p', b.object([])); + if (prop === 'is') { - el.add_is(value); + element.properties.push(b.prop('init', b.id(prop), b.literal(value))); return; } - const [namespace] = prop.split(':'); - let fn = namespace !== prop ? '.setAttributeNS' : '.setAttribute'; - let args = [b.literal(fix_attribute_casing(prop)), b.literal(value ?? '')]; + const prop_correct_case = fix_attribute_casing(prop); - // attributes like `xlink:href` need to be set with the `xlink` namespace - if (namespace === 'xlink') { - args.unshift(b.literal('http://www.w3.org/1999/xlink')); - } + const is_valid_id = regex_is_valid_identifier.test(prop_correct_case); - return { - call: b.call(el.name + fn, ...args) - }; + /** @type {ObjectExpression} */ (p.value).properties.push( + b.prop( + 'init', + (is_valid_id ? b.id : b.literal)(prop_correct_case), + b.literal(value), + !is_valid_id + ) + ); } /** * - * @param {Element} el - * @param {Node} child - * @param {Node} [anchor] + * @param {Element} element + * @param {Element} child */ -function insert(el, child, anchor) { - return { - call: b.call( - // if we have a template element we need to push into it's content rather than the element itself - el.name + (el.element === 'template' ? '.content' : '') + '.insertBefore', - b.id(child.name), - b.id(anchor?.name ?? 'undefined') - ) - }; +function insert(element, child) { + const c = get_or_create_prop(element, 'c', b.array([])); + /** @type {ArrayExpression} */ (c.value).elements.push(child); } let map = { diff --git a/packages/svelte/src/internal/client/dom/operations.js b/packages/svelte/src/internal/client/dom/operations.js index aae44d4b3989..97062f04e38d 100644 --- a/packages/svelte/src/internal/client/dom/operations.js +++ b/packages/svelte/src/internal/client/dom/operations.js @@ -204,3 +204,44 @@ export function sibling(node, count = 1, is_text = false) { export function clear_text_content(node) { node.textContent = ''; } + +/** + * + * @param {string} tag + * @param {string} [namespace] + * @param {string} [is] + * @returns + */ +export function create_element(tag, namespace, is) { + let options = is ? { is } : undefined; + if (namespace) { + return document.createElementNS(namespace, tag, options); + } + return document.createElement(tag, options); +} + +export function create_fragment() { + return document.createDocumentFragment(); +} + +/** + * @param {string} data + * @returns + */ +export function create_comment(data = '') { + return document.createComment(data); +} + +/** + * @param {Element} element + * @param {string} key + * @param {string} value + * @returns + */ +export function set_attribute(element, key, value = '') { + if (key.startsWith('xlink:')) { + element.setAttributeNS('http://www.w3.org/1999/xlink', key, value); + return; + } + return element.setAttribute(key, value); +} diff --git a/packages/svelte/src/internal/client/dom/template.js b/packages/svelte/src/internal/client/dom/template.js index bd4d60837d62..21fba1f5d909 100644 --- a/packages/svelte/src/internal/client/dom/template.js +++ b/packages/svelte/src/internal/client/dom/template.js @@ -1,9 +1,22 @@ /** @import { Effect, TemplateNode } from '#client' */ import { hydrate_next, hydrate_node, hydrating, set_hydrate_node } from './hydration.js'; -import { create_text, get_first_child, is_firefox } from './operations.js'; +import { + create_text, + get_first_child, + is_firefox, + create_element, + create_fragment, + create_comment, + set_attribute +} from './operations.js'; import { create_fragment_from_html } from './reconciler.js'; import { active_effect } from '../runtime.js'; -import { TEMPLATE_FRAGMENT, TEMPLATE_USE_IMPORT_NODE } from '../../../constants.js'; +import { + NAMESPACE_MATHML, + NAMESPACE_SVG, + TEMPLATE_FRAGMENT, + TEMPLATE_USE_IMPORT_NODE +} from '../../../constants.js'; /** * @param {TemplateNode} start @@ -65,12 +78,75 @@ export function template(content, flags) { } /** - * @param {()=>(DocumentFragment | Node)} fn + * @typedef {{e: string, is?: string, p: Record, c: Array} | null | string | [string]} TemplateStructure + */ + +/** + * @param {Array} structure + * @param {'svg' | 'math'} [ns] + * @param {Array} [namespace_stack] + */ +function structure_to_fragment(structure, ns, namespace_stack = [], foreign_object_count = 0) { + var fragment = create_fragment(); + for (var i = 0; i < structure.length; i += 1) { + var item = structure[i]; + if (item == null || Array.isArray(item)) { + const data = item ? item[0] : ''; + fragment.append(create_comment(data)); + } else if (typeof item === 'string') { + fragment.append(create_text(item)); + continue; + } else { + let namespace = + foreign_object_count > 0 + ? undefined + : namespace_stack[namespace_stack.length - 1] ?? + (ns + ? ns === 'svg' + ? NAMESPACE_SVG + : ns === 'math' + ? NAMESPACE_MATHML + : undefined + : item.e === 'svg' + ? NAMESPACE_SVG + : item.e === 'math' + ? NAMESPACE_MATHML + : undefined); + if (namespace !== namespace_stack[namespace_stack.length - 1]) { + namespace_stack.push(namespace); + } + var element = create_element(item.e, namespace, item.is); + + for (var key in item.p) { + set_attribute(element, key, item.p[key]); + } + if (item.c) { + (element.tagName === 'TEMPLATE' + ? /** @type {HTMLTemplateElement} */ (element).content + : element + ).append( + ...structure_to_fragment( + item.c, + ns, + namespace_stack, + element.tagName === 'foreignObject' ? foreign_object_count + 1 : foreign_object_count + ).childNodes + ); + } + namespace_stack.pop(); + fragment.append(element); + } + } + return fragment; +} + +/** + * @param {Array} structure * @param {number} flags * @returns {() => Node | Node[]} */ /*#__NO_SIDE_EFFECTS__*/ -export function template_fn(fn, flags) { +export function template_fn(structure, flags) { var is_fragment = (flags & TEMPLATE_FRAGMENT) !== 0; var use_import_node = (flags & TEMPLATE_USE_IMPORT_NODE) !== 0; @@ -84,7 +160,7 @@ export function template_fn(fn, flags) { } if (node === undefined) { - node = fn(); + node = structure_to_fragment(structure); if (!is_fragment) node = /** @type {Node} */ (get_first_child(node)); } @@ -117,12 +193,12 @@ export function template_with_script(content, flags) { } /** - * @param {()=>(DocumentFragment | Node)} fn + * @param {Array} structure * @param {number} flags * @returns {() => Node | Node[]} */ /*#__NO_SIDE_EFFECTS__*/ -export function template_with_script_fn(fn, flags) { - var templated_fn = template_fn(fn, flags); +export function template_with_script_fn(structure, flags) { + var templated_fn = template_fn(structure, flags); return () => run_scripts(/** @type {Element | DocumentFragment} */ (templated_fn())); } @@ -182,13 +258,13 @@ export function ns_template(content, flags, ns = 'svg') { } /** - * @param {()=>(DocumentFragment | Node)} fn + * @param {Array} structure * @param {number} flags * @param {'svg' | 'math'} ns * @returns {() => Node | Node[]} */ /*#__NO_SIDE_EFFECTS__*/ -export function ns_template_fn(fn, flags, ns = 'svg') { +export function ns_template_fn(structure, flags, ns = 'svg') { var is_fragment = (flags & TEMPLATE_FRAGMENT) !== 0; /** @type {Element | DocumentFragment} */ @@ -201,7 +277,7 @@ export function ns_template_fn(fn, flags, ns = 'svg') { } if (!node) { - var fragment = /** @type {DocumentFragment} */ (fn()); + var fragment = structure_to_fragment(structure, ns); if (is_fragment) { node = document.createDocumentFragment(); @@ -240,13 +316,13 @@ export function svg_template_with_script(content, flags) { } /** - * @param {()=>(DocumentFragment | Node)} fn + * @param {Array} structure * @param {number} flags * @returns {() => Node | Node[]} */ /*#__NO_SIDE_EFFECTS__*/ -export function svg_template_with_script_fn(fn, flags) { - var templated_fn = ns_template_fn(fn, flags); +export function svg_template_with_script_fn(structure, flags) { + var templated_fn = ns_template_fn(structure, flags); return () => run_scripts(/** @type {Element | DocumentFragment} */ (templated_fn())); } @@ -261,13 +337,13 @@ export function mathml_template(content, flags) { } /** - * @param {()=>(DocumentFragment | Node)} fn + * @param {Array} structure * @param {number} flags * @returns {() => Node | Node[]} */ /*#__NO_SIDE_EFFECTS__*/ -export function mathml_template_fn(fn, flags) { - return ns_template_fn(fn, flags, 'math'); +export function mathml_template_fn(structure, flags) { + return ns_template_fn(structure, flags, 'math'); } /** diff --git a/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/client-functional/index.svelte.js index 262454e9c329..44b0cd1557aa 100644 --- a/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/client-functional/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/await-block-scope/_expected/client-functional/index.svelte.js @@ -5,23 +5,7 @@ function increment(_, counter) { counter.count += 1; } -var root = $.template_fn( - () => { - var button = document.createElement('button'); - var text = document.createTextNode(' '); - - button.insertBefore(text, undefined) - - var text_1 = document.createTextNode(' '); - var comment = document.createComment(''); - var text_2 = document.createTextNode(' '); - var fragment = document.createDocumentFragment(); - - fragment.append(button, text_1, comment, text_2) - return fragment; - }, - 1 -); +var root = $.template_fn([{ e: 'button', c: [' '] }, ' ', , ' '], 1); export default function Await_block_scope($$anchor) { let counter = $.proxy({ count: 0 }); diff --git a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client-functional/index.svelte.js index 8c15aa74ba1f..e06c3bbf6bc8 100644 --- a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client-functional/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client-functional/index.svelte.js @@ -10,18 +10,7 @@ const snippet = ($$anchor) => { $.append($$anchor, text); }; -var root = $.template_fn( - () => { - var comment = document.createComment(''); - var comment_1 = document.createComment(''); - var text = document.createTextNode(' '); - var fragment = document.createDocumentFragment(); - - fragment.append(comment, comment_1, text) - return fragment; - }, - 1 -); +var root = $.template_fn([,, ' '], 1); export default function Bind_component_snippet($$anchor) { let value = $.state(''); diff --git a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client-functional/main.svelte.js b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client-functional/main.svelte.js index c05184f1f82a..6bf2d77a00bd 100644 --- a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client-functional/main.svelte.js +++ b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client-functional/main.svelte.js @@ -2,23 +2,19 @@ import 'svelte/internal/disclose-version'; import * as $ from 'svelte/internal/client'; var root = $.template_fn( - () => { - var div = document.createElement('div'); - var text = document.createTextNode(' '); - var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - var text_1 = document.createTextNode(' '); - var custom_element = document.createElement('custom-element'); - var text_2 = document.createTextNode(' '); - var div_1 = document.createElement('div'); - var text_3 = document.createTextNode(' '); - var svg_1 = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - var text_4 = document.createTextNode(' '); - var custom_element_1 = document.createElement('custom-element'); - var fragment = document.createDocumentFragment(); - - fragment.append(div, text, svg, text_1, custom_element, text_2, div_1, text_3, svg_1, text_4, custom_element_1) - return fragment; - }, + [ + { e: 'div' }, + ' ', + { e: 'svg' }, + ' ', + { e: 'custom-element' }, + ' ', + { e: 'div' }, + ' ', + { e: 'svg' }, + ' ', + { e: 'custom-element' } + ], 3 ); diff --git a/packages/svelte/tests/snapshot/samples/hello-world/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/hello-world/_expected/client-functional/index.svelte.js index 5f55a12c20c1..3cc49718838f 100644 --- a/packages/svelte/tests/snapshot/samples/hello-world/_expected/client-functional/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/hello-world/_expected/client-functional/index.svelte.js @@ -2,17 +2,7 @@ import 'svelte/internal/disclose-version'; import 'svelte/internal/flags/legacy'; import * as $ from 'svelte/internal/client'; -var root = $.template_fn(() => { - var h1 = document.createElement('h1'); - var text = document.createTextNode('hello world'); - - h1.insertBefore(text, undefined) - - var fragment = document.createDocumentFragment(); - - fragment.append(h1) - return fragment; -}); +var root = $.template_fn([{ e: 'h1', c: ['hello world'] }]); export default function Hello_world($$anchor) { var h1 = root(); diff --git a/packages/svelte/tests/snapshot/samples/hmr/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/hmr/_expected/client-functional/index.svelte.js index 6196ed18bbd8..d5bb01474cf9 100644 --- a/packages/svelte/tests/snapshot/samples/hmr/_expected/client-functional/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/hmr/_expected/client-functional/index.svelte.js @@ -2,17 +2,7 @@ import 'svelte/internal/disclose-version'; import 'svelte/internal/flags/legacy'; import * as $ from 'svelte/internal/client'; -var root = $.template_fn(() => { - var h1 = document.createElement('h1'); - var text = document.createTextNode('hello world'); - - h1.insertBefore(text, undefined) - - var fragment = document.createDocumentFragment(); - - fragment.append(h1) - return fragment; -}); +var root = $.template_fn([{ e: 'h1', c: ['hello world'] }]); function Hmr($$anchor) { var h1 = root(); diff --git a/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/client-functional/index.svelte.js index 6b48b03635c5..3a2d0ecaa29e 100644 --- a/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/client-functional/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/client-functional/index.svelte.js @@ -4,23 +4,15 @@ import * as $ from 'svelte/internal/client'; var on_click = (_, count) => $.update(count); var root = $.template_fn( - () => { - var h1 = document.createElement('h1'); - var text = document.createTextNode(' '); - var b = document.createElement('b'); - var text_1 = document.createTextNode(' '); - var button = document.createElement('button'); - var text_2 = document.createTextNode(' '); - - button.insertBefore(text_2, undefined) - - var text_3 = document.createTextNode(' '); - var h1_1 = document.createElement('h1'); - var fragment = document.createDocumentFragment(); - - fragment.append(h1, text, b, text_1, button, text_3, h1_1) - return fragment; - }, + [ + { e: 'h1' }, + ' ', + { e: 'b' }, + ' ', + { e: 'button', c: [' '] }, + ' ', + { e: 'h1' } + ], 1 ); diff --git a/packages/svelte/tests/snapshot/samples/purity/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/purity/_expected/client-functional/index.svelte.js index 409a0d93aa49..d6de4ff4d04f 100644 --- a/packages/svelte/tests/snapshot/samples/purity/_expected/client-functional/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/purity/_expected/client-functional/index.svelte.js @@ -2,20 +2,7 @@ import 'svelte/internal/disclose-version'; import 'svelte/internal/flags/legacy'; import * as $ from 'svelte/internal/client'; -var root = $.template_fn( - () => { - var p = document.createElement('p'); - var text = document.createTextNode(' '); - var p_1 = document.createElement('p'); - var text_1 = document.createTextNode(' '); - var comment = document.createComment(''); - var fragment = document.createDocumentFragment(); - - fragment.append(p, text, p_1, text_1, comment) - return fragment; - }, - 1 -); +var root = $.template_fn([{ e: 'p' }, ' ', { e: 'p' }, ' ', ,], 1); export default function Purity($$anchor) { var fragment = root(); diff --git a/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/client-functional/index.svelte.js index 8023738996ba..b838acb2d6c8 100644 --- a/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/client-functional/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/client-functional/index.svelte.js @@ -2,238 +2,94 @@ import 'svelte/internal/disclose-version'; import * as $ from 'svelte/internal/client'; var root = $.template_fn( - () => { - var header = document.createElement('header'); - var nav = document.createElement('nav'); - - header.insertBefore(nav, undefined) - - var a = document.createElement('a'); - - nav.insertBefore(a, undefined) - a.setAttribute('href', '/') - - var text = document.createTextNode('Home'); - - a.insertBefore(text, undefined) - - var text_1 = document.createTextNode(' '); - - nav.insertBefore(text_1, undefined) - - var a_1 = document.createElement('a'); - - nav.insertBefore(a_1, undefined) - a_1.setAttribute('href', '/away') - - var text_2 = document.createTextNode('Away'); - - a_1.insertBefore(text_2, undefined) - - var text_3 = document.createTextNode(' '); - var main = document.createElement('main'); - var h1 = document.createElement('h1'); - - main.insertBefore(h1, undefined) - - var text_4 = document.createTextNode(' '); - - h1.insertBefore(text_4, undefined) - - var text_5 = document.createTextNode(' '); - - main.insertBefore(text_5, undefined) - - var div = document.createElement('div'); - - main.insertBefore(div, undefined) - div.setAttribute('class', 'static') - - var p = document.createElement('p'); - - div.insertBefore(p, undefined) - - var text_6 = document.createTextNode('we don\'t need to traverse these nodes'); - - p.insertBefore(text_6, undefined) - - var text_7 = document.createTextNode(' '); - - main.insertBefore(text_7, undefined) - - var p_1 = document.createElement('p'); - - main.insertBefore(p_1, undefined) - - var text_8 = document.createTextNode('or'); - - p_1.insertBefore(text_8, undefined) - - var text_9 = document.createTextNode(' '); - - main.insertBefore(text_9, undefined) - - var p_2 = document.createElement('p'); - - main.insertBefore(p_2, undefined) - - var text_10 = document.createTextNode('these'); - - p_2.insertBefore(text_10, undefined) - - var text_11 = document.createTextNode(' '); - - main.insertBefore(text_11, undefined) - - var p_3 = document.createElement('p'); - - main.insertBefore(p_3, undefined) - - var text_12 = document.createTextNode('ones'); - - p_3.insertBefore(text_12, undefined) - - var text_13 = document.createTextNode(' '); - - main.insertBefore(text_13, undefined) - - var comment = document.createComment(''); - - main.insertBefore(comment, undefined) - - var text_14 = document.createTextNode(' '); - - main.insertBefore(text_14, undefined) - - var p_4 = document.createElement('p'); - - main.insertBefore(p_4, undefined) - - var text_15 = document.createTextNode('these'); - - p_4.insertBefore(text_15, undefined) - - var text_16 = document.createTextNode(' '); - - main.insertBefore(text_16, undefined) - - var p_5 = document.createElement('p'); - - main.insertBefore(p_5, undefined) - - var text_17 = document.createTextNode('trailing'); - - p_5.insertBefore(text_17, undefined) - - var text_18 = document.createTextNode(' '); - - main.insertBefore(text_18, undefined) - - var p_6 = document.createElement('p'); - - main.insertBefore(p_6, undefined) - - var text_19 = document.createTextNode('nodes'); - - p_6.insertBefore(text_19, undefined) - - var text_20 = document.createTextNode(' '); - - main.insertBefore(text_20, undefined) - - var p_7 = document.createElement('p'); - - main.insertBefore(p_7, undefined) - - var text_21 = document.createTextNode('can'); - - p_7.insertBefore(text_21, undefined) - - var text_22 = document.createTextNode(' '); - - main.insertBefore(text_22, undefined) - - var p_8 = document.createElement('p'); - - main.insertBefore(p_8, undefined) - - var text_23 = document.createTextNode('be'); - - p_8.insertBefore(text_23, undefined) - - var text_24 = document.createTextNode(' '); - - main.insertBefore(text_24, undefined) - - var p_9 = document.createElement('p'); - - main.insertBefore(p_9, undefined) - - var text_25 = document.createTextNode('completely'); - - p_9.insertBefore(text_25, undefined) - - var text_26 = document.createTextNode(' '); - - main.insertBefore(text_26, undefined) - - var p_10 = document.createElement('p'); - - main.insertBefore(p_10, undefined) - - var text_27 = document.createTextNode('ignored'); - - p_10.insertBefore(text_27, undefined) - - var text_28 = document.createTextNode(' '); - var cant_skip = document.createElement('cant-skip'); - var custom_elements = document.createElement('custom-elements'); - - cant_skip.insertBefore(custom_elements, undefined) - - var text_29 = document.createTextNode(' '); - var div_1 = document.createElement('div'); - var input = document.createElement('input'); - - div_1.insertBefore(input, undefined) - - var text_30 = document.createTextNode(' '); - var div_2 = document.createElement('div'); - var source = document.createElement('source'); - - div_2.insertBefore(source, undefined) - - var text_31 = document.createTextNode(' '); - var select = document.createElement('select'); - var option = document.createElement('option'); - - select.insertBefore(option, undefined) - - var text_32 = document.createTextNode('a'); - - option.insertBefore(text_32, undefined) - - var text_33 = document.createTextNode(' '); - var img = document.createElement('img'); - - img.setAttribute('src', '...') - img.setAttribute('alt', '') - img.setAttribute('loading', 'lazy') - - var text_34 = document.createTextNode(' '); - var div_3 = document.createElement('div'); - var img_1 = document.createElement('img'); - - div_3.insertBefore(img_1, undefined) - img_1.setAttribute('src', '...') - img_1.setAttribute('alt', '') - img_1.setAttribute('loading', 'lazy') - - var fragment = document.createDocumentFragment(); - - fragment.append(header, text_3, main, text_28, cant_skip, text_29, div_1, text_30, div_2, text_31, select, text_33, img, text_34, div_3) - return fragment; - }, + [ + { + e: 'header', + c: [ + { + e: 'nav', + c: [ + { e: 'a', p: { href: '/' }, c: ['Home'] }, + ' ', + { + e: 'a', + p: { href: '/away' }, + c: ['Away'] + } + ] + } + ] + }, + ' ', + { + e: 'main', + c: [ + { e: 'h1', c: [' '] }, + ' ', + { + e: 'div', + p: { class: 'static' }, + c: [ + { + e: 'p', + c: ['we don\'t need to traverse these nodes'] + } + ] + }, + ' ', + { e: 'p', c: ['or'] }, + ' ', + { e: 'p', c: ['these'] }, + ' ', + { e: 'p', c: ['ones'] }, + ' ', + , + ' ', + { e: 'p', c: ['these'] }, + ' ', + { e: 'p', c: ['trailing'] }, + ' ', + { e: 'p', c: ['nodes'] }, + ' ', + { e: 'p', c: ['can'] }, + ' ', + { e: 'p', c: ['be'] }, + ' ', + { e: 'p', c: ['completely'] }, + ' ', + { e: 'p', c: ['ignored'] } + ] + }, + ' ', + { + e: 'cant-skip', + c: [{ e: 'custom-elements' }] + }, + ' ', + { e: 'div', c: [{ e: 'input' }] }, + ' ', + { e: 'div', c: [{ e: 'source' }] }, + ' ', + { + e: 'select', + c: [{ e: 'option', c: ['a'] }] + }, + ' ', + { + e: 'img', + p: { src: '...', alt: '', loading: 'lazy' } + }, + ' ', + { + e: 'div', + c: [ + { + e: 'img', + p: { src: '...', alt: '', loading: 'lazy' } + } + ] + } + ], 3 ); diff --git a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client-functional/index.svelte.js index 4247dcfda3f5..2be761b88dc8 100644 --- a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client-functional/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client-functional/index.svelte.js @@ -9,21 +9,13 @@ function reset(_, str, tpl) { } var root = $.template_fn( - () => { - var input = document.createElement('input'); - var text = document.createTextNode(' '); - var input_1 = document.createElement('input'); - var text_1 = document.createTextNode(' '); - var button = document.createElement('button'); - var text_2 = document.createTextNode('reset'); - - button.insertBefore(text_2, undefined) - - var fragment = document.createDocumentFragment(); - - fragment.append(input, text, input_1, text_1, button) - return fragment; - }, + [ + { e: 'input' }, + ' ', + { e: 'input' }, + ' ', + { e: 'button', c: ['reset'] } + ], 1 ); diff --git a/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client-functional/index.svelte.js b/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client-functional/index.svelte.js index 5163dc350967..9176f1ab92cc 100644 --- a/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client-functional/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client-functional/index.svelte.js @@ -1,17 +1,7 @@ import 'svelte/internal/disclose-version'; import * as $ from 'svelte/internal/client'; -var root = $.template_fn(() => { - var p = document.createElement('p'); - var text = document.createTextNode(' '); - - p.insertBefore(text, undefined) - - var fragment = document.createDocumentFragment(); - - fragment.append(p) - return fragment; -}); +var root = $.template_fn([{ e: 'p', c: [' '] }]); export default function Text_nodes_deriveds($$anchor) { let count1 = 0;