Skip to content

Commit

Permalink
fix: rework directive name handling (#9470)
Browse files Browse the repository at this point in the history
* move snapshot test to a runtime test

* handle dynamic cases

* huh

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
  • Loading branch information
Rich-Harris and Rich-Harris committed Nov 15, 2023
1 parent 73e8820 commit d749685
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 168 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
EACH_ITEM_REACTIVE,
EACH_KEYED
} from '../../../../../constants.js';
import { regex_is_valid_identifier } from '../../../patterns.js';

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

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

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

for (let new_piece of splitted_expression) {
new_expression += `['${new_piece}']`;
while ((part = /** @type {string} */ (parts.shift()))) {
const computed = !regex_is_valid_identifier.test(part);
expression = b.member(expression, computed ? b.literal(part) : b.id(part), computed);
}
return new_expression;

return expression;
}

/**
Expand Down Expand Up @@ -1697,7 +1703,7 @@ export const template_visitors = {
b.call(
'$.animate',
state.node,
b.id(member_expression_id_to_literal(node.name)),
/** @type {import('estree').Expression} */ (visit(parse_directive_name(node.name))),
expression
)
)
Expand All @@ -1721,7 +1727,7 @@ export const template_visitors = {
b.call(
type,
state.node,
b.id(member_expression_id_to_literal(node.name)),
/** @type {import('estree').Expression} */ (visit(parse_directive_name(node.name))),
expression,
node.modifiers.includes('global') ? b.true : b.false
)
Expand Down Expand Up @@ -2445,7 +2451,7 @@ export const template_visitors = {
b.arrow(
params,
b.call(
serialize_get_binding(b.id(member_expression_id_to_literal(node.name)), state),
/** @type {import('estree').Expression} */ (visit(parse_directive_name(node.name))),
...params
)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { test } from '../../test';

// no need to compare the rendered HTML — we only care
// that the generated code is valid
export default test({});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script>
/**
* @param {Element} [node]
* @param {any} [options]
*/
const fn = (node, options) => ({});
let a = { b: { 'c-d': fn } };
let directive = $derived(a);
</script>

<!-- these will yield TypeScript errors, because it looks like e.g. `nested.with - string`,
in other words a number. Relatedly, people should not do this. It is stupid. -->
<div use:directive.b.c-d />
<div transition:directive.b.c-d />
<div animate:directive.b.c-d />
<div in:directive.b.c-d />
<div out:directive.b.c-d />

This file was deleted.

This file was deleted.

This file was deleted.

5 changes: 1 addition & 4 deletions packages/svelte/tests/snapshot/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@ 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);
if (!config.skip_if_ssr) {
compile_directory(cwd, 'server', config.compileOptions);
}
compile_directory(cwd, 'server', config.compileOptions);

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

1 comment on commit d749685

@vercel
Copy link

@vercel vercel bot commented on d749685 Nov 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

svelte-5-preview – ./sites/svelte-5-preview

svelte-5-preview.vercel.app
svelte-octane.vercel.app
svelte-5-preview-svelte.vercel.app
svelte-5-preview-git-main-svelte.vercel.app

Please sign in to comment.