Skip to content

Commit 7c92782

Browse files
committed
handle dynamic cases
1 parent 519be6e commit 7c92782

File tree

2 files changed

+26
-47
lines changed
  • packages/svelte
    • src/compiler/phases/3-transform/client/visitors
    • tests/runtime-runes/samples/directives-with-member-access

2 files changed

+26
-47
lines changed

packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
EACH_ITEM_REACTIVE,
3535
EACH_KEYED
3636
} from '../../../../../constants.js';
37+
import { regex_is_valid_identifier } from '../../../patterns.js';
3738

3839
/**
3940
* Serializes each style directive into something like `$.style(element, style_property, value)`
@@ -75,19 +76,24 @@ function serialize_style_directives(style_directives, element_id, context, is_at
7576
}
7677

7778
/**
78-
* goes from nested.access to nested['access']
79-
* @param {string} expression
79+
* For unfortunate legacy reasons, directive names can look like this `use:a.b-c`
80+
* This turns that string into a member expression
81+
* @param {string} name
8082
*/
81-
function member_expression_id_to_literal(expression) {
83+
function parse_directive_name(name) {
8284
// this allow for accessing members of an object
83-
const splitted_expression = expression.split('.');
85+
const parts = name.split('.');
86+
let part = /** @type {string} */ (parts.shift());
8487

85-
let new_expression = splitted_expression.shift() ?? '';
88+
/** @type {import('estree').Identifier | import('estree').MemberExpression} */
89+
let expression = b.id(part);
8690

87-
for (let new_piece of splitted_expression) {
88-
new_expression += `['${new_piece}']`;
91+
while ((part = /** @type {string} */ (parts.shift()))) {
92+
const computed = !regex_is_valid_identifier.test(part);
93+
expression = b.member(expression, computed ? b.literal(part) : b.id(part), computed);
8994
}
90-
return new_expression;
95+
96+
return expression;
9197
}
9298

9399
/**
@@ -1697,7 +1703,7 @@ export const template_visitors = {
16971703
b.call(
16981704
'$.animate',
16991705
state.node,
1700-
b.id(member_expression_id_to_literal(node.name)),
1706+
/** @type {import('estree').Expression} */ (visit(parse_directive_name(node.name))),
17011707
expression
17021708
)
17031709
)
@@ -1721,7 +1727,7 @@ export const template_visitors = {
17211727
b.call(
17221728
type,
17231729
state.node,
1724-
b.id(member_expression_id_to_literal(node.name)),
1730+
/** @type {import('estree').Expression} */ (visit(parse_directive_name(node.name))),
17251731
expression,
17261732
node.modifiers.includes('global') ? b.true : b.false
17271733
)
@@ -2445,7 +2451,7 @@ export const template_visitors = {
24452451
b.arrow(
24462452
params,
24472453
b.call(
2448-
serialize_get_binding(b.id(member_expression_id_to_literal(node.name)), state),
2454+
/** @type {import('estree').Expression} */ (visit(parse_directive_name(node.name))),
24492455
...params
24502456
)
24512457
)

packages/svelte/tests/runtime-runes/samples/directives-with-member-access/main.svelte

Lines changed: 9 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,17 @@
33
* @param {Element} [node]
44
* @param {any} [options]
55
*/
6-
const one = (node, options) => ({});
7-
const nested = { one, "with-string": one };
8-
const evenmore = { nested };
9-
</script>
10-
11-
<div use:one />
12-
<div use:nested.one />
13-
<div use:evenmore.nested.one />
14-
15-
<div transition:one />
16-
<div transition:nested.one />
17-
<div transition:evenmore.nested.one />
6+
const fn = (node, options) => ({});
187
19-
<div animate:one />
20-
<div animate:nested.one />
21-
<div animate:evenmore.nested.one />
8+
let a = { b: { 'c-d': fn } };
229
23-
<div in:one />
24-
<div in:nested.one />
25-
<div in:evenmore.nested.one />
26-
27-
<div out:one />
28-
<div out:nested.one />
29-
<div out:evenmore.nested.one />
10+
let directive = $derived(a);
11+
</script>
3012

3113
<!-- these will yield TypeScript errors, because it looks like e.g. `nested.with - string`,
3214
in other words a number. Relatedly, people should not do this. It is stupid. -->
33-
<div use:nested.with-string />
34-
<div use:evenmore.nested.with-string />
35-
36-
<div transition:nested.with-string />
37-
<div transition:evenmore.nested.with-string />
38-
39-
<div animate:nested.with-string />
40-
<div animate:evenmore.nested.with-string />
41-
42-
<div in:nested.with-string />
43-
<div in:evenmore.nested.with-string />
44-
45-
<div out:nested.with-string />
46-
<div out:evenmore.nested.with-string />
15+
<div use:directive.b.c-d />
16+
<div transition:directive.b.c-d />
17+
<div animate:directive.b.c-d />
18+
<div in:directive.b.c-d />
19+
<div out:directive.b.c-d />

0 commit comments

Comments
 (0)