experiment-s2
Dominic Gannaway 7 hours ago
parent 91399eeb85
commit be95b34f29

@ -500,3 +500,5 @@ declare namespace $host {
/** @deprecated */
export const toString: never;
}
declare function $await<V>(value: Promise<V>): [V, undefined | Promise<V>];

@ -69,7 +69,6 @@ import { TransitionDirective } from './visitors/TransitionDirective.js';
import { UpdateExpression } from './visitors/UpdateExpression.js';
import { UseDirective } from './visitors/UseDirective.js';
import { VariableDeclarator } from './visitors/VariableDeclarator.js';
import { AwaitExpression } from './visitors/AwaitExpression.js';
import is_reference from 'is-reference';
import { mark_subtree_dynamic } from './visitors/shared/fragment.js';
@ -159,7 +158,6 @@ const visitors = {
LetDirective,
MemberExpression,
NewExpression,
AwaitExpression,
OnDirective,
RegularElement,
RenderTag,

@ -1,35 +0,0 @@
/** @import { AwaitExpression } from 'estree' */
/** @import { Context } from '../types' */
import { extract_identifiers } from '../../../utils/ast.js';
import * as w from '../../../warnings.js';
/**
* @param {AwaitExpression} node
* @param {Context} context
*/
export function AwaitExpression(node, context) {
const declarator = context.path.at(-1);
const declaration = context.path.at(-2);
const program = context.path.at(-3);
if (context.state.ast_type === 'instance') {
if (
declarator?.type !== 'VariableDeclarator' ||
context.state.function_depth !== 1 ||
declaration?.type !== 'VariableDeclaration' ||
program?.type !== 'Program'
) {
throw new Error('TODO: invalid usage of AwaitExpression in component');
}
for (const declarator of declaration.declarations) {
for (const id of extract_identifiers(declarator.id)) {
const binding = context.state.scope.get(id.name);
if (binding !== null) {
binding.kind = 'derived';
}
}
}
}
context.next();
}

@ -3,7 +3,7 @@
/** @import { Context } from '../types' */
import { get_rune } from '../../scope.js';
import * as e from '../../../errors.js';
import { get_parent, unwrap_optional } from '../../../utils/ast.js';
import { extract_identifiers, get_parent, unwrap_optional } from '../../../utils/ast.js';
import { is_pure, is_safe_identifier } from './shared/utils.js';
import { dev, locate_node, source } from '../../../state.js';
import * as b from '../../../utils/builders.js';
@ -123,6 +123,39 @@ export function CallExpression(node, context) {
break;
case '$await': {
if (node.arguments.length !== 1) {
e.rune_invalid_arguments_length(node, rune, 'exactly one argument');
}
const declarator = context.path.at(-1);
const declaration = context.path.at(-2);
const program = context.path.at(-3);
if (context.state.ast_type !== 'instance') {
throw new Error('TODO: $await can only be used at the top-level of a component');
}
if (
declarator?.type !== 'VariableDeclarator' ||
declarator?.id.type !== 'ArrayPattern' ||
declaration?.type !== 'VariableDeclaration' ||
declaration?.declarations.length !== 1 ||
context.state.function_depth !== 1 ||
program?.type !== 'Program'
) {
throw new Error('TODO: invalid usage of $await in component');
}
for (const id of extract_identifiers(declarator.id)) {
const binding = context.state.scope.get(id.name);
if (binding !== null) {
binding.kind = 'derived';
}
}
break;
}
case '$inspect':
if (node.arguments.length < 1) {
e.rune_invalid_arguments_length(node, rune, 'one or more arguments');
@ -207,7 +240,7 @@ export function CallExpression(node, context) {
}
// `$inspect(foo)` or `$derived(foo) should not trigger the `static-state-reference` warning
if (rune === '$inspect' || rune === '$derived') {
if (rune === '$inspect' || rune === '$derived' || rune === '$await') {
context.next({ ...context.state, function_depth: context.state.function_depth + 1 });
} else {
context.next();

@ -55,7 +55,6 @@ import { SvelteWindow } from './visitors/SvelteWindow.js';
import { TitleElement } from './visitors/TitleElement.js';
import { TransitionDirective } from './visitors/TransitionDirective.js';
import { UpdateExpression } from './visitors/UpdateExpression.js';
import { AwaitExpression } from './visitors/AwaitExpression.js';
import { UseDirective } from './visitors/UseDirective.js';
import { VariableDeclaration } from './visitors/VariableDeclaration.js';
@ -132,8 +131,7 @@ const visitors = {
TransitionDirective,
UpdateExpression,
UseDirective,
VariableDeclaration,
AwaitExpression
VariableDeclaration
};
/**

@ -328,10 +328,7 @@ export function wrap_unsafe_async_statements(statements, context) {
const apply_async_statements = () => {
new_statements.push(
b.stmt(
b.call(
'$.script_effect',
b.thunk(b.block(/** @type {Statement[]} */ (async_statements)))
)
b.call('$.script_effect', b.thunk(b.block(/** @type {Statement[]} */ (async_statements))))
)
);
async_statements = null;
@ -364,23 +361,31 @@ export function wrap_unsafe_async_statements(statements, context) {
const declarator = statement.declarations[0];
const rune = get_rune(declarator.init, context.state.scope);
if (declarator.init?.type === 'AwaitExpression') {
// TODO: do we need to do anything here?
if (
declarator.init == null ||
declarator.init.type === 'FunctionExpression' ||
declarator.init.type === 'ArrowFunctionExpression' ||
declarator.init.type === 'Literal'
) {
// Safe to not wrap
} else if (rune === null || rune === '$state' || rune === '$state.raw') {
const visited_declarator = /** @type {VariableDeclaration} */ (visited).declarations[0];
new_statements.push(b.let(visited_declarator.id));
if (rune === '$state') {
debugger;
}
if (visited_declarator.init != null) {
push_async_statement(
b.stmt(b.assignment('=', visited_declarator.id, visited_declarator.init))
);
}
continue;
} else if (rune !== '$props' && rune !== '$derived' && rune !== '$derived.by') {
} else if (rune !== '$props' && rune !== '$derived' && rune !== '$derived.by' && rune !== '$await') {
debugger;
}
} else if (
statement.type === 'FunctionDeclaration' ||
statement.type === 'ClassDeclaration' ||
statement.type === 'EmptyStatement'
) {
// Safe to not wrap
}
if (async_statements !== null) {

@ -1,17 +0,0 @@
/** @import { AwaitExpression, Expression } from 'estree' */
/** @import { ComponentContext } from '../types' */
import * as b from '../../../../utils/builders.js';
/**
* @param {AwaitExpression} node
* @param {ComponentContext} context
*/
export function AwaitExpression(node, context) {
// Inside component
if (context.state.analysis.instance) {
return b.call('$.await_derived', b.thunk(/** @type {Expression} */ (context.visit(node.argument))));
}
context.next();
}

@ -194,6 +194,10 @@ export function VariableDeclaration(node, context) {
}
continue;
}
if (rune === '$await') {
declarations.push(b.declarator(declarator.id, b.call('$.await_derived', b.thunk(value))));
}
}
} else {
for (const declarator of node.declarations) {

@ -262,6 +262,7 @@ export function await_derived(fn) {
block(() => {
var promise = get(derived_promise)
try {
get(value)
} catch (e) {
@ -294,5 +295,13 @@ export function await_derived(fn) {
return value.v;
}, AWAIT_EFFECT);
return value;
var pending = derived(() => {
var promise = get(derived_promise);
if (previous_promise === promise) {
return null;
}
return promise;
});
return [value, pending];
}

@ -630,7 +630,7 @@ export function update_effect(effect) {
handle_error(error, effect, previous_effect, previous_component_context || effect.ctx);
} finally {
active_effect = previous_effect;
if ((flags & AWAIT_EFFECT) === 0) {
if ((flags & AWAIT_EFFECT) === 0 || previous_effect === null) {
is_within_await = previous_is_within_await;
}
@ -826,7 +826,7 @@ function process_effects(effect, collected_effects) {
var is_skippable_branch = is_branch && (flags & CLEAN) !== 0;
var sibling = current_effect.next;
if (!is_skippable_branch && ((flags & (INERT)) === 0 || (flags & (AWAIT_EFFECT)) !== 0)) {
if (!is_skippable_branch && ((flags & INERT) === 0 || (flags & AWAIT_EFFECT) !== 0)) {
if ((flags & RENDER_EFFECT) !== 0) {
if (is_branch) {
current_effect.f ^= CLEAN;
@ -1035,7 +1035,7 @@ export function get(signal) {
value = signal.v;
if (is_within_await && value === PENDING) {
if (value === PENDING) {
throw PENDING;
}

@ -429,6 +429,7 @@ const RUNES = /** @type {const} */ ([
'$effect.pre',
'$effect.tracking',
'$effect.root',
'$await',
'$inspect',
'$inspect().with',
'$inspect.trace',

@ -3157,4 +3157,6 @@ declare namespace $host {
export const toString: never;
}
declare function $await<V>(value: Promise<V>): [V, undefined | Promise<V>];
//# sourceMappingURL=index.d.ts.map

Loading…
Cancel
Save