diff --git a/.changeset/easy-paths-take.md b/.changeset/easy-paths-take.md new file mode 100644 index 0000000000..1378322abe --- /dev/null +++ b/.changeset/easy-paths-take.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: take into account static blocks when determining transition locality diff --git a/.changeset/slimy-turtles-yell.md b/.changeset/slimy-turtles-yell.md new file mode 100644 index 0000000000..e3f3a66264 --- /dev/null +++ b/.changeset/slimy-turtles-yell.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: flush pending changes after rendering `failed` snippet diff --git a/.changeset/three-wasps-work.md b/.changeset/three-wasps-work.md deleted file mode 100644 index 318d8668a4..0000000000 --- a/.changeset/three-wasps-work.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: improve `each_key_without_as` error diff --git a/documentation/docs/02-runes/07-$inspect.md b/documentation/docs/02-runes/07-$inspect.md index 13ac8b79a3..6d47e30e27 100644 --- a/documentation/docs/02-runes/07-$inspect.md +++ b/documentation/docs/02-runes/07-$inspect.md @@ -18,6 +18,8 @@ The `$inspect` rune is roughly equivalent to `console.log`, with the exception t ``` +On updates, a stack trace will be printed, making it easy to find the origin of a state change (unless you're in the playground, due to technical limitations). + ## $inspect(...).with `$inspect` returns a property `with`, which you can invoke with a callback, which will then be invoked instead of `console.log`. The first argument to the callback is either `"init"` or `"update"`; subsequent arguments are the values passed to `$inspect` ([demo](/playground/untitled#H4sIAAAAAAAACkVQ24qDMBD9lSEUqlTqPlsj7ON-w7pQG8c2VCchmVSK-O-bKMs-DefKYRYx6BG9qL4XQd2EohKf1opC8Nsm4F84MkbsTXAqMbVXTltuWmp5RAZlAjFIOHjuGLOP_BKVqB00eYuKs82Qn2fNjyxLtcWeyUE2sCRry3qATQIpJRyD7WPVMf9TW-7xFu53dBcoSzAOrsqQNyOe2XUKr0Xi5kcMvdDB2wSYO-I9vKazplV1-T-d6ltgNgSG1KjVUy7ZtmdbdjqtzRcphxMS1-XubOITJtPrQWMvKnYB15_1F7KKadA_AQAA)): @@ -36,13 +38,6 @@ The `$inspect` rune is roughly equivalent to `console.log`, with the exception t ``` -A convenient way to find the origin of some change is to pass `console.trace` to `with`: - -```js -// @errors: 2304 -$inspect(stuff).with(console.trace); -``` - ## $inspect.trace(...) This rune, added in 5.14, causes the surrounding function to be _traced_ in development. Any time the function re-runs as part of an [effect]($effect) or a [derived]($derived), information will be printed to the console about which pieces of reactive state caused the effect to fire. diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 81529104d9..7692383aed 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,35 @@ # svelte +## 5.41.3 + +### Patch Changes + +- chore: exclude vite optimized deps from stack traces ([#17008](https://github.com/sveltejs/svelte/pull/17008)) + +- perf: skip repeatedly traversing the same derived ([#17016](https://github.com/sveltejs/svelte/pull/17016)) + +## 5.41.2 + +### Patch Changes + +- fix: keep batches alive until all async work is complete ([#16971](https://github.com/sveltejs/svelte/pull/16971)) + +- fix: don't preserve reactivity context across function boundaries ([#17002](https://github.com/sveltejs/svelte/pull/17002)) + +- fix: make `$inspect` logs come from the callsite ([#17001](https://github.com/sveltejs/svelte/pull/17001)) + +- fix: ensure guards (eg. if, each, key) run before their contents ([#16930](https://github.com/sveltejs/svelte/pull/16930)) + +## 5.41.1 + +### Patch Changes + +- fix: place `let:` declarations before `{@const}` declarations ([#16985](https://github.com/sveltejs/svelte/pull/16985)) + +- fix: improve `each_key_without_as` error ([#16983](https://github.com/sveltejs/svelte/pull/16983)) + +- chore: centralise branch management ([#16977](https://github.com/sveltejs/svelte/pull/16977)) + ## 5.41.0 ### Minor Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 6d8463a52a..2cb3bf4ab3 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.41.0", + "version": "5.41.3", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 47fe37c44d..52be997374 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -306,7 +306,7 @@ export function analyze_module(source, options) { fragment: null, parent_element: null, reactive_statement: null, - in_derived: false + derived_function_depth: -1 }, visitors ); @@ -703,7 +703,7 @@ export function analyze_component(root, source, options) { state_fields: new Map(), function_depth: scope.function_depth, reactive_statement: null, - in_derived: false + derived_function_depth: -1 }; walk(/** @type {AST.SvelteNode} */ (ast), state, visitors); @@ -771,7 +771,7 @@ export function analyze_component(root, source, options) { expression: null, state_fields: new Map(), function_depth: scope.function_depth, - in_derived: false + derived_function_depth: -1 }; walk(/** @type {AST.SvelteNode} */ (ast), state, visitors); diff --git a/packages/svelte/src/compiler/phases/2-analyze/types.d.ts b/packages/svelte/src/compiler/phases/2-analyze/types.d.ts index a1c66c4052..667f04dccd 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/types.d.ts +++ b/packages/svelte/src/compiler/phases/2-analyze/types.d.ts @@ -29,9 +29,9 @@ export interface AnalysisState { reactive_statement: null | ReactiveStatement; /** - * True if we're directly inside a `$derived(...)` expression (but not `$derived.by(...)`) + * Set when we're inside a `$derived(...)` expression (but not `$derived.by(...)`) or `@const` */ - in_derived: boolean; + derived_function_depth: number; } export type Context = import('zimmerframe').Context< diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js index 9018623570..14757af4a3 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js @@ -15,7 +15,10 @@ export function AwaitExpression(node, context) { // b) awaits that precede other expressions in template or `$derived(...)` if ( tla || - (is_reactive_expression(context.path, context.state.in_derived) && + (is_reactive_expression( + context.path, + context.state.derived_function_depth === context.state.function_depth + ) && !is_last_evaluated_expression(context.path, node)) ) { context.state.analysis.pickled_awaits.add(node); @@ -53,9 +56,7 @@ export function AwaitExpression(node, context) { * @param {boolean} in_derived */ export function is_reactive_expression(path, in_derived) { - if (in_derived) { - return true; - } + if (in_derived) return true; let i = path.length; @@ -67,6 +68,7 @@ export function is_reactive_expression(path, in_derived) { parent.type === 'FunctionExpression' || parent.type === 'FunctionDeclaration' ) { + // No reactive expression found between function and await return false; } @@ -83,11 +85,16 @@ export function is_reactive_expression(path, in_derived) { * @param {AST.SvelteNode[]} path * @param {Expression | SpreadElement | Property} node */ -export function is_last_evaluated_expression(path, node) { +function is_last_evaluated_expression(path, node) { let i = path.length; while (i--) { - const parent = /** @type {Expression | Property | SpreadElement} */ (path[i]); + const parent = path[i]; + + if (parent.type === 'ConstTag') { + // {@const ...} tags are treated as deriveds and its contents should all get the preserve-reactivity treatment + return false; + } // @ts-expect-error we could probably use a neater/more robust mechanism if (parent.metadata) { diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js index 9db4148a2e..60f6b4fa3e 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js @@ -248,7 +248,7 @@ export function CallExpression(node, context) { context.next({ ...context.state, function_depth: context.state.function_depth + 1, - in_derived: true, + derived_function_depth: context.state.function_depth + 1, expression }); diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/ConstTag.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/ConstTag.js index 5849d828a3..77ea654905 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/ConstTag.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/ConstTag.js @@ -38,6 +38,8 @@ export function ConstTag(node, context) { context.visit(declaration.init, { ...context.state, expression: node.metadata.expression, - in_derived: true + // We're treating this like a $derived under the hood + function_depth: context.state.function_depth + 1, + derived_function_depth: context.state.function_depth + 1 }); } diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/VariableDeclarator.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/VariableDeclarator.js index 7a85b4a93a..dfb1d54040 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/VariableDeclarator.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/VariableDeclarator.js @@ -64,12 +64,6 @@ export function VariableDeclarator(node, context) { } } - if (rune === '$derived') { - context.visit(node.id); - context.visit(/** @type {Expression} */ (node.init), { ...context.state, in_derived: true }); - return; - } - if (rune === '$props') { if (node.id.type !== 'ObjectPattern' && node.id.type !== 'Identifier') { e.props_invalid_identifier(node); diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index 51707f4acc..2adafafc42 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -177,6 +177,7 @@ export function client_component(analysis, options) { // these are set inside the `Fragment` visitor, and cannot be used until then init: /** @type {any} */ (null), consts: /** @type {any} */ (null), + let_directives: /** @type {any} */ (null), update: /** @type {any} */ (null), after_update: /** @type {any} */ (null), template: /** @type {any} */ (null), @@ -389,7 +390,9 @@ export function client_component(analysis, options) { .../** @type {ESTree.Statement[]} */ (template.body) ]); - component_block.body.push(b.stmt(b.call(`$.async_body`, b.arrow([], body, true)))); + component_block.body.push( + b.stmt(b.call(`$.async_body`, b.id('$$anchor'), b.arrow([b.id('$$anchor')], body, true))) + ); } else { component_block.body.push( ...state.instance_level_snippets, diff --git a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts index 932d353671..b9a8691a6b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts +++ b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts @@ -54,6 +54,8 @@ export interface ComponentClientTransformState extends ClientTransformState { readonly after_update: Statement[]; /** Transformed `{@const }` declarations */ readonly consts: Statement[]; + /** Transformed `let:` directives */ + readonly let_directives: Statement[]; /** Memoized expressions */ readonly memoizer: Memoizer; /** The HTML template string */ diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/CallExpression.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/CallExpression.js index bf9a09bb74..ae60f3be40 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/CallExpression.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/CallExpression.js @@ -1,10 +1,10 @@ -/** @import { CallExpression, Expression } from 'estree' */ +/** @import { CallExpression, Expression, MemberExpression } from 'estree' */ /** @import { Context } from '../types' */ import { dev, is_ignored } from '../../../../state.js'; import * as b from '#compiler/builders'; import { get_rune } from '../../../scope.js'; -import { transform_inspect_rune } from '../../utils.js'; import { should_proxy } from '../utils.js'; +import { get_inspect_args } from '../../utils.js'; /** * @param {CallExpression} node @@ -73,7 +73,7 @@ export function CallExpression(node, context) { case '$inspect': case '$inspect().with': - return transform_inspect_rune(node, context); + return transform_inspect_rune(rune, node, context); } if ( @@ -104,3 +104,21 @@ export function CallExpression(node, context) { context.next(); } + +/** + * @param {'$inspect' | '$inspect().with'} rune + * @param {CallExpression} node + * @param {Context} context + */ +function transform_inspect_rune(rune, node, context) { + if (!dev) return b.empty; + + const { args, inspector } = get_inspect_args(rune, node, context.visit); + + // by passing an arrow function, the log appears to come from the `$inspect` callsite + // rather than the `inspect.js` file containing the utility + const id = b.id('$$args'); + const fn = b.arrow([b.rest(id)], b.call(inspector, b.spread(id))); + + return b.call('$.inspect', b.thunk(b.array(args)), fn, rune === '$inspect' && b.true); +} diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js index 85d8e3caff..8d6a2fac88 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js @@ -63,6 +63,7 @@ export function Fragment(node, context) { ...context.state, init: [], consts: [], + let_directives: [], update: [], after_update: [], memoizer: new Memoizer(), @@ -150,7 +151,7 @@ export function Fragment(node, context) { } } - body.push(...state.consts); + body.push(...state.let_directives, ...state.consts); if (has_await) { body.push(b.if(b.call('$.aborted'), b.return())); @@ -177,7 +178,11 @@ export function Fragment(node, context) { } if (has_await) { - return b.block([b.stmt(b.call('$.async_body', b.arrow([], b.block(body), true)))]); + return b.block([ + b.stmt( + b.call('$.async_body', b.id('$$anchor'), b.arrow([b.id('$$anchor')], b.block(body), true)) + ) + ]); } else { return b.block(body); } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/LetDirective.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/LetDirective.js index f33febeeb2..c134b4e1e7 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/LetDirective.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/LetDirective.js @@ -21,22 +21,24 @@ export function LetDirective(node, context) { }; } - return b.const( - name, - b.call( - '$.derived', - b.thunk( - b.block([ - b.let( - /** @type {Expression} */ (node.expression).type === 'ObjectExpression' - ? // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine - b.object_pattern(node.expression.properties) - : // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine - b.array_pattern(node.expression.elements), - b.member(b.id('$$slotProps'), node.name) - ), - b.return(b.object(bindings.map((binding) => b.init(binding.node.name, binding.node)))) - ]) + context.state.let_directives.push( + b.const( + name, + b.call( + '$.derived', + b.thunk( + b.block([ + b.let( + /** @type {Expression} */ (node.expression).type === 'ObjectExpression' + ? // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine + b.object_pattern(node.expression.properties) + : // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine + b.array_pattern(node.expression.elements), + b.member(b.id('$$slotProps'), node.name) + ), + b.return(b.object(bindings.map((binding) => b.init(binding.node.name, binding.node)))) + ]) + ) ) ) ); @@ -46,6 +48,8 @@ export function LetDirective(node, context) { read: (node) => b.call('$.get', node) }; - return b.const(name, create_derived(context.state, b.member(b.id('$$slotProps'), node.name))); + context.state.let_directives.push( + b.const(name, create_derived(context.state, b.member(b.id('$$slotProps'), node.name))) + ); } } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js index e35b7cbe5a..ab119e8f80 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js @@ -106,7 +106,7 @@ export function RegularElement(node, context) { case 'LetDirective': // visit let directives before everything else, to set state - lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute))); + context.visit(attribute, { ...context.state, let_directives: lets }); break; case 'OnDirective': diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/SlotElement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/SlotElement.js index a5c0974738..b87a13253b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/SlotElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/SlotElement.js @@ -49,7 +49,7 @@ export function SlotElement(node, context) { } } } else if (attribute.type === 'LetDirective') { - lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute))); + context.visit(attribute, { ...context.state, let_directives: lets }); } } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/SvelteFragment.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/SvelteFragment.js index 65cc170ce5..e3b46a4eef 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/SvelteFragment.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/SvelteFragment.js @@ -9,7 +9,7 @@ export function SvelteFragment(node, context) { for (const attribute of node.attributes) { if (attribute.type === 'LetDirective') { - context.state.init.push(/** @type {ExpressionStatement} */ (context.visit(attribute))); + context.visit(attribute); } } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js index 5c8ce897f4..5ca941fd70 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js @@ -101,7 +101,7 @@ export function build_component(node, component_name, context) { if (slot_scope_applies_to_itself) { for (const attribute of node.attributes) { if (attribute.type === 'LetDirective') { - lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute))); + context.visit(attribute, { ...context.state, let_directives: lets }); } } } @@ -109,7 +109,7 @@ export function build_component(node, component_name, context) { for (const attribute of node.attributes) { if (attribute.type === 'LetDirective') { if (!slot_scope_applies_to_itself) { - lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute, states.default))); + context.visit(attribute, { ...states.default, let_directives: lets }); } } else if (attribute.type === 'OnDirective') { if (!attribute.expression) { diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/CallExpression.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/CallExpression.js index d53b631aa5..bba6511eec 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/CallExpression.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/CallExpression.js @@ -1,9 +1,9 @@ -/** @import { CallExpression, Expression } from 'estree' */ +/** @import { CallExpression, Expression, MemberExpression } from 'estree' */ /** @import { Context } from '../types.js' */ -import { is_ignored } from '../../../../state.js'; +import { dev, is_ignored } from '../../../../state.js'; import * as b from '#compiler/builders'; import { get_rune } from '../../../scope.js'; -import { transform_inspect_rune } from '../../utils.js'; +import { get_inspect_args } from '../../utils.js'; /** * @param {CallExpression} node @@ -51,7 +51,13 @@ export function CallExpression(node, context) { } if (rune === '$inspect' || rune === '$inspect().with') { - return transform_inspect_rune(node, context); + if (!dev) return b.empty; + + const { args, inspector } = get_inspect_args(rune, node, context.visit); + + return rune === '$inspect' + ? b.call(inspector, b.literal('$inspect('), ...args, b.literal(')')) + : b.call(inspector, b.literal('init'), ...args); } context.next(); diff --git a/packages/svelte/src/compiler/phases/3-transform/utils.js b/packages/svelte/src/compiler/phases/3-transform/utils.js index 1445ce3aa6..dfc2ab1de1 100644 --- a/packages/svelte/src/compiler/phases/3-transform/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/utils.js @@ -1,7 +1,7 @@ /** @import { Context } from 'zimmerframe' */ /** @import { TransformState } from './types.js' */ /** @import { AST, Binding, Namespace, ValidatedCompileOptions } from '#compiler' */ -/** @import { Node, Expression, CallExpression } from 'estree' */ +/** @import { Node, Expression, CallExpression, MemberExpression } from 'estree' */ import { regex_ends_with_whitespaces, regex_not_whitespace, @@ -452,30 +452,19 @@ export function determine_namespace_for_children(node, namespace) { } /** - * @template {TransformState} T + * @param {'$inspect' | '$inspect().with'} rune * @param {CallExpression} node - * @param {Context} context + * @param {(node: AST.SvelteNode) => AST.SvelteNode} visit */ -export function transform_inspect_rune(node, context) { - const { state, visit } = context; - const as_fn = state.options.generate === 'client'; - - if (!dev) return b.empty; - - if (node.callee.type === 'MemberExpression') { - const raw_inspect_args = /** @type {CallExpression} */ (node.callee.object).arguments; - const inspect_args = - /** @type {Array} */ - (raw_inspect_args.map((arg) => visit(arg))); - const with_arg = /** @type {Expression} */ (visit(node.arguments[0])); - - return b.call( - '$.inspect', - as_fn ? b.thunk(b.array(inspect_args)) : b.array(inspect_args), - with_arg - ); - } else { - const arg = node.arguments.map((arg) => /** @type {Expression} */ (visit(arg))); - return b.call('$.inspect', as_fn ? b.thunk(b.array(arg)) : b.array(arg)); - } +export function get_inspect_args(rune, node, visit) { + const call = + rune === '$inspect' + ? node + : /** @type {CallExpression} */ (/** @type {MemberExpression} */ (node.callee).object); + + return { + args: call.arguments.map((arg) => /** @type {Expression} */ (visit(arg))), + inspector: + rune === '$inspect' ? 'console.log' : /** @type {Expression} */ (visit(node.arguments[0])) + }; } diff --git a/packages/svelte/src/internal/client/constants.js b/packages/svelte/src/internal/client/constants.js index 50a7a21ae8..6818fd9d30 100644 --- a/packages/svelte/src/internal/client/constants.js +++ b/packages/svelte/src/internal/client/constants.js @@ -1,3 +1,4 @@ +// General flags export const DERIVED = 1 << 1; export const EFFECT = 1 << 2; export const RENDER_EFFECT = 1 << 3; @@ -5,21 +6,34 @@ export const BLOCK_EFFECT = 1 << 4; export const BRANCH_EFFECT = 1 << 5; export const ROOT_EFFECT = 1 << 6; export const BOUNDARY_EFFECT = 1 << 7; -export const UNOWNED = 1 << 8; -export const DISCONNECTED = 1 << 9; export const CLEAN = 1 << 10; export const DIRTY = 1 << 11; export const MAYBE_DIRTY = 1 << 12; export const INERT = 1 << 13; export const DESTROYED = 1 << 14; + +// Flags exclusive to effects export const EFFECT_RAN = 1 << 15; -/** 'Transparent' effects do not create a transition boundary */ +/** + * 'Transparent' effects do not create a transition boundary. + * This is on a block effect 99% of the time but may also be on a branch effect if its parent block effect was pruned + */ export const EFFECT_TRANSPARENT = 1 << 16; export const INSPECT_EFFECT = 1 << 17; export const HEAD_EFFECT = 1 << 18; export const EFFECT_PRESERVED = 1 << 19; export const USER_EFFECT = 1 << 20; +// Flags exclusive to deriveds +export const UNOWNED = 1 << 8; +export const DISCONNECTED = 1 << 9; +/** + * Tells that we marked this derived and its reactions as visited during the "mark as (maybe) dirty"-phase. + * Will be lifted during execution of the derived and during checking its dirty state (both are necessary + * because a derived might be checked but not executed). + */ +export const WAS_MARKED = 1 << 15; + // Flags used for async export const REACTION_IS_UPDATING = 1 << 21; export const ASYNC = 1 << 22; diff --git a/packages/svelte/src/internal/client/dev/inspect.js b/packages/svelte/src/internal/client/dev/inspect.js index f79cf47299..db7ab0d976 100644 --- a/packages/svelte/src/internal/client/dev/inspect.js +++ b/packages/svelte/src/internal/client/dev/inspect.js @@ -2,13 +2,14 @@ import { UNINITIALIZED } from '../../../constants.js'; import { snapshot } from '../../shared/clone.js'; import { inspect_effect, render_effect, validate_effect } from '../reactivity/effects.js'; import { untrack } from '../runtime.js'; +import { get_stack } from './tracing.js'; /** * @param {() => any[]} get_value - * @param {Function} [inspector] + * @param {Function} inspector + * @param {boolean} show_stack */ -// eslint-disable-next-line no-console -export function inspect(get_value, inspector = console.log) { +export function inspect(get_value, inspector, show_stack = false) { validate_effect('$inspect'); let initial = true; @@ -28,7 +29,16 @@ export function inspect(get_value, inspector = console.log) { var snap = snapshot(value, true, true); untrack(() => { - inspector(initial ? 'init' : 'update', ...snap); + if (show_stack) { + inspector(...snap); + + if (!initial) { + // eslint-disable-next-line no-console + console.log(get_stack('UpdatedAt')); + } + } else { + inspector(initial ? 'init' : 'update', ...snap); + } }); initial = false; diff --git a/packages/svelte/src/internal/client/dev/tracing.js b/packages/svelte/src/internal/client/dev/tracing.js index 673a710fac..98be92d4b2 100644 --- a/packages/svelte/src/internal/client/dev/tracing.js +++ b/packages/svelte/src/internal/client/dev/tracing.js @@ -134,7 +134,16 @@ export function trace(label, fn) { * @returns {Error & { stack: string } | null} */ export function get_stack(label) { + // @ts-ignore stackTraceLimit doesn't exist everywhere + const limit = Error.stackTraceLimit; + + // @ts-ignore + Error.stackTraceLimit = Infinity; let error = Error(); + + // @ts-ignore + Error.stackTraceLimit = limit; + const stack = error.stack; if (!stack) return null; @@ -144,16 +153,20 @@ export function get_stack(label) { for (let i = 0; i < lines.length; i++) { const line = lines[i]; + const posixified = line.replaceAll('\\', '/'); if (line === 'Error') { continue; } + if (line.includes('validate_each_keys')) { return null; } - if (line.includes('svelte/src/internal')) { + + if (posixified.includes('svelte/src/internal') || posixified.includes('node_modules/.vite')) { continue; } + new_lines.push(line); } diff --git a/packages/svelte/src/internal/client/dom/blocks/async.js b/packages/svelte/src/internal/client/dom/blocks/async.js index 6df0739918..5ee9d25bce 100644 --- a/packages/svelte/src/internal/client/dom/blocks/async.js +++ b/packages/svelte/src/internal/client/dom/blocks/async.js @@ -1,5 +1,6 @@ /** @import { TemplateNode, Value } from '#client' */ import { flatten } from '../../reactivity/async.js'; +import { Batch, current_batch } from '../../reactivity/batch.js'; import { get } from '../../runtime.js'; import { hydrate_next, @@ -18,8 +19,11 @@ import { get_boundary } from './boundary.js'; */ export function async(node, expressions, fn) { var boundary = get_boundary(); + var batch = /** @type {Batch} */ (current_batch); + var blocking = !boundary.is_pending(); boundary.update_pending_count(1); + batch.increment(blocking); var was_hydrating = hydrating; @@ -44,6 +48,7 @@ export function async(node, expressions, fn) { fn(node, ...values); } finally { boundary.update_pending_count(-1); + batch.decrement(blocking); } if (was_hydrating) { diff --git a/packages/svelte/src/internal/client/dom/blocks/await.js b/packages/svelte/src/internal/client/dom/blocks/await.js index e7917fbd9e..bac01e4c33 100644 --- a/packages/svelte/src/internal/client/dom/blocks/await.js +++ b/packages/svelte/src/internal/client/dom/blocks/await.js @@ -1,12 +1,9 @@ -/** @import { Effect, Source, TemplateNode } from '#client' */ -import { DEV } from 'esm-env'; +/** @import { Source, TemplateNode } from '#client' */ import { is_promise } from '../../../shared/utils.js'; -import { block, branch, pause_effect, resume_effect } from '../../reactivity/effects.js'; +import { block } from '../../reactivity/effects.js'; import { internal_set, mutable_source, source } from '../../reactivity/sources.js'; -import { set_active_effect, set_active_reaction } from '../../runtime.js'; import { hydrate_next, - hydrate_node, hydrating, skip_nodes, set_hydrate_node, @@ -14,15 +11,10 @@ import { } from '../hydration.js'; import { queue_micro_task } from '../task.js'; import { HYDRATION_START_ELSE, UNINITIALIZED } from '../../../../constants.js'; -import { - component_context, - dev_stack, - is_runes, - set_component_context, - set_dev_current_component_function, - set_dev_stack -} from '../../context.js'; +import { is_runes } from '../../context.js'; import { flushSync, is_flushing_sync } from '../../reactivity/batch.js'; +import { BranchManager } from './branches.js'; +import { capture, unset_context } from '../../reactivity/async.js'; const PENDING = 0; const THEN = 1; @@ -33,7 +25,7 @@ const CATCH = 2; /** * @template V * @param {TemplateNode} node - * @param {(() => Promise)} get_input + * @param {(() => any)} get_input * @param {null | ((anchor: Node) => void)} pending_fn * @param {null | ((anchor: Node, value: Source) => void)} then_fn * @param {null | ((anchor: Node, error: unknown) => void)} catch_fn @@ -44,149 +36,94 @@ export function await_block(node, get_input, pending_fn, then_fn, catch_fn) { hydrate_next(); } - var anchor = node; var runes = is_runes(); - var active_component_context = component_context; - - /** @type {any} */ - var component_function = DEV ? component_context?.function : null; - var dev_original_stack = DEV ? dev_stack : null; - - /** @type {V | Promise | typeof UNINITIALIZED} */ - var input = UNINITIALIZED; - - /** @type {Effect | null} */ - var pending_effect; - - /** @type {Effect | null} */ - var then_effect; - - /** @type {Effect | null} */ - var catch_effect; - - var input_source = runes - ? source(/** @type {V} */ (undefined)) - : mutable_source(/** @type {V} */ (undefined), false, false); - var error_source = runes ? source(undefined) : mutable_source(undefined, false, false); - var resolved = false; - /** - * @param {AwaitState} state - * @param {boolean} restore - */ - function update(state, restore) { - resolved = true; - - if (restore) { - set_active_effect(effect); - set_active_reaction(effect); // TODO do we need both? - set_component_context(active_component_context); - if (DEV) { - set_dev_current_component_function(component_function); - set_dev_stack(dev_original_stack); - } - } - - try { - if (state === PENDING && pending_fn) { - if (pending_effect) resume_effect(pending_effect); - else pending_effect = branch(() => pending_fn(anchor)); - } - - if (state === THEN && then_fn) { - if (then_effect) resume_effect(then_effect); - else then_effect = branch(() => then_fn(anchor, input_source)); - } - - if (state === CATCH && catch_fn) { - if (catch_effect) resume_effect(catch_effect); - else catch_effect = branch(() => catch_fn(anchor, error_source)); - } - - if (state !== PENDING && pending_effect) { - pause_effect(pending_effect, () => (pending_effect = null)); - } - - if (state !== THEN && then_effect) { - pause_effect(then_effect, () => (then_effect = null)); - } - - if (state !== CATCH && catch_effect) { - pause_effect(catch_effect, () => (catch_effect = null)); - } - } finally { - if (restore) { - if (DEV) { - set_dev_current_component_function(null); - set_dev_stack(null); - } - set_component_context(null); - set_active_reaction(null); - set_active_effect(null); + var v = /** @type {V} */ (UNINITIALIZED); + var value = runes ? source(v) : mutable_source(v, false, false); + var error = runes ? source(v) : mutable_source(v, false, false); - // without this, the DOM does not update until two ticks after the promise - // resolves, which is unexpected behaviour (and somewhat irksome to test) - if (!is_flushing_sync) flushSync(); - } - } - } + var branches = new BranchManager(node); - var effect = block(() => { - if (input === (input = get_input())) return; + block(() => { + var input = get_input(); + var destroyed = false; /** Whether or not there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */ - // @ts-ignore coercing `anchor` to a `Comment` causes TypeScript and Prettier to fight - let mismatch = hydrating && is_promise(input) === (anchor.data === HYDRATION_START_ELSE); + // @ts-ignore coercing `node` to a `Comment` causes TypeScript and Prettier to fight + let mismatch = hydrating && is_promise(input) === (node.data === HYDRATION_START_ELSE); if (mismatch) { // Hydration mismatch: remove everything inside the anchor and start fresh - anchor = skip_nodes(); - - set_hydrate_node(anchor); + set_hydrate_node(skip_nodes()); set_hydrating(false); - mismatch = true; } if (is_promise(input)) { - var promise = input; + var restore = capture(); + var resolved = false; + + /** + * @param {() => void} fn + */ + const resolve = (fn) => { + if (destroyed) return; + + resolved = true; + restore(); + + if (hydrating) { + // `restore()` could set `hydrating` to `true`, which we very much + // don't want — we want to restore everything _except_ this + set_hydrating(false); + } - resolved = false; + try { + fn(); + } finally { + unset_context(); - promise.then( - (value) => { - if (promise !== input) return; - // we technically could use `set` here since it's on the next microtick - // but let's use internal_set for consistency and just to be safe - internal_set(input_source, value); - update(THEN, true); + // without this, the DOM does not update until two ticks after the promise + // resolves, which is unexpected behaviour (and somewhat irksome to test) + if (!is_flushing_sync) flushSync(); + } + }; + + input.then( + (v) => { + resolve(() => { + internal_set(value, v); + branches.ensure(THEN, then_fn && ((target) => then_fn(target, value))); + }); }, - (error) => { - if (promise !== input) return; - // we technically could use `set` here since it's on the next microtick - // but let's use internal_set for consistency and just to be safe - internal_set(error_source, error); - update(CATCH, true); - if (!catch_fn) { - // Rethrow the error if no catch block exists - throw error_source.v; - } + (e) => { + resolve(() => { + internal_set(error, e); + branches.ensure(THEN, catch_fn && ((target) => catch_fn(target, error))); + + if (!catch_fn) { + // Rethrow the error if no catch block exists + throw error.v; + } + }); } ); if (hydrating) { - if (pending_fn) { - pending_effect = branch(() => pending_fn(anchor)); - } + branches.ensure(PENDING, pending_fn); } else { // Wait a microtask before checking if we should show the pending state as - // the promise might have resolved by the next microtask. + // the promise might have resolved by then queue_micro_task(() => { - if (!resolved) update(PENDING, true); + if (!resolved) { + resolve(() => { + branches.ensure(PENDING, pending_fn); + }); + } }); } } else { - internal_set(input_source, input); - update(THEN, false); + internal_set(value, input); + branches.ensure(THEN, then_fn && ((target) => then_fn(target, value))); } if (mismatch) { @@ -194,11 +131,8 @@ export function await_block(node, get_input, pending_fn, then_fn, catch_fn) { set_hydrating(true); } - // Set the input to something else, in order to disable the promise callbacks - return () => (input = UNINITIALIZED); + return () => { + destroyed = true; + }; }); - - if (hydrating) { - anchor = hydrate_node; - } } diff --git a/packages/svelte/src/internal/client/dom/blocks/boundary.js b/packages/svelte/src/internal/client/dom/blocks/boundary.js index ca6437e384..72e64b1a3a 100644 --- a/packages/svelte/src/internal/client/dom/blocks/boundary.js +++ b/packages/svelte/src/internal/client/dom/blocks/boundary.js @@ -8,7 +8,13 @@ import { import { HYDRATION_START_ELSE } from '../../../../constants.js'; import { component_context, set_component_context } from '../../context.js'; import { handle_error, invoke_error_boundary } from '../../error-handling.js'; -import { block, branch, destroy_effect, pause_effect } from '../../reactivity/effects.js'; +import { + block, + branch, + destroy_effect, + move_effect, + pause_effect +} from '../../reactivity/effects.js'; import { active_effect, active_reaction, @@ -24,7 +30,6 @@ import { skip_nodes, set_hydrate_node } from '../hydration.js'; -import { get_next_sibling } from '../operations.js'; import { queue_micro_task } from '../task.js'; import * as e from '../../errors.js'; import * as w from '../../warnings.js'; @@ -285,13 +290,6 @@ export class Boundary { this.#anchor.before(this.#offscreen_fragment); this.#offscreen_fragment = null; } - - // TODO this feels like a little bit of a kludge, but until we - // overhaul the boundary/batch relationship it's probably - // the most pragmatic solution available to us - queue_micro_task(() => { - Batch.ensure().flush(); - }); } } @@ -403,6 +401,7 @@ export class Boundary { if (failed) { queue_micro_task(() => { this.#failed_effect = this.#run(() => { + Batch.ensure(); this.#is_creating_fallback = true; try { @@ -425,24 +424,6 @@ export class Boundary { } } -/** - * - * @param {Effect} effect - * @param {DocumentFragment} fragment - */ -function move_effect(effect, fragment) { - var node = effect.nodes_start; - var end = effect.nodes_end; - - while (node !== null) { - /** @type {TemplateNode | null} */ - var next = node === end ? null : /** @type {TemplateNode} */ (get_next_sibling(node)); - - fragment.append(node); - node = next; - } -} - export function get_boundary() { return /** @type {Boundary} */ (/** @type {Effect} */ (active_effect).b); } diff --git a/packages/svelte/src/internal/client/dom/blocks/branches.js b/packages/svelte/src/internal/client/dom/blocks/branches.js new file mode 100644 index 0000000000..827f9f44fa --- /dev/null +++ b/packages/svelte/src/internal/client/dom/blocks/branches.js @@ -0,0 +1,185 @@ +/** @import { Effect, TemplateNode } from '#client' */ +import { is_runes } from '../../context.js'; +import { Batch, current_batch } from '../../reactivity/batch.js'; +import { + branch, + destroy_effect, + move_effect, + pause_effect, + resume_effect +} from '../../reactivity/effects.js'; +import { set_should_intro, should_intro } from '../../render.js'; +import { hydrate_node, hydrating } from '../hydration.js'; +import { create_text, should_defer_append } from '../operations.js'; + +/** + * @typedef {{ effect: Effect, fragment: DocumentFragment }} Branch + */ + +/** + * @template Key + */ +export class BranchManager { + /** @type {TemplateNode} */ + anchor; + + /** @type {Map} */ + #batches = new Map(); + + /** @type {Map} */ + #onscreen = new Map(); + + /** @type {Map} */ + #offscreen = new Map(); + + /** + * Whether to pause (i.e. outro) on change, or destroy immediately. + * This is necessary for `` + */ + #transition = true; + + /** + * @param {TemplateNode} anchor + * @param {boolean} transition + */ + constructor(anchor, transition = true) { + this.anchor = anchor; + this.#transition = transition; + } + + #commit = () => { + var batch = /** @type {Batch} */ (current_batch); + + // if this batch was made obsolete, bail + if (!this.#batches.has(batch)) return; + + var key = /** @type {Key} */ (this.#batches.get(batch)); + + var onscreen = this.#onscreen.get(key); + + if (onscreen) { + // effect is already in the DOM — abort any current outro + resume_effect(onscreen); + } else { + // effect is currently offscreen. put it in the DOM + var offscreen = this.#offscreen.get(key); + + if (offscreen) { + this.#onscreen.set(key, offscreen.effect); + this.#offscreen.delete(key); + + // remove the anchor... + /** @type {TemplateNode} */ (offscreen.fragment.lastChild).remove(); + + // ...and append the fragment + this.anchor.before(offscreen.fragment); + onscreen = offscreen.effect; + } + } + + for (const [b, k] of this.#batches) { + this.#batches.delete(b); + + if (b === batch) { + // keep values for newer batches + break; + } + + const offscreen = this.#offscreen.get(k); + + if (offscreen) { + // for older batches, destroy offscreen effects + // as they will never be committed + destroy_effect(offscreen.effect); + this.#offscreen.delete(k); + } + } + + // outro/destroy all onscreen effects... + for (const [k, effect] of this.#onscreen) { + // ...except the one that was just committed + if (k === key) continue; + + const on_destroy = () => { + const keys = Array.from(this.#batches.values()); + + if (keys.includes(k)) { + // keep the effect offscreen, as another batch will need it + var fragment = document.createDocumentFragment(); + move_effect(effect, fragment); + + fragment.append(create_text()); // TODO can we avoid this? + + this.#offscreen.set(k, { effect, fragment }); + } else { + destroy_effect(effect); + } + + this.#onscreen.delete(k); + }; + + if (this.#transition || !onscreen) { + pause_effect(effect, on_destroy, false); + } else { + on_destroy(); + } + } + }; + + /** + * + * @param {any} key + * @param {null | ((target: TemplateNode) => void)} fn + */ + ensure(key, fn) { + var batch = /** @type {Batch} */ (current_batch); + var defer = should_defer_append(); + + if (fn && !this.#onscreen.has(key) && !this.#offscreen.has(key)) { + if (defer) { + var fragment = document.createDocumentFragment(); + var target = create_text(); + + fragment.append(target); + + this.#offscreen.set(key, { + effect: branch(() => fn(target)), + fragment + }); + } else { + this.#onscreen.set( + key, + branch(() => fn(this.anchor)) + ); + } + } + + this.#batches.set(batch, key); + + if (defer) { + for (const [k, effect] of this.#onscreen) { + if (k === key) { + batch.skipped_effects.delete(effect); + } else { + batch.skipped_effects.add(effect); + } + } + + for (const [k, branch] of this.#offscreen) { + if (k === key) { + batch.skipped_effects.delete(branch.effect); + } else { + batch.skipped_effects.add(branch.effect); + } + } + + batch.add_callback(this.#commit); + } else { + if (hydrating) { + this.anchor = hydrate_node; + } + + this.#commit(); + } + } +} diff --git a/packages/svelte/src/internal/client/dom/blocks/if.js b/packages/svelte/src/internal/client/dom/blocks/if.js index 6349ab8399..7fa5ca464d 100644 --- a/packages/svelte/src/internal/client/dom/blocks/if.js +++ b/packages/svelte/src/internal/client/dom/blocks/if.js @@ -1,19 +1,16 @@ -/** @import { Effect, TemplateNode } from '#client' */ -/** @import { Batch } from '../../reactivity/batch.js'; */ +/** @import { TemplateNode } from '#client' */ import { EFFECT_TRANSPARENT } from '#client/constants'; import { hydrate_next, - hydrate_node, hydrating, read_hydration_instruction, skip_nodes, set_hydrate_node, set_hydrating } from '../hydration.js'; -import { block, branch, pause_effect, resume_effect } from '../../reactivity/effects.js'; -import { HYDRATION_START_ELSE, UNINITIALIZED } from '../../../../constants.js'; -import { create_text, should_defer_append } from '../operations.js'; -import { current_batch } from '../../reactivity/batch.js'; +import { block } from '../../reactivity/effects.js'; +import { HYDRATION_START_ELSE } from '../../../../constants.js'; +import { BranchManager } from './branches.js'; // TODO reinstate https://github.com/sveltejs/svelte/pull/15250 @@ -28,122 +25,46 @@ export function if_block(node, fn, elseif = false) { hydrate_next(); } - var anchor = node; - - /** @type {Effect | null} */ - var consequent_effect = null; - - /** @type {Effect | null} */ - var alternate_effect = null; - - /** @type {typeof UNINITIALIZED | boolean | null} */ - var condition = UNINITIALIZED; - + var branches = new BranchManager(node); var flags = elseif ? EFFECT_TRANSPARENT : 0; - var has_branch = false; - - const set_branch = (/** @type {(anchor: Node) => void} */ fn, flag = true) => { - has_branch = true; - update_branch(flag, fn); - }; - - /** @type {DocumentFragment | null} */ - var offscreen_fragment = null; - - function commit() { - if (offscreen_fragment !== null) { - // remove the anchor - /** @type {Text} */ (offscreen_fragment.lastChild).remove(); - - anchor.before(offscreen_fragment); - offscreen_fragment = null; - } - - var active = condition ? consequent_effect : alternate_effect; - var inactive = condition ? alternate_effect : consequent_effect; - - if (active) { - resume_effect(active); - } - - if (inactive) { - pause_effect(inactive, () => { - if (condition) { - alternate_effect = null; - } else { - consequent_effect = null; - } - }); - } - } - - const update_branch = ( - /** @type {boolean | null} */ new_condition, - /** @type {null | ((anchor: Node) => void)} */ fn - ) => { - if (condition === (condition = new_condition)) return; - - /** Whether or not there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */ - let mismatch = false; - + /** + * @param {boolean} condition, + * @param {null | ((anchor: Node) => void)} fn + */ + function update_branch(condition, fn) { if (hydrating) { - const is_else = read_hydration_instruction(anchor) === HYDRATION_START_ELSE; + const is_else = read_hydration_instruction(node) === HYDRATION_START_ELSE; - if (!!condition === is_else) { + if (condition === is_else) { // Hydration mismatch: remove everything inside the anchor and start fresh. // This could happen with `{#if browser}...{/if}`, for example - anchor = skip_nodes(); + var anchor = skip_nodes(); set_hydrate_node(anchor); - set_hydrating(false); - mismatch = true; - } - } + branches.anchor = anchor; - var defer = should_defer_append(); - var target = anchor; - - if (defer) { - offscreen_fragment = document.createDocumentFragment(); - offscreen_fragment.append((target = create_text())); - } + set_hydrating(false); + branches.ensure(condition, fn); + set_hydrating(true); - if (condition) { - consequent_effect ??= fn && branch(() => fn(target)); - } else { - alternate_effect ??= fn && branch(() => fn(target)); + return; + } } - if (defer) { - var batch = /** @type {Batch} */ (current_batch); - - var active = condition ? consequent_effect : alternate_effect; - var inactive = condition ? alternate_effect : consequent_effect; - - if (active) batch.skipped_effects.delete(active); - if (inactive) batch.skipped_effects.add(inactive); + branches.ensure(condition, fn); + } - batch.add_callback(commit); - } else { - commit(); - } + block(() => { + var has_branch = false; - if (mismatch) { - // continue in hydration mode - set_hydrating(true); - } - }; + fn((fn, flag = true) => { + has_branch = true; + update_branch(flag, fn); + }); - block(() => { - has_branch = false; - fn(set_branch); if (!has_branch) { - update_branch(null, null); + update_branch(false, null); } }, flags); - - if (hydrating) { - anchor = hydrate_node; - } } diff --git a/packages/svelte/src/internal/client/dom/blocks/key.js b/packages/svelte/src/internal/client/dom/blocks/key.js index 5e3c42019f..849b1c2447 100644 --- a/packages/svelte/src/internal/client/dom/blocks/key.js +++ b/packages/svelte/src/internal/client/dom/blocks/key.js @@ -1,12 +1,8 @@ -/** @import { Effect, TemplateNode } from '#client' */ -/** @import { Batch } from '../../reactivity/batch.js'; */ -import { UNINITIALIZED } from '../../../../constants.js'; -import { block, branch, pause_effect } from '../../reactivity/effects.js'; -import { not_equal, safe_not_equal } from '../../reactivity/equality.js'; +/** @import { TemplateNode } from '#client' */ import { is_runes } from '../../context.js'; -import { hydrate_next, hydrate_node, hydrating } from '../hydration.js'; -import { create_text, should_defer_append } from '../operations.js'; -import { current_batch } from '../../reactivity/batch.js'; +import { block } from '../../reactivity/effects.js'; +import { hydrate_next, hydrating } from '../hydration.js'; +import { BranchManager } from './branches.js'; /** * @template V @@ -20,60 +16,18 @@ export function key(node, get_key, render_fn) { hydrate_next(); } - var anchor = node; + var branches = new BranchManager(node); - /** @type {V | typeof UNINITIALIZED} */ - var key = UNINITIALIZED; - - /** @type {Effect} */ - var effect; - - /** @type {Effect} */ - var pending_effect; - - /** @type {DocumentFragment | null} */ - var offscreen_fragment = null; - - var changed = is_runes() ? not_equal : safe_not_equal; - - function commit() { - if (effect) { - pause_effect(effect); - } - - if (offscreen_fragment !== null) { - // remove the anchor - /** @type {Text} */ (offscreen_fragment.lastChild).remove(); - - anchor.before(offscreen_fragment); - offscreen_fragment = null; - } - - effect = pending_effect; - } + var legacy = !is_runes(); block(() => { - if (changed(key, (key = get_key()))) { - var target = anchor; - - var defer = should_defer_append(); - - if (defer) { - offscreen_fragment = document.createDocumentFragment(); - offscreen_fragment.append((target = create_text())); - } - - pending_effect = branch(() => render_fn(target)); + var key = get_key(); - if (defer) { - /** @type {Batch} */ (current_batch).add_callback(commit); - } else { - commit(); - } + // key blocks in Svelte <5 had stupid semantics + if (legacy && key !== null && typeof key === 'object') { + key = /** @type {V} */ ({}); } - }); - if (hydrating) { - anchor = hydrate_node; - } + branches.ensure(key, render_fn); + }); } diff --git a/packages/svelte/src/internal/client/dom/blocks/snippet.js b/packages/svelte/src/internal/client/dom/blocks/snippet.js index 32d88d4c60..0c4948aca0 100644 --- a/packages/svelte/src/internal/client/dom/blocks/snippet.js +++ b/packages/svelte/src/internal/client/dom/blocks/snippet.js @@ -1,8 +1,8 @@ /** @import { Snippet } from 'svelte' */ -/** @import { Effect, TemplateNode } from '#client' */ +/** @import { TemplateNode } from '#client' */ /** @import { Getters } from '#shared' */ import { EFFECT_TRANSPARENT, ELEMENT_NODE } from '#client/constants'; -import { branch, block, destroy_effect, teardown } from '../../reactivity/effects.js'; +import { block, teardown } from '../../reactivity/effects.js'; import { dev_current_component_function, set_dev_current_component_function @@ -14,8 +14,8 @@ import * as w from '../../warnings.js'; import * as e from '../../errors.js'; import { DEV } from 'esm-env'; import { get_first_child, get_next_sibling } from '../operations.js'; -import { noop } from '../../../shared/utils.js'; import { prevent_snippet_stringification } from '../../../shared/validate.js'; +import { BranchManager } from './branches.js'; /** * @template {(node: TemplateNode, ...args: any[]) => void} SnippetFn @@ -25,33 +25,17 @@ import { prevent_snippet_stringification } from '../../../shared/validate.js'; * @returns {void} */ export function snippet(node, get_snippet, ...args) { - var anchor = node; - - /** @type {SnippetFn | null | undefined} */ - // @ts-ignore - var snippet = noop; - - /** @type {Effect | null} */ - var snippet_effect; + var branches = new BranchManager(node); block(() => { - if (snippet === (snippet = get_snippet())) return; - - if (snippet_effect) { - destroy_effect(snippet_effect); - snippet_effect = null; - } + const snippet = get_snippet() ?? null; if (DEV && snippet == null) { e.invalid_snippet(); } - snippet_effect = branch(() => /** @type {SnippetFn} */ (snippet)(anchor, ...args)); + branches.ensure(snippet, snippet && ((anchor) => snippet(anchor, ...args))); }, EFFECT_TRANSPARENT); - - if (hydrating) { - anchor = hydrate_node; - } } /** diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-component.js b/packages/svelte/src/internal/client/dom/blocks/svelte-component.js index 2697722b39..134e57e627 100644 --- a/packages/svelte/src/internal/client/dom/blocks/svelte-component.js +++ b/packages/svelte/src/internal/client/dom/blocks/svelte-component.js @@ -1,10 +1,8 @@ -/** @import { TemplateNode, Dom, Effect } from '#client' */ -/** @import { Batch } from '../../reactivity/batch.js'; */ +/** @import { TemplateNode, Dom } from '#client' */ import { EFFECT_TRANSPARENT } from '#client/constants'; -import { block, branch, pause_effect } from '../../reactivity/effects.js'; -import { current_batch } from '../../reactivity/batch.js'; -import { hydrate_next, hydrate_node, hydrating } from '../hydration.js'; -import { create_text, should_defer_append } from '../operations.js'; +import { block } from '../../reactivity/effects.js'; +import { hydrate_next, hydrating } from '../hydration.js'; +import { BranchManager } from './branches.js'; /** * @template P @@ -19,64 +17,10 @@ export function component(node, get_component, render_fn) { hydrate_next(); } - var anchor = node; - - /** @type {C} */ - var component; - - /** @type {Effect | null} */ - var effect; - - /** @type {DocumentFragment | null} */ - var offscreen_fragment = null; - - /** @type {Effect | null} */ - var pending_effect = null; - - function commit() { - if (effect) { - pause_effect(effect); - effect = null; - } - - if (offscreen_fragment) { - // remove the anchor - /** @type {Text} */ (offscreen_fragment.lastChild).remove(); - - anchor.before(offscreen_fragment); - offscreen_fragment = null; - } - - effect = pending_effect; - pending_effect = null; - } + var branches = new BranchManager(node); block(() => { - if (component === (component = get_component())) return; - - var defer = should_defer_append(); - - if (component) { - var target = anchor; - - if (defer) { - offscreen_fragment = document.createDocumentFragment(); - offscreen_fragment.append((target = create_text())); - if (effect) { - /** @type {Batch} */ (current_batch).skipped_effects.add(effect); - } - } - pending_effect = branch(() => render_fn(target, component)); - } - - if (defer) { - /** @type {Batch} */ (current_batch).add_callback(commit); - } else { - commit(); - } + var component = get_component() ?? null; + branches.ensure(component, component && ((target) => render_fn(target, component))); }, EFFECT_TRANSPARENT); - - if (hydrating) { - anchor = hydrate_node; - } } diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js index 231a3621b1..6533ff8921 100644 --- a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js +++ b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js @@ -8,13 +8,7 @@ import { set_hydrating } from '../hydration.js'; import { create_text, get_first_child } from '../operations.js'; -import { - block, - branch, - destroy_effect, - pause_effect, - resume_effect -} from '../../reactivity/effects.js'; +import { block, teardown } from '../../reactivity/effects.js'; import { set_should_intro } from '../../render.js'; import { current_each_item, set_current_each_item } from './each.js'; import { active_effect } from '../../runtime.js'; @@ -23,6 +17,7 @@ import { DEV } from 'esm-env'; import { EFFECT_TRANSPARENT, ELEMENT_NODE } from '#client/constants'; import { assign_nodes } from '../template.js'; import { is_raw_text_element } from '../../../../utils.js'; +import { BranchManager } from './branches.js'; /** * @param {Comment | Element} node @@ -42,12 +37,6 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio var filename = DEV && location && component_context?.function[FILENAME]; - /** @type {string | null} */ - var tag; - - /** @type {string | null} */ - var current_tag; - /** @type {null | Element} */ var element = null; @@ -58,9 +47,6 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio var anchor = /** @type {TemplateNode} */ (hydrating ? hydrate_node : node); - /** @type {Effect | null} */ - var effect; - /** * The keyed `{#each ...}` item block, if any, that this element is inside. * We track this so we can set it when changing the element, allowing any @@ -68,36 +54,24 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio */ var each_item_block = current_each_item; + var branches = new BranchManager(anchor, false); + block(() => { const next_tag = get_tag() || null; var ns = get_namespace ? get_namespace() : is_svg || next_tag === 'svg' ? NAMESPACE_SVG : null; - // Assumption: Noone changes the namespace but not the tag (what would that even mean?) - if (next_tag === tag) return; - - // See explanation of `each_item_block` above - var previous_each_item = current_each_item; - set_current_each_item(each_item_block); - - if (effect) { - if (next_tag === null) { - // start outro - pause_effect(effect, () => { - effect = null; - current_tag = null; - }); - } else if (next_tag === current_tag) { - // same tag as is currently rendered — abort outro - resume_effect(effect); - } else { - // tag is changing — destroy immediately, render contents without intro transitions - destroy_effect(effect); - set_should_intro(false); - } + if (next_tag === null) { + branches.ensure(null, null); + set_should_intro(true); + return; } - if (next_tag && next_tag !== current_tag) { - effect = branch(() => { + branches.ensure(next_tag, (anchor) => { + // See explanation of `each_item_block` above + var previous_each_item = current_each_item; + set_current_each_item(each_item_block); + + if (next_tag) { element = hydrating ? /** @type {Element} */ (element) : ns @@ -149,16 +123,31 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio /** @type {Effect} */ (active_effect).nodes_end = element; anchor.before(element); - }); - } + } + + set_current_each_item(previous_each_item); + + if (hydrating) { + set_hydrate_node(anchor); + } + }); - tag = next_tag; - if (tag) current_tag = tag; + // revert to the default state after the effect has been created set_should_intro(true); - set_current_each_item(previous_each_item); + return () => { + if (next_tag) { + // if we're in this callback because we're re-running the effect, + // disable intros (unless no element is currently displayed) + set_should_intro(false); + } + }; }, EFFECT_TRANSPARENT); + teardown(() => { + set_should_intro(true); + }); + if (was_hydrating) { set_hydrating(true); set_hydrate_node(anchor); diff --git a/packages/svelte/src/internal/client/reactivity/async.js b/packages/svelte/src/internal/client/reactivity/async.js index 45c78ff926..fb836df989 100644 --- a/packages/svelte/src/internal/client/reactivity/async.js +++ b/packages/svelte/src/internal/client/reactivity/async.js @@ -1,8 +1,13 @@ -/** @import { Effect, Value } from '#client' */ - +/** @import { Effect, TemplateNode, Value } from '#client' */ import { DESTROYED } from '#client/constants'; import { DEV } from 'esm-env'; -import { component_context, is_runes, set_component_context } from '../context.js'; +import { + component_context, + dev_stack, + is_runes, + set_component_context, + set_dev_stack +} from '../context.js'; import { get_boundary } from '../dom/blocks/boundary.js'; import { invoke_error_boundary } from '../error-handling.js'; import { @@ -28,6 +33,7 @@ import { set_hydrating, skip_nodes } from '../dom/hydration.js'; +import { create_text } from '../dom/operations.js'; /** * @@ -80,7 +86,7 @@ export function flatten(sync, async, fn) { * some asynchronous work has happened (so that e.g. `await a + b` * causes `b` to be registered as a dependency). */ -function capture() { +export function capture() { var previous_effect = active_effect; var previous_reaction = active_reaction; var previous_component_context = component_context; @@ -92,6 +98,10 @@ function capture() { var previous_hydrate_node = hydrate_node; } + if (DEV) { + var previous_dev_stack = dev_stack; + } + return function restore() { set_active_effect(previous_effect); set_active_reaction(previous_reaction); @@ -105,6 +115,7 @@ function capture() { if (DEV) { set_from_async_derived(null); + set_dev_stack(previous_dev_stack); } }; } @@ -193,19 +204,24 @@ export function unset_context() { set_active_effect(null); set_active_reaction(null); set_component_context(null); - if (DEV) set_from_async_derived(null); + + if (DEV) { + set_from_async_derived(null); + set_dev_stack(null); + } } /** - * @param {() => Promise} fn + * @param {TemplateNode} anchor + * @param {(target: TemplateNode) => Promise} fn */ -export async function async_body(fn) { +export async function async_body(anchor, fn) { var boundary = get_boundary(); var batch = /** @type {Batch} */ (current_batch); - var pending = boundary.is_pending(); + var blocking = !boundary.is_pending(); boundary.update_pending_count(1); - if (!pending) batch.increment(); + batch.increment(blocking); var active = /** @type {Effect} */ (active_effect); @@ -218,7 +234,7 @@ export async function async_body(fn) { } try { - var promise = fn(); + var promise = fn(anchor); } finally { if (next_hydrate_node) { set_hydrate_node(next_hydrate_node); @@ -238,12 +254,7 @@ export async function async_body(fn) { } boundary.update_pending_count(-1); - - if (pending) { - batch.flush(); - } else { - batch.decrement(); - } + batch.decrement(blocking); unset_context(); } diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index b35e16a409..2cef562ac9 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -11,7 +11,8 @@ import { RENDER_EFFECT, ROOT_EFFECT, MAYBE_DIRTY, - DERIVED + DERIVED, + BOUNDARY_EFFECT } from '#client/constants'; import { async_mode_flag } from '../../flags/index.js'; import { deferred, define_property } from '../../shared/utils.js'; @@ -31,6 +32,16 @@ import { invoke_error_boundary } from '../error-handling.js'; import { old_values, source, update } from './sources.js'; import { inspect_effect, unlink_effect } from './effects.js'; +/** + * @typedef {{ + * parent: EffectTarget | null; + * effect: Effect | null; + * effects: Effect[]; + * render_effects: Effect[]; + * block_effects: Effect[]; + * }} EffectTarget + */ + /** @type {Set} */ const batches = new Set(); @@ -65,6 +76,8 @@ let is_flushing = false; export let is_flushing_sync = false; export class Batch { + committed = false; + /** * The current values of any sources that are updated in this batch * They keys of this map are identical to `this.#previous` @@ -91,6 +104,11 @@ export class Batch { */ #pending = 0; + /** + * The number of async effects that are currently in flight, _not_ inside a pending boundary + */ + #blocking_pending = 0; + /** * A deferred that resolves when the batch is committed, used with `settled()` * TODO replace with Promise.withResolvers once supported widely enough @@ -98,26 +116,6 @@ export class Batch { */ #deferred = null; - /** - * Template effects and `$effect.pre` effects, which run when - * a batch is committed - * @type {Effect[]} - */ - #render_effects = []; - - /** - * The same as `#render_effects`, but for `$effect` (which runs after) - * @type {Effect[]} - */ - #effects = []; - - /** - * Block effects, which may need to re-run on subsequent flushes - * in order to update internal sources (e.g. each block items) - * @type {Effect[]} - */ - #block_effects = []; - /** * Deferred effects (which run after async work has completed) that are DIRTY * @type {Effect[]} @@ -148,41 +146,37 @@ export class Batch { this.apply(); + /** @type {EffectTarget} */ + var target = { + parent: null, + effect: null, + effects: [], + render_effects: [], + block_effects: [] + }; + for (const root of root_effects) { - this.#traverse_effect_tree(root); + this.#traverse_effect_tree(root, target); } - // if there is no outstanding async work, commit - if (this.#pending === 0) { - // TODO we need this because we commit _then_ flush effects... - // maybe there's a way we can reverse the order? - var previous_batch_sources = batch_values; - - this.#commit(); + this.#resolve(); - var render_effects = this.#render_effects; - var effects = this.#effects; - - this.#render_effects = []; - this.#effects = []; - this.#block_effects = []; + if (this.#blocking_pending > 0) { + this.#defer_effects(target.effects); + this.#defer_effects(target.render_effects); + this.#defer_effects(target.block_effects); + } else { + // TODO append/detach blocks here, not in #commit // If sources are written to, then work needs to happen in a separate batch, else prior sources would be mixed with // newly updated sources, which could lead to infinite loops when effects run over and over again. previous_batch = this; current_batch = null; - batch_values = previous_batch_sources; - flush_queued_effects(render_effects); - flush_queued_effects(effects); + flush_queued_effects(target.render_effects); + flush_queued_effects(target.effects); previous_batch = null; - - this.#deferred?.resolve(); - } else { - this.#defer_effects(this.#render_effects); - this.#defer_effects(this.#effects); - this.#defer_effects(this.#block_effects); } batch_values = null; @@ -192,8 +186,9 @@ export class Batch { * Traverse the effect tree, executing effects or stashing * them for later execution as appropriate * @param {Effect} root + * @param {EffectTarget} target */ - #traverse_effect_tree(root) { + #traverse_effect_tree(root, target) { root.f ^= CLEAN; var effect = root.first; @@ -205,15 +200,25 @@ export class Batch { var skip = is_skippable_branch || (flags & INERT) !== 0 || this.skipped_effects.has(effect); + if ((effect.f & BOUNDARY_EFFECT) !== 0 && effect.b?.is_pending()) { + target = { + parent: target, + effect, + effects: [], + render_effects: [], + block_effects: [] + }; + } + if (!skip && effect.fn !== null) { if (is_branch) { effect.f ^= CLEAN; } else if ((flags & EFFECT) !== 0) { - this.#effects.push(effect); + target.effects.push(effect); } else if (async_mode_flag && (flags & RENDER_EFFECT) !== 0) { - this.#render_effects.push(effect); + target.render_effects.push(effect); } else if (is_dirty(effect)) { - if ((effect.f & BLOCK_EFFECT) !== 0) this.#block_effects.push(effect); + if ((effect.f & BLOCK_EFFECT) !== 0) target.block_effects.push(effect); update_effect(effect); } @@ -229,6 +234,17 @@ export class Batch { effect = effect.next; while (effect === null && parent !== null) { + if (parent === target.effect) { + // TODO rather than traversing into pending boundaries and deferring the effects, + // could we just attach the effects _to_ the pending boundary and schedule them + // once the boundary is ready? + this.#defer_effects(target.effects); + this.#defer_effects(target.render_effects); + this.#defer_effects(target.block_effects); + + target = /** @type {EffectTarget} */ (target.parent); + } + effect = parent.next; parent = parent.parent; } @@ -246,8 +262,6 @@ export class Batch { // mark as clean so they get scheduled if they depend on pending async state set_signal_status(e, CLEAN); } - - effects.length = 0; } /** @@ -283,8 +297,8 @@ export class Batch { // this can happen if a new batch was created during `flush_effects()` return; } - } else if (this.#pending === 0) { - this.#commit(); + } else { + this.#resolve(); } this.deactivate(); @@ -300,16 +314,19 @@ export class Batch { } } - /** - * Append and remove branches to/from the DOM - */ - #commit() { - for (const fn of this.#callbacks) { - fn(); + #resolve() { + if (this.#blocking_pending === 0) { + // append/remove branches + for (const fn of this.#callbacks) fn(); + this.#callbacks.clear(); } - this.#callbacks.clear(); + if (this.#pending === 0) { + this.#commit(); + } + } + #commit() { // If there are other pending batches, they now need to be 'rebased' — // in other words, we re-run block/async effects with the newly // committed state, unless the batch in question has a more @@ -317,7 +334,17 @@ export class Batch { if (batches.size > 1) { this.#previous.clear(); - let is_earlier = true; + var previous_batch_values = batch_values; + var is_earlier = true; + + /** @type {EffectTarget} */ + var dummy_target = { + parent: null, + effect: null, + effects: [], + render_effects: [], + block_effects: [] + }; for (const batch of batches) { if (batch === this) { @@ -350,8 +377,12 @@ export class Batch { // Re-run async/block effects that depend on distinct values changed in both batches const others = [...batch.current.keys()].filter((s) => !this.current.has(s)); if (others.length > 0) { + /** @type {Set} */ + const marked = new Set(); + /** @type {Map} */ + const checked = new Map(); for (const source of sources) { - mark_effects(source, others); + mark_effects(source, others, marked, checked); } if (queued_root_effects.length > 0) { @@ -359,9 +390,11 @@ export class Batch { batch.apply(); for (const root of queued_root_effects) { - batch.#traverse_effect_tree(root); + batch.#traverse_effect_tree(root, dummy_target); } + // TODO do we need to do anything with `target`? defer block effects? + queued_root_effects = []; batch.deactivate(); } @@ -369,17 +402,31 @@ export class Batch { } current_batch = null; + batch_values = previous_batch_values; } + this.committed = true; batches.delete(this); + + this.#deferred?.resolve(); } - increment() { + /** + * + * @param {boolean} blocking + */ + increment(blocking) { this.#pending += 1; + if (blocking) this.#blocking_pending += 1; } - decrement() { + /** + * + * @param {boolean} blocking + */ + decrement(blocking) { this.#pending -= 1; + if (blocking) this.#blocking_pending -= 1; for (const e of this.#dirty_effects) { set_signal_status(e, DIRTY); @@ -391,6 +438,9 @@ export class Batch { schedule_effect(e); } + this.#dirty_effects = []; + this.#maybe_dirty_effects = []; + this.flush(); } @@ -561,7 +611,7 @@ function infinite_loop_guard() { } } -/** @type {Effect[] | null} */ +/** @type {Set | null} */ export let eager_block_effects = null; /** @@ -578,7 +628,7 @@ function flush_queued_effects(effects) { var effect = effects[i++]; if ((effect.f & (DESTROYED | INERT)) === 0 && is_dirty(effect)) { - eager_block_effects = []; + eager_block_effects = new Set(); update_effect(effect); @@ -601,15 +651,34 @@ function flush_queued_effects(effects) { // If update_effect() has a flushSync() in it, we may have flushed another flush_queued_effects(), // which already handled this logic and did set eager_block_effects to null. - if (eager_block_effects?.length > 0) { - // TODO this feels incorrect! it gets the tests passing + if (eager_block_effects?.size > 0) { old_values.clear(); for (const e of eager_block_effects) { - update_effect(e); + // Skip eager effects that have already been unmounted + if ((e.f & (DESTROYED | INERT)) !== 0) continue; + + // Run effects in order from ancestor to descendant, else we could run into nullpointers + /** @type {Effect[]} */ + const ordered_effects = [e]; + let ancestor = e.parent; + while (ancestor !== null) { + if (eager_block_effects.has(ancestor)) { + eager_block_effects.delete(ancestor); + ordered_effects.push(ancestor); + } + ancestor = ancestor.parent; + } + + for (let j = ordered_effects.length - 1; j >= 0; j--) { + const e = ordered_effects[j]; + // Skip eager effects that have already been unmounted + if ((e.f & (DESTROYED | INERT)) !== 0) continue; + update_effect(e); + } } - eager_block_effects = []; + eager_block_effects.clear(); } } } @@ -623,15 +692,24 @@ function flush_queued_effects(effects) { * these effects can re-run after another batch has been committed * @param {Value} value * @param {Source[]} sources + * @param {Set} marked + * @param {Map} checked */ -function mark_effects(value, sources) { +function mark_effects(value, sources, marked, checked) { + if (marked.has(value)) return; + marked.add(value); + if (value.reactions !== null) { for (const reaction of value.reactions) { const flags = reaction.f; if ((flags & DERIVED) !== 0) { - mark_effects(/** @type {Derived} */ (reaction), sources); - } else if ((flags & (ASYNC | BLOCK_EFFECT)) !== 0 && depends_on(reaction, sources)) { + mark_effects(/** @type {Derived} */ (reaction), sources, marked, checked); + } else if ( + (flags & (ASYNC | BLOCK_EFFECT)) !== 0 && + (flags & DIRTY) === 0 && // we may have scheduled this one already + depends_on(reaction, sources, checked) + ) { set_signal_status(reaction, DIRTY); schedule_effect(/** @type {Effect} */ (reaction)); } @@ -642,20 +720,27 @@ function mark_effects(value, sources) { /** * @param {Reaction} reaction * @param {Source[]} sources + * @param {Map} checked */ -function depends_on(reaction, sources) { +function depends_on(reaction, sources, checked) { + const depends = checked.get(reaction); + if (depends !== undefined) return depends; + if (reaction.deps !== null) { for (const dep of reaction.deps) { if (sources.includes(dep)) { return true; } - if ((dep.f & DERIVED) !== 0 && depends_on(/** @type {Derived} */ (dep), sources)) { + if ((dep.f & DERIVED) !== 0 && depends_on(/** @type {Derived} */ (dep), sources, checked)) { + checked.set(/** @type {Derived} */ (dep), true); return true; } } } + checked.set(reaction, false); + return false; } diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index 6aa9a1d9d9..5a3dee4b7f 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -10,7 +10,8 @@ import { MAYBE_DIRTY, STALE_REACTION, UNOWNED, - ASYNC + ASYNC, + WAS_MARKED } from '#client/constants'; import { active_reaction, @@ -127,7 +128,17 @@ export function async_derived(fn, location) { // If this code is changed at some point, make sure to still access the then property // of fn() to read any signals it might access, so that we track them as dependencies. // We call `unset_context` to undo any `save` calls that happen inside `fn()` - Promise.resolve(fn()).then(d.resolve, d.reject).then(unset_context); + Promise.resolve(fn()) + .then(d.resolve, d.reject) + .then(() => { + if (batch === current_batch && batch.committed) { + // if the batch was rejected as stale, we need to cleanup + // after any `$.save(...)` calls inside `fn()` + batch.deactivate(); + } + + unset_context(); + }); } catch (error) { d.reject(error); unset_context(); @@ -136,17 +147,16 @@ export function async_derived(fn, location) { if (DEV) current_async_effect = null; var batch = /** @type {Batch} */ (current_batch); - var pending = boundary.is_pending(); if (should_suspend) { + var blocking = !boundary.is_pending(); + boundary.update_pending_count(1); - if (!pending) { - batch.increment(); + batch.increment(blocking); - deferreds.get(batch)?.reject(STALE_REACTION); - deferreds.delete(batch); // delete to ensure correct order in Map iteration below - deferreds.set(batch, d); - } + deferreds.get(batch)?.reject(STALE_REACTION); + deferreds.delete(batch); // delete to ensure correct order in Map iteration below + deferreds.set(batch, d); } /** @@ -156,7 +166,7 @@ export function async_derived(fn, location) { const handler = (value, error = undefined) => { current_async_effect = null; - if (!pending) batch.activate(); + batch.activate(); if (error) { if (error !== STALE_REACTION) { @@ -193,7 +203,7 @@ export function async_derived(fn, location) { if (should_suspend) { boundary.update_pending_count(-1); - if (!pending) batch.decrement(); + batch.decrement(blocking); } }; @@ -317,6 +327,7 @@ export function execute_derived(derived) { stack.push(derived); + derived.f &= ~WAS_MARKED; destroy_derived_effects(derived); value = update_reaction(derived); } finally { @@ -326,6 +337,7 @@ export function execute_derived(derived) { } } else { try { + derived.f &= ~WAS_MARKED; destroy_derived_effects(derived); value = update_reaction(derived); } finally { diff --git a/packages/svelte/src/internal/client/reactivity/effects.js b/packages/svelte/src/internal/client/reactivity/effects.js index 2c9e4db911..9b54598f9e 100644 --- a/packages/svelte/src/internal/client/reactivity/effects.js +++ b/packages/svelte/src/internal/client/reactivity/effects.js @@ -149,6 +149,9 @@ function create_effect(type, fn, sync, push = true) { (e.f & EFFECT_PRESERVED) === 0 ) { e = e.first; + if ((type & BLOCK_EFFECT) !== 0 && (type & EFFECT_TRANSPARENT) !== 0 && e !== null) { + e.f |= EFFECT_TRANSPARENT; + } } if (e !== null) { @@ -553,15 +556,16 @@ export function unlink_effect(effect) { * A paused effect does not update, and the DOM subtree becomes inert. * @param {Effect} effect * @param {() => void} [callback] + * @param {boolean} [destroy] */ -export function pause_effect(effect, callback) { +export function pause_effect(effect, callback, destroy = true) { /** @type {TransitionManager[]} */ var transitions = []; pause_children(effect, transitions, true); run_out_transitions(transitions, () => { - destroy_effect(effect); + if (destroy) destroy_effect(effect); if (callback) callback(); }); } @@ -603,7 +607,12 @@ export function pause_children(effect, transitions, local) { while (child !== null) { var sibling = child.next; - var transparent = (child.f & EFFECT_TRANSPARENT) !== 0 || (child.f & BRANCH_EFFECT) !== 0; + var transparent = + (child.f & EFFECT_TRANSPARENT) !== 0 || + // If this is a branch effect without a block effect parent, + // it means the parent block effect was pruned. In that case, + // transparency information was transferred to the branch effect. + ((child.f & BRANCH_EFFECT) !== 0 && (effect.f & BLOCK_EFFECT) !== 0); // TODO we don't need to call pause_children recursively with a linked list in place // it's slightly more involved though as we have to account for `transparent` changing // through the tree. @@ -662,3 +671,20 @@ function resume_children(effect, local) { export function aborted(effect = /** @type {Effect} */ (active_effect)) { return (effect.f & DESTROYED) !== 0; } + +/** + * @param {Effect} effect + * @param {DocumentFragment} fragment + */ +export function move_effect(effect, fragment) { + var node = effect.nodes_start; + var end = effect.nodes_end; + + while (node !== null) { + /** @type {TemplateNode | null} */ + var next = node === end ? null : /** @type {TemplateNode} */ (get_next_sibling(node)); + + fragment.append(node); + node = next; + } +} diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js index cd0c28016d..2fe8c4f75d 100644 --- a/packages/svelte/src/internal/client/reactivity/sources.js +++ b/packages/svelte/src/internal/client/reactivity/sources.js @@ -27,7 +27,8 @@ import { MAYBE_DIRTY, BLOCK_EFFECT, ROOT_EFFECT, - ASYNC + ASYNC, + WAS_MARKED } from '#client/constants'; import * as e from '../errors.js'; import { legacy_mode_flag, tracing_mode_flag } from '../../flags/index.js'; @@ -332,11 +333,14 @@ function mark_reactions(signal, status) { } if ((flags & DERIVED) !== 0) { - mark_reactions(/** @type {Derived} */ (reaction), MAYBE_DIRTY); + if ((flags & WAS_MARKED) === 0) { + reaction.f |= WAS_MARKED; + mark_reactions(/** @type {Derived} */ (reaction), MAYBE_DIRTY); + } } else if (not_dirty) { if ((flags & BLOCK_EFFECT) !== 0) { if (eager_block_effects !== null) { - eager_block_effects.push(/** @type {Effect} */ (reaction)); + eager_block_effects.add(/** @type {Effect} */ (reaction)); } } diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index a146659bf6..2e6f05b4b1 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -20,7 +20,8 @@ import { DISCONNECTED, REACTION_IS_UPDATING, STALE_REACTION, - ERROR_VALUE + ERROR_VALUE, + WAS_MARKED } from './constants.js'; import { old_values } from './reactivity/sources.js'; import { @@ -161,6 +162,10 @@ export function is_dirty(reaction) { var dependencies = reaction.deps; var is_unowned = (flags & UNOWNED) !== 0; + if (flags & DERIVED) { + reaction.f &= ~WAS_MARKED; + } + if (dependencies !== null) { var i; var dependency; diff --git a/packages/svelte/src/internal/server/index.js b/packages/svelte/src/internal/server/index.js index 50bb629c4d..74a90a8600 100644 --- a/packages/svelte/src/internal/server/index.js +++ b/packages/svelte/src/internal/server/index.js @@ -418,15 +418,6 @@ export function ensure_array_like(array_like_or_iterator) { return []; } -/** - * @param {any[]} args - * @param {Function} [inspect] - */ -// eslint-disable-next-line no-console -export function inspect(args, inspect = console.log) { - inspect('init', ...args); -} - /** * @template V * @param {() => V} get_value diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index e88bf0d0ea..81ead49fca 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.41.0'; +export const VERSION = '5.41.3'; export const PUBLIC_VERSION = '5'; diff --git a/packages/svelte/tests/helpers.js b/packages/svelte/tests/helpers.js index 7a9640636c..bf708878a3 100644 --- a/packages/svelte/tests/helpers.js +++ b/packages/svelte/tests/helpers.js @@ -197,6 +197,26 @@ export const fragments = /** @type {'html' | 'tree'} */ (process.env.FRAGMENTS) export const async_mode = process.env.SVELTE_NO_ASYNC !== 'true'; +/** + * @param {any[]} logs + */ +export function normalise_inspect_logs(logs) { + return logs.map((log) => { + if (log instanceof Error) { + const last_line = log.stack + ?.trim() + .split('\n') + .filter((line) => !line.includes('at Module.get_stack'))[1]; + + const match = last_line && /(at .+) /.exec(last_line); + + return match && match[1]; + } + + return log; + }); +} + /** * @param {any[]} logs */ diff --git a/packages/svelte/tests/runtime-legacy/samples/let-directive-and-const-tag/_config.js b/packages/svelte/tests/runtime-legacy/samples/let-directive-and-const-tag/_config.js new file mode 100644 index 0000000000..2f7a7863a7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/let-directive-and-const-tag/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'foo' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/let-directive-and-const-tag/component.svelte b/packages/svelte/tests/runtime-legacy/samples/let-directive-and-const-tag/component.svelte new file mode 100644 index 0000000000..44e700bdd4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/let-directive-and-const-tag/component.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/let-directive-and-const-tag/main.svelte b/packages/svelte/tests/runtime-legacy/samples/let-directive-and-const-tag/main.svelte new file mode 100644 index 0000000000..abca25bab2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/let-directive-and-const-tag/main.svelte @@ -0,0 +1,7 @@ + + + {@const thing = data} + {thing} + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/async-abort-signal/_config.js b/packages/svelte/tests/runtime-runes/samples/async-abort-signal/_config.js index a947a91ab8..af49b1779c 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-abort-signal/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/async-abort-signal/_config.js @@ -6,7 +6,7 @@ export default test({ const [reset, resolve] = target.querySelectorAll('button'); reset.click(); - await settled(); + await tick(); assert.deepEqual(logs, ['aborted']); resolve.click(); diff --git a/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-2/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-2/main.svelte index e2f01a66c8..c0e4d862a8 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-2/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-2/main.svelte @@ -12,7 +12,7 @@ diff --git a/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-3/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-3/main.svelte index 566ea60ec5..8f5e2862eb 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-3/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-3/main.svelte @@ -12,7 +12,7 @@ diff --git a/packages/svelte/tests/runtime-runes/samples/async-block-reject-each-during-init/_config.js b/packages/svelte/tests/runtime-runes/samples/async-block-reject-each-during-init/_config.js index c5dae7fee2..ca5fd9ca89 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-block-reject-each-during-init/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/async-block-reject-each-during-init/_config.js @@ -24,5 +24,7 @@ export default test({

