is_async -> has_await

pull/16197/head
Rich Harris 6 months ago
parent fcbb54db3d
commit 888fc31f71

@ -203,9 +203,14 @@ function js(script, root, allow_reactive_declarations, parent) {
body: []
};
const { scope, scopes, is_async } = create_scopes(ast, root, allow_reactive_declarations, parent);
const { scope, scopes, has_await } = create_scopes(
ast,
root,
allow_reactive_declarations,
parent
);
return { ast, scope, scopes, is_async };
return { ast, scope, scopes, has_await };
}
/**
@ -230,7 +235,7 @@ const RESERVED = ['$$props', '$$restProps', '$$slots'];
* @returns {Analysis}
*/
export function analyze_module(ast, options) {
const { scope, scopes, is_async } = create_scopes(ast, new ScopeRoot(), false, null);
const { scope, scopes, has_await } = create_scopes(ast, new ScopeRoot(), false, null);
for (const [name, references] of scope.references) {
if (name[0] !== '$' || RESERVED.includes(name)) continue;
@ -247,7 +252,7 @@ export function analyze_module(ast, options) {
/** @type {Analysis} */
const analysis = {
module: { ast, scope, scopes, is_async },
module: { ast, scope, scopes, has_await },
name: options.filename,
accessors: false,
runes: true,
@ -293,7 +298,7 @@ export function analyze_component(root, source, options) {
const module = js(root.module, scope_root, false, null);
const instance = js(root.instance, scope_root, true, module.scope);
const { scope, scopes, is_async } = create_scopes(
const { scope, scopes, has_await } = create_scopes(
root.fragment,
scope_root,
false,
@ -408,7 +413,7 @@ export function analyze_component(root, source, options) {
const runes =
options.runes ??
(is_async || instance.is_async || Array.from(module.scope.references.keys()).some(is_rune));
(has_await || instance.has_await || Array.from(module.scope.references.keys()).some(is_rune));
if (!runes) {
for (let check of synthetic_stores_legacy_check) {

@ -12,7 +12,7 @@ export function AwaitExpression(node, context) {
let preserve_context = tla;
if (context.state.expression) {
context.state.expression.is_async = true;
context.state.expression.has_await = true;
suspend = true;
// wrap the expression in `(await $.save(...)).restore()` if necessary,

@ -242,7 +242,7 @@ export function CallExpression(node, context) {
expression
});
if (expression.is_async) {
if (expression.has_await) {
context.state.analysis.async_deriveds.add(node);
}
} else if (rune === '$inspect') {

@ -32,7 +32,7 @@ export function StyleDirective(node, context) {
node.metadata.expression.has_state ||= chunk.metadata.expression.has_state;
node.metadata.expression.has_call ||= chunk.metadata.expression.has_call;
node.metadata.expression.is_async ||= chunk.metadata.expression.is_async;
node.metadata.expression.has_await ||= chunk.metadata.expression.has_await;
}
}
}

@ -369,7 +369,7 @@ export function client_component(analysis, options) {
: b.stmt(b.call('$.init', analysis.immutable ? b.true : undefined))
]);
if (analysis.instance.is_async) {
if (analysis.instance.has_await) {
const body = b.function_declaration(
b.id('$$body'),
[b.id('$$anchor'), b.id('$$props')],
@ -379,9 +379,9 @@ export function client_component(analysis, options) {
b.if(b.call('$.aborted'), b.return()),
.../** @type {ESTree.Statement[]} */ (template.body),
b.stmt(b.call('$$unsuspend'))
])
]),
true
);
body.async = true;
state.hoisted.push(body);

@ -1,4 +1,4 @@
/** @import { ArrowFunctionExpression, BlockStatement, CallExpression, Expression, FunctionDeclaration, FunctionExpression, Statement } from 'estree' */
/** @import { ArrowFunctionExpression, BlockStatement, Expression, FunctionDeclaration, FunctionExpression, Statement } from 'estree' */
/** @import { ComponentContext } from '../types' */
import { add_state_transformers } from './shared/declarations.js';
import * as b from '../../../../utils/builders.js';

@ -293,9 +293,9 @@ export function EachBlock(node, context) {
);
}
const { is_async } = node.metadata.expression;
const { has_await } = node.metadata.expression;
const thunk = b.thunk(collection, is_async);
const thunk = b.thunk(collection, has_await);
const render_args = [b.id('$$anchor'), item];
if (uses_index || collection_id) render_args.push(index);
@ -305,7 +305,7 @@ export function EachBlock(node, context) {
const args = [
context.state.node,
b.literal(flags),
is_async ? b.thunk(b.call('$.get', b.id('$$collection'))) : thunk,
has_await ? b.thunk(b.call('$.get', b.id('$$collection'))) : thunk,
key_function,
b.arrow(render_args, b.block(declarations.concat(block.body)))
];
@ -316,7 +316,7 @@ export function EachBlock(node, context) {
);
}
if (is_async) {
if (has_await) {
context.state.init.push(
b.stmt(
b.call(

@ -11,10 +11,10 @@ import * as b from '../../../../utils/builders.js';
export function HtmlTag(node, context) {
context.state.template.push('<!>');
const { is_async } = node.metadata.expression;
const { has_await } = node.metadata.expression;
const expression = /** @type {Expression} */ (context.visit(node.expression));
const html = is_async ? b.call('$.get', b.id('$$html')) : expression;
const html = has_await ? b.call('$.get', b.id('$$html')) : expression;
const is_svg = context.state.metadata.namespace === 'svg';
const is_mathml = context.state.metadata.namespace === 'mathml';
@ -31,7 +31,7 @@ export function HtmlTag(node, context) {
);
// push into init, so that bindings run afterwards, which might trigger another run and override hydration
if (node.metadata.expression.is_async) {
if (node.metadata.expression.has_await) {
context.state.init.push(
b.stmt(
b.call(

@ -24,10 +24,10 @@ export function IfBlock(node, context) {
statements.push(b.var(b.id(alternate_id), b.arrow([b.id('$$anchor')], alternate)));
}
const { is_async } = node.metadata.expression;
const { has_await } = node.metadata.expression;
const expression = /** @type {Expression} */ (context.visit(node.test));
const test = is_async ? b.call('$.get', b.id('$$condition')) : expression;
const test = has_await ? b.call('$.get', b.id('$$condition')) : expression;
/** @type {Expression[]} */
const args = [
@ -79,7 +79,7 @@ export function IfBlock(node, context) {
statements.push(b.stmt(b.call('$.if', ...args)));
if (is_async) {
if (has_await) {
context.state.init.push(
b.stmt(
b.call(

@ -13,7 +13,7 @@ export function KeyBlock(node, context) {
const key = /** @type {Expression} */ (context.visit(node.expression));
const body = /** @type {Expression} */ (context.visit(node.fragment));
if (node.metadata.expression.is_async) {
if (node.metadata.expression.has_await) {
context.state.init.push(
b.stmt(
b.call(

@ -311,7 +311,7 @@ export function RegularElement(node, context) {
(value, metadata) =>
metadata.has_call
? get_expression_id(
metadata.is_async ? context.state.async_expressions : context.state.expressions,
metadata.has_await ? context.state.async_expressions : context.state.expressions,
value
)
: value
@ -386,7 +386,7 @@ export function RegularElement(node, context) {
trimmed.every(
(node) =>
node.type === 'Text' ||
(!node.metadata.expression.has_state && !node.metadata.expression.is_async)
(!node.metadata.expression.has_state && !node.metadata.expression.has_await)
) &&
trimmed.some((node) => node.type === 'ExpressionTag');
@ -532,7 +532,7 @@ export function build_class_directives_object(class_directives, context) {
const expression = /** @type Expression */ (context.visit(d.expression));
properties.push(b.init(d.name, expression));
has_call_or_state ||= d.metadata.expression.has_call || d.metadata.expression.has_state;
has_async ||= d.metadata.expression.is_async;
has_async ||= d.metadata.expression.has_await;
}
const directives = b.object(properties);
@ -561,7 +561,7 @@ export function build_style_directives_object(style_directives, context) {
: build_attribute_value(directive.value, context, (value, metadata) =>
metadata.has_call
? get_expression_id(
metadata.is_async ? context.state.async_expressions : context.state.expressions,
metadata.has_await ? context.state.async_expressions : context.state.expressions,
value
)
: value
@ -699,11 +699,11 @@ function build_element_special_value_attribute(element, node_id, attribute, cont
element === 'select' && attribute.value !== true && !is_text_attribute(attribute);
const { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) =>
metadata.has_call || metadata.is_async
metadata.has_call || metadata.has_await
? // if is a select with value we will also invoke `init_select` which need a reference before the template effect so we memoize separately
is_select_with_value
? memoize_expression(context.state, value)
: get_expression_id(metadata.is_async ? state.async_expressions : state.expressions, value)
: get_expression_id(metadata.has_await ? state.async_expressions : state.expressions, value)
: value
);

@ -29,12 +29,12 @@ export function RenderTag(node, context) {
for (let i = 0; i < raw_args.length; i++) {
let expression = /** @type {Expression} */ (context.visit(raw_args[i]));
const { has_call, is_async } = node.metadata.arguments[i];
const { has_call, has_await } = node.metadata.arguments[i];
if (is_async || has_call) {
if (has_await || has_call) {
expression = b.call(
'$.get',
get_expression_id(is_async ? async_expressions : expressions, expression)
get_expression_id(has_await ? async_expressions : expressions, expression)
);
}

@ -93,10 +93,10 @@ export function SvelteElement(node, context) {
);
}
const { is_async } = node.metadata.expression;
const { has_await } = node.metadata.expression;
const expression = /** @type {Expression} */ (context.visit(node.tag));
const get_tag = b.thunk(is_async ? b.call('$.get', b.id('$$tag')) : expression);
const get_tag = b.thunk(has_await ? b.call('$.get', b.id('$$tag')) : expression);
/** @type {Statement[]} */
const inner = inner_context.state.init;
@ -139,7 +139,7 @@ export function SvelteElement(node, context) {
)
);
if (is_async) {
if (has_await) {
context.state.init.push(
b.stmt(
b.call(

@ -126,11 +126,11 @@ export function build_component(node, component_name, context, anchor = context.
if (attribute.metadata.expression.has_state) {
props_and_spreads.push(
b.thunk(
attribute.metadata.expression.is_async || attribute.metadata.expression.has_call
attribute.metadata.expression.has_await || attribute.metadata.expression.has_call
? b.call(
'$.get',
get_expression_id(
attribute.metadata.expression.is_async ? async_expressions : expressions,
attribute.metadata.expression.has_await ? async_expressions : expressions,
expression
)
)
@ -147,10 +147,10 @@ export function build_component(node, component_name, context, anchor = context.
attribute.name,
build_attribute_value(attribute.value, context, (value, metadata) => {
// TODO put the derived in the local block
return metadata.has_call || metadata.is_async
return metadata.has_call || metadata.has_await
? b.call(
'$.get',
get_expression_id(metadata.is_async ? async_expressions : expressions, value)
get_expression_id(metadata.has_await ? async_expressions : expressions, value)
)
: value;
}).value
@ -171,13 +171,13 @@ export function build_component(node, component_name, context, anchor = context.
attribute.value,
context,
(value, metadata) => {
if (!metadata.has_state && !metadata.is_async) return value;
if (!metadata.has_state && !metadata.has_await) return value;
// When we have a non-simple computation, anything other than an Identifier or Member expression,
// then there's a good chance it needs to be memoized to avoid over-firing when read within the
// child component (e.g. `active={i === index}`)
const should_wrap_in_derived =
metadata.is_async ||
metadata.has_await ||
get_attribute_chunks(attribute.value).some((n) => {
return (
n.type === 'ExpressionTag' &&
@ -189,7 +189,7 @@ export function build_component(node, component_name, context, anchor = context.
return should_wrap_in_derived
? b.call(
'$.get',
get_expression_id(metadata.is_async ? async_expressions : expressions, value)
get_expression_id(metadata.has_await ? async_expressions : expressions, value)
)
: value;
}

@ -38,9 +38,9 @@ export function build_set_attributes(
attribute.value,
context,
(value, metadata) =>
metadata.has_call || metadata.is_async
metadata.has_call || metadata.has_await
? get_expression_id(
metadata.is_async ? context.state.async_expressions : context.state.expressions,
metadata.has_await ? context.state.async_expressions : context.state.expressions,
value
)
: value
@ -65,9 +65,9 @@ export function build_set_attributes(
let value = /** @type {Expression} */ (context.visit(attribute));
if (attribute.metadata.expression.has_call || attribute.metadata.expression.is_async) {
if (attribute.metadata.expression.has_call || attribute.metadata.expression.has_await) {
value = get_expression_id(
attribute.metadata.expression.is_async
attribute.metadata.expression.has_await
? context.state.async_expressions
: context.state.expressions,
value
@ -145,7 +145,7 @@ export function build_attribute_value(value, context, memoize = (value) => value
return {
value: memoize(expression, chunk.metadata.expression),
has_state: chunk.metadata.expression.has_state || chunk.metadata.expression.is_async
has_state: chunk.metadata.expression.has_state || chunk.metadata.expression.has_await
};
}
@ -178,9 +178,9 @@ export function build_set_class(element, node_id, attribute, class_directives, c
value = b.call('$.clsx', value);
}
return metadata.has_call || metadata.is_async
return metadata.has_call || metadata.has_await
? get_expression_id(
metadata.is_async ? context.state.async_expressions : context.state.expressions,
metadata.has_await ? context.state.async_expressions : context.state.expressions,
value
)
: value;
@ -253,7 +253,7 @@ export function build_set_style(node_id, attribute, style_directives, context) {
let { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) =>
metadata.has_call
? get_expression_id(
metadata.is_async ? context.state.async_expressions : context.state.expressions,
metadata.has_await ? context.state.async_expressions : context.state.expressions,
value
)
: value

@ -45,8 +45,8 @@ export function build_template_chunk(
visit,
state,
memoize = (value, metadata) =>
metadata.has_call || metadata.is_async
? get_expression_id(metadata.is_async ? state.async_expressions : state.expressions, value)
metadata.has_call || metadata.has_await
? get_expression_id(metadata.has_await ? state.async_expressions : state.expressions, value)
: value
) {
/** @type {Expression[]} */
@ -56,7 +56,7 @@ export function build_template_chunk(
const quasis = [quasi];
let has_state = false;
let is_async = false;
let has_await = false;
for (let i = 0; i < values.length; i++) {
const node = values[i];
@ -77,8 +77,8 @@ export function build_template_chunk(
node.metadata.expression
);
is_async ||= node.metadata.expression.is_async;
has_state ||= is_async || node.metadata.expression.has_state;
has_await ||= node.metadata.expression.has_await;
has_state ||= has_await || node.metadata.expression.has_state;
if (values.length === 1) {
// If we have a single expression, then pass that in directly to possibly avoid doing

@ -62,6 +62,6 @@ export function create_expression_metadata() {
dependencies: new Set(),
has_state: false,
has_call: false,
is_async: false
has_await: false
};
}

@ -736,7 +736,7 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
}
};
let is_async = false;
let has_await = false;
walk(ast, state, {
AwaitExpression(node, context) {
@ -744,7 +744,7 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
// automatically opt into runes mode on encountering
// blocking awaits, without doing an additional walk
// before the analysis occurs
is_async ||= context.path.every(
has_await ||= context.path.every(
({ type }) =>
type !== 'ArrowFunctionExpression' &&
type !== 'FunctionExpression' &&
@ -1108,7 +1108,7 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
}
return {
is_async,
has_await,
scope,
scopes
};

@ -13,7 +13,7 @@ export interface Js {
ast: Program;
scope: Scope;
scopes: Map<AST.SvelteNode, Scope>;
is_async: boolean;
has_await: boolean;
}
export interface Template {

@ -273,7 +273,7 @@ export interface ExpressionMetadata {
/** True if the expression involves a call expression (often, it will need to be wrapped in a derived) */
has_call: boolean;
/** True if the expression contains `await` */
is_async: boolean;
has_await: boolean;
}
export * from './template.js';

Loading…
Cancel
Save