From eafa3673db648f9db30997f6e8b6d2815c26601c Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 9 Feb 2024 15:39:18 -0500 Subject: [PATCH 1/3] rename $derived.call to $derived.by --- .../src/compiler/phases/2-analyze/index.js | 6 +-- .../compiler/phases/2-analyze/validation.js | 8 ++-- .../client/visitors/javascript-runes.js | 10 ++--- .../3-transform/server/transform-server.js | 4 +- .../svelte/src/compiler/phases/constants.js | 2 +- packages/svelte/src/compiler/warnings.js | 3 +- packages/svelte/src/main/ambient.d.ts | 8 ++-- .../class-state-derived-fn/main.svelte | 2 +- .../samples/derived-fn/main.svelte | 2 +- packages/svelte/types/index.d.ts | 40 +++++++++---------- 10 files changed, 42 insertions(+), 43 deletions(-) diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index a7d4a9180ab0..ec0bcd30ae49 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -681,7 +681,7 @@ const runes_scope_js_tweaker = { rune !== '$state' && rune !== '$state.frozen' && rune !== '$derived' && - rune !== '$derived.call' + rune !== '$derived.by' ) return; @@ -717,7 +717,7 @@ const runes_scope_tweaker = { rune !== '$state' && rune !== '$state.frozen' && rune !== '$derived' && - rune !== '$derived.call' && + rune !== '$derived.by' && rune !== '$props' ) return; @@ -730,7 +730,7 @@ const runes_scope_tweaker = { ? 'state' : rune === '$state.frozen' ? 'frozen_state' - : rune === '$derived' || rune === '$derived.call' + : rune === '$derived' || rune === '$derived.by' ? 'derived' : path.is_rest ? 'rest_prop' diff --git a/packages/svelte/src/compiler/phases/2-analyze/validation.js b/packages/svelte/src/compiler/phases/2-analyze/validation.js index 8af0a2940240..1a854ce47897 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/validation.js +++ b/packages/svelte/src/compiler/phases/2-analyze/validation.js @@ -746,7 +746,7 @@ function validate_call_expression(node, scope, path) { error(node, 'invalid-props-location'); } - if (rune === '$state' || rune === '$derived' || rune === '$derived.call') { + if (rune === '$state' || rune === '$derived' || rune === '$derived.by') { if (parent.type === 'VariableDeclarator') return; if (parent.type === 'PropertyDefinition' && !parent.static && !parent.computed) return; error(node, 'invalid-state-location', rune); @@ -817,7 +817,7 @@ export const validation_runes_js = { const args = /** @type {import('estree').CallExpression} */ (init).arguments; - if ((rune === '$derived' || rune === '$derived.call') && args.length !== 1) { + if ((rune === '$derived' || rune === '$derived.by') && args.length !== 1) { error(node, 'invalid-rune-args-length', rune, [1]); } else if (rune === '$state' && args.length > 1) { error(node, 'invalid-rune-args-length', rune, [0, 1]); @@ -842,7 +842,7 @@ export const validation_runes_js = { definition.value?.type === 'CallExpression' ) { const rune = get_rune(definition.value, context.state.scope); - if (rune === '$derived' || rune === '$derived.call') { + if (rune === '$derived' || rune === '$derived.by') { private_derived_state.push(definition.key.name); } } @@ -988,7 +988,7 @@ export const validation_runes = merge(validation, a11y_validators, { const args = /** @type {import('estree').CallExpression} */ (init).arguments; // TODO some of this is duplicated with above, seems off - if ((rune === '$derived' || rune === '$derived.call') && args.length !== 1) { + if ((rune === '$derived' || rune === '$derived.by') && args.length !== 1) { error(node, 'invalid-rune-args-length', rune, [1]); } else if (rune === '$state' && args.length > 1) { error(node, 'invalid-rune-args-length', rune, [0, 1]); diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js index e69cb42ae3fd..12cd8d2052bd 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js @@ -33,7 +33,7 @@ export const javascript_visitors_runes = { rune === '$state' || rune === '$state.frozen' || rune === '$derived' || - rune === '$derived.call' + rune === '$derived.by' ) { /** @type {import('../types.js').StateField} */ const field = { @@ -42,7 +42,7 @@ export const javascript_visitors_runes = { ? 'state' : rune === '$state.frozen' ? 'frozen_state' - : rune === '$derived.call' + : rune === '$derived.by' ? 'derived_call' : 'derived', // @ts-expect-error this is set in the next pass @@ -289,12 +289,12 @@ export const javascript_visitors_runes = { continue; } - if (rune === '$derived' || rune === '$derived.call') { + if (rune === '$derived' || rune === '$derived.by') { if (declarator.id.type === 'Identifier') { declarations.push( b.declarator( declarator.id, - b.call('$.derived', rune === '$derived.call' ? value : b.thunk(value)) + b.call('$.derived', rune === '$derived.by' ? value : b.thunk(value)) ) ); } else { @@ -307,7 +307,7 @@ export const javascript_visitors_runes = { '$.derived', b.thunk( b.block([ - b.let(declarator.id, rune === '$derived.call' ? b.call(value) : value), + b.let(declarator.id, rune === '$derived.by' ? b.call(value) : value), b.return(b.array(bindings.map((binding) => binding.node))) ]) ) diff --git a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js index 8112a30c1c9f..2cda4ae8f656 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js @@ -548,7 +548,7 @@ const javascript_visitors_runes = { : /** @type {import('estree').Expression} */ (visit(node.value.arguments[0])) }; } - if (rune === '$derived.call') { + if (rune === '$derived.by') { return { ...node, value: @@ -582,7 +582,7 @@ const javascript_visitors_runes = { ? b.id('undefined') : /** @type {import('estree').Expression} */ (visit(args[0])); - if (rune === '$derived.call') { + if (rune === '$derived.by') { declarations.push( b.declarator( /** @type {import('estree').Pattern} */ (visit(declarator.id)), diff --git a/packages/svelte/src/compiler/phases/constants.js b/packages/svelte/src/compiler/phases/constants.js index 33580703698b..eaf01b7f341a 100644 --- a/packages/svelte/src/compiler/phases/constants.js +++ b/packages/svelte/src/compiler/phases/constants.js @@ -33,7 +33,7 @@ export const Runes = /** @type {const} */ ([ '$state.frozen', '$props', '$derived', - '$derived.call', + '$derived.by', '$effect', '$effect.pre', '$effect.active', diff --git a/packages/svelte/src/compiler/warnings.js b/packages/svelte/src/compiler/warnings.js index 5c810664ba85..9a6124f023bd 100644 --- a/packages/svelte/src/compiler/warnings.js +++ b/packages/svelte/src/compiler/warnings.js @@ -24,8 +24,7 @@ const runes = { /** @param {string} name */ 'non-state-reference': (name) => `${name} is updated, but is not declared with $state(...). Changing its value will not correctly trigger updates.`, - 'derived-iife': () => - `Use \`$derived.call(() => {...})\` instead of \`$derived((() => {...})());\`` + 'derived-iife': () => `Use \`$derived.by(() => {...})\` instead of \`$derived((() => {...})());\`` }; /** @satisfies {Warnings} */ diff --git a/packages/svelte/src/main/ambient.d.ts b/packages/svelte/src/main/ambient.d.ts index bbc91c2f5b8e..9d7f1d84c14d 100644 --- a/packages/svelte/src/main/ambient.d.ts +++ b/packages/svelte/src/main/ambient.d.ts @@ -62,11 +62,11 @@ declare function $derived(expression: T): T; declare namespace $derived { /** * Sometimes you need to create complex derivations that don't fit inside a short expression. - * In these cases, you can use `$derived.call` which accepts a function as its argument. + * In these cases, you can use `$derived.by` which accepts a function as its argument. * * Example: * ```ts - * let total = $derived.call(() => { + * let total = $derived.by(() => { * let result = 0; * for (const n of numbers) { * result += n; @@ -75,9 +75,9 @@ declare namespace $derived { * }); * ``` * - * https://svelte-5-preview.vercel.app/docs/runes#$derived-call + * https://svelte-5-preview.vercel.app/docs/runes#$derived-by */ - export function call(fn: () => T): T; + export function by(fn: () => T): T; } /** diff --git a/packages/svelte/tests/runtime-runes/samples/class-state-derived-fn/main.svelte b/packages/svelte/tests/runtime-runes/samples/class-state-derived-fn/main.svelte index 2816780c25ac..5fa0e97b1b9e 100644 --- a/packages/svelte/tests/runtime-runes/samples/class-state-derived-fn/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/class-state-derived-fn/main.svelte @@ -1,7 +1,7 @@ diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index c6d0ad3d5aa4..ac267961a345 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -980,15 +980,15 @@ declare module 'svelte/compiler' { filename?: string | undefined; } | undefined): Promise; export class CompileError extends Error { - + constructor(code: string, message: string, position: [number, number] | undefined); - + filename: CompileError_1['filename']; - + position: CompileError_1['position']; - + start: CompileError_1['start']; - + end: CompileError_1['end']; code: string; } @@ -999,9 +999,9 @@ declare module 'svelte/compiler' { * */ export const VERSION: string; class Scope { - + constructor(root: ScopeRoot, parent: Scope | null, porous: boolean); - + root: ScopeRoot; /** * A map of every identifier declared by this scope, and all the @@ -1025,25 +1025,25 @@ declare module 'svelte/compiler' { * which is usually an error. Block statements do not increase this value */ function_depth: number; - + declare(node: import('estree').Identifier, kind: Binding['kind'], declaration_kind: DeclarationKind, initial?: null | import('estree').Expression | import('estree').FunctionDeclaration | import('estree').ClassDeclaration | import('estree').ImportDeclaration | EachBlock): Binding; child(porous?: boolean): Scope; - + generate(preferred_name: string): string; - + get(name: string): Binding | null; - + get_bindings(node: import('estree').VariableDeclarator | LetDirective): Binding[]; - + owner(name: string): Scope | null; - + reference(node: import('estree').Identifier, path: SvelteNode[]): void; #private; } class ScopeRoot { - + conflicts: Set; - + unique(preferred_name: string): import("estree").Identifier; } interface BaseNode { @@ -2501,11 +2501,11 @@ declare function $derived(expression: T): T; declare namespace $derived { /** * Sometimes you need to create complex derivations that don't fit inside a short expression. - * In these cases, you can use `$derived.call` which accepts a function as its argument. + * In these cases, you can use `$derived.by` which accepts a function as its argument. * * Example: * ```ts - * let total = $derived.call(() => { + * let total = $derived.by(() => { * let result = 0; * for (const n of numbers) { * result += n; @@ -2514,9 +2514,9 @@ declare namespace $derived { * }); * ``` * - * https://svelte-5-preview.vercel.app/docs/runes#$derived-call + * https://svelte-5-preview.vercel.app/docs/runes#$derived-by */ - export function call(fn: () => T): T; + export function by(fn: () => T): T; } /** @@ -2640,4 +2640,4 @@ declare function $inspect( ...values: T ): { with: (fn: (type: 'init' | 'update', ...values: T) => void) => void }; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file +//# sourceMappingURL=index.d.ts.map From 536e5080bdd360432c9569a5771dea7908f45a39 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 9 Feb 2024 15:50:30 -0500 Subject: [PATCH 2/3] more replacements, plus a compiler error --- .changeset/dirty-donuts-yell.md | 5 +++++ packages/svelte/src/compiler/errors.js | 3 ++- packages/svelte/src/compiler/phases/scope.js | 2 ++ sites/svelte-5-preview/src/lib/CodeMirror.svelte | 4 ++-- .../src/routes/docs/content/01-api/02-runes.md | 8 ++++---- 5 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 .changeset/dirty-donuts-yell.md diff --git a/.changeset/dirty-donuts-yell.md b/.changeset/dirty-donuts-yell.md new file mode 100644 index 000000000000..a44431390543 --- /dev/null +++ b/.changeset/dirty-donuts-yell.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +breaking: replace `$derived.call` with `$derived.by` diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index 9ecd14141633..891b0956d4c8 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -208,7 +208,8 @@ const runes = { 'invalid-runes-mode-import': (name) => `${name} cannot be used in runes mode`, 'duplicate-props-rune': () => `Cannot use $props() more than once`, 'invalid-each-assignment': () => - `Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. 'array[i] = value' instead of 'entry = value')` + `Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. 'array[i] = value' instead of 'entry = value')`, + 'invalid-derived-call': () => `$derived.call(...) has been replaced with $derived.by(...)` }; /** @satisfies {Errors} */ diff --git a/packages/svelte/src/compiler/phases/scope.js b/packages/svelte/src/compiler/phases/scope.js index c4fb1ba49361..5d46c3187158 100644 --- a/packages/svelte/src/compiler/phases/scope.js +++ b/packages/svelte/src/compiler/phases/scope.js @@ -717,6 +717,8 @@ export function get_rune(node, scope) { if (n.type !== 'Identifier') return null; joined = n.name + joined; + + if (joined === '$derived.call') error(node, 'invalid-derived-call'); if (!Runes.includes(/** @type {any} */ (joined))) return null; const binding = scope.get(n.name); diff --git a/sites/svelte-5-preview/src/lib/CodeMirror.svelte b/sites/svelte-5-preview/src/lib/CodeMirror.svelte index 9a2438be02b2..3f29dfe17623 100644 --- a/sites/svelte-5-preview/src/lib/CodeMirror.svelte +++ b/sites/svelte-5-preview/src/lib/CodeMirror.svelte @@ -208,8 +208,8 @@ { label: '$state', type: 'keyword', boost: 10 }, { label: '$props', type: 'keyword', boost: 9 }, { label: '$derived', type: 'keyword', boost: 8 }, - snip('$derived.call(() => {\n\t${}\n});', { - label: '$derived.call', + snip('$derived.by(() => {\n\t${}\n});', { + label: '$derived.by', type: 'keyword', boost: 7 }), diff --git a/sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md b/sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md index 7cccfeb23f0f..379336a99382 100644 --- a/sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md +++ b/sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md @@ -134,14 +134,14 @@ If the value of a reactive variable is being computed it should be replaced with ``` ...`double` will be calculated first despite the source order. In runes mode, `triple` cannot reference `double` before it has been declared. -## `$derived.call` +## `$derived.by` -Sometimes you need to create complex derivations that don't fit inside a short expression. In these cases, you can use `$derived.call` which accepts a function as its argument. +Sometimes you need to create complex derivations that don't fit inside a short expression. In these cases, you can use `$derived.by` which accepts a function as its argument. ```svelte