|
|
@ -1,13 +1,19 @@
|
|
|
|
/** @import { BlockStatement, Expression, ExpressionStatement, Identifier, MemberExpression, Pattern, Property, SequenceExpression, Statement } from 'estree' */
|
|
|
|
/** @import { BlockStatement, Expression, ExpressionStatement, Identifier, MemberExpression, Pattern, Property, SequenceExpression, Statement } from 'estree' */
|
|
|
|
/** @import { AST } from '#compiler' */
|
|
|
|
/** @import { AST } from '#compiler' */
|
|
|
|
/** @import { ComponentContext } from '../../types.js' */
|
|
|
|
/** @import { ComponentContext, MemoizedExpression } from '../../types.js' */
|
|
|
|
import { dev, is_ignored } from '../../../../../state.js';
|
|
|
|
import { dev, is_ignored } from '../../../../../state.js';
|
|
|
|
import { get_attribute_chunks, object } from '../../../../../utils/ast.js';
|
|
|
|
import { get_attribute_chunks, object } from '../../../../../utils/ast.js';
|
|
|
|
import * as b from '../../../../../utils/builders.js';
|
|
|
|
import * as b from '../../../../../utils/builders.js';
|
|
|
|
import { build_bind_this, memoize_expression, validate_binding } from '../shared/utils.js';
|
|
|
|
import {
|
|
|
|
|
|
|
|
build_bind_this,
|
|
|
|
|
|
|
|
get_expression_id,
|
|
|
|
|
|
|
|
memoize_expression,
|
|
|
|
|
|
|
|
validate_binding
|
|
|
|
|
|
|
|
} from '../shared/utils.js';
|
|
|
|
import { build_attribute_value } from '../shared/element.js';
|
|
|
|
import { build_attribute_value } from '../shared/element.js';
|
|
|
|
import { build_event_handler } from './events.js';
|
|
|
|
import { build_event_handler } from './events.js';
|
|
|
|
import { determine_slot } from '../../../../../utils/slot.js';
|
|
|
|
import { determine_slot } from '../../../../../utils/slot.js';
|
|
|
|
|
|
|
|
import { create_derived } from '../../utils.js';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* @param {AST.Component | AST.SvelteComponent | AST.SvelteSelf} node
|
|
|
|
* @param {AST.Component | AST.SvelteComponent | AST.SvelteSelf} node
|
|
|
@ -40,6 +46,12 @@ export function build_component(node, component_name, context, anchor = context.
|
|
|
|
/** @type {Record<string, Expression[]>} */
|
|
|
|
/** @type {Record<string, Expression[]>} */
|
|
|
|
const events = {};
|
|
|
|
const events = {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @type {MemoizedExpression[]} */
|
|
|
|
|
|
|
|
const expressions = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @type {MemoizedExpression[]} */
|
|
|
|
|
|
|
|
const async_expressions = [];
|
|
|
|
|
|
|
|
|
|
|
|
/** @type {Property[]} */
|
|
|
|
/** @type {Property[]} */
|
|
|
|
const custom_css_props = [];
|
|
|
|
const custom_css_props = [];
|
|
|
|
|
|
|
|
|
|
|
@ -115,16 +127,21 @@ export function build_component(node, component_name, context, anchor = context.
|
|
|
|
(events[attribute.name] ||= []).push(handler);
|
|
|
|
(events[attribute.name] ||= []).push(handler);
|
|
|
|
} else if (attribute.type === 'SpreadAttribute') {
|
|
|
|
} else if (attribute.type === 'SpreadAttribute') {
|
|
|
|
const expression = /** @type {Expression} */ (context.visit(attribute));
|
|
|
|
const expression = /** @type {Expression} */ (context.visit(attribute));
|
|
|
|
if (attribute.metadata.expression.has_state) {
|
|
|
|
|
|
|
|
let value = expression;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (attribute.metadata.expression.has_call) {
|
|
|
|
if (attribute.metadata.expression.has_state) {
|
|
|
|
const id = b.id(context.state.scope.generate('spread_element'));
|
|
|
|
props_and_spreads.push(
|
|
|
|
context.state.init.push(b.var(id, b.call('$.derived', b.thunk(value))));
|
|
|
|
b.thunk(
|
|
|
|
value = b.call('$.get', id);
|
|
|
|
attribute.metadata.expression.is_async || attribute.metadata.expression.has_call
|
|
|
|
}
|
|
|
|
? b.call(
|
|
|
|
|
|
|
|
'$.get',
|
|
|
|
props_and_spreads.push(b.thunk(value));
|
|
|
|
get_expression_id(
|
|
|
|
|
|
|
|
attribute.metadata.expression.is_async ? async_expressions : expressions,
|
|
|
|
|
|
|
|
expression
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
: expression
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
props_and_spreads.push(expression);
|
|
|
|
props_and_spreads.push(expression);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -133,10 +150,15 @@ export function build_component(node, component_name, context, anchor = context.
|
|
|
|
custom_css_props.push(
|
|
|
|
custom_css_props.push(
|
|
|
|
b.init(
|
|
|
|
b.init(
|
|
|
|
attribute.name,
|
|
|
|
attribute.name,
|
|
|
|
build_attribute_value(attribute.value, context, (value, metadata) =>
|
|
|
|
build_attribute_value(attribute.value, context, (value, metadata) => {
|
|
|
|
// TODO put the derived in the local block
|
|
|
|
// TODO put the derived in the local block
|
|
|
|
metadata.has_call ? memoize_expression(context.state, value) : value
|
|
|
|
return metadata.has_call || metadata.is_async
|
|
|
|
).value
|
|
|
|
? b.call(
|
|
|
|
|
|
|
|
'$.get',
|
|
|
|
|
|
|
|
get_expression_id(metadata.is_async ? async_expressions : expressions, value)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
: value;
|
|
|
|
|
|
|
|
}).value
|
|
|
|
)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
@ -154,7 +176,7 @@ export function build_component(node, component_name, context, anchor = context.
|
|
|
|
attribute.value,
|
|
|
|
attribute.value,
|
|
|
|
context,
|
|
|
|
context,
|
|
|
|
(value, metadata) => {
|
|
|
|
(value, metadata) => {
|
|
|
|
if (!metadata.has_state) return value;
|
|
|
|
if (!metadata.has_state && !metadata.is_async) return value;
|
|
|
|
|
|
|
|
|
|
|
|
// When we have a non-simple computation, anything other than an Identifier or Member expression,
|
|
|
|
// 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
|
|
|
|
// then there's a good chance it needs to be memoized to avoid over-firing when read within the
|
|
|
@ -167,7 +189,12 @@ export function build_component(node, component_name, context, anchor = context.
|
|
|
|
);
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return should_wrap_in_derived ? memoize_expression(context.state, value) : value;
|
|
|
|
return should_wrap_in_derived
|
|
|
|
|
|
|
|
? b.call(
|
|
|
|
|
|
|
|
'$.get',
|
|
|
|
|
|
|
|
get_expression_id(metadata.is_async ? async_expressions : expressions, value)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
: value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
@ -420,7 +447,12 @@ export function build_component(node, component_name, context, anchor = context.
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const statements = [...snippet_declarations];
|
|
|
|
const statements = [
|
|
|
|
|
|
|
|
...snippet_declarations,
|
|
|
|
|
|
|
|
...expressions.map((memo) =>
|
|
|
|
|
|
|
|
b.let(memo.id, create_derived(context.state, b.thunk(memo.expression)))
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
if (node.type === 'SvelteComponent') {
|
|
|
|
if (node.type === 'SvelteComponent') {
|
|
|
|
const prev = fn;
|
|
|
|
const prev = fn;
|
|
|
@ -457,5 +489,20 @@ export function build_component(node, component_name, context, anchor = context.
|
|
|
|
statements.push(b.stmt(fn(anchor)));
|
|
|
|
statements.push(b.stmt(fn(anchor)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[...async_expressions, ...expressions].forEach((memo, i) => {
|
|
|
|
|
|
|
|
memo.id.name = `$${i}`;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (async_expressions.length > 0) {
|
|
|
|
|
|
|
|
return b.stmt(
|
|
|
|
|
|
|
|
b.call(
|
|
|
|
|
|
|
|
'$.async',
|
|
|
|
|
|
|
|
anchor,
|
|
|
|
|
|
|
|
b.array(async_expressions.map(({ expression }) => b.thunk(expression, true))),
|
|
|
|
|
|
|
|
b.arrow([b.id('$$anchor'), ...async_expressions.map(({ id }) => id)], b.block(statements))
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return statements.length > 1 ? b.block(statements) : statements[0];
|
|
|
|
return statements.length > 1 ? b.block(statements) : statements[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|