diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index bc079ac618..404cd1a537 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -77,10 +77,6 @@ import { UseDirective } from './visitors/UseDirective.js'; import { VariableDeclarator } from './visitors/VariableDeclarator.js'; import is_reference from 'is-reference'; import { mark_subtree_dynamic } from './visitors/shared/fragment.js'; -import { is_last_evaluated_expression } from './utils/awaits.js'; - -/** @type {Array} */ -const metadata_stack = []; /** * @type {Visitors} @@ -132,23 +128,9 @@ const visitors = { ignore_map.set(node, structuredClone(ignore_stack)); - metadata_stack.push(state.expression); - const scope = state.scopes.get(node); next(scope !== undefined && scope !== state.scope ? { ...state, scope } : state); - metadata_stack.pop(); - - // if this node set `state.expression`, now that we've visited it we can determine - // which `await` expressions need to be wrapped in `$.save(...)` - if (state.expression && metadata_stack[metadata_stack.length - 1] === null) { - for (const { path, node } of state.expression.awaits) { - if (!is_last_evaluated_expression(path, node)) { - state.analysis.context_preserving_awaits.add(node); - } - } - } - if (ignores.length > 0) { pop_ignore(); } @@ -291,7 +273,6 @@ export function analyze_module(source, options) { immutable: true, tracing: false, async_deriveds: new Set(), - context_preserving_awaits: new Set(), comments, classes: new Map() }; @@ -538,8 +519,7 @@ export function analyze_component(root, source, options) { undefined_exports: new Map(), snippet_renderers: new Map(), snippets: new Set(), - async_deriveds: new Set(), - context_preserving_awaits: new Set() + async_deriveds: new Set() }; if (!runes) { diff --git a/packages/svelte/src/compiler/phases/2-analyze/utils/awaits.js b/packages/svelte/src/compiler/phases/2-analyze/utils/awaits.js deleted file mode 100644 index e9e5cdc8ba..0000000000 --- a/packages/svelte/src/compiler/phases/2-analyze/utils/awaits.js +++ /dev/null @@ -1,70 +0,0 @@ -/** @import { Expression, Property, SpreadElement } from 'estree' */ -/** @import { AST } from '#compiler' */ - -/** - * - * @param {AST.SvelteNode[]} path - * @param {Expression | SpreadElement | Property} node - */ -export function is_last_evaluated_expression(path, node) { - let i = path.length; - - while (i--) { - const parent = /** @type {Expression | Property | SpreadElement} */ (path[i]); - - // @ts-expect-error we could probably use a neater/more robust mechanism - if (parent.metadata) { - return true; - } - - switch (parent.type) { - case 'ArrayExpression': - if (node !== parent.elements.at(-1)) return false; - break; - - case 'AssignmentExpression': - case 'BinaryExpression': - case 'LogicalExpression': - if (node === parent.left) return false; - break; - - case 'CallExpression': - case 'NewExpression': - if (node !== parent.arguments.at(-1)) return false; - break; - - case 'ConditionalExpression': - if (node === parent.test) return false; - break; - - case 'MemberExpression': - if (parent.computed && node === parent.object) return false; - break; - - case 'ObjectExpression': - if (node !== parent.properties.at(-1)) return false; - break; - - case 'Property': - if (node === parent.key) return false; - break; - - case 'SequenceExpression': - if (node !== parent.expressions.at(-1)) return false; - break; - - case 'TaggedTemplateExpression': - if (node !== parent.quasi.expressions.at(-1)) return false; - break; - - case 'TemplateLiteral': - if (node !== parent.expressions.at(-1)) return false; - break; - - default: - return false; - } - - node = parent; - } -} diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js index bd96e99d88..af7d0307e9 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js @@ -7,20 +7,15 @@ import * as e from '../../../errors.js'; * @param {Context} context */ export function AwaitExpression(node, context) { - const tla = context.state.ast_type === 'instance' && context.state.function_depth === 1; - - if (tla) { - context.state.analysis.context_preserving_awaits.add(node); - } - - let suspend = tla; + let suspend = context.state.ast_type === 'instance' && context.state.function_depth === 1; if (context.state.expression) { - context.state.expression.awaits.push({ node, path: context.path.slice() }); context.state.expression.has_await = true; suspend = true; } + // disallow top-level `await` or `await` in template expressions + // unless a) in runes mode and b) opted into `experimental.async` if (suspend) { if (!context.state.options.experimental.async) { e.experimental_async(node); diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index dd093ca428..a424d9c65c 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -702,7 +702,8 @@ export function client_module(analysis, options) { scopes: analysis.module.scopes, state_fields: new Map(), transform: {}, - in_constructor: false + in_constructor: false, + is_instance: false }; const module = /** @type {ESTree.Program} */ ( diff --git a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts index cf5c942268..4b099eed52 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts +++ b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts @@ -21,6 +21,9 @@ export interface ClientTransformState extends TransformState { */ readonly in_constructor: boolean; + /** `true` if we're transforming the contents of `