Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: allow member access on directives #9462

Merged
merged 4 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/itchy-lions-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte": patch
---

fix: allow member access on directives
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ function serialize_style_directives(style_directives, element_id, context, is_at
}
}

/**
* goes from nested.access to nested['access']
* @param {string} expression
*/
function member_expression_id_to_literal(expression) {
// this allow for accessing members of an object
const splitted_expression = expression.split('.');

let new_expression = splitted_expression.shift() ?? '';

for (let new_piece of splitted_expression) {
new_expression += `['${new_piece}']`;
}
return new_expression;
}

/**
* Serializes each class directive into something like `$.class_toogle(element, class_name, value)`
* and adds it either to init or update, depending on whether or not the value or the attributes are dynamic.
Expand Down Expand Up @@ -1676,7 +1692,16 @@ export const template_visitors = {
? b.literal(null)
: b.thunk(/** @type {import('estree').Expression} */ (visit(node.expression)));

state.init.push(b.stmt(b.call('$.animate', state.node, b.id(node.name), expression)));
state.init.push(
b.stmt(
b.call(
'$.animate',
state.node,
b.id(member_expression_id_to_literal(node.name)),
expression
)
)
);
},
ClassDirective(node, { state, next }) {
error(node, 'INTERNAL', 'Node should have been handled elsewhere');
Expand All @@ -1696,7 +1721,7 @@ export const template_visitors = {
b.call(
type,
state.node,
b.id(node.name),
b.id(member_expression_id_to_literal(node.name)),
expression,
node.modifiers.includes('global') ? b.true : b.false
)
Expand Down Expand Up @@ -2417,7 +2442,13 @@ export const template_visitors = {
/** @type {import('estree').Expression[]} */
const args = [
state.node,
b.arrow(params, b.call(serialize_get_binding(b.id(node.name), state), ...params))
b.arrow(
params,
b.call(
serialize_get_binding(b.id(member_expression_id_to_literal(node.name)), state),
...params
)
)
];

if (node.expression) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { test } from '../../test';

export default test({
skip_if_ssr: true
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// index.svelte (Svelte VERSION)
// Note: compiler output will change before 5.0 is released!
import "svelte/internal/disclose-version";
import * as $ from "svelte/internal";

var frag = $.template(`<div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div>`, true);

export default function Directives_with_member_access($$anchor, $$props) {
$.push($$props, false);

const one = () => {};
const nested = { one, "with-string": one };
const evenmore = { nested };

/* Init */
var fragment = $.open_frag($$anchor, true, frag);
var div = $.child_frag(fragment);
var div_1 = $.sibling($.sibling(div));
var div_2 = $.sibling($.sibling(div_1));
var div_3 = $.sibling($.sibling(div_2));

$.transition(div_3, one, null, false);

var div_4 = $.sibling($.sibling(div_3));

$.transition(div_4, nested['one'], null, false);

var div_5 = $.sibling($.sibling(div_4));

$.transition(div_5, evenmore['nested']['one'], null, false);

var div_6 = $.sibling($.sibling(div_5));

$.animate(div_6, one, null);

var div_7 = $.sibling($.sibling(div_6));

$.animate(div_7, nested['one'], null);

var div_8 = $.sibling($.sibling(div_7));

$.animate(div_8, evenmore['nested']['one'], null);

var div_9 = $.sibling($.sibling(div_8));

$.in(div_9, one, null, false);

var div_10 = $.sibling($.sibling(div_9));

$.in(div_10, nested['one'], null, false);

var div_11 = $.sibling($.sibling(div_10));

$.in(div_11, evenmore['nested']['one'], null, false);

var div_12 = $.sibling($.sibling(div_11));

$.out(div_12, one, null, false);

var div_13 = $.sibling($.sibling(div_12));

$.out(div_13, nested['one'], null, false);

var div_14 = $.sibling($.sibling(div_13));

$.out(div_14, evenmore['nested']['one'], null, false);

var div_15 = $.sibling($.sibling(div_14));
var div_16 = $.sibling($.sibling(div_15));
var div_17 = $.sibling($.sibling(div_16));

$.transition(div_17, nested['with-string'], null, false);

var div_18 = $.sibling($.sibling(div_17));

$.transition(div_18, evenmore['nested']['with-string'], null, false);

var div_19 = $.sibling($.sibling(div_18));

$.animate(div_19, nested['with-string'], null);

var div_20 = $.sibling($.sibling(div_19));

$.animate(div_20, evenmore['nested']['with-string'], null);

var div_21 = $.sibling($.sibling(div_20));

$.in(div_21, nested['with-string'], null, false);

var div_22 = $.sibling($.sibling(div_21));

$.in(div_22, evenmore['nested']['with-string'], null, false);

var div_23 = $.sibling($.sibling(div_22));

$.out(div_23, nested['with-string'], null, false);

var div_24 = $.sibling($.sibling(div_23));

$.out(div_24, evenmore['nested']['with-string'], null, false);
$.action(div, $$node => one($$node));
$.action(div_1, $$node => nested['one']($$node));
$.action(div_2, $$node => evenmore['nested']['one']($$node));
$.action(div_15, $$node => nested['with-string']($$node));
$.action(div_16, $$node => evenmore['nested']['with-string']($$node));
$.close_frag($$anchor, fragment);
$.pop();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<script>
const one = ()=>{};
const nested = {one, "with-string": one};
const evenmore = {nested};
</script>

<div use:one />
<div use:nested.one />
<div use:evenmore.nested.one />

<div transition:one />
<div transition:nested.one />
<div transition:evenmore.nested.one />

<div animate:one />
<div animate:nested.one />
<div animate:evenmore.nested.one />

<div in:one />
<div in:nested.one />
<div in:evenmore.nested.one />

<div out:one />
<div out:nested.one />
<div out:evenmore.nested.one />

<div use:nested.with-string />
<div use:evenmore.nested.with-string />

<div transition:nested.with-string />
<div transition:evenmore.nested.with-string />

<div animate:nested.with-string />
<div animate:evenmore.nested.with-string />

<div in:nested.with-string />
<div in:evenmore.nested.with-string />

<div out:nested.with-string />
<div out:evenmore.nested.with-string />
5 changes: 4 additions & 1 deletion packages/svelte/tests/snapshot/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import { VERSION } from 'svelte/compiler';

interface SnapshotTest extends BaseTest {
compileOptions?: Partial<import('#compiler').CompileOptions>;
skip_if_ssr?: boolean;
}

const { test, run } = suite<SnapshotTest>(async (config, cwd) => {
compile_directory(cwd, 'client', config.compileOptions);
compile_directory(cwd, 'server', config.compileOptions);
if (!config.skip_if_ssr) {
compile_directory(cwd, 'server', config.compileOptions);
}

// run `UPDATE_SNAPSHOTS=true pnpm test snapshot` to update snapshot tests
if (process.env.UPDATE_SNAPSHOTS) {
Expand Down