|
|
@ -1099,50 +1099,58 @@ function create_block(parent, name, nodes, context) {
|
|
|
|
body.push(...state.init);
|
|
|
|
body.push(...state.init);
|
|
|
|
} else if (trimmed.length > 0) {
|
|
|
|
} else if (trimmed.length > 0) {
|
|
|
|
const id = b.id(context.state.scope.generate('fragment'));
|
|
|
|
const id = b.id(context.state.scope.generate('fragment'));
|
|
|
|
const node_id = b.id(context.state.scope.generate('node'));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
process_children(trimmed, node_id, {
|
|
|
|
const use_space_template =
|
|
|
|
...context,
|
|
|
|
trimmed.some((node) => node.type === 'ExpressionTag') &&
|
|
|
|
state
|
|
|
|
trimmed.every((node) => node.type === 'Text' || node.type === 'ExpressionTag');
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (use_space_template) {
|
|
|
|
|
|
|
|
// special case — we can use `$.space` instead of creating a unique template
|
|
|
|
|
|
|
|
const id = b.id(context.state.scope.generate('text'));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
process_children(trimmed, () => id, false, {
|
|
|
|
|
|
|
|
...context,
|
|
|
|
|
|
|
|
state
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
body.push(b.var(id, b.call('$.space', b.id('$$anchor'))), ...state.init);
|
|
|
|
|
|
|
|
close = b.stmt(b.call('$.close', b.id('$$anchor'), id));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/** @type {(is_text: boolean) => import('estree').Expression} */
|
|
|
|
|
|
|
|
const expression = (is_text) =>
|
|
|
|
|
|
|
|
is_text ? b.call('$.child_frag', id, b.true) : b.call('$.child_frag', id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
process_children(trimmed, expression, false, { ...context, state });
|
|
|
|
|
|
|
|
|
|
|
|
const template = state.template[0];
|
|
|
|
const use_comment_template = state.template.length === 1 && state.template[0] === '<!>';
|
|
|
|
|
|
|
|
|
|
|
|
if (state.template.length === 1 && (template === ' ' || template === '<!>')) {
|
|
|
|
if (use_comment_template) {
|
|
|
|
if (template === ' ') {
|
|
|
|
// special case — we can use `$.comment` instead of creating a unique template
|
|
|
|
body.push(b.var(node_id, b.call('$.space', b.id('$$anchor'))), ...state.init);
|
|
|
|
body.push(b.var(id, b.call('$.comment', b.id('$$anchor'))));
|
|
|
|
close = b.stmt(b.call('$.close', b.id('$$anchor'), node_id));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
|
|
|
|
const callee = namespace === 'svg' ? '$.svg_template' : '$.template';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
state.hoisted.push(
|
|
|
|
|
|
|
|
b.var(
|
|
|
|
|
|
|
|
template_name,
|
|
|
|
|
|
|
|
b.call(callee, b.template([b.quasi(state.template.join(''), true)], []), b.true)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
body.push(
|
|
|
|
body.push(
|
|
|
|
b.var(id, b.call('$.comment', b.id('$$anchor'))),
|
|
|
|
b.var(
|
|
|
|
b.var(node_id, b.call('$.child_frag', id)),
|
|
|
|
id,
|
|
|
|
...state.init
|
|
|
|
b.call(
|
|
|
|
|
|
|
|
'$.open_frag',
|
|
|
|
|
|
|
|
b.id('$$anchor'),
|
|
|
|
|
|
|
|
b.literal(!state.metadata.template_needs_import_node),
|
|
|
|
|
|
|
|
template_name
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
);
|
|
|
|
);
|
|
|
|
close = b.stmt(b.call('$.close_frag', b.id('$$anchor'), id));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
const callee = namespace === 'svg' ? '$.svg_template' : '$.template';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
state.hoisted.push(
|
|
|
|
body.push(...state.init);
|
|
|
|
b.var(
|
|
|
|
|
|
|
|
template_name,
|
|
|
|
|
|
|
|
b.call(callee, b.template([b.quasi(state.template.join(''), true)], []), b.true)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
body.push(
|
|
|
|
|
|
|
|
b.var(
|
|
|
|
|
|
|
|
id,
|
|
|
|
|
|
|
|
b.call(
|
|
|
|
|
|
|
|
'$.open_frag',
|
|
|
|
|
|
|
|
b.id('$$anchor'),
|
|
|
|
|
|
|
|
b.literal(!state.metadata.template_needs_import_node),
|
|
|
|
|
|
|
|
template_name
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
b.var(node_id, b.call('$.child_frag', id)),
|
|
|
|
|
|
|
|
...state.init
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
close = b.stmt(b.call('$.close_frag', b.id('$$anchor'), id));
|
|
|
|
close = b.stmt(b.call('$.close_frag', b.id('$$anchor'), id));
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1418,10 +1426,11 @@ function serialize_event_attribute(node, context) {
|
|
|
|
* (e.g. `{a} b {c}`) into a single update function. Along the way it creates
|
|
|
|
* (e.g. `{a} b {c}`) into a single update function. Along the way it creates
|
|
|
|
* corresponding template node references these updates are applied to.
|
|
|
|
* corresponding template node references these updates are applied to.
|
|
|
|
* @param {import('#compiler').SvelteNode[]} nodes
|
|
|
|
* @param {import('#compiler').SvelteNode[]} nodes
|
|
|
|
* @param {import('estree').Expression} parent
|
|
|
|
* @param {(is_text: boolean) => import('estree').Expression} expression
|
|
|
|
|
|
|
|
* @param {boolean} is_element
|
|
|
|
* @param {import('../types.js').ComponentContext} context
|
|
|
|
* @param {import('../types.js').ComponentContext} context
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
function process_children(nodes, parent, { visit, state }) {
|
|
|
|
function process_children(nodes, expression, is_element, { visit, state }) {
|
|
|
|
const within_bound_contenteditable = state.metadata.bound_contenteditable;
|
|
|
|
const within_bound_contenteditable = state.metadata.bound_contenteditable;
|
|
|
|
|
|
|
|
|
|
|
|
/** @typedef {Array<import('#compiler').Text | import('#compiler').ExpressionTag>} Sequence */
|
|
|
|
/** @typedef {Array<import('#compiler').Text | import('#compiler').ExpressionTag>} Sequence */
|
|
|
@ -1429,28 +1438,24 @@ function process_children(nodes, parent, { visit, state }) {
|
|
|
|
/** @type {Sequence} */
|
|
|
|
/** @type {Sequence} */
|
|
|
|
let sequence = [];
|
|
|
|
let sequence = [];
|
|
|
|
|
|
|
|
|
|
|
|
let expression = parent;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* @param {Sequence} sequence
|
|
|
|
* @param {Sequence} sequence
|
|
|
|
* @param {boolean} in_fragment
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
function flush_sequence(sequence, in_fragment) {
|
|
|
|
function flush_sequence(sequence) {
|
|
|
|
if (sequence.length === 1) {
|
|
|
|
if (sequence.length === 1) {
|
|
|
|
const node = sequence[0];
|
|
|
|
const node = sequence[0];
|
|
|
|
|
|
|
|
|
|
|
|
if ((in_fragment && node.type === 'ExpressionTag') || node.type === 'Text') {
|
|
|
|
|
|
|
|
expression = b.call('$.sibling', expression);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (node.type === 'Text') {
|
|
|
|
if (node.type === 'Text') {
|
|
|
|
|
|
|
|
let prev = expression;
|
|
|
|
|
|
|
|
expression = () => b.call('$.sibling', prev(true));
|
|
|
|
state.template.push(node.raw);
|
|
|
|
state.template.push(node.raw);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
state.template.push(' ');
|
|
|
|
state.template.push(' ');
|
|
|
|
|
|
|
|
|
|
|
|
const text_id = get_node_id(expression, state, 'text');
|
|
|
|
const text_id = get_node_id(expression(true), state, 'text');
|
|
|
|
|
|
|
|
|
|
|
|
const singular = b.stmt(
|
|
|
|
const singular = b.stmt(
|
|
|
|
b.call(
|
|
|
|
b.call(
|
|
|
|
'$.text_effect',
|
|
|
|
'$.text_effect',
|
|
|
@ -1487,37 +1492,39 @@ function process_children(nodes, parent, { visit, state }) {
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
expression = (is_text) =>
|
|
|
|
}
|
|
|
|
is_text ? b.call('$.sibling', text_id, b.true) : b.call('$.sibling', text_id);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
const text_id = get_node_id(expression(true), state, 'text');
|
|
|
|
|
|
|
|
|
|
|
|
state.template.push(' ');
|
|
|
|
state.template.push(' ');
|
|
|
|
|
|
|
|
|
|
|
|
const text_id = get_node_id(expression, state, 'text');
|
|
|
|
const contains_call_expression = sequence.some(
|
|
|
|
const contains_call_expression = sequence.some(
|
|
|
|
(n) => n.type === 'ExpressionTag' && n.metadata.contains_call_expression
|
|
|
|
(n) => n.type === 'ExpressionTag' && n.metadata.contains_call_expression
|
|
|
|
);
|
|
|
|
);
|
|
|
|
const assignment = serialize_template_literal(sequence, visit, state)[1];
|
|
|
|
const assignment = serialize_template_literal(sequence, visit, state)[1];
|
|
|
|
const init = b.stmt(b.assignment('=', b.member(text_id, b.id('nodeValue')), assignment));
|
|
|
|
const init = b.stmt(b.assignment('=', b.member(text_id, b.id('nodeValue')), assignment));
|
|
|
|
const singular = b.stmt(b.call('$.text_effect', text_id, b.thunk(assignment)));
|
|
|
|
const singular = b.stmt(b.call('$.text_effect', text_id, b.thunk(assignment)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (contains_call_expression && !within_bound_contenteditable) {
|
|
|
|
if (contains_call_expression && !within_bound_contenteditable) {
|
|
|
|
state.update_effects.push(singular);
|
|
|
|
state.update_effects.push(singular);
|
|
|
|
} else if (
|
|
|
|
} else if (
|
|
|
|
sequence.some((node) => node.type === 'ExpressionTag' && node.metadata.dynamic) &&
|
|
|
|
sequence.some((node) => node.type === 'ExpressionTag' && node.metadata.dynamic) &&
|
|
|
|
!within_bound_contenteditable
|
|
|
|
!within_bound_contenteditable
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
state.update.push({
|
|
|
|
state.update.push({
|
|
|
|
singular,
|
|
|
|
singular,
|
|
|
|
grouped: b.stmt(b.call('$.text', text_id, assignment))
|
|
|
|
grouped: b.stmt(b.call('$.text', text_id, assignment))
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
state.init.push(init);
|
|
|
|
state.init.push(init);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
expression = b.call('$.sibling', text_id);
|
|
|
|
expression = (is_text) =>
|
|
|
|
|
|
|
|
is_text ? b.call('$.sibling', text_id, b.true) : b.call('$.sibling', text_id);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let is_fragment = false;
|
|
|
|
|
|
|
|
for (let i = 0; i < nodes.length; i += 1) {
|
|
|
|
for (let i = 0; i < nodes.length; i += 1) {
|
|
|
|
const node = nodes[i];
|
|
|
|
const node = nodes[i];
|
|
|
|
|
|
|
|
|
|
|
@ -1525,12 +1532,7 @@ function process_children(nodes, parent, { visit, state }) {
|
|
|
|
sequence.push(node);
|
|
|
|
sequence.push(node);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
if (sequence.length > 0) {
|
|
|
|
if (sequence.length > 0) {
|
|
|
|
flush_sequence(sequence, is_fragment);
|
|
|
|
flush_sequence(sequence);
|
|
|
|
// Ensure we move to the next sibling for the case where we move reference within a fragment
|
|
|
|
|
|
|
|
if (!is_fragment && sequence.length === 1 && sequence[0].type === 'ExpressionTag') {
|
|
|
|
|
|
|
|
expression = b.call('$.sibling', expression);
|
|
|
|
|
|
|
|
is_fragment = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
sequence = [];
|
|
|
|
sequence = [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1544,23 +1546,18 @@ function process_children(nodes, parent, { visit, state }) {
|
|
|
|
// get hoisted inside clean_nodes?
|
|
|
|
// get hoisted inside clean_nodes?
|
|
|
|
visit(node, state);
|
|
|
|
visit(node, state);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
if (
|
|
|
|
if (node.type === 'EachBlock' && nodes.length === 1 && is_element) {
|
|
|
|
node.type === 'EachBlock' &&
|
|
|
|
|
|
|
|
nodes.length === 1 &&
|
|
|
|
|
|
|
|
parent.type === 'CallExpression' &&
|
|
|
|
|
|
|
|
parent.callee.type === 'Identifier' &&
|
|
|
|
|
|
|
|
parent.callee.name === '$.child'
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
node.metadata.is_controlled = true;
|
|
|
|
node.metadata.is_controlled = true;
|
|
|
|
visit(node, state);
|
|
|
|
visit(node, state);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
const id = get_node_id(
|
|
|
|
const id = get_node_id(
|
|
|
|
expression,
|
|
|
|
expression(false),
|
|
|
|
state,
|
|
|
|
state,
|
|
|
|
node.type === 'RegularElement' ? node.name : 'node'
|
|
|
|
node.type === 'RegularElement' ? node.name : 'node'
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
expression = b.call('$.sibling', id);
|
|
|
|
expression = (is_text) =>
|
|
|
|
|
|
|
|
is_text ? b.call('$.sibling', id, b.true) : b.call('$.sibling', id);
|
|
|
|
|
|
|
|
|
|
|
|
visit(node, {
|
|
|
|
visit(node, {
|
|
|
|
...state,
|
|
|
|
...state,
|
|
|
@ -1572,7 +1569,7 @@ function process_children(nodes, parent, { visit, state }) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (sequence.length > 0) {
|
|
|
|
if (sequence.length > 0) {
|
|
|
|
flush_sequence(sequence, false);
|
|
|
|
flush_sequence(sequence);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -2041,12 +2038,14 @@ export const template_visitors = {
|
|
|
|
|
|
|
|
|
|
|
|
process_children(
|
|
|
|
process_children(
|
|
|
|
trimmed,
|
|
|
|
trimmed,
|
|
|
|
b.call(
|
|
|
|
() =>
|
|
|
|
'$.child',
|
|
|
|
b.call(
|
|
|
|
node.name === 'template'
|
|
|
|
'$.child',
|
|
|
|
? b.member(context.state.node, b.id('content'))
|
|
|
|
node.name === 'template'
|
|
|
|
: context.state.node
|
|
|
|
? b.member(context.state.node, b.id('content'))
|
|
|
|
),
|
|
|
|
: context.state.node
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
true,
|
|
|
|
{ ...context, state }
|
|
|
|
{ ...context, state }
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|