UNPKG

svelte

Version:

Cybernetically enhanced web apps

137 lines (112 loc) 3.78 kB
/** @import { CallExpression, Expression } from 'estree' */ /** @import { Context } from '../types' */ import { dev, is_ignored } from '../../../../state.js'; import * as b from '#compiler/builders'; import { get_rune } from '../../../scope.js'; import { should_proxy } from '../utils.js'; import { get_inspect_args } from '../../utils.js'; /** * @param {CallExpression} node * @param {Context} context */ export function CallExpression(node, context) { const rune = get_rune(node, context.state.scope); switch (rune) { case '$host': return b.id('$$props.$$host'); case '$effect.tracking': return b.call('$.effect_tracking'); // transform state field assignments in constructors case '$state': case '$state.raw': { let arg = node.arguments[0]; /** @type {Expression | undefined} */ let value = undefined; if (arg) { value = /** @type {Expression} */ (context.visit(node.arguments[0])); if ( rune === '$state' && should_proxy(/** @type {Expression} */ (arg), context.state.scope) ) { value = b.call('$.proxy', value); } } const callee = b.id('$.state', node.callee.loc); return b.call(callee, value); } case '$derived': case '$derived.by': { let fn = /** @type {Expression} */ (context.visit(node.arguments[0])); return b.call('$.derived', rune === '$derived' ? b.thunk(fn) : fn); } case '$state.eager': return b.call( '$.eager', b.thunk(/** @type {Expression} */ (context.visit(node.arguments[0]))) ); case '$state.snapshot': return b.call( '$.snapshot', /** @type {Expression} */ (context.visit(node.arguments[0])), is_ignored(node, 'state_snapshot_uncloneable') && b.true ); case '$effect': case '$effect.pre': { const callee = rune === '$effect' ? '$.user_effect' : '$.user_pre_effect'; const func = /** @type {Expression} */ (context.visit(node.arguments[0])); const expr = b.call(callee, /** @type {Expression} */ (func)); expr.callee.loc = node.callee.loc; // ensure correct mapping return expr; } case '$effect.root': return b.call( '$.effect_root', .../** @type {Expression[]} */ (node.arguments.map((arg) => context.visit(arg))) ); case '$effect.pending': return b.call('$.eager', b.thunk(b.call('$.pending'))); case '$inspect': case '$inspect().with': return transform_inspect_rune(rune, node, context); } if ( dev && node.callee.type === 'MemberExpression' && node.callee.object.type === 'Identifier' && node.callee.object.name === 'console' && context.state.scope.get('console') === null && node.callee.property.type === 'Identifier' && ['debug', 'dir', 'error', 'group', 'groupCollapsed', 'info', 'log', 'trace', 'warn'].includes( node.callee.property.name ) && node.arguments.some( (arg) => arg.type === 'SpreadElement' || context.state.scope.evaluate(arg).has_unknown ) ) { return b.call( node.callee, b.spread( b.call( '$.log_if_contains_state', b.literal(node.callee.property.name), .../** @type {Expression[]} */ (node.arguments.map((arg) => context.visit(arg))) ) ) ); } context.next(); } /** * @param {'$inspect' | '$inspect().with'} rune * @param {CallExpression} node * @param {Context} context */ function transform_inspect_rune(rune, node, context) { if (!dev) return b.empty; const { args, inspector } = get_inspect_args(rune, node, context.visit); // by passing an arrow function, the log appears to come from the `$inspect` callsite // rather than the `inspect.js` file containing the utility const id = b.id('$$args'); const fn = b.arrow([b.rest(id)], b.call(inspector, b.spread(id))); return b.call('$.inspect', b.thunk(b.array(args)), fn, rune === '$inspect' && b.true); }