pull/15844/head
Rich Harris 3 months ago
parent 36947c5922
commit 923d8f67dd

@ -14,7 +14,7 @@ export function AwaitExpression(node, context) {
// preserve context if this is a top-level await in `<script>` // preserve context if this is a top-level await in `<script>`
(context.state.is_instance && context.state.scope.function_depth === 1) || (context.state.is_instance && context.state.scope.function_depth === 1) ||
// or if this is a derived/template expression // or if this is a derived/template expression
(is_reactive_expression(context) && !is_last_evaluated_expression(context.path, node)); (is_reactive_expression(context) && !is_last_evaluated_expression(context, node));
if (dev || save) { if (dev || save) {
const expression = /** @type {Expression} */ (context.visit(node.argument)); const expression = /** @type {Expression} */ (context.visit(node.argument));
@ -28,6 +28,10 @@ export function AwaitExpression(node, context) {
* @param {Context} context * @param {Context} context
*/ */
function is_reactive_expression(context) { function is_reactive_expression(context) {
if (context.state.in_derived) {
return true;
}
let i = context.path.length; let i = context.path.length;
while (i--) { while (i--) {
@ -41,10 +45,6 @@ function is_reactive_expression(context) {
return false; return false;
} }
if (parent.type === 'CallExpression' && get_rune(parent, context.state.scope) === '$derived') {
return true;
}
// @ts-expect-error we could probably use a neater/more robust mechanism // @ts-expect-error we could probably use a neater/more robust mechanism
if (parent.metadata) { if (parent.metadata) {
return true; return true;
@ -55,14 +55,14 @@ function is_reactive_expression(context) {
} }
/** /**
* @param {AST.SvelteNode[]} path * @param {Context} context
* @param {Expression | SpreadElement | Property} node * @param {Expression | SpreadElement | Property} node
*/ */
function is_last_evaluated_expression(path, node) { function is_last_evaluated_expression(context, node) {
let i = path.length; let i = context.path.length;
while (i--) { while (i--) {
const parent = /** @type {Expression | Property | SpreadElement} */ (path[i]); const parent = /** @type {Expression | Property | SpreadElement} */ (context.path[i]);
// @ts-expect-error we could probably use a neater/more robust mechanism // @ts-expect-error we could probably use a neater/more robust mechanism
if (parent.metadata) { if (parent.metadata) {

@ -44,10 +44,11 @@ export function CallExpression(node, context) {
case '$derived': case '$derived':
case '$derived.by': { case '$derived.by': {
let fn = /** @type {Expression} */ (context.visit(node.arguments[0])); let fn = /** @type {Expression} */ (
if (rune === '$derived') fn = b.thunk(fn); context.visit(node.arguments[0], { ...context.state, in_derived: rune === '$derived' })
);
return b.call('$.derived', fn); return b.call('$.derived', rune === '$derived' ? b.thunk(fn) : fn);
} }
case '$state.snapshot': case '$state.snapshot':

@ -8,7 +8,7 @@ import * as b from '#compiler/builders';
* @param {ComponentContext} context * @param {ComponentContext} context
*/ */
export function FunctionDeclaration(node, context) { export function FunctionDeclaration(node, context) {
const state = { ...context.state, in_constructor: false }; const state = { ...context.state, in_constructor: false, in_derived: false };
if (node.metadata?.hoisted === true) { if (node.metadata?.hoisted === true) {
const params = build_hoisted_params(node, context); const params = build_hoisted_params(node, context);

@ -199,29 +199,23 @@ export function VariableDeclaration(node, context) {
); );
if (declarator.id.type === 'Identifier') { if (declarator.id.type === 'Identifier') {
let expression = /** @type {Expression} */ (
context.visit(value, {
...context.state,
in_derived: rune === '$derived'
})
);
if (is_async) { if (is_async) {
const location = dev && is_ignored(init, 'await_waterfall') && locate_node(init); const location = dev && is_ignored(init, 'await_waterfall') && locate_node(init);
const expression = /** @type {Expression} */ (context.visit(value)); const call = b.call(
'$.async_derived',
declarations.push( b.thunk(expression, true),
b.declarator( location ? b.literal(location) : undefined
declarator.id,
b.call(
b.await(
b.call(
'$.save',
b.call(
'$.async_derived',
b.thunk(expression, true),
location ? b.literal(location) : undefined
)
)
)
)
)
); );
declarations.push(b.declarator(declarator.id, b.call(b.await(b.call('$.save', call)))));
} else { } else {
let expression = /** @type {Expression} */ (context.visit(value));
if (rune === '$derived') expression = b.thunk(expression); if (rune === '$derived') expression = b.thunk(expression);
let call = b.call('$.derived', expression); let call = b.call('$.derived', expression);

@ -9,7 +9,7 @@ import { build_hoisted_params } from '../../utils.js';
export const visit_function = (node, context) => { export const visit_function = (node, context) => {
const metadata = node.metadata; const metadata = node.metadata;
let state = { ...context.state, in_constructor: false }; let state = { ...context.state, in_constructor: false, in_derived: false };
if (node.type === 'FunctionExpression') { if (node.type === 'FunctionExpression') {
const parent = /** @type {Node} */ (context.path.at(-1)); const parent = /** @type {Node} */ (context.path.at(-1));

@ -8,5 +8,8 @@ export interface TransformState {
readonly scope: Scope; readonly scope: Scope;
readonly scopes: Map<AST.SvelteNode, Scope>; readonly scopes: Map<AST.SvelteNode, Scope>;
/** True if we're directly inside a `$derived(...)` expression (but not `$derived.by(...)`) */
readonly in_derived: boolean;
readonly state_fields: Map<string, StateField>; readonly state_fields: Map<string, StateField>;
} }

Loading…
Cancel
Save