chore: tidy up some SSR compiler code (#11976)

* tidy up some SSR code

* tidy up

* more
pull/11979/head
Rich Harris 5 months ago committed by GitHub
parent 088632b06d
commit 36a5143758
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1344,64 +1344,48 @@ const template_visitors = {
state.template.push(block_close);
},
ClassDirective(node) {
ClassDirective() {
throw new Error('Node should have been handled elsewhere');
},
StyleDirective(node) {
StyleDirective() {
throw new Error('Node should have been handled elsewhere');
},
RegularElement(node, context) {
const metadata = {
...context.state.metadata,
namespace: determine_namespace_for_children(node, context.state.metadata.namespace)
};
context.state.template.push(t_string(`<${node.name}`));
const body_expression = serialize_element_attributes(node, context);
const body = serialize_element_attributes(node, context);
context.state.template.push(t_string('>'));
const namespace = determine_namespace_for_children(node, context.state.metadata.namespace);
/** @type {import('./types').ComponentServerTransformState} */
const state = {
...context.state,
metadata,
metadata: { ...context.state.metadata, namespace },
preserve_whitespace:
context.state.preserve_whitespace ||
((node.name === 'pre' || node.name === 'textarea') && metadata.namespace !== 'foreign')
((node.name === 'pre' || node.name === 'textarea') && namespace !== 'foreign')
};
/** @type {import('./types').ComponentContext} */
const inner_context =
body_expression !== null
? {
...context,
state: {
...state,
template: [],
init: []
}
}
: { ...context, state };
const { hoisted, trimmed } = clean_nodes(
node,
node.fragment.nodes,
inner_context.path,
metadata.namespace,
context.path,
namespace,
{
...context.state,
scope: /** @type {import('../../scope').Scope} */ (context.state.scopes.get(node.fragment))
...state,
scope: /** @type {import('../../scope').Scope} */ (state.scopes.get(node.fragment))
},
state.preserve_whitespace,
state.options.preserveComments
);
for (const node of hoisted) {
inner_context.visit(node, state);
context.visit(node, state);
}
if (context.state.options.dev) {
if (state.options.dev) {
const location = /** @type {import('locate-character').Location} */ (locator(node.start));
context.state.template.push(
state.template.push(
t_statement(
b.stmt(
b.call(
@ -1416,40 +1400,39 @@ const template_visitors = {
);
}
process_children(trimmed, node, inner_context);
if (body === null) {
process_children(trimmed, node, { ...context, state });
} else {
let id = body;
if (body_expression !== null) {
let body_id;
const expression = body_expression.escape
? b.call('$.escape', body_expression.expression)
: body_expression.expression;
if (expression.type === 'Identifier') {
body_id = expression;
} else {
body_id = b.id(context.state.scope.generate('$$body'));
context.state.template.push(t_statement(b.const(body_id, expression)));
if (body.type !== 'Identifier') {
id = b.id(state.scope.generate('$$body'));
state.template.push(t_statement(b.const(id, body)));
}
// if this is a `<textarea>` value or a contenteditable binding, we only add
// the body if the attribute/binding is falsy
const inner_state = { ...state, template: [], init: [] };
process_children(trimmed, node, { ...context, state: inner_state });
// Use the body expression as the body if it's truthy, otherwise use the inner template
context.state.template.push(
state.template.push(
t_statement(
b.if(
body_id,
b.block(serialize_template([t_expression(body_id)])),
b.block([
...inner_context.state.init,
...serialize_template(inner_context.state.template)
])
id,
b.block(serialize_template([t_expression(id)])),
b.block([...inner_state.init, ...serialize_template(inner_state.template)])
)
)
);
}
if (!VoidElements.includes(node.name) && metadata.namespace !== 'foreign') {
context.state.template.push(t_string(`</${node.name}>`));
if (!VoidElements.includes(node.name) && namespace !== 'foreign') {
state.template.push(t_string(`</${node.name}>`));
}
if (context.state.options.dev) {
context.state.template.push(t_statement(b.stmt(b.call('$.pop_element'))));
if (state.options.dev) {
state.template.push(t_statement(b.stmt(b.call('$.pop_element'))));
}
},
SvelteElement(node, context) {
@ -1467,29 +1450,17 @@ const template_visitors = {
context.state.init.push(b.stmt(b.call('$.validate_dynamic_element_tag', b.thunk(tag))));
}
const metadata = {
...context.state.metadata,
namespace: determine_namespace_for_children(node, context.state.metadata.namespace)
};
/** @type {import('./types').ComponentContext} */
const inner_context = {
...context,
state: {
...context.state,
metadata,
template: [],
init: []
}
const state = {
...context.state,
metadata: {
...context.state.metadata,
namespace: determine_namespace_for_children(node, context.state.metadata.namespace)
},
template: [],
init: []
};
const main = /** @type {import('estree').BlockStatement} */ (
context.visit(node.fragment, {
...context.state,
metadata
})
);
serialize_element_attributes(node, inner_context);
serialize_element_attributes(node, { ...context, state });
if (context.state.options.dev) {
context.state.template.push(
@ -1497,29 +1468,17 @@ const template_visitors = {
);
}
context.state.template.push(
t_statement(
b.if(
tag,
const attributes = b.block([...state.init, ...serialize_template(state.template)]);
const children = /** @type {import('estree').BlockStatement} */ (
context.visit(node.fragment, state)
);
b.stmt(
b.call(
'$.element',
b.id('$$payload'),
tag,
b.thunk(
b.block([
...inner_context.state.init,
...serialize_template(inner_context.state.template)
])
),
b.thunk(main)
)
)
)
),
block_anchor
const body = b.stmt(
b.call('$.element', b.id('$$payload'), tag, b.thunk(attributes), b.thunk(children))
);
context.state.template.push(t_statement(b.if(tag, body)), block_anchor);
if (context.state.options.dev) {
context.state.template.push(t_statement(b.stmt(b.call('$.pop_element'))));
}
@ -1834,7 +1793,7 @@ function serialize_element_attributes(node, context) {
/** @type {import('estree').ExpressionStatement[]} */
const lets = [];
/** @type {{ escape: boolean; expression: import('estree').Expression } | null} */
/** @type {import('estree').Expression | null} */
let content = null;
let has_spread = false;
@ -1857,10 +1816,7 @@ function serialize_element_attributes(node, context) {
// also see related code in analysis phase
attribute.value[0].data = '\n' + attribute.value[0].data;
}
content = {
escape: true,
expression: serialize_attribute_value(attribute.value, context)
};
content = b.call('$.escape', serialize_attribute_value(attribute.value, context));
} else if (node.name !== 'select') {
// omit value attribute for select elements, it's irrelevant for the initially selected value and has no
// effect on the selected value after the user interacts with the select element (the value _property_ does, but not the attribute)
@ -1903,19 +1859,12 @@ function serialize_element_attributes(node, context) {
if (binding?.omit_in_ssr) continue;
if (ContentEditableBindings.includes(attribute.name)) {
content = {
escape: false,
expression: /** @type {import('estree').Expression} */ (
context.visit(attribute.expression)
)
};
content = /** @type {import('estree').Expression} */ (context.visit(attribute.expression));
} else if (attribute.name === 'value' && node.name === 'textarea') {
content = {
escape: true,
expression: /** @type {import('estree').Expression} */ (
context.visit(attribute.expression)
)
};
content = b.call(
'$.escape',
/** @type {import('estree').Expression} */ (context.visit(attribute.expression))
);
} else if (attribute.name === 'group') {
const value_attribute = /** @type {import('#compiler').Attribute | undefined} */ (
node.attributes.find((attr) => attr.type === 'Attribute' && attr.name === 'value')

Loading…
Cancel
Save