diff --git a/.changeset/witty-frogs-cheat.md b/.changeset/witty-frogs-cheat.md new file mode 100644 index 0000000000..2b5b81006a --- /dev/null +++ b/.changeset/witty-frogs-cheat.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +chore: simpler fallback values diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js index f7809af43a..bd8a8f435e 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js @@ -2,7 +2,7 @@ /** @import { Binding } from '#compiler' */ /** @import { Context } from '../types.js' */ /** @import { Scope } from '../../../scope.js' */ -import { extract_paths, is_expression_async } from '../../../../utils/ast.js'; +import { build_fallback, extract_paths } from '../../../../utils/ast.js'; import * as b from '../../../../utils/builders.js'; import { get_rune } from '../../../scope.js'; import { walk } from 'zimmerframe'; @@ -96,9 +96,7 @@ export function VariableDeclaration(node, context) { const name = /** @type {Identifier} */ (path.node).name; const binding = /** @type {Binding} */ (context.state.scope.get(name)); const prop = b.member(b.id('$$props'), b.literal(binding.prop_alias ?? name), true); - declarations.push( - b.declarator(path.node, b.call('$.value_or_fallback', prop, b.thunk(value))) - ); + declarations.push(b.declarator(path.node, build_fallback(prop, value))); } continue; } @@ -114,9 +112,7 @@ export function VariableDeclaration(node, context) { let init = prop; if (declarator.init) { const default_value = /** @type {Expression} */ (context.visit(declarator.init)); - init = is_expression_async(default_value) - ? b.await(b.call('$.value_or_fallback_async', prop, b.thunk(default_value, true))) - : b.call('$.value_or_fallback', prop, b.thunk(default_value)); + init = build_fallback(prop, default_value); } declarations.push(b.declarator(declarator.id, init)); diff --git a/packages/svelte/src/compiler/utils/ast.js b/packages/svelte/src/compiler/utils/ast.js index 1998b0c98e..95b5d2fb2d 100644 --- a/packages/svelte/src/compiler/utils/ast.js +++ b/packages/svelte/src/compiler/utils/ast.js @@ -368,12 +368,7 @@ function _extract_paths(assignments = [], param, expression, update_expression, case 'AssignmentPattern': { /** @type {DestructuredAssignment['expression']} */ - const fallback_expression = (object) => - is_expression_async(param.right) - ? b.await( - b.call('$.value_or_fallback_async', expression(object), b.thunk(param.right, true)) - ) - : b.call('$.value_or_fallback', expression(object), b.thunk(param.right)); + const fallback_expression = (object) => build_fallback(expression(object), param.right); if (param.left.type === 'Identifier') { assignments.push({ @@ -549,3 +544,22 @@ export function is_expression_async(expression) { return false; } } + +/** + * + * @param {ESTree.Expression} expression + * @param {ESTree.Expression} fallback + */ +export function build_fallback(expression, fallback) { + if (is_simple_expression(fallback)) { + return b.call('$.fallback', expression, fallback); + } + + if (fallback.type === 'AwaitExpression' && is_simple_expression(fallback.argument)) { + return b.await(b.call('$.fallback', expression, fallback.argument)); + } + + return is_expression_async(fallback) + ? b.await(b.call('$.fallback', expression, b.thunk(fallback, true), b.true)) + : b.call('$.fallback', expression, b.thunk(fallback), b.true); +} diff --git a/packages/svelte/src/internal/client/index.js b/packages/svelte/src/internal/client/index.js index d1885e7d00..dc51d3caae 100644 --- a/packages/svelte/src/internal/client/index.js +++ b/packages/svelte/src/internal/client/index.js @@ -134,8 +134,6 @@ export { untrack, update, update_pre, - value_or_fallback, - value_or_fallback_async, exclude_from_object, pop, push, @@ -164,7 +162,7 @@ export { $document as document } from './dom/operations.js'; export { snapshot } from '../shared/clone.js'; -export { noop } from '../shared/utils.js'; +export { noop, fallback } from '../shared/utils.js'; export { invalid_default_snippet, validate_dynamic_element_tag, diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index f748fa3993..8939244cf8 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -1003,26 +1003,6 @@ export function exclude_from_object(obj, keys) { return result; } -/** - * @template V - * @param {V} value - * @param {() => V} fallback lazy because could contain side effects - * @returns {V} - */ -export function value_or_fallback(value, fallback) { - return value === undefined ? fallback() : value; -} - -/** - * @template V - * @param {V} value - * @param {() => Promise} fallback lazy because could contain side effects - * @returns {Promise} - */ -export async function value_or_fallback_async(value, fallback) { - return value === undefined ? fallback() : value; -} - /** * @param {Record} props * @param {any} runes diff --git a/packages/svelte/src/internal/server/index.js b/packages/svelte/src/internal/server/index.js index 8ab7e52162..422784d765 100644 --- a/packages/svelte/src/internal/server/index.js +++ b/packages/svelte/src/internal/server/index.js @@ -383,26 +383,6 @@ export function unsubscribe_stores(store_values) { } } -/** - * @template V - * @param {V} value - * @param {() => V} fallback lazy because could contain side effects - * @returns {V} - */ -export function value_or_fallback(value, fallback) { - return value === undefined ? fallback() : value; -} - -/** - * @template V - * @param {V} value - * @param {() => Promise} fallback lazy because could contain side effects - * @returns {Promise} - */ -export async function value_or_fallback_async(value, fallback) { - return value === undefined ? fallback() : value; -} - /** * @param {Payload} payload * @param {void | ((payload: Payload, props: Record) => void)} slot_fn @@ -536,6 +516,8 @@ export { push_element, pop_element } from './dev.js'; export { snapshot } from '../shared/clone.js'; +export { fallback } from '../shared/utils.js'; + export { invalid_default_snippet, validate_dynamic_element_tag, diff --git a/packages/svelte/src/internal/shared/utils.js b/packages/svelte/src/internal/shared/utils.js index 5285b2c2e1..f32af747a4 100644 --- a/packages/svelte/src/internal/shared/utils.js +++ b/packages/svelte/src/internal/shared/utils.js @@ -46,3 +46,18 @@ export function run_all(arr) { arr[i](); } } + +/** + * @template V + * @param {V} value + * @param {V | (() => V)} fallback + * @param {boolean} [lazy] + * @returns {V} + */ +export function fallback(value, fallback, lazy = false) { + return value === undefined + ? lazy + ? /** @type {() => V} */ (fallback)() + : /** @type {V} */ (fallback) + : value; +}