skip the noop if known to be a function

pull/16021/head
Rich Harris 4 months ago
parent 8f152de6dc
commit a34c2337c0

@ -258,12 +258,17 @@ export function build_component(node, component_name, context, anchor = context.
} }
} }
} else if (attribute.type === 'AttachTag') { } else if (attribute.type === 'AttachTag') {
const evaluated = context.state.scope.evaluate(attribute.expression);
let expression = /** @type {Expression} */ (context.visit(attribute.expression)); let expression = /** @type {Expression} */ (context.visit(attribute.expression));
if (attribute.metadata.expression.has_state) { if (attribute.metadata.expression.has_state) {
expression = b.arrow( expression = b.arrow(
[b.id('$$node')], [b.id('$$node')],
b.call(b.call('$.safe_call', expression), b.id('$$node')) b.call(
evaluated.is_function ? expression : b.logical('||', expression, b.id('$.noop')),
b.id('$$node')
)
); );
} }

@ -20,6 +20,7 @@ const UNKNOWN = Symbol('unknown');
/** Includes `BigInt` */ /** Includes `BigInt` */
export const NUMBER = Symbol('number'); export const NUMBER = Symbol('number');
export const STRING = Symbol('string'); export const STRING = Symbol('string');
export const FUNCTION = Symbol('string');
/** @type {Record<string, [type: NUMBER | STRING | UNKNOWN, fn?: Function]>} */ /** @type {Record<string, [type: NUMBER | STRING | UNKNOWN, fn?: Function]>} */
const globals = { const globals = {
@ -200,6 +201,13 @@ class Evaluation {
*/ */
is_number = true; is_number = true;
/**
* True if the value is known to be a function
* @readonly
* @type {boolean}
*/
is_function = true;
/** /**
* @readonly * @readonly
* @type {any} * @type {any}
@ -209,7 +217,7 @@ class Evaluation {
/** /**
* *
* @param {Scope} scope * @param {Scope} scope
* @param {Expression} expression * @param {Expression | FunctionDeclaration} expression
* @param {Set<any>} values * @param {Set<any>} values
*/ */
constructor(scope, expression, values) { constructor(scope, expression, values) {
@ -500,6 +508,13 @@ class Evaluation {
break; break;
} }
case 'ArrowFunctionExpression':
case 'FunctionExpression':
case 'FunctionDeclaration': {
this.values.add(FUNCTION);
break;
}
default: { default: {
this.values.add(UNKNOWN); this.values.add(UNKNOWN);
} }
@ -516,6 +531,10 @@ class Evaluation {
this.is_number = false; this.is_number = false;
} }
if (value !== FUNCTION) {
this.is_function = false;
}
if (value == null || value === UNKNOWN) { if (value == null || value === UNKNOWN) {
this.is_defined = false; this.is_defined = false;
} }

@ -155,7 +155,7 @@ export {
} from './dom/operations.js'; } from './dom/operations.js';
export { attr, clsx } from '../shared/attributes.js'; export { attr, clsx } from '../shared/attributes.js';
export { snapshot } from '../shared/clone.js'; export { snapshot } from '../shared/clone.js';
export { noop, fallback, safe_call, to_array } from '../shared/utils.js'; export { noop, fallback, to_array } from '../shared/utils.js';
export { export {
invalid_default_snippet, invalid_default_snippet,
validate_dynamic_element_tag, validate_dynamic_element_tag,

@ -82,16 +82,6 @@ export function fallback(value, fallback, lazy = false) {
: value; : value;
} }
/**
* @param {*} value
*/
export function safe_call(value) {
if (is_function(value)) {
return value;
}
return noop;
}
/** /**
* When encountering a situation like `let [a, b, c] = $derived(blah())`, * When encountering a situation like `let [a, b, c] = $derived(blah())`,
* we need to stash an intermediate value that `a`, `b`, and `c` derive * we need to stash an intermediate value that `a`, `b`, and `c` derive

Loading…
Cancel
Save