pull/16073/head
7nik 4 months ago
parent bcb6b72af2
commit ac9c130887

@ -12,14 +12,6 @@ export function AttachTag(node, context) {
const expression = context.state.analysis.runes
? /** @type {Expression} */ (context.visit(node.expression))
: build_legacy_expression(node.expression, context);
context.state.init.push(
b.stmt(
b.call(
'$.attach',
context.state.node,
b.thunk(expression)
)
)
);
context.state.init.push(b.stmt(b.call('$.attach', context.state.node, b.thunk(expression))));
context.next();
}

@ -19,7 +19,7 @@ export function AwaitBlock(node, context) {
context.state.analysis.runes
? /** @type {Expression} */ (context.visit(node.expression))
: build_legacy_expression(node.expression, context)
);
);
let then_block;
let catch_block;

@ -19,15 +19,7 @@ export function ConstTag(node, context) {
const init = context.state.analysis.runes
? /** @type {Expression} */ (context.visit(declaration.init))
: build_legacy_expression(declaration.init, context);
context.state.init.push(
b.const(
declaration.id,
create_derived(
context.state,
b.thunk(init)
)
)
);
context.state.init.push(b.const(declaration.id, create_derived(context.state, b.thunk(init))));
context.state.transform[declaration.id.name] = { read: get_value };
@ -58,10 +50,7 @@ export function ConstTag(node, context) {
const fn = b.arrow(
[],
b.block([
b.const(
/** @type {Pattern} */ (context.visit(declaration.id, child_state)),
init,
),
b.const(/** @type {Pattern} */ (context.visit(declaration.id, child_state)), init),
b.return(b.object(identifiers.map((node) => b.prop('init', node, node))))
])
);

@ -32,9 +32,9 @@ export function EachBlock(node, context) {
const collection = context.state.analysis.runes
? /** @type {Expression} */ (context.visit(node.expression, parent_scope_state))
: build_legacy_expression(node.expression, {
...context,
state: parent_scope_state
});
...context,
state: parent_scope_state
});
if (!each_node_meta.is_controlled) {
context.state.template.push_comment();

@ -51,7 +51,6 @@ export function IfBlock(node, context) {
)
];
if (node.elseif) {
// We treat this...
//

@ -34,7 +34,7 @@ export function RenderTag(node, context) {
let snippet_function = context.state.analysis.runes
? /** @type {Expression} */ (context.visit(callee))
: build_legacy_expression(/** @type {Expression} */(callee), context);
: build_legacy_expression(/** @type {Expression} */ (callee), context);
if (node.metadata.dynamic) {
// If we have a chain expression then ensure a nullish snippet function gets turned into an empty one

@ -370,41 +370,67 @@ function is_pure_expression(expression) {
// It's supposed that values do not have custom @@toPrimitive() or toString(),
// which may be implicitly called in expressions like `a + b`, `a & b`, `+a`, `str: ${a}`
switch (expression.type) {
case "ArrayExpression": return expression.elements.every((element) => element == null || (element.type === "SpreadElement" ? false : is_pure_expression(element)));
case "BinaryExpression": return expression.left.type !== "PrivateIdentifier" && is_pure_expression(expression.left) && is_pure_expression(expression.right);
case "ConditionalExpression": return is_pure_expression(expression.test) && is_pure_expression(expression.consequent) && is_pure_expression(expression.alternate);
case "Identifier": return true;
case "Literal": return true;
case "LogicalExpression": return is_pure_expression(expression.left) && is_pure_expression(expression.right);
case "MetaProperty": return true; // new.target
case "ObjectExpression": return expression.properties.every((property) =>
property.type !== "SpreadElement"
&& property.key.type !== "PrivateIdentifier"
&& is_pure_expression(property.key)
&& is_pure_expression(property.value)
);
case "SequenceExpression": return expression.expressions.every(is_pure_expression);
case "TemplateLiteral": return expression.expressions.every(is_pure_expression);
case "ThisExpression": return true;
case "UnaryExpression": return is_pure_expression(expression.argument);
case "YieldExpression": return expression.argument == null || is_pure_expression(expression.argument);
case "ArrayPattern":
case "ArrowFunctionExpression":
case "AssignmentExpression":
case "AssignmentPattern":
case "AwaitExpression":
case "CallExpression":
case "ChainExpression":
case "ClassExpression":
case "FunctionExpression":
case "ImportExpression":
case "MemberExpression":
case "NewExpression":
case "ObjectPattern":
case "RestElement":
case "TaggedTemplateExpression":
case "UpdateExpression":
case 'ArrayExpression':
return expression.elements.every(
(element) =>
element == null ||
(element.type === 'SpreadElement' ? false : is_pure_expression(element))
);
case 'BinaryExpression':
return (
expression.left.type !== 'PrivateIdentifier' &&
is_pure_expression(expression.left) &&
is_pure_expression(expression.right)
);
case 'ConditionalExpression':
return (
is_pure_expression(expression.test) &&
is_pure_expression(expression.consequent) &&
is_pure_expression(expression.alternate)
);
case 'Identifier':
return true;
case 'Literal':
return true;
case 'LogicalExpression':
return is_pure_expression(expression.left) && is_pure_expression(expression.right);
case 'MetaProperty':
return true; // new.target
case 'ObjectExpression':
return expression.properties.every(
(property) =>
property.type !== 'SpreadElement' &&
property.key.type !== 'PrivateIdentifier' &&
is_pure_expression(property.key) &&
is_pure_expression(property.value)
);
case 'SequenceExpression':
return expression.expressions.every(is_pure_expression);
case 'TemplateLiteral':
return expression.expressions.every(is_pure_expression);
case 'ThisExpression':
return true;
case 'UnaryExpression':
return is_pure_expression(expression.argument);
case 'YieldExpression':
return expression.argument == null || is_pure_expression(expression.argument);
case 'ArrayPattern':
case 'ArrowFunctionExpression':
case 'AssignmentExpression':
case 'AssignmentPattern':
case 'AwaitExpression':
case 'CallExpression':
case 'ChainExpression':
case 'ClassExpression':
case 'FunctionExpression':
case 'ImportExpression':
case 'MemberExpression':
case 'NewExpression':
case 'ObjectPattern':
case 'RestElement':
case 'TaggedTemplateExpression':
case 'UpdateExpression':
return false;
}
}
@ -426,23 +452,27 @@ export function build_legacy_expression(expression, context) {
for (const [name, nodes] of context.state.scope.references) {
const binding = context.state.scope.get(name);
if (binding === null || binding.kind === 'normal' && binding.declaration_kind !== 'import') continue;
if (binding === null || (binding.kind === 'normal' && binding.declaration_kind !== 'import'))
continue;
let used = false;
for (const { node, path } of nodes) {
const expressionIdx = path.indexOf(expression);
if (expressionIdx < 0) continue;
const expression_idx = path.indexOf(expression);
if (expression_idx < 0) continue;
// in Svelte 4, #if, #each and #await copy context, so assignments
// aren't propagated to the parent block / component root
const track_assignment = !path.find((node, i) =>
i < expressionIdx - 1 && ["IfBlock", "EachBlock", "AwaitBlock"].includes(node.type)
)
const track_assignment = !path.find(
(node, i) =>
i < expression_idx - 1 && ['IfBlock', 'EachBlock', 'AwaitBlock'].includes(node.type)
);
if (track_assignment) {
used = true;
break;
}
const assignment = /** @type {AssignmentExpression|undefined} */(path.find((node, i) => i >= expressionIdx && node.type === "AssignmentExpression"));
if (!assignment || assignment.left !== node && !path.includes(assignment.left)) {
const assignment = /** @type {AssignmentExpression|undefined} */ (
path.find((node, i) => i >= expression_idx && node.type === 'AssignmentExpression')
);
if (!assignment || (assignment.left !== node && !path.includes(assignment.left))) {
used = true;
break;
}
@ -461,4 +491,4 @@ export function build_legacy_expression(expression, context) {
}
return b.sequence([...sequence, b.call('$.untrack', b.thunk(serialized_expression))]);
}
}

Loading…
Cancel
Save