1

` ); - } + }, + + expect_unhandled_rejections: true }); diff --git a/packages/svelte/tests/runtime-runes/samples/async-block-resolve/_config.js b/packages/svelte/tests/runtime-runes/samples/async-block-resolve/_config.js new file mode 100644 index 0000000000..ee403290bc --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-block-resolve/_config.js @@ -0,0 +1,63 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const [increment, shift] = target.querySelectorAll('button'); + + shift.click(); + await tick(); + + shift.click(); + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` + + +

even

+

0

+ ` + ); + + increment.click(); + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` + + +

even

+

0

+ ` + ); + + shift.click(); + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` + + +

odd

+

loading...

+ ` + ); + + shift.click(); + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` + + +

odd

+

1

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-block-resolve/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-block-resolve/main.svelte new file mode 100644 index 0000000000..73fe83889a --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-block-resolve/main.svelte @@ -0,0 +1,36 @@ + + + + + + + {#if await push(count) % 2 === 0} +

even

+ {:else} +

odd

+ {/if} + + {#key count} + +

{await push(count)}

+ + {#snippet pending()} +

loading...

+ {/snippet} +
+ {/key} + + {#snippet pending()} +

loading...

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-effect-after-await/Child.svelte b/packages/svelte/tests/runtime-runes/samples/async-effect-after-await/Child.svelte index 682f7a0631..758ebc0004 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-effect-after-await/Child.svelte +++ b/packages/svelte/tests/runtime-runes/samples/async-effect-after-await/Child.svelte @@ -1,7 +1,11 @@ diff --git a/packages/svelte/tests/runtime-runes/samples/async-effect-after-await/_config.js b/packages/svelte/tests/runtime-runes/samples/async-effect-after-await/_config.js index 81548a25ea..0908b6a9fe 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-effect-after-await/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/async-effect-after-await/_config.js @@ -3,7 +3,8 @@ import { test } from '../../test'; export default test({ async test({ assert, logs }) { + assert.deepEqual(logs, []); await tick(); - assert.deepEqual(logs, ['hello']); + assert.deepEqual(logs, ['before', 'after']); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/async-effect-after-boundary/Child.svelte b/packages/svelte/tests/runtime-runes/samples/async-effect-after-boundary/Child.svelte new file mode 100644 index 0000000000..65a225431b --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-effect-after-boundary/Child.svelte @@ -0,0 +1,5 @@ + diff --git a/packages/svelte/tests/runtime-runes/samples/async-effect-after-boundary/_config.js b/packages/svelte/tests/runtime-runes/samples/async-effect-after-boundary/_config.js new file mode 100644 index 0000000000..f7b6c513d4 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-effect-after-boundary/_config.js @@ -0,0 +1,16 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target, logs }) { + const [shift] = target.querySelectorAll('button'); + + await tick(); + assert.deepEqual(logs, []); + + shift.click(); + await tick(); + + assert.deepEqual(logs, ['in effect']); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-effect-after-boundary/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-effect-after-boundary/main.svelte new file mode 100644 index 0000000000..edfd3c4d10 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-effect-after-boundary/main.svelte @@ -0,0 +1,22 @@ + + + + + +

{await push('hello')}

+ + + {#snippet pending()} +

loading...

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-resolve-stale/_config.js b/packages/svelte/tests/runtime-runes/samples/async-resolve-stale/_config.js index 50bb414afc..7fb49c473e 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-resolve-stale/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/async-resolve-stale/_config.js @@ -3,23 +3,28 @@ import { test } from '../../test'; export default test({ async test({ assert, target }) { // We gotta wait a bit more in this test because of the macrotasks in App.svelte - function macrotask(t = 3) { + function sleep(t = 50) { return new Promise((r) => setTimeout(r, t)); } - await macrotask(); + await sleep(); assert.htmlEqual(target.innerHTML, ' 1 | '); const [input] = target.querySelectorAll('input'); input.value = '1'; input.dispatchEvent(new Event('input', { bubbles: true })); - await macrotask(); + await sleep(); assert.htmlEqual(target.innerHTML, ' 1 | '); input.value = '12'; input.dispatchEvent(new Event('input', { bubbles: true })); - await macrotask(6); + await sleep(); assert.htmlEqual(target.innerHTML, ' 3 | 12'); + + input.value = ''; + input.dispatchEvent(new Event('input', { bubbles: true })); + await sleep(); + assert.htmlEqual(target.innerHTML, ' 4 | '); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/async-resolve-stale/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-resolve-stale/main.svelte index dc4a157928..dec5a55899 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-resolve-stale/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/async-resolve-stale/main.svelte @@ -1,26 +1,31 @@ + + + {fail ? error() : 'all good'} + + + {#snippet failed()} +
oops!
+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/guard-else-effect/_config.js b/packages/svelte/tests/runtime-runes/samples/guard-else-effect/_config.js new file mode 100644 index 0000000000..4e8eec8b16 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/guard-else-effect/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + mode: ['client'], + async test({ target, assert, logs }) { + const button = target.querySelector('button'); + + button?.click(); + flushSync(); + button?.click(); + flushSync(); + button?.click(); + flushSync(); + button?.click(); + flushSync(); + + assert.deepEqual(logs, ['two', 'one', 'two', 'one', 'two']); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/guard-else-effect/main.svelte b/packages/svelte/tests/runtime-runes/samples/guard-else-effect/main.svelte new file mode 100644 index 0000000000..91fd0442bd --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/guard-else-effect/main.svelte @@ -0,0 +1,18 @@ + + + + +{#if v === "one"} +
if1 matched! {console.log('one')}
+{:else if v === "two"} +
if2 matched! {console.log('two')}
+{:else} +
nothing matched {console.log('else')}
+{/if} diff --git a/packages/svelte/tests/runtime-runes/samples/guard-if-nested/_config.js b/packages/svelte/tests/runtime-runes/samples/guard-if-nested/_config.js new file mode 100644 index 0000000000..881c1545ee --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/guard-if-nested/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + mode: ['client'], + async test({ target, assert }) { + const button = target.querySelector('button'); + + flushSync(() => button?.click()); + + assert.equal(target.textContent?.trim(), 'Trigger'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/guard-if-nested/main.svelte b/packages/svelte/tests/runtime-runes/samples/guard-if-nested/main.svelte new file mode 100644 index 0000000000..4514bd114e --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/guard-if-nested/main.svelte @@ -0,0 +1,18 @@ + + +{#if centerRow?.nested} + {#if centerRow?.nested?.optional != undefined && centerRow.nested.optional > 0} + op: {centerRow.nested.optional}
+ {:else} + req: {centerRow.nested.required}
+ {/if} +{/if} + + diff --git a/packages/svelte/tests/runtime-runes/samples/guard-nested-if-pre/Component.svelte b/packages/svelte/tests/runtime-runes/samples/guard-nested-if-pre/Component.svelte new file mode 100644 index 0000000000..b7322e7530 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/guard-nested-if-pre/Component.svelte @@ -0,0 +1,6 @@ + diff --git a/packages/svelte/tests/runtime-runes/samples/guard-nested-if-pre/_config.js b/packages/svelte/tests/runtime-runes/samples/guard-nested-if-pre/_config.js new file mode 100644 index 0000000000..9706855fb4 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/guard-nested-if-pre/_config.js @@ -0,0 +1,13 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['client'], + async test({ assert, target, logs }) { + const button = target.querySelector('button'); + + button?.click(); + flushSync(); + assert.deepEqual(logs, ['pre', 'running b', 'pre', 'pre']); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/guard-nested-if-pre/main.svelte b/packages/svelte/tests/runtime-runes/samples/guard-nested-if-pre/main.svelte new file mode 100644 index 0000000000..4ebb13eca3 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/guard-nested-if-pre/main.svelte @@ -0,0 +1,18 @@ + + +{#if p || !p} + {#if p} + + {/if} +{/if} + + diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-deep-array/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-deep-array/_config.js index 49f1b5de41..1b331f5b40 100644 --- a/packages/svelte/tests/runtime-runes/samples/inspect-deep-array/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/inspect-deep-array/_config.js @@ -1,5 +1,6 @@ import { flushSync } from 'svelte'; import { test } from '../../test'; +import { normalise_inspect_logs } from '../../../helpers.js'; export default test({ compileOptions: { @@ -13,6 +14,6 @@ export default test({ button?.click(); }); - assert.deepEqual(logs, ['init', [1, 2, 3, 7], 'update', [2, 3, 7]]); + assert.deepEqual(normalise_inspect_logs(logs), [[1, 2, 3, 7], [2, 3, 7], 'at Object.doSplice']); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-deep/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-deep/_config.js index f7480b0e7b..89b01da499 100644 --- a/packages/svelte/tests/runtime-runes/samples/inspect-deep/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/inspect-deep/_config.js @@ -1,3 +1,4 @@ +import { normalise_inspect_logs } from '../../../helpers.js'; import { test } from '../../test'; export default test({ @@ -6,6 +7,6 @@ export default test({ }, async test({ assert, logs }) { - assert.deepEqual(logs, ['init', undefined, 'update', [{}]]); + assert.deepEqual(normalise_inspect_logs(logs), [undefined, [{}], 'at $effect']); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-derived-2/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-derived-2/_config.js index 9474397f7f..3742382759 100644 --- a/packages/svelte/tests/runtime-runes/samples/inspect-derived-2/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/inspect-derived-2/_config.js @@ -1,5 +1,6 @@ import { flushSync } from 'svelte'; import { test } from '../../test'; +import { normalise_inspect_logs } from '../../../helpers.js'; export default test({ compileOptions: { @@ -14,8 +15,7 @@ export default test({ }); assert.htmlEqual(target.innerHTML, `\n1`); - assert.deepEqual(logs, [ - 'init', + assert.deepEqual(normalise_inspect_logs(logs), [ { data: { derived: 0, @@ -23,14 +23,14 @@ export default test({ }, derived: [] }, - 'update', { data: { derived: 0, list: [1] }, derived: [1] - } + }, + 'at HTMLButtonElement.Main.button.__click' ]); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-derived-3/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-derived-3/_config.js index d2226f433e..017de6c0c7 100644 --- a/packages/svelte/tests/runtime-runes/samples/inspect-derived-3/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/inspect-derived-3/_config.js @@ -1,5 +1,6 @@ import { flushSync } from 'svelte'; import { test } from '../../test'; +import { normalise_inspect_logs } from '../../../helpers.js'; export default test({ compileOptions: { @@ -13,22 +14,19 @@ export default test({ button?.click(); }); - assert.deepEqual(logs, [ - 'init', + assert.deepEqual(normalise_inspect_logs(logs), [ '0', true, - 'init', '1', false, - 'init', '2', false, - 'update', '0', false, - 'update', + 'at $effect', '1', - true + true, + 'at $effect' ]); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-map-set/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-map-set/_config.js index 2052cb7f13..2f91e84288 100644 --- a/packages/svelte/tests/runtime-runes/samples/inspect-map-set/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/inspect-map-set/_config.js @@ -1,5 +1,6 @@ import { flushSync } from 'svelte'; import { test } from '../../test'; +import { normalise_inspect_logs } from '../../../helpers.js'; export default test({ compileOptions: { @@ -12,15 +13,13 @@ export default test({ btn2.click(); flushSync(); - assert.deepEqual(logs, [ - 'init', + assert.deepEqual(normalise_inspect_logs(logs), [ new Map(), - 'init', new Set(), - 'update', new Map([['a', 'a']]), - 'update', - new Set(['a']) + 'at SvelteMap.set', + new Set(['a']), + 'at SvelteSet.add' ]); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-multiple/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-multiple/_config.js index fc9a0cda9a..6886f5e53e 100644 --- a/packages/svelte/tests/runtime-runes/samples/inspect-multiple/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/inspect-multiple/_config.js @@ -1,3 +1,4 @@ +import { normalise_inspect_logs } from '../../../helpers.js'; import { test } from '../../test'; export default test({ @@ -11,6 +12,15 @@ export default test({ b2.click(); await Promise.resolve(); - assert.deepEqual(logs, ['init', 0, 0, 'update', 1, 0, 'update', 1, 1]); + assert.deepEqual(normalise_inspect_logs(logs), [ + 0, + 0, + 1, + 0, + 'at HTMLButtonElement.', + 1, + 1, + 'at HTMLButtonElement.' + ]); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-nested-effect/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-nested-effect/_config.js index 82429e5e36..86e65d5044 100644 --- a/packages/svelte/tests/runtime-runes/samples/inspect-nested-effect/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/inspect-nested-effect/_config.js @@ -1,3 +1,4 @@ +import { normalise_inspect_logs } from '../../../helpers.js'; import { test } from '../../test'; export default test({ @@ -6,6 +7,6 @@ export default test({ }, async test({ assert, logs }) { - assert.deepEqual(logs, ['init', 0, 'update', 1]); + assert.deepEqual(normalise_inspect_logs(logs), [0, 1, 'at $effect']); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-nested-state/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-nested-state/_config.js index e4d9fb5013..34cd74d780 100644 --- a/packages/svelte/tests/runtime-runes/samples/inspect-nested-state/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/inspect-nested-state/_config.js @@ -1,3 +1,4 @@ +import { normalise_inspect_logs } from '../../../helpers.js'; import { test } from '../../test'; export default test({ @@ -10,13 +11,12 @@ export default test({ b1.click(); await Promise.resolve(); - assert.deepEqual(logs, [ - 'init', + assert.deepEqual(normalise_inspect_logs(logs), [ { x: { count: 0 } }, [{ count: 0 }], - 'update', { x: { count: 1 } }, - [{ count: 1 }] + [{ count: 1 }], + 'at HTMLButtonElement.' ]); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-new-property/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-new-property/_config.js index a85972a0f9..8134044b16 100644 --- a/packages/svelte/tests/runtime-runes/samples/inspect-new-property/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/inspect-new-property/_config.js @@ -1,3 +1,4 @@ +import { normalise_inspect_logs } from '../../../helpers.js'; import { test } from '../../test'; export default test({ @@ -10,6 +11,13 @@ export default test({ btn.click(); await Promise.resolve(); - assert.deepEqual(logs, ['init', {}, 'init', [], 'update', { x: 'hello' }, 'update', ['hello']]); + assert.deepEqual(normalise_inspect_logs(logs), [ + {}, + [], + { x: 'hello' }, + 'at HTMLButtonElement.on_click', + ['hello'], + 'at HTMLButtonElement.on_click' + ]); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-recursive-2/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-recursive-2/_config.js index ab49697195..1bfc2dc68f 100644 --- a/packages/svelte/tests/runtime-runes/samples/inspect-recursive-2/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/inspect-recursive-2/_config.js @@ -18,6 +18,6 @@ export default test({ }; b.a.b = b; - assert.deepEqual(logs, ['init', a, 'init', b]); + assert.deepEqual(logs, [a, b]); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-recursive/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-recursive/_config.js index e35917b1f3..9d95956e7d 100644 --- a/packages/svelte/tests/runtime-runes/samples/inspect-recursive/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/inspect-recursive/_config.js @@ -1,3 +1,4 @@ +import { normalise_inspect_logs } from '../../../helpers.js'; import { test } from '../../test'; export default test({ @@ -11,6 +12,12 @@ export default test({ btn.click(); await Promise.resolve(); - assert.deepEqual(logs, ['init', [], 'update', [{}], 'update', [{}, {}]]); + assert.deepEqual(normalise_inspect_logs(logs), [ + [], + [{}], + 'at HTMLButtonElement.on_click', + [{}, {}], + 'at HTMLButtonElement.on_click' + ]); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect/_config.js index 09a921abee..c05c4b15c4 100644 --- a/packages/svelte/tests/runtime-runes/samples/inspect/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/inspect/_config.js @@ -1,3 +1,4 @@ +import { normalise_inspect_logs } from '../../../helpers.js'; import { test } from '../../test'; export default test({ @@ -11,6 +12,6 @@ export default test({ b2.click(); await Promise.resolve(); - assert.deepEqual(logs, ['init', 0, 'update', 1]); + assert.deepEqual(normalise_inspect_logs(logs), [0, 1, 'at HTMLButtonElement.']); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/_config.js b/packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/_config.js new file mode 100644 index 0000000000..900d6daff8 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/_config.js @@ -0,0 +1,22 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const btn = target.querySelector('button'); + + btn?.click(); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + +
Should not transition out
+ ` + ); + + btn?.click(); + flushSync(); + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/main.svelte b/packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/main.svelte new file mode 100644 index 0000000000..84f6ee77af --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/main.svelte @@ -0,0 +1,18 @@ + + + + + +{#if showText} + {#if show} +
+ Should not transition out +
+ {/if} +{/if} diff --git a/packages/svelte/tests/snapshot/samples/async-in-derived/_config.js b/packages/svelte/tests/snapshot/samples/async-in-derived/_config.js new file mode 100644 index 0000000000..2e30bbeb16 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/async-in-derived/_config.js @@ -0,0 +1,3 @@ +import { test } from '../../test'; + +export default test({ compileOptions: { experimental: { async: true } } }); diff --git a/packages/svelte/tests/snapshot/samples/async-in-derived/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/async-in-derived/_expected/client/index.svelte.js new file mode 100644 index 0000000000..7a97850175 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/async-in-derived/_expected/client/index.svelte.js @@ -0,0 +1,52 @@ +import 'svelte/internal/disclose-version'; +import 'svelte/internal/flags/async'; +import * as $ from 'svelte/internal/client'; + +export default function Async_in_derived($$anchor, $$props) { + $.push($$props, true); + + $.async_body($$anchor, async ($$anchor) => { + let yes1 = (await $.save($.async_derived(async () => (await $.save(1))())))(); + let yes2 = (await $.save($.async_derived(async () => foo((await $.save(1))()))))(); + + let no1 = $.derived(async () => { + return await 1; + }); + + let no2 = $.derived(() => async () => { + return await 1; + }); + + if ($.aborted()) return; + + var fragment = $.comment(); + var node = $.first_child(fragment); + + { + var consequent = ($$anchor) => { + $.async_body($$anchor, async ($$anchor) => { + const yes1 = (await $.save($.async_derived(async () => (await $.save(1))())))(); + const yes2 = (await $.save($.async_derived(async () => foo((await $.save(1))()))))(); + + const no1 = $.derived(() => (async () => { + return await 1; + })()); + + const no2 = $.derived(() => (async () => { + return await 1; + })()); + + if ($.aborted()) return; + }); + }; + + $.if(node, ($$render) => { + if (true) $$render(consequent); + }); + } + + $.append($$anchor, fragment); + }); + + $.pop(); +} \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/async-in-derived/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/async-in-derived/_expected/server/index.svelte.js new file mode 100644 index 0000000000..69eca5a383 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/async-in-derived/_expected/server/index.svelte.js @@ -0,0 +1,40 @@ +import 'svelte/internal/flags/async'; +import * as $ from 'svelte/internal/server'; + +export default function Async_in_derived($$renderer, $$props) { + $$renderer.component(($$renderer) => { + $$renderer.async(async ($$renderer) => { + let yes1 = (await $.save(1))(); + let yes2 = foo((await $.save(1))()); + + let no1 = (async () => { + return await 1; + })(); + + let no2 = async () => { + return await 1; + }; + + $$renderer.async(async ($$renderer) => { + if (true) { + $$renderer.push(''); + + const yes1 = (await $.save(1))(); + const yes2 = foo((await $.save(1))()); + + const no1 = (async () => { + return await 1; + })(); + + const no2 = (async () => { + return await 1; + })(); + } else { + $$renderer.push(''); + } + }); + + $$renderer.push(``); + }); + }); +} \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/async-in-derived/index.svelte b/packages/svelte/tests/snapshot/samples/async-in-derived/index.svelte new file mode 100644 index 0000000000..bda88fd3ae --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/async-in-derived/index.svelte @@ -0,0 +1,21 @@ + + +{#if true} + {@const yes1 = await 1} + {@const yes2 = foo(await 1)} + {@const no1 = (async () => { + return await 1; + })()} + {@const no2 = (async () => { + return await 1; + })()} +{/if} diff --git a/playgrounds/sandbox/package.json b/playgrounds/sandbox/package.json index 84aeab586b..629cb33b5a 100644 --- a/playgrounds/sandbox/package.json +++ b/playgrounds/sandbox/package.json @@ -21,7 +21,7 @@ "polka": "^1.0.0-next.25", "svelte": "workspace:*", "tinyglobby": "^0.2.12", - "vite": "^7.1.5", + "vite": "^7.1.11", "vite-plugin-devtools-json": "^1.0.0", "vite-plugin-inspect": "^11.3.3" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f585619252..0afaef0ceb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -158,7 +158,7 @@ importers: devDependencies: '@sveltejs/vite-plugin-svelte': specifier: ^6.2.0 - version: 6.2.0(svelte@packages+svelte)(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) + version: 6.2.0(svelte@packages+svelte)(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) '@types/node': specifier: ^24.5.2 version: 24.5.2 @@ -172,14 +172,14 @@ importers: specifier: ^0.2.12 version: 0.2.15 vite: - specifier: ^7.1.5 - version: 7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) + specifier: ^7.1.11 + version: 7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) vite-plugin-devtools-json: specifier: ^1.0.0 - version: 1.0.0(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) + version: 1.0.0(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) vite-plugin-inspect: specifier: ^11.3.3 - version: 11.3.3(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) + version: 11.3.3(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) packages: @@ -285,6 +285,12 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.25.11': + resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.21.5': resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} @@ -297,6 +303,12 @@ packages: cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.25.11': + resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.21.5': resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} @@ -309,6 +321,12 @@ packages: cpu: [arm] os: [android] + '@esbuild/android-arm@0.25.11': + resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.21.5': resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} @@ -321,6 +339,12 @@ packages: cpu: [x64] os: [android] + '@esbuild/android-x64@0.25.11': + resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.21.5': resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} @@ -333,6 +357,12 @@ packages: cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.25.11': + resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.21.5': resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} @@ -345,6 +375,12 @@ packages: cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.25.11': + resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.21.5': resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} @@ -357,6 +393,12 @@ packages: cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.25.11': + resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.21.5': resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} @@ -369,6 +411,12 @@ packages: cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.25.11': + resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.21.5': resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} @@ -381,6 +429,12 @@ packages: cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.25.11': + resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.21.5': resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} @@ -393,6 +447,12 @@ packages: cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.25.11': + resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.21.5': resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} @@ -405,6 +465,12 @@ packages: cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.25.11': + resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.21.5': resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} @@ -417,6 +483,12 @@ packages: cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.25.11': + resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.21.5': resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} @@ -429,6 +501,12 @@ packages: cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.25.11': + resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.21.5': resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} @@ -441,6 +519,12 @@ packages: cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.25.11': + resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.21.5': resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} @@ -453,6 +537,12 @@ packages: cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.25.11': + resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.21.5': resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} @@ -465,6 +555,12 @@ packages: cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.25.11': + resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.21.5': resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} @@ -477,12 +573,24 @@ packages: cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.25.11': + resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.10': resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.25.11': + resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.21.5': resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} @@ -495,12 +603,24 @@ packages: cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.25.11': + resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.10': resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.25.11': + resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.21.5': resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} @@ -513,12 +633,24 @@ packages: cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.25.11': + resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.10': resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.25.11': + resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.21.5': resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} @@ -531,6 +663,12 @@ packages: cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.25.11': + resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.21.5': resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} @@ -543,6 +681,12 @@ packages: cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.25.11': + resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.21.5': resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} @@ -555,6 +699,12 @@ packages: cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.25.11': + resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.21.5': resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} @@ -567,6 +717,12 @@ packages: cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.25.11': + resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -577,6 +733,10 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint/config-array@0.18.0': resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -722,51 +882,106 @@ packages: cpu: [arm] os: [android] + '@rollup/rollup-android-arm-eabi@4.52.5': + resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} + cpu: [arm] + os: [android] + '@rollup/rollup-android-arm64@4.50.1': resolution: {integrity: sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==} cpu: [arm64] os: [android] + '@rollup/rollup-android-arm64@4.52.5': + resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==} + cpu: [arm64] + os: [android] + '@rollup/rollup-darwin-arm64@4.50.1': resolution: {integrity: sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==} cpu: [arm64] os: [darwin] + '@rollup/rollup-darwin-arm64@4.52.5': + resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==} + cpu: [arm64] + os: [darwin] + '@rollup/rollup-darwin-x64@4.50.1': resolution: {integrity: sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==} cpu: [x64] os: [darwin] + '@rollup/rollup-darwin-x64@4.52.5': + resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==} + cpu: [x64] + os: [darwin] + '@rollup/rollup-freebsd-arm64@4.50.1': resolution: {integrity: sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==} cpu: [arm64] os: [freebsd] + '@rollup/rollup-freebsd-arm64@4.52.5': + resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==} + cpu: [arm64] + os: [freebsd] + '@rollup/rollup-freebsd-x64@4.50.1': resolution: {integrity: sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==} cpu: [x64] os: [freebsd] + '@rollup/rollup-freebsd-x64@4.52.5': + resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==} + cpu: [x64] + os: [freebsd] + '@rollup/rollup-linux-arm-gnueabihf@4.50.1': resolution: {integrity: sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==} cpu: [arm] os: [linux] + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==} + cpu: [arm] + os: [linux] + '@rollup/rollup-linux-arm-musleabihf@4.50.1': resolution: {integrity: sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==} cpu: [arm] os: [linux] + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==} + cpu: [arm] + os: [linux] + '@rollup/rollup-linux-arm64-gnu@4.50.1': resolution: {integrity: sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==} cpu: [arm64] os: [linux] + '@rollup/rollup-linux-arm64-gnu@4.52.5': + resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==} + cpu: [arm64] + os: [linux] + '@rollup/rollup-linux-arm64-musl@4.50.1': resolution: {integrity: sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==} cpu: [arm64] os: [linux] + '@rollup/rollup-linux-arm64-musl@4.52.5': + resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.52.5': + resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==} + cpu: [loong64] + os: [linux] + '@rollup/rollup-linux-loongarch64-gnu@4.50.1': resolution: {integrity: sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==} cpu: [loong64] @@ -777,51 +992,106 @@ packages: cpu: [ppc64] os: [linux] + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==} + cpu: [ppc64] + os: [linux] + '@rollup/rollup-linux-riscv64-gnu@4.50.1': resolution: {integrity: sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==} cpu: [riscv64] os: [linux] + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==} + cpu: [riscv64] + os: [linux] + '@rollup/rollup-linux-riscv64-musl@4.50.1': resolution: {integrity: sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==} cpu: [riscv64] os: [linux] + '@rollup/rollup-linux-riscv64-musl@4.52.5': + resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==} + cpu: [riscv64] + os: [linux] + '@rollup/rollup-linux-s390x-gnu@4.50.1': resolution: {integrity: sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==} cpu: [s390x] os: [linux] + '@rollup/rollup-linux-s390x-gnu@4.52.5': + resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==} + cpu: [s390x] + os: [linux] + '@rollup/rollup-linux-x64-gnu@4.50.1': resolution: {integrity: sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==} cpu: [x64] os: [linux] + '@rollup/rollup-linux-x64-gnu@4.52.5': + resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==} + cpu: [x64] + os: [linux] + '@rollup/rollup-linux-x64-musl@4.50.1': resolution: {integrity: sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==} cpu: [x64] os: [linux] + '@rollup/rollup-linux-x64-musl@4.52.5': + resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==} + cpu: [x64] + os: [linux] + '@rollup/rollup-openharmony-arm64@4.50.1': resolution: {integrity: sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==} cpu: [arm64] os: [openharmony] + '@rollup/rollup-openharmony-arm64@4.52.5': + resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==} + cpu: [arm64] + os: [openharmony] + '@rollup/rollup-win32-arm64-msvc@4.50.1': resolution: {integrity: sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==} cpu: [arm64] os: [win32] + '@rollup/rollup-win32-arm64-msvc@4.52.5': + resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==} + cpu: [arm64] + os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.50.1': resolution: {integrity: sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==} cpu: [ia32] os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.52.5': + resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.52.5': + resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==} + cpu: [x64] + os: [win32] + '@rollup/rollup-win32-x64-msvc@4.50.1': resolution: {integrity: sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==} cpu: [x64] os: [win32] + '@rollup/rollup-win32-x64-msvc@4.52.5': + resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==} + cpu: [x64] + os: [win32] + '@stylistic/eslint-plugin-js@1.8.0': resolution: {integrity: sha512-jdvnzt+pZPg8TfclZlTZPiUbbima93ylvQ+wNgHLNmup3obY6heQvgewSu9i2CfS61BnRByv+F9fxQLPoNeHag==} engines: {node: ^16.0.0 || >=18.0.0} @@ -905,8 +1175,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/project-service@8.43.0': - resolution: {integrity: sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==} + '@typescript-eslint/project-service@8.46.2': + resolution: {integrity: sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -915,12 +1185,12 @@ packages: resolution: {integrity: sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.43.0': - resolution: {integrity: sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==} + '@typescript-eslint/scope-manager@8.46.2': + resolution: {integrity: sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.43.0': - resolution: {integrity: sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==} + '@typescript-eslint/tsconfig-utils@8.46.2': + resolution: {integrity: sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -936,8 +1206,8 @@ packages: resolution: {integrity: sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.43.0': - resolution: {integrity: sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==} + '@typescript-eslint/types@8.46.2': + resolution: {integrity: sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@8.26.0': @@ -946,8 +1216,8 @@ packages: peerDependencies: typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/typescript-estree@8.43.0': - resolution: {integrity: sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==} + '@typescript-eslint/typescript-estree@8.46.2': + resolution: {integrity: sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -959,8 +1229,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/utils@8.43.0': - resolution: {integrity: sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==} + '@typescript-eslint/utils@8.46.2': + resolution: {integrity: sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -970,8 +1240,8 @@ packages: resolution: {integrity: sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.43.0': - resolution: {integrity: sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==} + '@typescript-eslint/visitor-keys@8.46.2': + resolution: {integrity: sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@vitest/coverage-v8@2.1.9': @@ -1197,6 +1467,15 @@ packages: supports-color: optional: true + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} @@ -1287,6 +1566,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.25.11: + resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} + engines: {node: '>=18'} + hasBin: true + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -1475,8 +1759,8 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - get-tsconfig@4.10.1: - resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} @@ -2062,6 +2346,11 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rollup@4.52.5: + resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + rrweb-cssom@0.7.1: resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} @@ -2096,6 +2385,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} @@ -2196,8 +2490,8 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - tapable@2.2.3: - resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==} + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} term-size@2.2.1: @@ -2394,8 +2688,8 @@ packages: terser: optional: true - vite@7.1.5: - resolution: {integrity: sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==} + vite@7.1.11: + resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -2731,147 +3025,225 @@ snapshots: '@esbuild/aix-ppc64@0.25.10': optional: true + '@esbuild/aix-ppc64@0.25.11': + optional: true + '@esbuild/android-arm64@0.21.5': optional: true '@esbuild/android-arm64@0.25.10': optional: true + '@esbuild/android-arm64@0.25.11': + optional: true + '@esbuild/android-arm@0.21.5': optional: true '@esbuild/android-arm@0.25.10': optional: true + '@esbuild/android-arm@0.25.11': + optional: true + '@esbuild/android-x64@0.21.5': optional: true '@esbuild/android-x64@0.25.10': optional: true + '@esbuild/android-x64@0.25.11': + optional: true + '@esbuild/darwin-arm64@0.21.5': optional: true '@esbuild/darwin-arm64@0.25.10': optional: true + '@esbuild/darwin-arm64@0.25.11': + optional: true + '@esbuild/darwin-x64@0.21.5': optional: true '@esbuild/darwin-x64@0.25.10': optional: true + '@esbuild/darwin-x64@0.25.11': + optional: true + '@esbuild/freebsd-arm64@0.21.5': optional: true '@esbuild/freebsd-arm64@0.25.10': optional: true + '@esbuild/freebsd-arm64@0.25.11': + optional: true + '@esbuild/freebsd-x64@0.21.5': optional: true '@esbuild/freebsd-x64@0.25.10': optional: true + '@esbuild/freebsd-x64@0.25.11': + optional: true + '@esbuild/linux-arm64@0.21.5': optional: true '@esbuild/linux-arm64@0.25.10': optional: true + '@esbuild/linux-arm64@0.25.11': + optional: true + '@esbuild/linux-arm@0.21.5': optional: true '@esbuild/linux-arm@0.25.10': optional: true + '@esbuild/linux-arm@0.25.11': + optional: true + '@esbuild/linux-ia32@0.21.5': optional: true '@esbuild/linux-ia32@0.25.10': optional: true + '@esbuild/linux-ia32@0.25.11': + optional: true + '@esbuild/linux-loong64@0.21.5': optional: true '@esbuild/linux-loong64@0.25.10': optional: true + '@esbuild/linux-loong64@0.25.11': + optional: true + '@esbuild/linux-mips64el@0.21.5': optional: true '@esbuild/linux-mips64el@0.25.10': optional: true + '@esbuild/linux-mips64el@0.25.11': + optional: true + '@esbuild/linux-ppc64@0.21.5': optional: true '@esbuild/linux-ppc64@0.25.10': optional: true + '@esbuild/linux-ppc64@0.25.11': + optional: true + '@esbuild/linux-riscv64@0.21.5': optional: true '@esbuild/linux-riscv64@0.25.10': optional: true + '@esbuild/linux-riscv64@0.25.11': + optional: true + '@esbuild/linux-s390x@0.21.5': optional: true '@esbuild/linux-s390x@0.25.10': optional: true + '@esbuild/linux-s390x@0.25.11': + optional: true + '@esbuild/linux-x64@0.21.5': optional: true '@esbuild/linux-x64@0.25.10': optional: true + '@esbuild/linux-x64@0.25.11': + optional: true + '@esbuild/netbsd-arm64@0.25.10': optional: true + '@esbuild/netbsd-arm64@0.25.11': + optional: true + '@esbuild/netbsd-x64@0.21.5': optional: true '@esbuild/netbsd-x64@0.25.10': optional: true + '@esbuild/netbsd-x64@0.25.11': + optional: true + '@esbuild/openbsd-arm64@0.25.10': optional: true + '@esbuild/openbsd-arm64@0.25.11': + optional: true + '@esbuild/openbsd-x64@0.21.5': optional: true '@esbuild/openbsd-x64@0.25.10': optional: true + '@esbuild/openbsd-x64@0.25.11': + optional: true + '@esbuild/openharmony-arm64@0.25.10': optional: true + '@esbuild/openharmony-arm64@0.25.11': + optional: true + '@esbuild/sunos-x64@0.21.5': optional: true '@esbuild/sunos-x64@0.25.10': optional: true + '@esbuild/sunos-x64@0.25.11': + optional: true + '@esbuild/win32-arm64@0.21.5': optional: true '@esbuild/win32-arm64@0.25.10': optional: true + '@esbuild/win32-arm64@0.25.11': + optional: true + '@esbuild/win32-ia32@0.21.5': optional: true '@esbuild/win32-ia32@0.25.10': optional: true + '@esbuild/win32-ia32@0.25.11': + optional: true + '@esbuild/win32-x64@0.21.5': optional: true '@esbuild/win32-x64@0.25.10': optional: true + '@esbuild/win32-x64@0.25.11': + optional: true + '@eslint-community/eslint-utils@4.9.0(eslint@9.9.1)': dependencies: eslint: 9.9.1 @@ -2879,6 +3251,8 @@ snapshots: '@eslint-community/regexpp@4.12.1': {} + '@eslint-community/regexpp@4.12.2': {} + '@eslint/config-array@0.18.0': dependencies: '@eslint/object-schema': 2.1.4 @@ -3036,66 +3410,132 @@ snapshots: '@rollup/rollup-android-arm-eabi@4.50.1': optional: true + '@rollup/rollup-android-arm-eabi@4.52.5': + optional: true + '@rollup/rollup-android-arm64@4.50.1': optional: true + '@rollup/rollup-android-arm64@4.52.5': + optional: true + '@rollup/rollup-darwin-arm64@4.50.1': optional: true + '@rollup/rollup-darwin-arm64@4.52.5': + optional: true + '@rollup/rollup-darwin-x64@4.50.1': optional: true + '@rollup/rollup-darwin-x64@4.52.5': + optional: true + '@rollup/rollup-freebsd-arm64@4.50.1': optional: true + '@rollup/rollup-freebsd-arm64@4.52.5': + optional: true + '@rollup/rollup-freebsd-x64@4.50.1': optional: true + '@rollup/rollup-freebsd-x64@4.52.5': + optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.50.1': optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + optional: true + '@rollup/rollup-linux-arm-musleabihf@4.50.1': optional: true + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + optional: true + '@rollup/rollup-linux-arm64-gnu@4.50.1': optional: true + '@rollup/rollup-linux-arm64-gnu@4.52.5': + optional: true + '@rollup/rollup-linux-arm64-musl@4.50.1': optional: true + '@rollup/rollup-linux-arm64-musl@4.52.5': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.52.5': + optional: true + '@rollup/rollup-linux-loongarch64-gnu@4.50.1': optional: true '@rollup/rollup-linux-ppc64-gnu@4.50.1': optional: true + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + optional: true + '@rollup/rollup-linux-riscv64-gnu@4.50.1': optional: true + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + optional: true + '@rollup/rollup-linux-riscv64-musl@4.50.1': optional: true + '@rollup/rollup-linux-riscv64-musl@4.52.5': + optional: true + '@rollup/rollup-linux-s390x-gnu@4.50.1': optional: true + '@rollup/rollup-linux-s390x-gnu@4.52.5': + optional: true + '@rollup/rollup-linux-x64-gnu@4.50.1': optional: true + '@rollup/rollup-linux-x64-gnu@4.52.5': + optional: true + '@rollup/rollup-linux-x64-musl@4.50.1': optional: true + '@rollup/rollup-linux-x64-musl@4.52.5': + optional: true + '@rollup/rollup-openharmony-arm64@4.50.1': optional: true + '@rollup/rollup-openharmony-arm64@4.52.5': + optional: true + '@rollup/rollup-win32-arm64-msvc@4.50.1': optional: true + '@rollup/rollup-win32-arm64-msvc@4.52.5': + optional: true + '@rollup/rollup-win32-ia32-msvc@4.50.1': optional: true + '@rollup/rollup-win32-ia32-msvc@4.52.5': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.52.5': + optional: true + '@rollup/rollup-win32-x64-msvc@4.50.1': optional: true + '@rollup/rollup-win32-x64-msvc@4.52.5': + optional: true + '@stylistic/eslint-plugin-js@1.8.0(eslint@9.9.1)': dependencies: '@types/eslint': 8.56.12 @@ -3120,24 +3560,24 @@ snapshots: typescript: 5.5.4 typescript-eslint: 8.26.0(eslint@9.9.1)(typescript@5.5.4) - '@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@packages+svelte)(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)))(svelte@packages+svelte)(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))': + '@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@packages+svelte)(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)))(svelte@packages+svelte)(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 6.2.0(svelte@packages+svelte)(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) + '@sveltejs/vite-plugin-svelte': 6.2.0(svelte@packages+svelte)(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) debug: 4.4.1 svelte: link:packages/svelte - vite: 7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) + vite: 7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@6.2.0(svelte@packages+svelte)(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))': + '@sveltejs/vite-plugin-svelte@6.2.0(svelte@packages+svelte)(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@packages+svelte)(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)))(svelte@packages+svelte)(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) + '@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@packages+svelte)(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)))(svelte@packages+svelte)(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) debug: 4.4.1 deepmerge: 4.3.1 magic-string: 0.30.17 svelte: link:packages/svelte - vite: 7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) - vitefu: 1.1.1(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) + vite: 7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) + vitefu: 1.1.1(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) transitivePeerDependencies: - supports-color @@ -3202,11 +3642,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.43.0(typescript@5.5.4)': + '@typescript-eslint/project-service@8.46.2(typescript@5.5.4)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.5.4) - '@typescript-eslint/types': 8.43.0 - debug: 4.4.1 + '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.5.4) + '@typescript-eslint/types': 8.46.2 + debug: 4.4.3 typescript: 5.5.4 transitivePeerDependencies: - supports-color @@ -3216,12 +3656,12 @@ snapshots: '@typescript-eslint/types': 8.26.0 '@typescript-eslint/visitor-keys': 8.26.0 - '@typescript-eslint/scope-manager@8.43.0': + '@typescript-eslint/scope-manager@8.46.2': dependencies: - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/visitor-keys': 8.43.0 + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/visitor-keys': 8.46.2 - '@typescript-eslint/tsconfig-utils@8.43.0(typescript@5.5.4)': + '@typescript-eslint/tsconfig-utils@8.46.2(typescript@5.5.4)': dependencies: typescript: 5.5.4 @@ -3238,7 +3678,7 @@ snapshots: '@typescript-eslint/types@8.26.0': {} - '@typescript-eslint/types@8.43.0': {} + '@typescript-eslint/types@8.46.2': {} '@typescript-eslint/typescript-estree@8.26.0(typescript@5.5.4)': dependencies: @@ -3254,17 +3694,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.43.0(typescript@5.5.4)': + '@typescript-eslint/typescript-estree@8.46.2(typescript@5.5.4)': dependencies: - '@typescript-eslint/project-service': 8.43.0(typescript@5.5.4) - '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.5.4) - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/visitor-keys': 8.43.0 - debug: 4.4.1 + '@typescript-eslint/project-service': 8.46.2(typescript@5.5.4) + '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.5.4) + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/visitor-keys': 8.46.2 + debug: 4.4.3 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.2 + semver: 7.7.3 ts-api-utils: 2.1.0(typescript@5.5.4) typescript: 5.5.4 transitivePeerDependencies: @@ -3281,12 +3721,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.43.0(eslint@9.9.1)(typescript@5.5.4)': + '@typescript-eslint/utils@8.46.2(eslint@9.9.1)(typescript@5.5.4)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.9.1) - '@typescript-eslint/scope-manager': 8.43.0 - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.5.4) + '@typescript-eslint/scope-manager': 8.46.2 + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.5.4) eslint: 9.9.1 typescript: 5.5.4 transitivePeerDependencies: @@ -3297,9 +3737,9 @@ snapshots: '@typescript-eslint/types': 8.26.0 eslint-visitor-keys: 4.2.1 - '@typescript-eslint/visitor-keys@8.43.0': + '@typescript-eslint/visitor-keys@8.46.2': dependencies: - '@typescript-eslint/types': 8.43.0 + '@typescript-eslint/types': 8.46.2 eslint-visitor-keys: 4.2.1 '@vitest/coverage-v8@2.1.9(vitest@2.1.9(@types/node@20.19.17)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))': @@ -3522,6 +3962,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.3: + dependencies: + ms: 2.1.3 + decimal.js@10.4.3: {} deep-eql@5.0.2: {} @@ -3573,7 +4017,7 @@ snapshots: enhanced-resolve@5.18.3: dependencies: graceful-fs: 4.2.11 - tapable: 2.2.3 + tapable: 2.3.0 enquirer@2.4.1: dependencies: @@ -3641,12 +4085,41 @@ snapshots: '@esbuild/win32-ia32': 0.25.10 '@esbuild/win32-x64': 0.25.10 + esbuild@0.25.11: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.11 + '@esbuild/android-arm': 0.25.11 + '@esbuild/android-arm64': 0.25.11 + '@esbuild/android-x64': 0.25.11 + '@esbuild/darwin-arm64': 0.25.11 + '@esbuild/darwin-x64': 0.25.11 + '@esbuild/freebsd-arm64': 0.25.11 + '@esbuild/freebsd-x64': 0.25.11 + '@esbuild/linux-arm': 0.25.11 + '@esbuild/linux-arm64': 0.25.11 + '@esbuild/linux-ia32': 0.25.11 + '@esbuild/linux-loong64': 0.25.11 + '@esbuild/linux-mips64el': 0.25.11 + '@esbuild/linux-ppc64': 0.25.11 + '@esbuild/linux-riscv64': 0.25.11 + '@esbuild/linux-s390x': 0.25.11 + '@esbuild/linux-x64': 0.25.11 + '@esbuild/netbsd-arm64': 0.25.11 + '@esbuild/netbsd-x64': 0.25.11 + '@esbuild/openbsd-arm64': 0.25.11 + '@esbuild/openbsd-x64': 0.25.11 + '@esbuild/openharmony-arm64': 0.25.11 + '@esbuild/sunos-x64': 0.25.11 + '@esbuild/win32-arm64': 0.25.11 + '@esbuild/win32-ia32': 0.25.11 + '@esbuild/win32-x64': 0.25.11 + escape-string-regexp@4.0.0: {} eslint-compat-utils@0.5.1(eslint@9.9.1): dependencies: eslint: 9.9.1 - semver: 7.7.2 + semver: 7.7.3 eslint-config-prettier@9.1.0(eslint@9.9.1): dependencies: @@ -3655,7 +4128,7 @@ snapshots: eslint-plugin-es-x@7.8.0(eslint@9.9.1): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.9.1) - '@eslint-community/regexpp': 4.12.1 + '@eslint-community/regexpp': 4.12.2 eslint: 9.9.1 eslint-compat-utils: 0.5.1(eslint@9.9.1) @@ -3664,15 +4137,15 @@ snapshots: eslint-plugin-n@17.16.1(eslint@9.9.1)(typescript@5.5.4): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.9.1) - '@typescript-eslint/utils': 8.43.0(eslint@9.9.1)(typescript@5.5.4) + '@typescript-eslint/utils': 8.46.2(eslint@9.9.1)(typescript@5.5.4) enhanced-resolve: 5.18.3 eslint: 9.9.1 eslint-plugin-es-x: 7.8.0(eslint@9.9.1) - get-tsconfig: 4.10.1 + get-tsconfig: 4.13.0 globals: 15.15.0 ignore: 5.3.2 minimatch: 9.0.5 - semver: 7.7.2 + semver: 7.7.3 ts-declaration-location: 1.0.7(typescript@5.5.4) transitivePeerDependencies: - supports-color @@ -3864,7 +4337,7 @@ snapshots: function-bind@1.1.2: {} - get-tsconfig@4.10.1: + get-tsconfig@4.13.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -4408,6 +4881,34 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.50.1 fsevents: 2.3.3 + rollup@4.52.5: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.52.5 + '@rollup/rollup-android-arm64': 4.52.5 + '@rollup/rollup-darwin-arm64': 4.52.5 + '@rollup/rollup-darwin-x64': 4.52.5 + '@rollup/rollup-freebsd-arm64': 4.52.5 + '@rollup/rollup-freebsd-x64': 4.52.5 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.5 + '@rollup/rollup-linux-arm-musleabihf': 4.52.5 + '@rollup/rollup-linux-arm64-gnu': 4.52.5 + '@rollup/rollup-linux-arm64-musl': 4.52.5 + '@rollup/rollup-linux-loong64-gnu': 4.52.5 + '@rollup/rollup-linux-ppc64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-musl': 4.52.5 + '@rollup/rollup-linux-s390x-gnu': 4.52.5 + '@rollup/rollup-linux-x64-gnu': 4.52.5 + '@rollup/rollup-linux-x64-musl': 4.52.5 + '@rollup/rollup-openharmony-arm64': 4.52.5 + '@rollup/rollup-win32-arm64-msvc': 4.52.5 + '@rollup/rollup-win32-ia32-msvc': 4.52.5 + '@rollup/rollup-win32-x64-gnu': 4.52.5 + '@rollup/rollup-win32-x64-msvc': 4.52.5 + fsevents: 2.3.3 + rrweb-cssom@0.7.1: {} run-applescript@7.0.0: {} @@ -4437,6 +4938,8 @@ snapshots: semver@7.7.2: {} + semver@7.7.3: {} + serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 @@ -4526,7 +5029,7 @@ snapshots: symbol-tree@3.2.4: {} - tapable@2.2.3: {} + tapable@2.3.0: {} term-size@2.2.1: {} @@ -4638,15 +5141,15 @@ snapshots: v8-natives@1.2.5: {} - vite-dev-rpc@1.1.0(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)): + vite-dev-rpc@1.1.0(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)): dependencies: birpc: 2.5.0 - vite: 7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) - vite-hot-client: 2.1.0(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) + vite: 7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) + vite-hot-client: 2.1.0(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) - vite-hot-client@2.1.0(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)): + vite-hot-client@2.1.0(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)): dependencies: - vite: 7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) + vite: 7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) vite-node@2.1.9(@types/node@20.19.17)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0): dependencies: @@ -4666,12 +5169,12 @@ snapshots: - supports-color - terser - vite-plugin-devtools-json@1.0.0(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)): + vite-plugin-devtools-json@1.0.0(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)): dependencies: uuid: 11.1.0 - vite: 7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) + vite: 7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) - vite-plugin-inspect@11.3.3(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)): + vite-plugin-inspect@11.3.3(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)): dependencies: ansis: 4.1.0 debug: 4.4.1 @@ -4681,8 +5184,8 @@ snapshots: perfect-debounce: 2.0.0 sirv: 3.0.2 unplugin-utils: 0.3.0 - vite: 7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) - vite-dev-rpc: 1.1.0(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) + vite: 7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) + vite-dev-rpc: 1.1.0(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) transitivePeerDependencies: - supports-color @@ -4698,13 +5201,13 @@ snapshots: sass: 1.70.0 terser: 5.27.0 - vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0): + vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0): dependencies: - esbuild: 0.25.10 + esbuild: 0.25.11 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.50.1 + rollup: 4.52.5 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.5.2 @@ -4713,9 +5216,9 @@ snapshots: sass: 1.70.0 terser: 5.27.0 - vitefu@1.1.1(vite@7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)): + vitefu@1.1.1(vite@7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)): optionalDependencies: - vite: 7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) + vite: 7.1.11(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) vitest@2.1.9(@types/node@20.19.17)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0): dependencies: