chore: rename `$derived.call` to `$derived.by` (#10445)

* rename $derived.call to $derived.by

* more replacements, plus a compiler error

* regenerate types

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/10470/head
Rich Harris 8 months ago committed by GitHub
parent 9cee83c864
commit d41d0c26ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
breaking: replace `$derived.call` with `$derived.by`

@ -208,7 +208,8 @@ const runes = {
'invalid-runes-mode-import': (name) => `${name} cannot be used in runes mode`, 'invalid-runes-mode-import': (name) => `${name} cannot be used in runes mode`,
'duplicate-props-rune': () => `Cannot use $props() more than once`, 'duplicate-props-rune': () => `Cannot use $props() more than once`,
'invalid-each-assignment': () => '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} */ /** @satisfies {Errors} */

@ -681,7 +681,7 @@ const runes_scope_js_tweaker = {
rune !== '$state' && rune !== '$state' &&
rune !== '$state.frozen' && rune !== '$state.frozen' &&
rune !== '$derived' && rune !== '$derived' &&
rune !== '$derived.call' rune !== '$derived.by'
) )
return; return;
@ -717,7 +717,7 @@ const runes_scope_tweaker = {
rune !== '$state' && rune !== '$state' &&
rune !== '$state.frozen' && rune !== '$state.frozen' &&
rune !== '$derived' && rune !== '$derived' &&
rune !== '$derived.call' && rune !== '$derived.by' &&
rune !== '$props' rune !== '$props'
) )
return; return;
@ -730,7 +730,7 @@ const runes_scope_tweaker = {
? 'state' ? 'state'
: rune === '$state.frozen' : rune === '$state.frozen'
? 'frozen_state' ? 'frozen_state'
: rune === '$derived' || rune === '$derived.call' : rune === '$derived' || rune === '$derived.by'
? 'derived' ? 'derived'
: path.is_rest : path.is_rest
? 'rest_prop' ? 'rest_prop'

@ -746,7 +746,7 @@ function validate_call_expression(node, scope, path) {
error(node, 'invalid-props-location'); 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 === 'VariableDeclarator') return;
if (parent.type === 'PropertyDefinition' && !parent.static && !parent.computed) return; if (parent.type === 'PropertyDefinition' && !parent.static && !parent.computed) return;
error(node, 'invalid-state-location', rune); error(node, 'invalid-state-location', rune);
@ -817,7 +817,7 @@ export const validation_runes_js = {
const args = /** @type {import('estree').CallExpression} */ (init).arguments; 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]); error(node, 'invalid-rune-args-length', rune, [1]);
} else if (rune === '$state' && args.length > 1) { } else if (rune === '$state' && args.length > 1) {
error(node, 'invalid-rune-args-length', rune, [0, 1]); error(node, 'invalid-rune-args-length', rune, [0, 1]);
@ -842,7 +842,7 @@ export const validation_runes_js = {
definition.value?.type === 'CallExpression' definition.value?.type === 'CallExpression'
) { ) {
const rune = get_rune(definition.value, context.state.scope); 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); 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; const args = /** @type {import('estree').CallExpression} */ (init).arguments;
// TODO some of this is duplicated with above, seems off // 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]); error(node, 'invalid-rune-args-length', rune, [1]);
} else if (rune === '$state' && args.length > 1) { } else if (rune === '$state' && args.length > 1) {
error(node, 'invalid-rune-args-length', rune, [0, 1]); error(node, 'invalid-rune-args-length', rune, [0, 1]);

@ -33,7 +33,7 @@ export const javascript_visitors_runes = {
rune === '$state' || rune === '$state' ||
rune === '$state.frozen' || rune === '$state.frozen' ||
rune === '$derived' || rune === '$derived' ||
rune === '$derived.call' rune === '$derived.by'
) { ) {
/** @type {import('../types.js').StateField} */ /** @type {import('../types.js').StateField} */
const field = { const field = {
@ -42,7 +42,7 @@ export const javascript_visitors_runes = {
? 'state' ? 'state'
: rune === '$state.frozen' : rune === '$state.frozen'
? 'frozen_state' ? 'frozen_state'
: rune === '$derived.call' : rune === '$derived.by'
? 'derived_call' ? 'derived_call'
: 'derived', : 'derived',
// @ts-expect-error this is set in the next pass // @ts-expect-error this is set in the next pass
@ -289,12 +289,12 @@ export const javascript_visitors_runes = {
continue; continue;
} }
if (rune === '$derived' || rune === '$derived.call') { if (rune === '$derived' || rune === '$derived.by') {
if (declarator.id.type === 'Identifier') { if (declarator.id.type === 'Identifier') {
declarations.push( declarations.push(
b.declarator( b.declarator(
declarator.id, declarator.id,
b.call('$.derived', rune === '$derived.call' ? value : b.thunk(value)) b.call('$.derived', rune === '$derived.by' ? value : b.thunk(value))
) )
); );
} else { } else {
@ -307,7 +307,7 @@ export const javascript_visitors_runes = {
'$.derived', '$.derived',
b.thunk( b.thunk(
b.block([ 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))) b.return(b.array(bindings.map((binding) => binding.node)))
]) ])
) )

@ -548,7 +548,7 @@ const javascript_visitors_runes = {
: /** @type {import('estree').Expression} */ (visit(node.value.arguments[0])) : /** @type {import('estree').Expression} */ (visit(node.value.arguments[0]))
}; };
} }
if (rune === '$derived.call') { if (rune === '$derived.by') {
return { return {
...node, ...node,
value: value:
@ -582,7 +582,7 @@ const javascript_visitors_runes = {
? b.id('undefined') ? b.id('undefined')
: /** @type {import('estree').Expression} */ (visit(args[0])); : /** @type {import('estree').Expression} */ (visit(args[0]));
if (rune === '$derived.call') { if (rune === '$derived.by') {
declarations.push( declarations.push(
b.declarator( b.declarator(
/** @type {import('estree').Pattern} */ (visit(declarator.id)), /** @type {import('estree').Pattern} */ (visit(declarator.id)),

@ -33,7 +33,7 @@ export const Runes = /** @type {const} */ ([
'$state.frozen', '$state.frozen',
'$props', '$props',
'$derived', '$derived',
'$derived.call', '$derived.by',
'$effect', '$effect',
'$effect.pre', '$effect.pre',
'$effect.active', '$effect.active',

@ -717,6 +717,8 @@ export function get_rune(node, scope) {
if (n.type !== 'Identifier') return null; if (n.type !== 'Identifier') return null;
joined = n.name + joined; joined = n.name + joined;
if (joined === '$derived.call') error(node, 'invalid-derived-call');
if (!Runes.includes(/** @type {any} */ (joined))) return null; if (!Runes.includes(/** @type {any} */ (joined))) return null;
const binding = scope.get(n.name); const binding = scope.get(n.name);

@ -24,8 +24,7 @@ const runes = {
/** @param {string} name */ /** @param {string} name */
'non-state-reference': (name) => 'non-state-reference': (name) =>
`${name} is updated, but is not declared with $state(...). Changing its value will not correctly trigger updates.`, `${name} is updated, but is not declared with $state(...). Changing its value will not correctly trigger updates.`,
'derived-iife': () => 'derived-iife': () => `Use \`$derived.by(() => {...})\` instead of \`$derived((() => {...})());\``
`Use \`$derived.call(() => {...})\` instead of \`$derived((() => {...})());\``
}; };
/** @satisfies {Warnings} */ /** @satisfies {Warnings} */

@ -62,11 +62,11 @@ declare function $derived<T>(expression: T): T;
declare namespace $derived { declare namespace $derived {
/** /**
* Sometimes you need to create complex derivations that don't fit inside a short expression. * 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: * Example:
* ```ts * ```ts
* let total = $derived.call(() => { * let total = $derived.by(() => {
* let result = 0; * let result = 0;
* for (const n of numbers) { * for (const n of numbers) {
* result += n; * 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<T>(fn: () => T): T; export function by<T>(fn: () => T): T;
} }
/** /**

@ -1,7 +1,7 @@
<script> <script>
class Counter { class Counter {
count = $state(0); count = $state(0);
doubled = $derived.call(() => this.count * 2); doubled = $derived.by(() => this.count * 2);
} }
const counter = new Counter(); const counter = new Counter();

@ -1,6 +1,6 @@
<script> <script>
let count = $state(0); let count = $state(0);
let double = $derived.call(() => count * 2); let double = $derived.by(() => count * 2);
</script> </script>
<button on:click={() => count++}>{double}</button> <button on:click={() => count++}>{double}</button>

@ -2501,11 +2501,11 @@ declare function $derived<T>(expression: T): T;
declare namespace $derived { declare namespace $derived {
/** /**
* Sometimes you need to create complex derivations that don't fit inside a short expression. * 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: * Example:
* ```ts * ```ts
* let total = $derived.call(() => { * let total = $derived.by(() => {
* let result = 0; * let result = 0;
* for (const n of numbers) { * for (const n of numbers) {
* result += n; * 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<T>(fn: () => T): T; export function by<T>(fn: () => T): T;
} }
/** /**

@ -208,8 +208,8 @@
{ label: '$state', type: 'keyword', boost: 10 }, { label: '$state', type: 'keyword', boost: 10 },
{ label: '$props', type: 'keyword', boost: 9 }, { label: '$props', type: 'keyword', boost: 9 },
{ label: '$derived', type: 'keyword', boost: 8 }, { label: '$derived', type: 'keyword', boost: 8 },
snip('$derived.call(() => {\n\t${}\n});', { snip('$derived.by(() => {\n\t${}\n});', {
label: '$derived.call', label: '$derived.by',
type: 'keyword', type: 'keyword',
boost: 7 boost: 7
}), }),

@ -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. ...`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 ```svelte
<script> <script>
let numbers = $state([1, 2, 3]); let numbers = $state([1, 2, 3]);
let total = $derived.call(() => { let total = $derived.by(() => {
let total = 0; let total = 0;
for (const n of numbers) { for (const n of numbers) {
total += n; total += n;
@ -155,7 +155,7 @@ Sometimes you need to create complex derivations that don't fit inside a short e
</button> </button>
``` ```
In essence, `$derived(expression)` is equivalent to `$derived.call(() => expression)`. In essence, `$derived(expression)` is equivalent to `$derived.by(() => expression)`.
## `$effect` ## `$effect`

Loading…
Cancel
Save