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 const expression = context.state.analysis.runes
? /** @type {Expression} */ (context.visit(node.expression)) ? /** @type {Expression} */ (context.visit(node.expression))
: build_legacy_expression(node.expression, context); : build_legacy_expression(node.expression, context);
context.state.init.push( context.state.init.push(b.stmt(b.call('$.attach', context.state.node, b.thunk(expression))));
b.stmt(
b.call(
'$.attach',
context.state.node,
b.thunk(expression)
)
)
);
context.next(); context.next();
} }

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

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

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

Loading…
Cancel
Save