remove indirection

pull/15538/head
Rich Harris 4 months ago
parent 8c819e5bdd
commit 448cff1141

@ -1,5 +1,4 @@
/** @import { AST } from '#compiler' */ /** @import { AST } from '#compiler' */
/** @import { TemplateOperation } from '../types.js' */
/** @import { Node, Element } from './types'; */ /** @import { Node, Element } from './types'; */
export class Template { export class Template {
@ -14,43 +13,6 @@ export class Template {
#fragment = this.nodes; #fragment = this.nodes;
/**
* @param {...TemplateOperation} nodes
* @deprecated
*/
push(...nodes) {
for (const node of nodes) {
switch (node.kind) {
case 'create_element':
this.create_element(node.name);
break;
case 'create_anchor':
this.create_anchor(node.data);
break;
case 'create_text':
this.create_text(node.nodes);
break;
case 'push_element': {
this.push_element();
break;
}
case 'pop_element': {
this.pop_element();
break;
}
case 'set_prop': {
this.set_prop(node.key, node.value);
break;
}
}
}
}
/** @param {string} name */ /** @param {string} name */
create_element(name) { create_element(name) {
this.#element = { this.#element = {
@ -63,7 +25,7 @@ export class Template {
this.#fragment.push(this.#element); this.#fragment.push(this.#element);
} }
/** @param {string | undefined} data */ /** @param {string} [data] */
create_anchor(data) { create_anchor(data) {
this.#fragment.push({ type: 'anchor', data }); this.#fragment.push({ type: 'anchor', data });
} }

@ -37,31 +37,6 @@ export interface ClientTransformState extends TransformState {
>; >;
} }
type TemplateOperation =
| {
kind: 'create_element';
name: string;
}
| {
kind: 'create_text';
nodes: AST.Text[];
}
| {
kind: 'create_anchor';
data?: string;
}
| {
kind: 'set_prop';
key: string;
value: string | undefined;
}
| {
kind: 'push_element';
}
| {
kind: 'pop_element';
};
export interface ComponentClientTransformState extends ClientTransformState { export interface ComponentClientTransformState extends ClientTransformState {
readonly analysis: ComponentAnalysis; readonly analysis: ComponentAnalysis;
readonly options: ValidatedCompileOptions; readonly options: ValidatedCompileOptions;

@ -11,7 +11,7 @@ import { get_value } from './shared/declarations.js';
* @param {ComponentContext} context * @param {ComponentContext} context
*/ */
export function AwaitBlock(node, context) { export function AwaitBlock(node, context) {
context.state.template.push({ kind: 'create_anchor' }); context.state.template.create_anchor();
// Visit {#await <expression>} first to ensure that scopes are in the correct order // Visit {#await <expression>} first to ensure that scopes are in the correct order
const expression = b.thunk(/** @type {Expression} */ (context.visit(node.expression))); const expression = b.thunk(/** @type {Expression} */ (context.visit(node.expression)));

@ -7,5 +7,5 @@
*/ */
export function Comment(node, context) { export function Comment(node, context) {
// We'll only get here if comments are not filtered out, which they are unless preserveComments is true // We'll only get here if comments are not filtered out, which they are unless preserveComments is true
context.state.template.push({ kind: 'create_anchor', data: node.data }); context.state.template.create_anchor(node.data);
} }

@ -32,7 +32,7 @@ export function EachBlock(node, context) {
); );
if (!each_node_meta.is_controlled) { if (!each_node_meta.is_controlled) {
context.state.template.push({ kind: 'create_anchor' }); context.state.template.create_anchor();
} }
let flags = 0; let flags = 0;

@ -9,7 +9,7 @@ import * as b from '#compiler/builders';
* @param {ComponentContext} context * @param {ComponentContext} context
*/ */
export function HtmlTag(node, context) { export function HtmlTag(node, context) {
context.state.template.push({ kind: 'create_anchor' }); context.state.template.create_anchor();
const expression = /** @type {Expression} */ (context.visit(node.expression)); const expression = /** @type {Expression} */ (context.visit(node.expression));

@ -8,7 +8,7 @@ import * as b from '#compiler/builders';
* @param {ComponentContext} context * @param {ComponentContext} context
*/ */
export function IfBlock(node, context) { export function IfBlock(node, context) {
context.state.template.push({ kind: 'create_anchor' }); context.state.template.create_anchor();
const statements = []; const statements = [];
const consequent = /** @type {BlockStatement} */ (context.visit(node.consequent)); const consequent = /** @type {BlockStatement} */ (context.visit(node.consequent));

@ -8,7 +8,7 @@ import * as b from '#compiler/builders';
* @param {ComponentContext} context * @param {ComponentContext} context
*/ */
export function KeyBlock(node, context) { export function KeyBlock(node, context) {
context.state.template.push({ kind: 'create_anchor' }); context.state.template.create_anchor();
const key = /** @type {Expression} */ (context.visit(node.expression)); const key = /** @type {Expression} */ (context.visit(node.expression));
const body = /** @type {Expression} */ (context.visit(node.fragment)); const body = /** @type {Expression} */ (context.visit(node.fragment));

@ -52,10 +52,7 @@ export function RegularElement(node, context) {
} }
if (node.name === 'noscript') { if (node.name === 'noscript') {
context.state.template.push({ context.state.template.create_element('noscript');
kind: 'create_element',
name: 'noscript'
});
return; return;
} }
@ -75,10 +72,7 @@ export function RegularElement(node, context) {
context.state.metadata.context.template_contains_script_tag = true; context.state.metadata.context.template_contains_script_tag = true;
} }
context.state.template.push({ context.state.template.create_element(node.name);
kind: 'create_element',
name: node.name
});
/** @type {Array<AST.Attribute | AST.SpreadAttribute>} */ /** @type {Array<AST.Attribute | AST.SpreadAttribute>} */
const attributes = []; const attributes = [];
@ -116,11 +110,7 @@ export function RegularElement(node, context) {
const { value } = build_attribute_value(attribute.value, context); const { value } = build_attribute_value(attribute.value, context);
if (value.type === 'Literal' && typeof value.value === 'string') { if (value.type === 'Literal' && typeof value.value === 'string') {
context.state.template.push({ context.state.template.set_prop('is', value.value);
kind: 'set_prop',
key: 'is',
value: value.value
});
continue; continue;
} }
} }
@ -300,12 +290,10 @@ export function RegularElement(node, context) {
} }
if (name !== 'class' || value) { if (name !== 'class' || value) {
context.state.template.push({ context.state.template.set_prop(
kind: 'set_prop', attribute.name,
key: attribute.name, is_boolean_attribute(name) && value === true ? undefined : value === true ? '' : value
value: );
is_boolean_attribute(name) && value === true ? undefined : value === true ? '' : value
});
} }
} else if (name === 'autofocus') { } else if (name === 'autofocus') {
let { value } = build_attribute_value(attribute.value, context); let { value } = build_attribute_value(attribute.value, context);
@ -337,7 +325,8 @@ export function RegularElement(node, context) {
) { ) {
context.state.after_update.push(b.stmt(b.call('$.replay_events', node_id))); context.state.after_update.push(b.stmt(b.call('$.replay_events', node_id)));
} }
context.state.template.push({ kind: 'push_element' });
context.state.template.push_element();
const metadata = { const metadata = {
...context.state.metadata, ...context.state.metadata,
@ -458,7 +447,7 @@ export function RegularElement(node, context) {
// @ts-expect-error // @ts-expect-error
location.push(state.locations); location.push(state.locations);
} }
context.state.template.push({ kind: 'pop_element' }); context.state.template.pop_element();
} }
/** /**

@ -9,7 +9,7 @@ import * as b from '#compiler/builders';
* @param {ComponentContext} context * @param {ComponentContext} context
*/ */
export function RenderTag(node, context) { export function RenderTag(node, context) {
context.state.template.push({ kind: 'create_anchor' }); context.state.template.create_anchor();
const expression = unwrap_optional(node.expression); const expression = unwrap_optional(node.expression);

@ -11,7 +11,7 @@ import { memoize_expression } from './shared/utils.js';
*/ */
export function SlotElement(node, context) { export function SlotElement(node, context) {
// <slot {a}>fallback</slot> --> $.slot($$slots.default, { get a() { .. } }, () => ...fallback); // <slot {a}>fallback</slot> --> $.slot($$slots.default, { get a() { .. } }, () => ...fallback);
context.state.template.push({ kind: 'create_anchor' }); context.state.template.create_anchor();
/** @type {Property[]} */ /** @type {Property[]} */
const props = []; const props = [];

@ -88,7 +88,7 @@ export function SvelteBoundary(node, context) {
b.call('$.boundary', context.state.node, props, b.arrow([b.id('$$anchor')], block)) b.call('$.boundary', context.state.node, props, b.arrow([b.id('$$anchor')], block))
); );
context.state.template.push({ kind: 'create_anchor' }); context.state.template.create_anchor();
context.state.init.push( context.state.init.push(
external_statements.length > 0 ? b.block([...external_statements, boundary]) : boundary external_statements.length > 0 ? b.block([...external_statements, boundary]) : boundary
); );

@ -13,7 +13,7 @@ import { build_render_statement } from './shared/utils.js';
* @param {ComponentContext} context * @param {ComponentContext} context
*/ */
export function SvelteElement(node, context) { export function SvelteElement(node, context) {
context.state.template.push({ kind: 'create_anchor' }); context.state.template.create_anchor();
/** @type {Array<AST.Attribute | AST.SpreadAttribute>} */ /** @type {Array<AST.Attribute | AST.SpreadAttribute>} */
const attributes = []; const attributes = [];

@ -1,6 +1,6 @@
/** @import { BlockStatement, Expression, ExpressionStatement, Identifier, MemberExpression, Pattern, Property, SequenceExpression, Statement } from 'estree' */ /** @import { BlockStatement, Expression, ExpressionStatement, Identifier, MemberExpression, Pattern, Property, SequenceExpression, Statement } from 'estree' */
/** @import { AST } from '#compiler' */ /** @import { AST } from '#compiler' */
/** @import { ComponentContext, TemplateOperation } from '../../types.js' */ /** @import { ComponentContext } from '../../types.js' */
import { dev, is_ignored } from '../../../../../state.js'; import { dev, is_ignored } from '../../../../../state.js';
import { get_attribute_chunks, object } from '../../../../../utils/ast.js'; import { get_attribute_chunks, object } from '../../../../../utils/ast.js';
import * as b from '#compiler/builders'; import * as b from '#compiler/builders';
@ -440,33 +440,28 @@ export function build_component(node, component_name, context, anchor = context.
} }
if (Object.keys(custom_css_props).length > 0) { if (Object.keys(custom_css_props).length > 0) {
/** @type {TemplateOperation[]} */
const template_operations = [];
if (context.state.metadata.namespace === 'svg') { if (context.state.metadata.namespace === 'svg') {
// this boils down to <g><!></g> // this boils down to <g><!></g>
template_operations.push({ kind: 'create_element', name: 'g' }); context.state.template.create_element('g');
template_operations.push({ kind: 'push_element' }); context.state.template.push_element();
template_operations.push({ kind: 'create_anchor' }); context.state.template.create_anchor();
template_operations.push({ kind: 'pop_element' }); context.state.template.pop_element();
} else { } else {
// this boils down to <svelte-css-wrapper style='display: contents'><!></svelte-css-wrapper> // this boils down to <svelte-css-wrapper style='display: contents'><!></svelte-css-wrapper>
template_operations.push({ kind: 'create_element', name: 'svelte-css-wrapper' }); context.state.template.create_element('svelte-css-wrapper');
template_operations.push({ kind: 'set_prop', key: 'style', value: 'display: contents' }); context.state.template.set_prop('style', 'display: contents');
template_operations.push({ kind: 'push_element' }); context.state.template.push_element();
template_operations.push({ kind: 'create_anchor' }); context.state.template.create_anchor();
template_operations.push({ kind: 'pop_element' }); context.state.template.pop_element();
} }
context.state.template.push(...template_operations);
statements.push( statements.push(
b.stmt(b.call('$.css_props', anchor, b.thunk(b.object(custom_css_props)))), b.stmt(b.call('$.css_props', anchor, b.thunk(b.object(custom_css_props)))),
b.stmt(fn(b.member(anchor, 'lastChild'))), b.stmt(fn(b.member(anchor, 'lastChild'))),
b.stmt(b.call('$.reset', anchor)) b.stmt(b.call('$.reset', anchor))
); );
} else { } else {
context.state.template.push({ kind: 'create_anchor' }); context.state.template.create_anchor();
statements.push(b.stmt(fn(anchor))); statements.push(b.stmt(fn(anchor)));
} }

@ -64,16 +64,11 @@ export function process_children(nodes, initial, is_element, { visit, state }) {
function flush_sequence(sequence) { function flush_sequence(sequence) {
if (sequence.every((node) => node.type === 'Text')) { if (sequence.every((node) => node.type === 'Text')) {
skipped += 1; skipped += 1;
state.template.push({ state.template.create_text(sequence);
kind: 'create_text',
nodes: sequence
});
return; return;
} }
state.template.push({
kind: 'create_text', state.template.create_text([{ type: 'Text', data: ' ', raw: ' ', start: -1, end: -1 }]);
nodes: [{ type: 'Text', data: ' ', raw: ' ', start: -1, end: -1 }]
});
const { has_state, value } = build_template_chunk(sequence, visit, state); const { has_state, value } = build_template_chunk(sequence, visit, state);

Loading…
Cancel
Save