diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/global.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/global.js index 51032cdd5f..3e2ed55637 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/global.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/global.js @@ -45,6 +45,7 @@ export const global_visitors = { const binding = state.scope.get(argument.name); const is_store = binding?.kind === 'store_sub'; const name = is_store ? argument.name.slice(1) : argument.name; + // use runtime functions for smaller output if ( binding?.kind === 'state' || @@ -55,16 +56,17 @@ export const global_visitors = { ) { let fn = node.operator === '++' ? '$.increment' : '$.decrement'; if (node.prefix) fn += '_pre'; + if (binding.kind === 'prop') fn += '_prop'; if (is_store) { fn += '_store'; return b.call(fn, serialize_get_binding(b.id(name), state), b.call('$' + name)); - } else { - return b.call(fn, b.id(name)); } - } else { - return next(); + + return b.call(fn, b.id(name)); } + + return next(); } else if ( argument.type === 'MemberExpression' && argument.object.type === 'ThisExpression' && diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index e5fb3f1afe..a1ca68daa3 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -1555,6 +1555,16 @@ export function increment(signal) { return value; } +/** + * @param {((value?: number) => number)} fn + * @returns {number} + */ +export function increment_prop(fn) { + const value = fn(); + fn(value + 1); + return value; +} + /** * @param {import('./types.js').Store} store * @param {number} store_value @@ -1575,6 +1585,16 @@ export function decrement(signal) { return value; } +/** + * @param {((value?: number) => number)} fn + * @returns {number} + */ +export function decrement_prop(fn) { + const value = fn(); + fn(value - 1); + return value; +} + /** * @param {import('./types.js').Store} store * @param {number} store_value @@ -1595,6 +1615,16 @@ export function increment_pre(signal) { return value; } +/** + * @param {((value?: number) => number)} fn + * @returns {number} + */ +export function increment_pre_prop(fn) { + const value = fn() + 1; + fn(value); + return value; +} + /** * @param {import('./types.js').Store} store * @param {number} store_value @@ -1616,6 +1646,16 @@ export function decrement_pre(signal) { return value; } +/** + * @param {((value?: number) => number)} fn + * @returns {number} + */ +export function decrement_pre_prop(fn) { + const value = fn() - 1; + fn(value); + return value; +} + /** * @param {import('./types.js').Store} store * @param {number} store_value diff --git a/packages/svelte/src/internal/index.js b/packages/svelte/src/internal/index.js index 6c0e8c43d1..8cdf28a48d 100644 --- a/packages/svelte/src/internal/index.js +++ b/packages/svelte/src/internal/index.js @@ -18,12 +18,16 @@ export { tick, untrack, increment, + increment_prop, increment_store, decrement, + decrement_prop, decrement_store, increment_pre, + increment_pre_prop, increment_pre_store, decrement_pre, + decrement_pre_prop, decrement_pre_store, mutate, mutate_store, diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-indirect/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-indirect/_config.js index 196c74950c..b0db992d3b 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-indirect/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-indirect/_config.js @@ -80,7 +80,7 @@ export default test({ select.dispatchEvent(change); }); - assert.equal(component.selected, tasks[1]); + assert.deepEqual(component.selected, tasks[1]); // TODO this should be assert.equal, but that crashes the entire test suite in mysterious ways... something to do with proxies not being reused? assert.ok(!input.checked); input.checked = true;