chore: tweak render tag logic (#15109)

pull/15110/head
Rich Harris 7 months ago committed by GitHub
parent 24b6fab58b
commit e3d4a0fa8e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -706,7 +706,7 @@ function special(parser) {
expression: /** @type {AST.RenderTag['expression']} */ (expression), expression: /** @type {AST.RenderTag['expression']} */ (expression),
metadata: { metadata: {
dynamic: false, dynamic: false,
args_with_call_expression: new Set(), arguments: [],
path: [], path: [],
snippets: new Set() snippets: new Set()
} }

@ -605,7 +605,6 @@ export function analyze_component(root, source, options) {
has_props_rune: false, has_props_rune: false,
component_slots: new Set(), component_slots: new Set(),
expression: null, expression: null,
render_tag: null,
private_derived_state: [], private_derived_state: [],
function_depth: scope.function_depth, function_depth: scope.function_depth,
instance_scope: instance.scope, instance_scope: instance.scope,
@ -677,7 +676,6 @@ export function analyze_component(root, source, options) {
reactive_statements: analysis.reactive_statements, reactive_statements: analysis.reactive_statements,
component_slots: new Set(), component_slots: new Set(),
expression: null, expression: null,
render_tag: null,
private_derived_state: [], private_derived_state: [],
function_depth: scope.function_depth function_depth: scope.function_depth
}; };

@ -19,8 +19,6 @@ export interface AnalysisState {
component_slots: Set<string>; component_slots: Set<string>;
/** Information about the current expression/directive/block value */ /** Information about the current expression/directive/block value */
expression: ExpressionMetadata | null; expression: ExpressionMetadata | null;
/** The current {@render ...} tag, if any */
render_tag: null | AST.RenderTag;
private_derived_state: string[]; private_derived_state: string[];
function_depth: number; function_depth: number;

@ -186,18 +186,6 @@ export function CallExpression(node, context) {
break; break;
} }
if (context.state.render_tag) {
// Find out which of the render tag arguments contains this call expression
const arg_idx = unwrap_optional(context.state.render_tag.expression).arguments.findIndex(
(arg) => arg === node || context.path.includes(arg)
);
// -1 if this is the call expression of the render tag itself
if (arg_idx !== -1) {
context.state.render_tag.metadata.args_with_call_expression.add(arg_idx);
}
}
if (node.callee.type === 'Identifier') { if (node.callee.type === 'Identifier') {
const binding = context.state.scope.get(node.callee.name); const binding = context.state.scope.get(node.callee.name);

@ -5,6 +5,7 @@ import * as e from '../../../errors.js';
import { validate_opening_tag } from './shared/utils.js'; import { validate_opening_tag } from './shared/utils.js';
import { mark_subtree_dynamic } from './shared/fragment.js'; import { mark_subtree_dynamic } from './shared/fragment.js';
import { is_resolved_snippet } from './shared/snippets.js'; import { is_resolved_snippet } from './shared/snippets.js';
import { create_expression_metadata } from '../../nodes.js';
/** /**
* @param {AST.RenderTag} node * @param {AST.RenderTag} node
@ -15,7 +16,8 @@ export function RenderTag(node, context) {
node.metadata.path = [...context.path]; node.metadata.path = [...context.path];
const callee = unwrap_optional(node.expression).callee; const expression = unwrap_optional(node.expression);
const callee = expression.callee;
const binding = callee.type === 'Identifier' ? context.state.scope.get(callee.name) : null; const binding = callee.type === 'Identifier' ? context.state.scope.get(callee.name) : null;
@ -52,5 +54,15 @@ export function RenderTag(node, context) {
mark_subtree_dynamic(context.path); mark_subtree_dynamic(context.path);
context.next({ ...context.state, render_tag: node }); context.visit(callee);
for (const arg of expression.arguments) {
const metadata = create_expression_metadata();
node.metadata.arguments.push(metadata);
context.visit(arg, {
...context.state,
expression: metadata
});
}
} }

@ -10,20 +10,24 @@ import * as b from '../../../../utils/builders.js';
*/ */
export function RenderTag(node, context) { export function RenderTag(node, context) {
context.state.template.push('<!>'); context.state.template.push('<!>');
const callee = unwrap_optional(node.expression).callee;
const raw_args = unwrap_optional(node.expression).arguments; const expression = unwrap_optional(node.expression);
const callee = expression.callee;
const raw_args = expression.arguments;
/** @type {Expression[]} */ /** @type {Expression[]} */
let args = []; let args = [];
for (let i = 0; i < raw_args.length; i++) { for (let i = 0; i < raw_args.length; i++) {
const raw = raw_args[i]; let thunk = b.thunk(/** @type {Expression} */ (context.visit(raw_args[i])));
const arg = /** @type {Expression} */ (context.visit(raw)); const { has_call } = node.metadata.arguments[i];
if (node.metadata.args_with_call_expression.has(i)) {
if (has_call) {
const id = b.id(context.state.scope.generate('render_arg')); const id = b.id(context.state.scope.generate('render_arg'));
context.state.init.push(b.var(id, b.call('$.derived_safe_equal', b.thunk(arg)))); context.state.init.push(b.var(id, b.call('$.derived_safe_equal', thunk)));
args.push(b.thunk(b.call('$.get', id))); args.push(b.thunk(b.call('$.get', id)));
} else { } else {
args.push(b.thunk(arg)); args.push(thunk);
} }
} }

@ -166,7 +166,7 @@ export namespace AST {
/** @internal */ /** @internal */
metadata: { metadata: {
dynamic: boolean; dynamic: boolean;
args_with_call_expression: Set<number>; arguments: ExpressionMetadata[];
path: SvelteNode[]; path: SvelteNode[];
/** The set of locally-defined snippets that this render tag could correspond to, /** The set of locally-defined snippets that this render tag could correspond to,
* used for CSS pruning purposes */ * used for CSS pruning purposes */

Loading…
Cancel
Save