diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/AttachTag.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/AttachTag.js index 7ec9e63172..85b3720e9c 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/AttachTag.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/AttachTag.js @@ -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(); } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/AwaitBlock.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/AwaitBlock.js index 80453027a5..044424d14d 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/AwaitBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/AwaitBlock.js @@ -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; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/ConstTag.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/ConstTag.js index cde0fd8bc2..c61df71222 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/ConstTag.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/ConstTag.js @@ -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)))) ]) ); diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js index 522a49e7c0..27fdebf9d5 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js @@ -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(); diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/IfBlock.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/IfBlock.js index 9a67e33645..3b3badce4b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/IfBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/IfBlock.js @@ -51,7 +51,6 @@ export function IfBlock(node, context) { ) ]; - if (node.elseif) { // We treat this... // diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RenderTag.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RenderTag.js index 825f18e3ec..083011681f 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RenderTag.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RenderTag.js @@ -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 diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js index d3b5b09bc4..4703faedb6 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js @@ -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))]); -} \ No newline at end of file +}