Skip to content

Commit 51c553f

Browse files
committed
fix: cache call expressions in render tag arguments
Ensure that they're called at most once per change, not once per access within the snippet fixes #12187
1 parent 36a6a6b commit 51c553f

File tree

7 files changed

+214
-194
lines changed

7 files changed

+214
-194
lines changed

.changeset/tricky-avocados-play.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: cache call expressions in render tag arguments

packages/svelte/src/compiler/phases/1-parse/state/tag.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,8 @@ function special(parser) {
600600
end: parser.index,
601601
expression: expression,
602602
metadata: {
603-
dynamic: false
603+
dynamic: false,
604+
args_with_call_expression: new Set()
604605
}
605606
});
606607
}

packages/svelte/src/compiler/phases/2-analyze/index.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
extract_paths,
99
is_event_attribute,
1010
is_text_attribute,
11-
object
11+
object,
12+
unwrap_optional
1213
} from '../../utils/ast.js';
1314
import * as b from '../../utils/builders.js';
1415
import { MathMLElements, ReservedKeywords, Runes, SVGElements } from '../constants.js';
@@ -1297,6 +1298,30 @@ const common_visitors = {
12971298
expression.metadata.contains_call_expression = true;
12981299
}
12991300

1301+
if (context.state.ast_type === 'template') {
1302+
// Find out if this is a call expression inside a render tag argument
1303+
let i = -1;
1304+
let parent = context.path.at(i);
1305+
1306+
while (parent && parent.type !== 'RenderTag') {
1307+
i -= 1;
1308+
parent = context.path.at(i);
1309+
}
1310+
1311+
if (parent) {
1312+
const arg_path_idx = i + (parent.expression.type === 'CallExpression' ? 2 : 3);
1313+
1314+
if (arg_path_idx <= 0) {
1315+
const arg =
1316+
arg_path_idx === 0
1317+
? node
1318+
: /** @type {import('estree').Expression} */ (context.path.at(arg_path_idx));
1319+
const arg_idx = unwrap_optional(parent.expression).arguments.indexOf(arg);
1320+
parent.metadata.args_with_call_expression.add(arg_idx);
1321+
}
1322+
}
1323+
}
1324+
13001325
const callee = node.callee;
13011326
const rune = get_rune(node, context.state.scope);
13021327

0 commit comments

Comments
 (0)