Merge remote-tracking branch 'upstream/main' into $state-invalidate

pull/15673/head
ComputerGuy 5 months ago
commit 1d3833f3b5

@ -1,5 +0,0 @@
---
'svelte': patch
---
fix: ensure clearing of old values happens independent of root flushes

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: set deriveds as `CLEAN` if they are assigned to

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: better scope `:global()` with nesting selector `&`

@ -11,13 +11,10 @@ jobs:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: install corepack
run: npm i -g corepack@0.31.0
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: 18.x node-version: 22.x
cache: pnpm cache: pnpm
- name: Install dependencies - name: Install dependencies

@ -25,7 +25,7 @@ You can create an effect with the `$effect` rune ([demo](/playground/untitled#H4
}); });
</script> </script>
<canvas bind:this={canvas} width="100" height="100" /> <canvas bind:this={canvas} width="100" height="100"></canvas>
``` ```
When Svelte runs an effect function, it tracks which pieces of state (and derived state) are accessed (unless accessed inside [`untrack`](svelte#untrack)), and re-runs the function when that state later changes. When Svelte runs an effect function, it tracks which pieces of state (and derived state) are accessed (unless accessed inside [`untrack`](svelte#untrack)), and re-runs the function when that state later changes.
@ -135,19 +135,33 @@ An effect only reruns when the object it reads changes, not when a property insi
An effect only depends on the values that it read the last time it ran. This has interesting implications for effects that have conditional code. An effect only depends on the values that it read the last time it ran. This has interesting implications for effects that have conditional code.
For instance, if `a` is `true` in the code snippet below, the code inside the `if` block will run and `b` will be evaluated. As such, changes to either `a` or `b` [will cause the effect to re-run](/playground/untitled#H4sIAAAAAAAAE3VQzWrDMAx-FdUU4kBp71li6EPstOxge0ox8-QQK2PD-N1nLy2F0Z2Evj9_chKkP1B04pnYscc3cRCT8xhF95IEf8-Vq0DBr8rzPB_jJ3qumNERH-E2ECNxiRF9tIubWY00lgcYNAywj6wZJS8rtk83wjwgCrXHaULLUrYwKEgVGrnkx-Dx6MNFNstK5OjSbFGbwE0gdXuT_zGYrjmAuco515Hr1p_uXak3K3MgCGS9s-9D2grU-judlQYXIencnzad-tdR79qZrMyvw9wd5Z8Yv1h09dz8mn8AkM7Pfo0BAAA=). For instance, if `condition` is `true` in the code snippet below, the code inside the `if` block will run and `color` will be evaluated. As such, changes to either `condition` or `color` [will cause the effect to re-run](/playground/untitled#H4sIAAAAAAAAE21RQW6DMBD8ytaNBJHaJFLViwNIVZ8RcnBgXVk1xsILTYT4e20TQg89IOPZ2fHM7siMaJBx9tmaWpFqjQNlAKXEihx7YVJpdIyfRkY3G4gB8Pi97cPanRtQU8AuwuF_eNUaQuPlOMtc1SlLRWlKUo1tOwJflUikQHZtA0klzCDc64Imx0ANn8bInV1CDhtHgjClrsftcSXotluLybOUb3g4JJHhOZs5WZpuIS9gjNqkJKQP5e2ClrR4SMdZ13E4xZ8zTPOTJU2A2uE_PQ9COCI926_hTVarIU4hu_REPlBrKq2q73ycrf1N-vS4TMUsulaVg3EtR8H9rFgsg8uUsT1B2F9eshigZHBRpuaD0D3mY8Qm2BfB5N2YyRzdNEYVDy0Ja-WsFjcOUuP1HvFLWA6H3XuHTUSmmDV2--0TXonxsKbp7G9C6R__NONS-MFNvxj_d6mBAgAA).
Conversely, if `a` is `false`, `b` will not be evaluated, and the effect will _only_ re-run when `a` changes. Conversely, if `condition` is `false`, `color` will not be evaluated, and the effect will _only_ re-run again when `condition` changes.
```ts ```ts
let a = false; // @filename: ambient.d.ts
let b = false; declare module 'canvas-confetti' {
interface ConfettiOptions {
colors: string[];
}
function confetti(opts?: ConfettiOptions): void;
export default confetti;
}
// @filename: index.js
// ---cut--- // ---cut---
$effect(() => { import confetti from 'canvas-confetti';
console.log('running');
if (a) { let condition = $state(true);
console.log('b:', b); let color = $state('#ff3e00');
$effect(() => {
if (condition) {
confetti({ colors: [color] });
} else {
confetti();
} }
}); });
``` ```
@ -211,20 +225,19 @@ It is used to implement abstractions like [`createSubscriber`](/docs/svelte/svel
The `$effect.root` rune is an advanced feature that creates a non-tracked scope that doesn't auto-cleanup. This is useful for nested effects that you want to manually control. This rune also allows for the creation of effects outside of the component initialisation phase. The `$effect.root` rune is an advanced feature that creates a non-tracked scope that doesn't auto-cleanup. This is useful for nested effects that you want to manually control. This rune also allows for the creation of effects outside of the component initialisation phase.
```svelte ```js
<script> const destroy = $effect.root(() => {
let count = $state(0); $effect(() => {
// setup
});
const cleanup = $effect.root(() => { return () => {
$effect(() => { // cleanup
console.log(count); };
}); });
return () => { // later...
console.log('effect root cleanup'); destroy();
};
});
</script>
``` ```
## When not to use `$effect` ## When not to use `$effect`

@ -2,7 +2,7 @@
title: $host title: $host
--- ---
When compiling a component as a custom element, the `$host` rune provides access to the host element, allowing you to (for example) dispatch custom events ([demo](/playground/untitled#H4sIAAAAAAAAE41Ry2rDMBD8FSECtqkTt1fHFpSSL-ix7sFRNkTEXglrnTYY_3uRlDgxTaEHIfYxs7szA9-rBizPPwZOZwM89wmecqxbF70as7InaMjltrWFR3mpkQDJ8pwXVnbKkKiwItUa3RGLVtk7gTHQXRDR2lXda4CY1D0SK9nCUk0QPyfrCovsRoNFe17aQOAwGncgO2gBqRzihJXiQrEs2csYOhQ-7HgKHaLIbpRhhBG-I2eD_8ciM4KnnOCbeE5dD2P6h0Dz0-Yi_arNhPLJXBtSGi2TvSXdbpqwdsXvjuYsC1veabvvUTog2ylrapKH2G2XsMFLS4uDthQnq2t1cwKkGOGLvYU5PvaQxLsxOkPmsm97Io1Mo2yUPF6VnOZFkw1RMoopKLKAE_9gmGxyDFMwMcwN-Bx_ABXQWmOtAgAA)): When compiling a component as a [custom element](custom-elements), the `$host` rune provides access to the host element, allowing you to (for example) dispatch custom events ([demo](/playground/untitled#H4sIAAAAAAAAE41Ry2rDMBD8FSECtqkTt1fHFpSSL-ix7sFRNkTEXglrnTYY_3uRlDgxTaEHIfYxs7szA9-rBizPPwZOZwM89wmecqxbF70as7InaMjltrWFR3mpkQDJ8pwXVnbKkKiwItUa3RGLVtk7gTHQXRDR2lXda4CY1D0SK9nCUk0QPyfrCovsRoNFe17aQOAwGncgO2gBqRzihJXiQrEs2csYOhQ-7HgKHaLIbpRhhBG-I2eD_8ciM4KnnOCbeE5dD2P6h0Dz0-Yi_arNhPLJXBtSGi2TvSXdbpqwdsXvjuYsC1veabvvUTog2ylrapKH2G2XsMFLS4uDthQnq2t1cwKkGOGLvYU5PvaQxLsxOkPmsm97Io1Mo2yUPF6VnOZFkw1RMoopKLKAE_9gmGxyDFMwMcwN-Bx_ABXQWmOtAgAA)):
<!-- prettier-ignore --> <!-- prettier-ignore -->
```svelte ```svelte

@ -22,10 +22,6 @@ The `transition:` directive indicates a _bidirectional_ transition, which means
{/if} {/if}
``` ```
## Built-in transitions
A selection of built-in transitions can be imported from the [`svelte/transition`](svelte-transition) module.
## Local vs global ## Local vs global
Transitions are local by default. Local transitions only play when the block they belong to is created or destroyed, _not_ when parent blocks are created or destroyed. Transitions are local by default. Local transitions only play when the block they belong to is created or destroyed, _not_ when parent blocks are created or destroyed.
@ -40,6 +36,10 @@ Transitions are local by default. Local transitions only play when the block the
{/if} {/if}
``` ```
## Built-in transitions
A selection of built-in transitions can be imported from the [`svelte/transition`](svelte-transition) module.
## Transition parameters ## Transition parameters
Transitions can have parameters. Transitions can have parameters.

@ -94,7 +94,7 @@ interface User {}
// ---cut--- // ---cut---
import { getContext, setContext } from 'svelte'; import { getContext, setContext } from 'svelte';
let key = {}; const key = {};
/** @param {User} user */ /** @param {User} user */
export function setUserContext(user) { export function setUserContext(user) {

@ -161,7 +161,7 @@ Tried to unmount a component that was not mounted
### ownership_invalid_binding ### ownership_invalid_binding
``` ```
%parent% passed a value to %child% with `bind:`, but the value is owned by %owner%. Consider creating a binding between %owner% and %parent% %parent% passed property `%prop%` to %child% with `bind:`, but its parent component %owner% did not declare `%prop%` as a binding. Consider creating a binding between %owner% and %parent% (e.g. `bind:%prop%={...}` instead of `%prop%={...}`)
``` ```
Consider three components `GrandParent`, `Parent` and `Child`. If you do `<GrandParent bind:value>`, inside `GrandParent` pass on the variable via `<Parent {value} />` (note the missing `bind:`) and then do `<Child bind:value>` inside `Parent`, this warning is thrown. Consider three components `GrandParent`, `Parent` and `Child`. If you do `<GrandParent bind:value>`, inside `GrandParent` pass on the variable via `<Parent {value} />` (note the missing `bind:`) and then do `<Child bind:value>` inside `Parent`, this warning is thrown.
@ -171,11 +171,7 @@ To fix it, `bind:` to the value instead of just passing a property (i.e. in this
### ownership_invalid_mutation ### ownership_invalid_mutation
``` ```
Mutating a value outside the component that created it is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead Mutating unbound props (`%name%`, at %location%) is strongly discouraged. Consider using `bind:%prop%={...}` in %parent% (or using a callback) instead
```
```
%component% mutated a value owned by %owner%. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead
``` ```
Consider the following code: Consider the following code:

@ -5,7 +5,7 @@
"private": true, "private": true,
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"packageManager": "pnpm@9.4.0", "packageManager": "pnpm@10.4.0",
"engines": { "engines": {
"pnpm": ">=9.0.0" "pnpm": ">=9.0.0"
}, },

@ -1,5 +1,25 @@
# svelte # svelte
## 5.25.9
### Patch Changes
- fix: allow `$.state` and `$.derived` to be treeshaken ([#15702](https://github.com/sveltejs/svelte/pull/15702))
- fix: rework binding ownership validation ([#15678](https://github.com/sveltejs/svelte/pull/15678))
## 5.25.8
### Patch Changes
- fix: address untracked_writes memory leak ([#15694](https://github.com/sveltejs/svelte/pull/15694))
## 5.25.7
### Patch Changes
- fix: ensure clearing of old values happens independent of root flushes ([#15664](https://github.com/sveltejs/svelte/pull/15664))
## 5.25.6 ## 5.25.6
### Patch Changes ### Patch Changes

@ -132,7 +132,7 @@ During development, this error is often preceeded by a `console.error` detailing
## ownership_invalid_binding ## ownership_invalid_binding
> %parent% passed a value to %child% with `bind:`, but the value is owned by %owner%. Consider creating a binding between %owner% and %parent% > %parent% passed property `%prop%` to %child% with `bind:`, but its parent component %owner% did not declare `%prop%` as a binding. Consider creating a binding between %owner% and %parent% (e.g. `bind:%prop%={...}` instead of `%prop%={...}`)
Consider three components `GrandParent`, `Parent` and `Child`. If you do `<GrandParent bind:value>`, inside `GrandParent` pass on the variable via `<Parent {value} />` (note the missing `bind:`) and then do `<Child bind:value>` inside `Parent`, this warning is thrown. Consider three components `GrandParent`, `Parent` and `Child`. If you do `<GrandParent bind:value>`, inside `GrandParent` pass on the variable via `<Parent {value} />` (note the missing `bind:`) and then do `<Child bind:value>` inside `Parent`, this warning is thrown.
@ -140,9 +140,7 @@ To fix it, `bind:` to the value instead of just passing a property (i.e. in this
## ownership_invalid_mutation ## ownership_invalid_mutation
> Mutating a value outside the component that created it is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead > Mutating unbound props (`%name%`, at %location%) is strongly discouraged. Consider using `bind:%prop%={...}` in %parent% (or using a callback) instead
> %component% mutated a value owned by %owner%. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead
Consider the following code: Consider the following code:

@ -2,7 +2,7 @@
"name": "svelte", "name": "svelte",
"description": "Cybernetically enhanced web apps", "description": "Cybernetically enhanced web apps",
"license": "MIT", "license": "MIT",
"version": "5.25.6", "version": "5.25.9",
"type": "module", "type": "module",
"types": "./types/index.d.ts", "types": "./types/index.d.ts",
"engines": { "engines": {

@ -1,6 +1,11 @@
/** @import * as Compiler from '#compiler' */ /** @import * as Compiler from '#compiler' */
import { walk } from 'zimmerframe'; import { walk } from 'zimmerframe';
import { get_parent_rules, get_possible_values, is_outer_global } from './utils.js'; import {
get_parent_rules,
get_possible_values,
is_outer_global,
is_unscoped_pseudo_class
} from './utils.js';
import { regex_ends_with_whitespace, regex_starts_with_whitespace } from '../../patterns.js'; import { regex_ends_with_whitespace, regex_starts_with_whitespace } from '../../patterns.js';
import { get_attribute_chunks, is_text_attribute } from '../../../utils/ast.js'; import { get_attribute_chunks, is_text_attribute } from '../../../utils/ast.js';
@ -286,20 +291,26 @@ function apply_combinator(relative_selector, rest_selectors, rule, node, directi
* a global selector * a global selector
* @param {Compiler.AST.CSS.RelativeSelector} selector * @param {Compiler.AST.CSS.RelativeSelector} selector
* @param {Compiler.AST.CSS.Rule} rule * @param {Compiler.AST.CSS.Rule} rule
* @returns {boolean}
*/ */
function is_global(selector, rule) { function is_global(selector, rule) {
if (selector.metadata.is_global || selector.metadata.is_global_like) { if (selector.metadata.is_global || selector.metadata.is_global_like) {
return true; return true;
} }
let explicitly_global = false;
for (const s of selector.selectors) { for (const s of selector.selectors) {
/** @type {Compiler.AST.CSS.SelectorList | null} */ /** @type {Compiler.AST.CSS.SelectorList | null} */
let selector_list = null; let selector_list = null;
let can_be_global = false;
let owner = rule; let owner = rule;
if (s.type === 'PseudoClassSelector') { if (s.type === 'PseudoClassSelector') {
if ((s.name === 'is' || s.name === 'where') && s.args) { if ((s.name === 'is' || s.name === 'where') && s.args) {
selector_list = s.args; selector_list = s.args;
} else {
can_be_global = is_unscoped_pseudo_class(s);
} }
} }
@ -308,18 +319,19 @@ function is_global(selector, rule) {
selector_list = owner.prelude; selector_list = owner.prelude;
} }
const has_global_selectors = selector_list?.children.some((complex_selector) => { const has_global_selectors = !!selector_list?.children.some((complex_selector) => {
return complex_selector.children.every((relative_selector) => return complex_selector.children.every((relative_selector) =>
is_global(relative_selector, owner) is_global(relative_selector, owner)
); );
}); });
explicitly_global ||= has_global_selectors;
if (!has_global_selectors) { if (!has_global_selectors && !can_be_global) {
return false; return false;
} }
} }
return true; return explicitly_global || selector.selectors.length === 0;
} }
const regex_backslash_and_following_character = /\\(.)/g; const regex_backslash_and_following_character = /\\(.)/g;

@ -432,6 +432,7 @@ export function analyze_component(root, source, options) {
uses_component_bindings: false, uses_component_bindings: false,
uses_render_tags: false, uses_render_tags: false,
needs_context: false, needs_context: false,
needs_mutation_validation: false,
needs_props: false, needs_props: false,
event_directive_node: null, event_directive_node: null,
uses_event_attributes: false, uses_event_attributes: false,

@ -393,6 +393,12 @@ export function client_component(analysis, options) {
); );
} }
if (analysis.needs_mutation_validation) {
component_block.body.unshift(
b.var('$$ownership_validator', b.call('$.create_ownership_validator', b.id('$$props')))
);
}
const should_inject_context = const should_inject_context =
dev || dev ||
analysis.needs_context || analysis.needs_context ||

@ -1,10 +1,10 @@
/** @import { ArrowFunctionExpression, Expression, FunctionDeclaration, FunctionExpression, Identifier, Pattern, PrivateIdentifier, Statement } from 'estree' */ /** @import { ArrowFunctionExpression, AssignmentExpression, Expression, FunctionDeclaration, FunctionExpression, Identifier, Node, Pattern, UpdateExpression } from 'estree' */
/** @import { AST, Binding } from '#compiler' */ /** @import { Binding } from '#compiler' */
/** @import { ClientTransformState, ComponentClientTransformState, ComponentContext } from './types.js' */ /** @import { ClientTransformState, ComponentClientTransformState, ComponentContext } from './types.js' */
/** @import { Analysis } from '../../types.js' */ /** @import { Analysis } from '../../types.js' */
/** @import { Scope } from '../../scope.js' */ /** @import { Scope } from '../../scope.js' */
import * as b from '../../../utils/builders.js'; import * as b from '../../../utils/builders.js';
import { extract_identifiers, is_simple_expression } from '../../../utils/ast.js'; import { is_simple_expression } from '../../../utils/ast.js';
import { import {
PROPS_IS_LAZY_INITIAL, PROPS_IS_LAZY_INITIAL,
PROPS_IS_IMMUTABLE, PROPS_IS_IMMUTABLE,
@ -13,7 +13,8 @@ import {
PROPS_IS_BINDABLE PROPS_IS_BINDABLE
} from '../../../../constants.js'; } from '../../../../constants.js';
import { dev } from '../../../state.js'; import { dev } from '../../../state.js';
import { get_value } from './visitors/shared/declarations.js'; import { walk } from 'zimmerframe';
import { validate_mutation } from './visitors/shared/utils.js';
/** /**
* @param {Binding} binding * @param {Binding} binding
@ -110,6 +111,30 @@ function get_hoisted_params(node, context) {
} }
} }
} }
if (dev) {
// this is a little hacky, but necessary for ownership validation
// to work inside hoisted event handlers
/**
* @param {AssignmentExpression | UpdateExpression} node
* @param {{ next: () => void, stop: () => void }} context
*/
function visit(node, { next, stop }) {
if (validate_mutation(node, /** @type {any} */ (context), node) !== node) {
params.push(b.id('$$ownership_validator'));
stop();
} else {
next();
}
}
walk(/** @type {Node} */ (node), null, {
AssignmentExpression: visit,
UpdateExpression: visit
});
}
return params; return params;
} }

@ -7,9 +7,10 @@ import {
get_attribute_expression, get_attribute_expression,
is_event_attribute is_event_attribute
} from '../../../../utils/ast.js'; } from '../../../../utils/ast.js';
import { dev, is_ignored, locate_node } from '../../../../state.js'; import { dev, locate_node } from '../../../../state.js';
import { should_proxy } from '../utils.js'; import { should_proxy } from '../utils.js';
import { visit_assignment_expression } from '../../shared/assignments.js'; import { visit_assignment_expression } from '../../shared/assignments.js';
import { validate_mutation } from './shared/utils.js';
/** /**
* @param {AssignmentExpression} node * @param {AssignmentExpression} node
@ -20,9 +21,7 @@ export function AssignmentExpression(node, context) {
visit_assignment_expression(node, context, build_assignment) ?? context.next() visit_assignment_expression(node, context, build_assignment) ?? context.next()
); );
return is_ignored(node, 'ownership_invalid_mutation') return validate_mutation(node, context, expression);
? b.call('$.skip_ownership_validation', b.thunk(expression))
: expression;
} }
/** /**

@ -161,33 +161,6 @@ export function ClassBody(node, context) {
body.push(/** @type {MethodDefinition} **/ (context.visit(definition, child_state))); body.push(/** @type {MethodDefinition} **/ (context.visit(definition, child_state)));
} }
if (dev && public_state.size > 0) {
// add an `[$.ADD_OWNER]` method so that a class with state fields can widen ownership
body.push(
b.method(
'method',
b.id('$.ADD_OWNER'),
[b.id('owner')],
[
b.stmt(
b.call(
'$.add_owner_to_class',
b.this,
b.id('owner'),
b.array(
Array.from(public_state).map(([name]) =>
b.thunk(b.call('$.get', b.member(b.this, b.private_id(name))))
)
),
is_ignored(node, 'ownership_invalid_binding') && b.true
)
)
],
true
)
);
}
return { ...node, body }; return { ...node, body };
} }

@ -1,8 +1,8 @@
/** @import { AssignmentExpression, Expression, UpdateExpression } from 'estree' */ /** @import { AssignmentExpression, Expression, UpdateExpression } from 'estree' */
/** @import { Context } from '../types' */ /** @import { Context } from '../types' */
import { is_ignored } from '../../../../state.js';
import { object } from '../../../../utils/ast.js'; import { object } from '../../../../utils/ast.js';
import * as b from '../../../../utils/builders.js'; import * as b from '../../../../utils/builders.js';
import { validate_mutation } from './shared/utils.js';
/** /**
* @param {UpdateExpression} node * @param {UpdateExpression} node
@ -51,7 +51,5 @@ export function UpdateExpression(node, context) {
); );
} }
return is_ignored(node, 'ownership_invalid_mutation') return validate_mutation(node, context, update);
? b.call('$.skip_ownership_validation', b.thunk(update))
: update;
} }

@ -179,19 +179,29 @@ export function build_component(node, component_name, context, anchor = context.
} else if (attribute.type === 'BindDirective') { } else if (attribute.type === 'BindDirective') {
const expression = /** @type {Expression} */ (context.visit(attribute.expression)); const expression = /** @type {Expression} */ (context.visit(attribute.expression));
if (dev && attribute.name !== 'this') { if (
binding_initializers.push( dev &&
b.stmt( attribute.name !== 'this' &&
b.call( !is_ignored(node, 'ownership_invalid_binding') &&
b.id('$.add_owner_effect'), // bind:x={() => x.y, y => x.y = y} will be handled by the assignment expression binding validation
expression.type === 'SequenceExpression' attribute.expression.type !== 'SequenceExpression'
? expression.expressions[0] ) {
: b.thunk(expression), const left = object(attribute.expression);
b.id(component_name), const binding = left && context.state.scope.get(left.name);
is_ignored(node, 'ownership_invalid_binding') && b.true
if (binding?.kind === 'bindable_prop' || binding?.kind === 'prop') {
context.state.analysis.needs_mutation_validation = true;
binding_initializers.push(
b.stmt(
b.call(
'$$ownership_validator.binding',
b.literal(binding.node.name),
b.id(component_name),
b.thunk(expression)
)
) )
) );
); }
} }
if (expression.type === 'SequenceExpression') { if (expression.type === 'SequenceExpression') {

@ -1,13 +1,13 @@
/** @import { Expression, ExpressionStatement, Identifier, MemberExpression, SequenceExpression, Statement, Super } from 'estree' */ /** @import { AssignmentExpression, Expression, ExpressionStatement, Identifier, MemberExpression, SequenceExpression, Literal, Super, UpdateExpression } from 'estree' */
/** @import { AST, ExpressionMetadata } from '#compiler' */ /** @import { AST, ExpressionMetadata } from '#compiler' */
/** @import { ComponentClientTransformState } from '../../types' */ /** @import { ComponentClientTransformState, Context } from '../../types' */
import { walk } from 'zimmerframe'; import { walk } from 'zimmerframe';
import { object } from '../../../../../utils/ast.js'; import { object } from '../../../../../utils/ast.js';
import * as b from '../../../../../utils/builders.js'; import * as b from '../../../../../utils/builders.js';
import { sanitize_template_string } from '../../../../../utils/sanitize_template_string.js'; import { sanitize_template_string } from '../../../../../utils/sanitize_template_string.js';
import { regex_is_valid_identifier } from '../../../../patterns.js'; import { regex_is_valid_identifier } from '../../../../patterns.js';
import is_reference from 'is-reference'; import is_reference from 'is-reference';
import { locator } from '../../../../../state.js'; import { dev, is_ignored, locator } from '../../../../../state.js';
import { create_derived } from '../../utils.js'; import { create_derived } from '../../utils.js';
/** /**
@ -295,3 +295,60 @@ export function validate_binding(state, binding, expression) {
) )
); );
} }
/**
* In dev mode validate mutations to props
* @param {AssignmentExpression | UpdateExpression} node
* @param {Context} context
* @param {Expression} expression
*/
export function validate_mutation(node, context, expression) {
let left = /** @type {Expression | Super} */ (
node.type === 'AssignmentExpression' ? node.left : node.argument
);
if (!dev || left.type !== 'MemberExpression' || is_ignored(node, 'ownership_invalid_mutation')) {
return expression;
}
const name = object(left);
if (!name) return expression;
const binding = context.state.scope.get(name.name);
if (binding?.kind !== 'prop' && binding?.kind !== 'bindable_prop') return expression;
const state = /** @type {ComponentClientTransformState} */ (context.state);
state.analysis.needs_mutation_validation = true;
/** @type {Array<Identifier | Literal>} */
const path = [];
while (left.type === 'MemberExpression') {
if (left.property.type === 'Literal') {
path.unshift(left.property);
} else if (left.property.type === 'Identifier') {
if (left.computed) {
path.unshift(left.property);
} else {
path.unshift(b.literal(left.property.name));
}
} else {
return expression;
}
left = left.object;
}
path.unshift(b.literal(name.name));
const loc = locator(/** @type {number} */ (left.start));
return b.call(
'$$ownership_validator.mutation',
b.literal(binding.prop_alias),
b.array(path),
expression,
loc && b.literal(loc.line),
loc && b.literal(loc.column)
);
}

@ -53,6 +53,7 @@ export interface ComponentAnalysis extends Analysis {
uses_component_bindings: boolean; uses_component_bindings: boolean;
uses_render_tags: boolean; uses_render_tags: boolean;
needs_context: boolean; needs_context: boolean;
needs_mutation_validation: boolean;
needs_props: boolean; needs_props: boolean;
/** Set to the first event directive (on:x) found on a DOM element in the code */ /** Set to the first event directive (on:x) found on a DOM element in the code */
event_directive_node: AST.OnDirective | null; event_directive_node: AST.OnDirective | null;

@ -23,6 +23,5 @@ export const EFFECT_HAS_DERIVED = 1 << 20;
export const EFFECT_IS_UPDATING = 1 << 21; export const EFFECT_IS_UPDATING = 1 << 21;
export const STATE_SYMBOL = Symbol('$state'); export const STATE_SYMBOL = Symbol('$state');
export const STATE_SYMBOL_METADATA = Symbol('$state metadata');
export const LEGACY_PROPS = Symbol('legacy props'); export const LEGACY_PROPS = Symbol('legacy props');
export const LOADING_ATTR_SYMBOL = Symbol(''); export const LOADING_ATTR_SYMBOL = Symbol('');

@ -1,7 +1,6 @@
/** @import { ComponentContext } from '#client' */ /** @import { ComponentContext } from '#client' */
import { DEV } from 'esm-env'; import { DEV } from 'esm-env';
import { add_owner } from './dev/ownership.js';
import { lifecycle_outside_component } from '../shared/errors.js'; import { lifecycle_outside_component } from '../shared/errors.js';
import { source } from './reactivity/sources.js'; import { source } from './reactivity/sources.js';
import { import {
@ -67,15 +66,6 @@ export function getContext(key) {
*/ */
export function setContext(key, context) { export function setContext(key, context) {
const context_map = get_or_init_context_map('setContext'); const context_map = get_or_init_context_map('setContext');
if (DEV) {
// When state is put into context, we treat as if it's global from now on.
// We do for performance reasons (it's for example very expensive to call
// getContext on a big object many times when part of a list component)
// and danger of false positives.
untrack(() => add_owner(context, null, true));
}
context_map.set(key, context); context_map.set(key, context);
return context; return context;
} }

@ -1,12 +1,11 @@
/** @import { ProxyMetadata } from '#client' */
/** @typedef {{ file: string, line: number, column: number }} Location */ /** @typedef {{ file: string, line: number, column: number }} Location */
import { STATE_SYMBOL_METADATA } from '../constants.js'; import { get_descriptor } from '../../shared/utils.js';
import { render_effect, user_pre_effect } from '../reactivity/effects.js'; import { LEGACY_PROPS, STATE_SYMBOL } from '../constants.js';
import { dev_current_component_function } from '../context.js'; import { FILENAME } from '../../../constants.js';
import { get_prototype_of } from '../../shared/utils.js'; import { component_context } from '../context.js';
import * as w from '../warnings.js'; import * as w from '../warnings.js';
import { FILENAME, UNINITIALIZED } from '../../../constants.js'; import { sanitize_location } from '../../../utils.js';
/** @type {Record<string, Array<{ start: Location, end: Location, component: Function }>>} */ /** @type {Record<string, Array<{ start: Location, end: Location, component: Function }>>} */
const boundaries = {}; const boundaries = {};
@ -71,8 +70,6 @@ export function get_component() {
return null; return null;
} }
export const ADD_OWNER = Symbol('ADD_OWNER');
/** /**
* Together with `mark_module_end`, this function establishes the boundaries of a `.svelte` file, * Together with `mark_module_end`, this function establishes the boundaries of a `.svelte` file,
* such that subsequent calls to `get_component` can tell us which component is responsible * such that subsequent calls to `get_component` can tell us which component is responsible
@ -108,197 +105,69 @@ export function mark_module_end(component) {
} }
/** /**
* @param {any} object * Sets up a validator that
* @param {any | null} owner * - traverses the path of a prop to find out if it is allowed to be mutated
* @param {boolean} [global] * - checks that the binding chain is not interrupted
* @param {boolean} [skip_warning] * @param {Record<string, any>} props
*/ */
export function add_owner(object, owner, global = false, skip_warning = false) { export function create_ownership_validator(props) {
if (object && !global) { const component = component_context?.function;
const component = dev_current_component_function; const parent = component_context?.p?.function;
const metadata = object[STATE_SYMBOL_METADATA];
if (metadata && !has_owner(metadata, component)) { return {
let original = get_owner(metadata); /**
* @param {string} prop
if (owner && owner[FILENAME] !== component[FILENAME] && !skip_warning) { * @param {any[]} path
w.ownership_invalid_binding(component[FILENAME], owner[FILENAME], original[FILENAME]); * @param {any} result
* @param {number} line
* @param {number} column
*/
mutation: (prop, path, result, line, column) => {
const name = path[0];
if (is_bound(props, name) || !parent) {
return result;
} }
}
}
add_owner_to_object(object, owner, new Set()); let value = props[name];
}
/**
* @param {() => unknown} get_object
* @param {any} Component
* @param {boolean} [skip_warning]
*/
export function add_owner_effect(get_object, Component, skip_warning = false) {
user_pre_effect(() => {
add_owner(get_object(), Component, false, skip_warning);
});
}
/**
* @param {any} _this
* @param {Function} owner
* @param {Array<() => any>} getters
* @param {boolean} skip_warning
*/
export function add_owner_to_class(_this, owner, getters, skip_warning) {
_this[ADD_OWNER].current ||= getters.map(() => UNINITIALIZED);
for (let i = 0; i < getters.length; i += 1) {
const current = getters[i]();
// For performance reasons we only re-add the owner if the state has changed
if (current !== _this[ADD_OWNER][i]) {
_this[ADD_OWNER].current[i] = current;
add_owner(current, owner, false, skip_warning);
}
}
}
/**
* @param {ProxyMetadata | null} from
* @param {ProxyMetadata} to
*/
export function widen_ownership(from, to) {
if (to.owners === null) {
return;
}
while (from) {
if (from.owners === null) {
to.owners = null;
break;
}
for (const owner of from.owners) {
to.owners.add(owner);
}
from = from.parent;
}
}
/**
* @param {any} object
* @param {Function | null} owner If `null`, then the object is globally owned and will not be checked
* @param {Set<any>} seen
*/
function add_owner_to_object(object, owner, seen) {
const metadata = /** @type {ProxyMetadata} */ (object?.[STATE_SYMBOL_METADATA]);
if (metadata) { for (let i = 1; i < path.length - 1; i++) {
// this is a state proxy, add owner directly, if not globally shared if (!value?.[STATE_SYMBOL]) {
if ('owners' in metadata && metadata.owners != null) { return result;
if (owner) { }
metadata.owners.add(owner); value = value[path[i]];
} else {
metadata.owners = null;
} }
}
} else if (object && typeof object === 'object') {
if (seen.has(object)) return;
seen.add(object);
if (ADD_OWNER in object && object[ADD_OWNER]) {
// this is a class with state fields. we put this in a render effect
// so that if state is replaced (e.g. `instance.name = { first, last }`)
// the new state is also co-owned by the caller of `getContext`
render_effect(() => {
object[ADD_OWNER](owner);
});
} else {
var proto = get_prototype_of(object);
if (proto === Object.prototype) { const location = sanitize_location(`${component[FILENAME]}:${line}:${column}`);
// recurse until we find a state proxy
for (const key in object) { w.ownership_invalid_mutation(name, location, prop, parent[FILENAME]);
if (Object.getOwnPropertyDescriptor(object, key)?.get) {
// Similar to the class case; the getter could update with a new state return result;
let current = UNINITIALIZED; },
render_effect(() => { /**
const next = object[key]; * @param {any} key
if (current !== next) { * @param {any} child_component
current = next; * @param {() => any} value
add_owner_to_object(next, owner, seen); */
} binding: (key, child_component, value) => {
}); if (!is_bound(props, key) && parent && value()?.[STATE_SYMBOL]) {
} else { w.ownership_invalid_binding(
add_owner_to_object(object[key], owner, seen); component[FILENAME],
} key,
} child_component[FILENAME],
} else if (proto === Array.prototype) { parent[FILENAME]
// recurse until we find a state proxy );
for (let i = 0; i < object.length; i += 1) {
add_owner_to_object(object[i], owner, seen);
}
} }
} }
} };
} }
/** /**
* @param {ProxyMetadata} metadata * @param {Record<string, any>} props
* @param {Function} component * @param {string} prop_name
* @returns {boolean}
*/ */
function has_owner(metadata, component) { function is_bound(props, prop_name) {
if (metadata.owners === null) { // Can be the case when someone does `mount(Component, props)` with `let props = $state({...})`
return true; // or `createClassComponent(Component, props)`
} const is_entry_props = STATE_SYMBOL in props || LEGACY_PROPS in props;
return !!get_descriptor(props, prop_name)?.set || (is_entry_props && prop_name in props);
return (
metadata.owners.has(component) ||
// This helps avoid false positives when using HMR, where the component function is replaced
(FILENAME in component &&
[...metadata.owners].some(
(owner) => /** @type {any} */ (owner)[FILENAME] === component[FILENAME]
)) ||
(metadata.parent !== null && has_owner(metadata.parent, component))
);
}
/**
* @param {ProxyMetadata} metadata
* @returns {any}
*/
function get_owner(metadata) {
return (
metadata?.owners?.values().next().value ??
get_owner(/** @type {ProxyMetadata} */ (metadata.parent))
);
}
let skip = false;
/**
* @param {() => any} fn
*/
export function skip_ownership_validation(fn) {
skip = true;
fn();
skip = false;
}
/**
* @param {ProxyMetadata} metadata
*/
export function check_ownership(metadata) {
if (skip) return;
const component = get_component();
if (component && !has_owner(metadata, component)) {
let original = get_owner(metadata);
// @ts-expect-error
if (original[FILENAME] !== component[FILENAME]) {
// @ts-expect-error
w.ownership_invalid_mutation(component[FILENAME], original[FILENAME]);
} else {
w.ownership_invalid_mutation();
}
}
} }

@ -4,15 +4,7 @@ export { assign, assign_and, assign_or, assign_nullish } from './dev/assign.js';
export { cleanup_styles } from './dev/css.js'; export { cleanup_styles } from './dev/css.js';
export { add_locations } from './dev/elements.js'; export { add_locations } from './dev/elements.js';
export { hmr } from './dev/hmr.js'; export { hmr } from './dev/hmr.js';
export { export { mark_module_start, mark_module_end, create_ownership_validator } from './dev/ownership.js';
ADD_OWNER,
add_owner,
mark_module_start,
mark_module_end,
add_owner_effect,
add_owner_to_class,
skip_ownership_validation
} from './dev/ownership.js';
export { check_target, legacy_api } from './dev/legacy.js'; export { check_target, legacy_api } from './dev/legacy.js';
export { trace } from './dev/tracing.js'; export { trace } from './dev/tracing.js';
export { inspect } from './dev/inspect.js'; export { inspect } from './dev/inspect.js';

@ -1,7 +1,6 @@
/** @import { ProxyMetadata, Source } from '#client' */ /** @import { Source } from '#client' */
import { DEV } from 'esm-env'; import { DEV } from 'esm-env';
import { get, active_effect, active_reaction, set_active_reaction } from './runtime.js'; import { get, active_effect, active_reaction, set_active_reaction } from './runtime.js';
import { component_context } from './context.js';
import { import {
array_prototype, array_prototype,
get_descriptor, get_descriptor,
@ -9,24 +8,19 @@ import {
is_array, is_array,
object_prototype object_prototype
} from '../shared/utils.js'; } from '../shared/utils.js';
import { check_ownership, widen_ownership } from './dev/ownership.js';
import { state as source, set } from './reactivity/sources.js'; import { state as source, set } from './reactivity/sources.js';
import { STATE_SYMBOL, STATE_SYMBOL_METADATA } from './constants.js'; import { STATE_SYMBOL } from './constants.js';
import { UNINITIALIZED } from '../../constants.js'; import { UNINITIALIZED } from '../../constants.js';
import * as e from './errors.js'; import * as e from './errors.js';
import { get_stack } from './dev/tracing.js'; import { get_stack } from './dev/tracing.js';
import { tracing_mode_flag } from '../flags/index.js'; import { tracing_mode_flag } from '../flags/index.js';
/** @type {ProxyMetadata | null} */
var parent_metadata = null;
/** /**
* @template T * @template T
* @param {T} value * @param {T} value
* @param {Source<T>} [prev] dev mode only
* @returns {T} * @returns {T}
*/ */
export function proxy(value, prev) { export function proxy(value) {
// if non-proxyable, or is already a proxy, return `value` // if non-proxyable, or is already a proxy, return `value`
if (typeof value !== 'object' || value === null || STATE_SYMBOL in value) { if (typeof value !== 'object' || value === null || STATE_SYMBOL in value) {
return value; return value;
@ -55,16 +49,7 @@ export function proxy(value, prev) {
set_active_reaction(reaction); set_active_reaction(reaction);
/** @type {T} */ /** @type {T} */
var result; var result = fn();
if (DEV) {
var previous_metadata = parent_metadata;
parent_metadata = metadata;
result = fn();
parent_metadata = previous_metadata;
} else {
result = fn();
}
set_active_reaction(previous_reaction); set_active_reaction(previous_reaction);
return result; return result;
@ -76,31 +61,6 @@ export function proxy(value, prev) {
sources.set('length', source(/** @type {any[]} */ (value).length, stack)); sources.set('length', source(/** @type {any[]} */ (value).length, stack));
} }
/** @type {ProxyMetadata} */
var metadata;
if (DEV) {
metadata = {
parent: parent_metadata,
owners: null
};
if (prev) {
// Reuse owners from previous state; necessary because reassignment is not guaranteed to have correct component context.
// If no previous proxy exists we play it safe and assume ownerless state
// @ts-expect-error
const prev_owners = prev.v?.[STATE_SYMBOL_METADATA]?.owners;
metadata.owners = prev_owners ? new Set(prev_owners) : null;
} else {
metadata.owners =
parent_metadata === null
? component_context !== null
? new Set([component_context.function])
: null
: new Set();
}
}
return new Proxy(/** @type {any} */ (value), { return new Proxy(/** @type {any} */ (value), {
defineProperty(_, prop, descriptor) { defineProperty(_, prop, descriptor) {
if ( if (
@ -160,10 +120,6 @@ export function proxy(value, prev) {
}, },
get(target, prop, receiver) { get(target, prop, receiver) {
if (DEV && prop === STATE_SYMBOL_METADATA) {
return metadata;
}
if (prop === STATE_SYMBOL) { if (prop === STATE_SYMBOL) {
return value; return value;
} }
@ -179,22 +135,6 @@ export function proxy(value, prev) {
if (s !== undefined) { if (s !== undefined) {
var v = get(s); var v = get(s);
// In case of something like `foo = bar.map(...)`, foo would have ownership
// of the array itself, while the individual items would have ownership
// of the component that created bar. That means if we later do `foo[0].baz = 42`,
// we could get a false-positive ownership violation, since the two proxies
// are not connected to each other via the parent metadata relationship.
// For this reason, we need to widen the ownership of the children
// upon access when we detect they are not connected.
if (DEV) {
/** @type {ProxyMetadata | undefined} */
var prop_metadata = v?.[STATE_SYMBOL_METADATA];
if (prop_metadata && prop_metadata?.parent !== metadata) {
widen_ownership(metadata, prop_metadata);
}
}
return v === UNINITIALIZED ? undefined : v; return v === UNINITIALIZED ? undefined : v;
} }
@ -225,10 +165,6 @@ export function proxy(value, prev) {
}, },
has(target, prop) { has(target, prop) {
if (DEV && prop === STATE_SYMBOL_METADATA) {
return true;
}
if (prop === STATE_SYMBOL) { if (prop === STATE_SYMBOL) {
return true; return true;
} }
@ -295,15 +231,6 @@ export function proxy(value, prev) {
); );
} }
if (DEV) {
/** @type {ProxyMetadata | undefined} */
var prop_metadata = value?.[STATE_SYMBOL_METADATA];
if (prop_metadata && prop_metadata?.parent !== metadata) {
widen_ownership(metadata, prop_metadata);
}
check_ownership(metadata);
}
var descriptor = Reflect.getOwnPropertyDescriptor(target, prop); var descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
// Set the new value before updating any signals so that any listeners get the new value // Set the new value before updating any signals so that any listeners get the new value

@ -67,6 +67,7 @@ export function derived(fn) {
* @param {() => V} fn * @param {() => V} fn
* @returns {Derived<V>} * @returns {Derived<V>}
*/ */
/*#__NO_SIDE_EFFECTS__*/
export function user_derived(fn) { export function user_derived(fn) {
const d = derived(fn); const d = derived(fn);
@ -130,7 +131,7 @@ function get_derived_parent_effect(derived) {
* @param {Derived} derived * @param {Derived} derived
* @returns {T} * @returns {T}
*/ */
function execute_derived(derived) { export function execute_derived(derived) {
var value; var value;
var prev_active_effect = active_effect; var prev_active_effect = active_effect;

@ -28,14 +28,14 @@ import {
UNOWNED, UNOWNED,
MAYBE_DIRTY, MAYBE_DIRTY,
BLOCK_EFFECT, BLOCK_EFFECT,
ROOT_EFFECT, ROOT_EFFECT
EFFECT_IS_UPDATING
} from '../constants.js'; } from '../constants.js';
import * as e from '../errors.js'; import * as e from '../errors.js';
import { legacy_mode_flag, tracing_mode_flag } from '../../flags/index.js'; import { legacy_mode_flag, tracing_mode_flag } from '../../flags/index.js';
import { get_stack } from '../dev/tracing.js'; import { get_stack } from '../dev/tracing.js';
import { component_context, is_runes } from '../context.js'; import { component_context, is_runes } from '../context.js';
import { proxy } from '../proxy.js'; import { proxy } from '../proxy.js';
import { execute_derived } from './deriveds.js';
export let inspect_effects = new Set(); export let inspect_effects = new Set();
export const old_values = new Map(); export const old_values = new Map();
@ -78,6 +78,7 @@ export function source(v, stack) {
* @param {V} v * @param {V} v
* @param {Error | null} [stack] * @param {Error | null} [stack]
*/ */
/*#__NO_SIDE_EFFECTS__*/
export function state(v, stack) { export function state(v, stack) {
const s = source(v, stack); const s = source(v, stack);
@ -139,7 +140,7 @@ export function set(source, value, should_proxy = false) {
e.state_unsafe_mutation(); e.state_unsafe_mutation();
} }
let new_value = should_proxy ? proxy(value, source) : value; let new_value = should_proxy ? proxy(value) : value;
return internal_set(source, new_value); return internal_set(source, new_value);
} }
@ -171,6 +172,14 @@ export function internal_set(source, value) {
} }
} }
if ((source.f & DERIVED) !== 0) {
// if we are assigning to a dirty derived we set it to clean/maybe dirty but we also eagerly execute it to track the dependencies
if ((source.f & DIRTY) !== 0) {
execute_derived(/** @type {Derived} */ (source));
}
set_signal_status(source, (source.f & UNOWNED) === 0 ? CLEAN : MAYBE_DIRTY);
}
mark_reactions(source, DIRTY); mark_reactions(source, DIRTY);
// It's possible that the current reaction might not have up-to-date dependencies // It's possible that the current reaction might not have up-to-date dependencies

@ -27,7 +27,7 @@ import {
} from './constants.js'; } from './constants.js';
import { flush_tasks } from './dom/task.js'; import { flush_tasks } from './dom/task.js';
import { internal_set, old_values } from './reactivity/sources.js'; import { internal_set, old_values } from './reactivity/sources.js';
import { destroy_derived_effects, update_derived } from './reactivity/deriveds.js'; import { destroy_derived_effects, execute_derived, update_derived } from './reactivity/deriveds.js';
import * as e from './errors.js'; import * as e from './errors.js';
import { FILENAME } from '../../constants.js'; import { FILENAME } from '../../constants.js';
import { tracing_mode_flag } from '../flags/index.js'; import { tracing_mode_flag } from '../flags/index.js';
@ -476,7 +476,7 @@ export function update_reaction(reaction) {
// we need to increment the read version to ensure that // we need to increment the read version to ensure that
// any dependencies in this reaction aren't marked with // any dependencies in this reaction aren't marked with
// the same version // the same version
if (previous_reaction !== null) { if (previous_reaction !== reaction) {
read_version++; read_version++;
if (untracked_writes !== null) { if (untracked_writes !== null) {

@ -179,14 +179,6 @@ export type TaskCallback = (now: number) => boolean | void;
export type TaskEntry = { c: TaskCallback; f: () => void }; export type TaskEntry = { c: TaskCallback; f: () => void };
/** Dev-only */
export interface ProxyMetadata {
/** The components that 'own' this state, if any. `null` means no owners, i.e. everyone can mutate this state. */
owners: null | Set<Function>;
/** The parent metadata object */
parent: null | ProxyMetadata;
}
export type ProxyStateObject<T = Record<string | symbol, any>> = T & { export type ProxyStateObject<T = Record<string | symbol, any>> = T & {
[STATE_SYMBOL]: T; [STATE_SYMBOL]: T;
}; };

@ -129,27 +129,30 @@ export function lifecycle_double_unmount() {
} }
/** /**
* %parent% passed a value to %child% with `bind:`, but the value is owned by %owner%. Consider creating a binding between %owner% and %parent% * %parent% passed property `%prop%` to %child% with `bind:`, but its parent component %owner% did not declare `%prop%` as a binding. Consider creating a binding between %owner% and %parent% (e.g. `bind:%prop%={...}` instead of `%prop%={...}`)
* @param {string} parent * @param {string} parent
* @param {string} prop
* @param {string} child * @param {string} child
* @param {string} owner * @param {string} owner
*/ */
export function ownership_invalid_binding(parent, child, owner) { export function ownership_invalid_binding(parent, prop, child, owner) {
if (DEV) { if (DEV) {
console.warn(`%c[svelte] ownership_invalid_binding\n%c${parent} passed a value to ${child} with \`bind:\`, but the value is owned by ${owner}. Consider creating a binding between ${owner} and ${parent}\nhttps://svelte.dev/e/ownership_invalid_binding`, bold, normal); console.warn(`%c[svelte] ownership_invalid_binding\n%c${parent} passed property \`${prop}\` to ${child} with \`bind:\`, but its parent component ${owner} did not declare \`${prop}\` as a binding. Consider creating a binding between ${owner} and ${parent} (e.g. \`bind:${prop}={...}\` instead of \`${prop}={...}\`)\nhttps://svelte.dev/e/ownership_invalid_binding`, bold, normal);
} else { } else {
console.warn(`https://svelte.dev/e/ownership_invalid_binding`); console.warn(`https://svelte.dev/e/ownership_invalid_binding`);
} }
} }
/** /**
* %component% mutated a value owned by %owner%. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead * Mutating unbound props (`%name%`, at %location%) is strongly discouraged. Consider using `bind:%prop%={...}` in %parent% (or using a callback) instead
* @param {string | undefined | null} [component] * @param {string} name
* @param {string | undefined | null} [owner] * @param {string} location
* @param {string} prop
* @param {string} parent
*/ */
export function ownership_invalid_mutation(component, owner) { export function ownership_invalid_mutation(name, location, prop, parent) {
if (DEV) { if (DEV) {
console.warn(`%c[svelte] ownership_invalid_mutation\n%c${component ? `${component} mutated a value owned by ${owner}. This is strongly discouraged. Consider passing values to child components with \`bind:\`, or use a callback instead` : 'Mutating a value outside the component that created it is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead'}\nhttps://svelte.dev/e/ownership_invalid_mutation`, bold, normal); console.warn(`%c[svelte] ownership_invalid_mutation\n%cMutating unbound props (\`${name}\`, at ${location}) is strongly discouraged. Consider using \`bind:${prop}={...}\` in ${parent} (or using a callback) instead\nhttps://svelte.dev/e/ownership_invalid_mutation`, bold, normal);
} else { } else {
console.warn(`https://svelte.dev/e/ownership_invalid_mutation`); console.warn(`https://svelte.dev/e/ownership_invalid_mutation`);
} }

@ -466,8 +466,10 @@ export function is_raw_text_element(name) {
/** /**
* Prevent devtools trying to make `location` a clickable link by inserting a zero-width space * Prevent devtools trying to make `location` a clickable link by inserting a zero-width space
* @param {string | undefined} location * @template {string | undefined} T
* @param {T} location
* @returns {T};
*/ */
export function sanitize_location(location) { export function sanitize_location(location) {
return location?.replace(/\//g, '/\u200b'); return /** @type {T} */ (location?.replace(/\//g, '/\u200b'));
} }

@ -4,5 +4,5 @@
* The current version, as set in package.json. * The current version, as set in package.json.
* @type {string} * @type {string}
*/ */
export const VERSION = '5.25.6'; export const VERSION = '5.25.9';
export const PUBLIC_VERSION = '5'; export const PUBLIC_VERSION = '5';

@ -1,5 +1,10 @@
div.svelte-xyz { div.svelte-xyz {
&.class{ &.class{
color: red; color: green;
}
}
* {
&:hover .class.svelte-xyz {
color: green;
} }
} }

@ -1,7 +1,12 @@
<style> <style>
div { div {
&:global(.class){ &:global(.class){
color: red; color: green;
}
}
:global(*) {
&:hover .class {
color: green;
} }
} }
</style> </style>

@ -10,7 +10,7 @@ export default test({
test({ assert, target, warnings }) { test({ assert, target, warnings }) {
const warning = const warning =
'Counter.svelte mutated a value owned by main.svelte. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead'; 'Mutating unbound props (`object`, at Counter.svelte:5:23) is strongly discouraged. Consider using `bind:object={...}` in main.svelte (or using a callback) instead';
const [btn1, btn2] = target.querySelectorAll('button'); const [btn1, btn2] = target.querySelectorAll('button');
btn1.click(); btn1.click();

@ -1,11 +0,0 @@
import { test } from '../../test';
export default test({
compileOptions: {
dev: true
},
async test({ assert, warnings }) {
assert.deepEqual(warnings, []);
}
});

@ -1,18 +0,0 @@
<script module>
let toast1 = $state();
let toast2 = $state({});
export async function show_toast() {
toast1 = {
message: 'foo',
show: true
};
toast1.show = false;
toast2 = {
message: 'foo',
show: true
};
toast2.show = false;
}
</script>

@ -1,5 +0,0 @@
<script>
import { show_toast } from "./child.svelte";
show_toast();
</script>

@ -8,7 +8,7 @@ let warn;
let warnings = []; let warnings = [];
export default test({ export default test({
html: `<button>clicks: 0</button>`, html: `<button>[]</button>`,
compileOptions: { compileOptions: {
dev: true dev: true
@ -34,8 +34,8 @@ export default test({
btn?.click(); btn?.click();
}); });
assert.htmlEqual(target.innerHTML, `<button>clicks: 1</button>`); assert.htmlEqual(target.innerHTML, `<button>[foo]</button>`);
assert.deepEqual(warnings, []); assert.deepEqual(warnings, [], 'expected getContext to have widened ownership');
} }
}); });

@ -0,0 +1,9 @@
<script>
import { setContext } from 'svelte';
import Sub from './sub.svelte';
let list = $state([]);
setContext('list', list);
</script>
<Sub />

@ -1,41 +1,24 @@
import { flushSync } from 'svelte'; import { flushSync } from 'svelte';
import { test } from '../../test'; import { test } from '../../test';
/** @type {typeof console.warn} */
let warn;
/** @type {any[]} */
let warnings = [];
export default test({ export default test({
html: `<button>clicks: 0</button>`,
compileOptions: { compileOptions: {
dev: true dev: true
}, },
before_test: () => { test({ assert, target, warnings }) {
warn = console.warn; const [btn1, btn2] = target.querySelectorAll('button');
console.warn = (...args) => {
warnings.push(...args);
};
},
after_test: () => { flushSync(() => {
console.warn = warn; btn1.click();
warnings = []; });
},
test({ assert, target }) { assert.deepEqual(warnings.length, 0);
const btn = target.querySelector('button');
flushSync(() => { flushSync(() => {
btn?.click(); btn2.click();
}); });
assert.htmlEqual(target.innerHTML, `<button>clicks: 1</button>`); assert.deepEqual(warnings.length, 1);
assert.deepEqual(warnings, []);
} }
}); });

@ -1,9 +1,8 @@
<script> <script lang="ts">
import { global } from './state.svelte.js'; import Sub from './sub.svelte';
import { create_my_state } from './state.svelte';
global.a = { b: 0 }; const myState = create_my_state();
</script> </script>
<button onclick={() => global.a.b += 1}> <Sub count={myState.my_state} inc={myState.inc} />
clicks: {global.a.b}
</button>

@ -1 +1,14 @@
export let global = $state({}); export function create_my_state() {
const my_state = $state({
a: 0
});
function inc() {
my_state.a++;
}
return {
my_state,
inc
};
}

@ -1,41 +1,24 @@
import { flushSync } from 'svelte'; import { flushSync } from 'svelte';
import { test } from '../../test'; import { test } from '../../test';
/** @type {typeof console.warn} */
let warn;
/** @type {any[]} */
let warnings = [];
export default test({ export default test({
html: `<button>[]</button>`,
compileOptions: { compileOptions: {
dev: true dev: true
}, },
before_test: () => { async test({ assert, target, warnings }) {
warn = console.warn; const [btn1, btn2] = target.querySelectorAll('button');
console.warn = (...args) => {
warnings.push(...args);
};
},
after_test: () => { flushSync(() => {
console.warn = warn; btn1.click();
warnings = []; });
},
test({ assert, target }) { assert.deepEqual(warnings.length, 0);
const btn = target.querySelector('button');
flushSync(() => { flushSync(() => {
btn?.click(); btn2.click();
}); });
assert.htmlEqual(target.innerHTML, `<button>[foo]</button>`); assert.deepEqual(warnings.length, 1);
assert.deepEqual(warnings, [], 'expected getContext to have widened ownership');
} }
}); });

@ -1,9 +1,13 @@
<script> <script>
import { setContext } from 'svelte'; import Child from './Child.svelte';
import Sub from './sub.svelte';
let list = $state([]); let items = $state([{ id: "test", name: "this is a test"}, { id:"test2", name: "this is a second test"}]);
setContext('list', list); let found = $state();
function onclick() {
found = items.find(c => c.id === 'test2');
}
</script> </script>
<Sub /> <button {onclick}>First click here</button>
<Child item={found} />

@ -1,37 +0,0 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
/** @type {typeof console.warn} */
let warn;
/** @type {any[]} */
let warnings = [];
export default test({
compileOptions: {
dev: true
},
before_test: () => {
warn = console.warn;
console.warn = (...args) => {
warnings.push(...args);
};
},
after_test: () => {
console.warn = warn;
warnings = [];
},
test({ assert, target }) {
const btn = target.querySelector('button');
flushSync(() => {
btn?.click();
});
assert.deepEqual(warnings, []);
}
});

@ -1,11 +0,0 @@
<script>
import { global } from './state.svelte.js';
import Sub from './sub.svelte';
</script>
<Sub />
<!-- it's important _NOT_ to read global.a.b in the template,
else the proxy would set up the structure with its own component context already -->
<button onclick={() => global.increment_a_b()}>
click me
</button>

@ -1,13 +0,0 @@
class Global {
state = $state({});
add_a(a) {
this.state.a = a;
}
increment_a_b() {
this.state.a.b++;
}
}
export const global = new Global();

@ -1,8 +0,0 @@
<script>
import { global } from "./state.svelte";
// The real world use case would be someone manipulating state locally, for example form state,
// and then push the values to a global state for everyone else to see / possibly mutate.
const local_soon_global = $state({ b: 0 });
global.add_a(local_soon_global);
</script>

@ -1,24 +0,0 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
compileOptions: {
dev: true
},
test({ assert, target, warnings }) {
const [btn1, btn2] = target.querySelectorAll('button');
flushSync(() => {
btn1.click();
});
assert.deepEqual(warnings.length, 0);
flushSync(() => {
btn2.click();
});
assert.deepEqual(warnings.length, 1);
}
});

@ -1,8 +0,0 @@
<script lang="ts">
import Sub from './sub.svelte';
import { create_my_state } from './state.svelte';
const myState = create_my_state();
</script>
<Sub count={myState.my_state} inc={myState.inc} />

@ -1,14 +0,0 @@
export function create_my_state() {
const my_state = $state({
a: 0
});
function inc() {
my_state.a++;
}
return {
my_state,
inc
};
}

@ -1,9 +0,0 @@
<script>
import { getContext } from 'svelte';
const foo = getContext('foo')
</script>
<button onclick={() => {
foo.person.name.last = 'T';
}}>mutate</button>

@ -1,37 +0,0 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
/** @type {typeof console.warn} */
let warn;
/** @type {any[]} */
let warnings = [];
export default test({
compileOptions: {
dev: true
},
before_test: () => {
warn = console.warn;
console.warn = (...args) => {
warnings.push(...args);
};
},
after_test: () => {
console.warn = warn;
warnings = [];
},
async test({ assert, target }) {
const btn = target.querySelector('button');
flushSync(() => {
btn?.click();
});
assert.deepEqual(warnings.length, 0);
}
});

@ -1,17 +0,0 @@
<script>
import { setContext } from 'svelte';
import Child from './Child.svelte';
class Person {
name = $state({
first: 'Mr',
last: 'Bean'
});
}
setContext('foo', {
person: new Person()
});
</script>
<Child />

@ -1,24 +0,0 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
compileOptions: {
dev: true
},
async test({ assert, target, warnings }) {
const [btn1, btn2] = target.querySelectorAll('button');
flushSync(() => {
btn1.click();
});
assert.deepEqual(warnings.length, 0);
flushSync(() => {
btn2.click();
});
assert.deepEqual(warnings.length, 1);
}
});

@ -1,13 +0,0 @@
<script>
import Child from './Child.svelte';
let items = $state([{ id: "test", name: "this is a test"}, { id:"test2", name: "this is a second test"}]);
let found = $state();
function onclick() {
found = items.find(c => c.id === 'test2');
}
</script>
<button {onclick}>First click here</button>
<Child item={found} />

@ -1,7 +0,0 @@
<script>
import { global } from './state.svelte.js';
</script>
<button onclick={() => global.object.count += 1}>
clicks: {global.object.count}
</button>

@ -1,9 +0,0 @@
<script>
import Counter from './Counter.svelte';
import { global } from './state.svelte.js';
let object = $state({ count: 0 });
global.object = object;
</script>
<Counter />

@ -8,6 +8,6 @@ export default test({
}, },
warnings: [ warnings: [
'Intermediate.svelte passed a value to Counter.svelte with `bind:`, but the value is owned by main.svelte. Consider creating a binding between main.svelte and Intermediate.svelte' 'Intermediate.svelte passed property `object` to Counter.svelte with `bind:`, but its parent component main.svelte did not declare `object` as a binding. Consider creating a binding between main.svelte and Intermediate.svelte (e.g. `bind:object={...}` instead of `object={...}`)'
] ]
}); });

@ -33,7 +33,7 @@ export default test({
assert.htmlEqual(target.innerHTML, `<button>clicks: 1</button><button>clicks: 1</button>`); assert.htmlEqual(target.innerHTML, `<button>clicks: 1</button><button>clicks: 1</button>`);
assert.deepEqual(warnings, [ assert.deepEqual(warnings, [
'Counter.svelte mutated a value owned by main.svelte. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead' 'Mutating unbound props (`notshared`, at Counter.svelte:10:23) is strongly discouraged. Consider using `bind:notshared={...}` in main.svelte (or using a callback) instead'
]); ]);
} }
}); });

@ -1,7 +1,6 @@
import { flushSync } from 'svelte'; import { flushSync } from 'svelte';
import { ok, test } from '../../test'; import { ok, test } from '../../test';
// Tests that proxies widen ownership correctly even if not directly connected to each other
export default test({ export default test({
compileOptions: { compileOptions: {
dev: true dev: true

@ -1,7 +0,0 @@
<script>
let { linked3 = $bindable(), linked4 = $bindable() } = $props();
</script>
<p>Binding</p>
<button onclick={() => linked3.count++}>Increment Linked 1 ({linked3.count})</button>
<button onclick={() => linked4.count++}>Increment Linked 2 ({linked4.count})</button>

@ -1,13 +0,0 @@
<script>
import { getContext } from 'svelte';
const linked1 = getContext('linked1');
const linked2 = getContext('linked2');
</script>
<p>Context</p>
<button onclick={() => linked1.linked.current.count++}
>Increment Linked 1 ({linked1.linked.current.count})</button
>
<button onclick={() => linked2.linked.current.count++}
>Increment Linked 2 ({linked2.linked.current.count})</button
>

@ -1,34 +0,0 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
// Tests that ownership is widened with $derived (on class or on its own) that contains $state
export default test({
compileOptions: {
dev: true
},
test({ assert, target, warnings }) {
const [root, counter_context1, counter_context2, counter_binding1, counter_binding2] =
target.querySelectorAll('button');
counter_context1.click();
counter_context2.click();
counter_binding1.click();
counter_binding2.click();
flushSync();
assert.equal(warnings.length, 0);
root.click();
flushSync();
counter_context1.click();
counter_context2.click();
counter_binding1.click();
counter_binding2.click();
flushSync();
assert.equal(warnings.length, 0);
},
warnings: []
});

@ -1,46 +0,0 @@
<script>
import CounterBinding from './CounterBinding.svelte';
import CounterContext from './CounterContext.svelte';
import { setContext } from 'svelte';
let counter = $state({ count: 0 });
class Linked {
#getter;
linked = $derived.by(() => {
const state = $state({ current: $state.snapshot(this.#getter()) });
return state;
});
constructor(fn) {
this.#getter = fn;
}
}
const linked1 = $derived.by(() => {
const state = $state({ current: $state.snapshot(counter) });
return state;
});
const linked2 = new Linked(() => counter);
setContext('linked1', {
get linked() {
return linked1;
}
});
setContext('linked2', linked2);
const linked3 = $derived.by(() => {
const state = $state({ current: $state.snapshot(counter) });
return state;
});
const linked4 = new Linked(() => counter);
</script>
<p>Parent</p>
<button onclick={() => counter.count++}>
Increment Original ({counter.count})
</button>
<CounterContext />
<CounterBinding bind:linked3={linked3.current} bind:linked4={linked4.linked.current} />

@ -1086,6 +1086,38 @@ describe('signals', () => {
}; };
}); });
test("deriveds set after they are DIRTY doesn't get updated on get", () => {
return () => {
const a = state(0);
const b = derived(() => $.get(a));
set(b, 1);
assert.equal($.get(b), 1);
set(a, 2);
assert.equal($.get(b), 2);
set(b, 3);
assert.equal($.get(b), 3);
};
});
test("unowned deriveds set after they are DIRTY doesn't get updated on get", () => {
return () => {
const a = state(0);
const b = derived(() => $.get(a));
const c = derived(() => $.get(b));
set(b, 1);
assert.equal($.get(c), 1);
set(a, 2);
assert.equal($.get(b), 2);
assert.equal($.get(c), 2);
};
});
test('deriveds containing effects work correctly when used with untrack', () => { test('deriveds containing effects work correctly when used with untrack', () => {
return () => { return () => {
let a = render_effect(() => {}); let a = render_effect(() => {});

@ -18,7 +18,7 @@
"polka": "^1.0.0-next.25", "polka": "^1.0.0-next.25",
"svelte": "workspace:*", "svelte": "workspace:*",
"tinyglobby": "^0.2.12", "tinyglobby": "^0.2.12",
"vite": "^5.4.16", "vite": "^5.4.17",
"vite-plugin-inspect": "^0.8.4" "vite-plugin-inspect": "^0.8.4"
} }
} }

@ -152,7 +152,7 @@ importers:
devDependencies: devDependencies:
'@sveltejs/vite-plugin-svelte': '@sveltejs/vite-plugin-svelte':
specifier: ^4.0.0-next.6 specifier: ^4.0.0-next.6
version: 4.0.0-next.6(svelte@packages+svelte)(vite@5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) version: 4.0.0-next.6(svelte@packages+svelte)(vite@5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))
polka: polka:
specifier: ^1.0.0-next.25 specifier: ^1.0.0-next.25
version: 1.0.0-next.25 version: 1.0.0-next.25
@ -163,11 +163,11 @@ importers:
specifier: ^0.2.12 specifier: ^0.2.12
version: 0.2.12 version: 0.2.12
vite: vite:
specifier: ^5.4.16 specifier: ^5.4.17
version: 5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) version: 5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
vite-plugin-inspect: vite-plugin-inspect:
specifier: ^0.8.4 specifier: ^0.8.4
version: 0.8.4(rollup@4.38.0)(vite@5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) version: 0.8.4(rollup@4.39.0)(vite@5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))
packages: packages:
@ -551,8 +551,8 @@ packages:
cpu: [arm] cpu: [arm]
os: [android] os: [android]
'@rollup/rollup-android-arm-eabi@4.38.0': '@rollup/rollup-android-arm-eabi@4.39.0':
resolution: {integrity: sha512-ldomqc4/jDZu/xpYU+aRxo3V4mGCV9HeTgUBANI3oIQMOL+SsxB+S2lxMpkFp5UamSS3XuTMQVbsS24R4J4Qjg==} resolution: {integrity: sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==}
cpu: [arm] cpu: [arm]
os: [android] os: [android]
@ -561,8 +561,8 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [android] os: [android]
'@rollup/rollup-android-arm64@4.38.0': '@rollup/rollup-android-arm64@4.39.0':
resolution: {integrity: sha512-VUsgcy4GhhT7rokwzYQP+aV9XnSLkkhlEJ0St8pbasuWO/vwphhZQxYEKUP3ayeCYLhk6gEtacRpYP/cj3GjyQ==} resolution: {integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==}
cpu: [arm64] cpu: [arm64]
os: [android] os: [android]
@ -571,8 +571,8 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@rollup/rollup-darwin-arm64@4.38.0': '@rollup/rollup-darwin-arm64@4.39.0':
resolution: {integrity: sha512-buA17AYXlW9Rn091sWMq1xGUvWQFOH4N1rqUxGJtEQzhChxWjldGCCup7r/wUnaI6Au8sKXpoh0xg58a7cgcpg==} resolution: {integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
@ -581,18 +581,18 @@ packages:
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@rollup/rollup-darwin-x64@4.38.0': '@rollup/rollup-darwin-x64@4.39.0':
resolution: {integrity: sha512-Mgcmc78AjunP1SKXl624vVBOF2bzwNWFPMP4fpOu05vS0amnLcX8gHIge7q/lDAHy3T2HeR0TqrriZDQS2Woeg==} resolution: {integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@rollup/rollup-freebsd-arm64@4.38.0': '@rollup/rollup-freebsd-arm64@4.39.0':
resolution: {integrity: sha512-zzJACgjLbQTsscxWqvrEQAEh28hqhebpRz5q/uUd1T7VTwUNZ4VIXQt5hE7ncs0GrF+s7d3S4on4TiXUY8KoQA==} resolution: {integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==}
cpu: [arm64] cpu: [arm64]
os: [freebsd] os: [freebsd]
'@rollup/rollup-freebsd-x64@4.38.0': '@rollup/rollup-freebsd-x64@4.39.0':
resolution: {integrity: sha512-hCY/KAeYMCyDpEE4pTETam0XZS4/5GXzlLgpi5f0IaPExw9kuB+PDTOTLuPtM10TlRG0U9OSmXJ+Wq9J39LvAg==} resolution: {integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==}
cpu: [x64] cpu: [x64]
os: [freebsd] os: [freebsd]
@ -601,8 +601,8 @@ packages:
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@rollup/rollup-linux-arm-gnueabihf@4.38.0': '@rollup/rollup-linux-arm-gnueabihf@4.39.0':
resolution: {integrity: sha512-mimPH43mHl4JdOTD7bUMFhBdrg6f9HzMTOEnzRmXbOZqjijCw8LA5z8uL6LCjxSa67H2xiLFvvO67PT05PRKGg==} resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
@ -611,8 +611,8 @@ packages:
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@rollup/rollup-linux-arm-musleabihf@4.38.0': '@rollup/rollup-linux-arm-musleabihf@4.39.0':
resolution: {integrity: sha512-tPiJtiOoNuIH8XGG8sWoMMkAMm98PUwlriOFCCbZGc9WCax+GLeVRhmaxjJtz6WxrPKACgrwoZ5ia/uapq3ZVg==} resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
@ -621,8 +621,8 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@rollup/rollup-linux-arm64-gnu@4.38.0': '@rollup/rollup-linux-arm64-gnu@4.39.0':
resolution: {integrity: sha512-wZco59rIVuB0tjQS0CSHTTUcEde+pXQWugZVxWaQFdQQ1VYub/sTrNdY76D1MKdN2NB48JDuGABP6o6fqos8mA==} resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
@ -631,13 +631,13 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@rollup/rollup-linux-arm64-musl@4.38.0': '@rollup/rollup-linux-arm64-musl@4.39.0':
resolution: {integrity: sha512-fQgqwKmW0REM4LomQ+87PP8w8xvU9LZfeLBKybeli+0yHT7VKILINzFEuggvnV9M3x1Ed4gUBmGUzCo/ikmFbQ==} resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@rollup/rollup-linux-loongarch64-gnu@4.38.0': '@rollup/rollup-linux-loongarch64-gnu@4.39.0':
resolution: {integrity: sha512-hz5oqQLXTB3SbXpfkKHKXLdIp02/w3M+ajp8p4yWOWwQRtHWiEOCKtc9U+YXahrwdk+3qHdFMDWR5k+4dIlddg==} resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==}
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
@ -646,8 +646,8 @@ packages:
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
'@rollup/rollup-linux-powerpc64le-gnu@4.38.0': '@rollup/rollup-linux-powerpc64le-gnu@4.39.0':
resolution: {integrity: sha512-NXqygK/dTSibQ+0pzxsL3r4Xl8oPqVoWbZV9niqOnIHV/J92fe65pOir0xjkUZDRSPyFRvu+4YOpJF9BZHQImw==} resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
@ -656,13 +656,13 @@ packages:
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
'@rollup/rollup-linux-riscv64-gnu@4.38.0': '@rollup/rollup-linux-riscv64-gnu@4.39.0':
resolution: {integrity: sha512-GEAIabR1uFyvf/jW/5jfu8gjM06/4kZ1W+j1nWTSSB3w6moZEBm7iBtzwQ3a1Pxos2F7Gz+58aVEnZHU295QTg==} resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
'@rollup/rollup-linux-riscv64-musl@4.38.0': '@rollup/rollup-linux-riscv64-musl@4.39.0':
resolution: {integrity: sha512-9EYTX+Gus2EGPbfs+fh7l95wVADtSQyYw4DfSBcYdUEAmP2lqSZY0Y17yX/3m5VKGGJ4UmIH5LHLkMJft3bYoA==} resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
@ -671,8 +671,8 @@ packages:
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
'@rollup/rollup-linux-s390x-gnu@4.38.0': '@rollup/rollup-linux-s390x-gnu@4.39.0':
resolution: {integrity: sha512-Mpp6+Z5VhB9VDk7RwZXoG2qMdERm3Jw07RNlXHE0bOnEeX+l7Fy4bg+NxfyN15ruuY3/7Vrbpm75J9QHFqj5+Q==} resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
@ -681,8 +681,8 @@ packages:
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@rollup/rollup-linux-x64-gnu@4.38.0': '@rollup/rollup-linux-x64-gnu@4.39.0':
resolution: {integrity: sha512-vPvNgFlZRAgO7rwncMeE0+8c4Hmc+qixnp00/Uv3ht2x7KYrJ6ERVd3/R0nUtlE6/hu7/HiiNHJ/rP6knRFt1w==} resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
@ -691,8 +691,8 @@ packages:
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@rollup/rollup-linux-x64-musl@4.38.0': '@rollup/rollup-linux-x64-musl@4.39.0':
resolution: {integrity: sha512-q5Zv+goWvQUGCaL7fU8NuTw8aydIL/C9abAVGCzRReuj5h30TPx4LumBtAidrVOtXnlB+RZkBtExMsfqkMfb8g==} resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
@ -701,8 +701,8 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@rollup/rollup-win32-arm64-msvc@4.38.0': '@rollup/rollup-win32-arm64-msvc@4.39.0':
resolution: {integrity: sha512-u/Jbm1BU89Vftqyqbmxdq14nBaQjQX1HhmsdBWqSdGClNaKwhjsg5TpW+5Ibs1mb8Es9wJiMdl86BcmtUVXNZg==} resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
@ -711,8 +711,8 @@ packages:
cpu: [ia32] cpu: [ia32]
os: [win32] os: [win32]
'@rollup/rollup-win32-ia32-msvc@4.38.0': '@rollup/rollup-win32-ia32-msvc@4.39.0':
resolution: {integrity: sha512-mqu4PzTrlpNHHbu5qleGvXJoGgHpChBlrBx/mEhTPpnAL1ZAYFlvHD7rLK839LLKQzqEQMFJfGrrOHItN4ZQqA==} resolution: {integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==}
cpu: [ia32] cpu: [ia32]
os: [win32] os: [win32]
@ -721,8 +721,8 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@rollup/rollup-win32-x64-msvc@4.38.0': '@rollup/rollup-win32-x64-msvc@4.39.0':
resolution: {integrity: sha512-jjqy3uWlecfB98Psxb5cD6Fny9Fupv9LrDSPTQZUROqjvZmcCqNu4UMl7qqhlUUGpwiAkotj6GYu4SZdcr/nLw==} resolution: {integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
@ -1974,8 +1974,8 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'} engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true hasBin: true
rollup@4.38.0: rollup@4.39.0:
resolution: {integrity: sha512-5SsIRtJy9bf1ErAOiFMFzl64Ex9X5V7bnJ+WlFMb+zmP459OSWCEG7b0ERZ+PEU7xPt4OG3RHbrp1LJlXxYTrw==} resolution: {integrity: sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'} engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true hasBin: true
@ -2310,8 +2310,8 @@ packages:
terser: terser:
optional: true optional: true
vite@5.4.16: vite@5.4.17:
resolution: {integrity: sha512-Y5gnfp4NemVfgOTDQAunSD4346fal44L9mszGGY/e+qxsRT5y1sMlS/8tiQ8AFAp+MFgYNSINdfEchJiPm41vQ==} resolution: {integrity: sha512-5+VqZryDj4wgCs55o9Lp+p8GE78TLVg0lasCH5xFZ4jacZjtqZa6JUw9/p0WeAojaOfncSM6v77InkFPGnvPvg==}
engines: {node: ^18.0.0 || >=20.0.0} engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -2860,120 +2860,120 @@ snapshots:
optionalDependencies: optionalDependencies:
rollup: 4.22.4 rollup: 4.22.4
'@rollup/pluginutils@5.1.0(rollup@4.38.0)': '@rollup/pluginutils@5.1.0(rollup@4.39.0)':
dependencies: dependencies:
'@types/estree': 1.0.6 '@types/estree': 1.0.6
estree-walker: 2.0.2 estree-walker: 2.0.2
picomatch: 2.3.1 picomatch: 2.3.1
optionalDependencies: optionalDependencies:
rollup: 4.38.0 rollup: 4.39.0
'@rollup/rollup-android-arm-eabi@4.22.4': '@rollup/rollup-android-arm-eabi@4.22.4':
optional: true optional: true
'@rollup/rollup-android-arm-eabi@4.38.0': '@rollup/rollup-android-arm-eabi@4.39.0':
optional: true optional: true
'@rollup/rollup-android-arm64@4.22.4': '@rollup/rollup-android-arm64@4.22.4':
optional: true optional: true
'@rollup/rollup-android-arm64@4.38.0': '@rollup/rollup-android-arm64@4.39.0':
optional: true optional: true
'@rollup/rollup-darwin-arm64@4.22.4': '@rollup/rollup-darwin-arm64@4.22.4':
optional: true optional: true
'@rollup/rollup-darwin-arm64@4.38.0': '@rollup/rollup-darwin-arm64@4.39.0':
optional: true optional: true
'@rollup/rollup-darwin-x64@4.22.4': '@rollup/rollup-darwin-x64@4.22.4':
optional: true optional: true
'@rollup/rollup-darwin-x64@4.38.0': '@rollup/rollup-darwin-x64@4.39.0':
optional: true optional: true
'@rollup/rollup-freebsd-arm64@4.38.0': '@rollup/rollup-freebsd-arm64@4.39.0':
optional: true optional: true
'@rollup/rollup-freebsd-x64@4.38.0': '@rollup/rollup-freebsd-x64@4.39.0':
optional: true optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.22.4': '@rollup/rollup-linux-arm-gnueabihf@4.22.4':
optional: true optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.38.0': '@rollup/rollup-linux-arm-gnueabihf@4.39.0':
optional: true optional: true
'@rollup/rollup-linux-arm-musleabihf@4.22.4': '@rollup/rollup-linux-arm-musleabihf@4.22.4':
optional: true optional: true
'@rollup/rollup-linux-arm-musleabihf@4.38.0': '@rollup/rollup-linux-arm-musleabihf@4.39.0':
optional: true optional: true
'@rollup/rollup-linux-arm64-gnu@4.22.4': '@rollup/rollup-linux-arm64-gnu@4.22.4':
optional: true optional: true
'@rollup/rollup-linux-arm64-gnu@4.38.0': '@rollup/rollup-linux-arm64-gnu@4.39.0':
optional: true optional: true
'@rollup/rollup-linux-arm64-musl@4.22.4': '@rollup/rollup-linux-arm64-musl@4.22.4':
optional: true optional: true
'@rollup/rollup-linux-arm64-musl@4.38.0': '@rollup/rollup-linux-arm64-musl@4.39.0':
optional: true optional: true
'@rollup/rollup-linux-loongarch64-gnu@4.38.0': '@rollup/rollup-linux-loongarch64-gnu@4.39.0':
optional: true optional: true
'@rollup/rollup-linux-powerpc64le-gnu@4.22.4': '@rollup/rollup-linux-powerpc64le-gnu@4.22.4':
optional: true optional: true
'@rollup/rollup-linux-powerpc64le-gnu@4.38.0': '@rollup/rollup-linux-powerpc64le-gnu@4.39.0':
optional: true optional: true
'@rollup/rollup-linux-riscv64-gnu@4.22.4': '@rollup/rollup-linux-riscv64-gnu@4.22.4':
optional: true optional: true
'@rollup/rollup-linux-riscv64-gnu@4.38.0': '@rollup/rollup-linux-riscv64-gnu@4.39.0':
optional: true optional: true
'@rollup/rollup-linux-riscv64-musl@4.38.0': '@rollup/rollup-linux-riscv64-musl@4.39.0':
optional: true optional: true
'@rollup/rollup-linux-s390x-gnu@4.22.4': '@rollup/rollup-linux-s390x-gnu@4.22.4':
optional: true optional: true
'@rollup/rollup-linux-s390x-gnu@4.38.0': '@rollup/rollup-linux-s390x-gnu@4.39.0':
optional: true optional: true
'@rollup/rollup-linux-x64-gnu@4.22.4': '@rollup/rollup-linux-x64-gnu@4.22.4':
optional: true optional: true
'@rollup/rollup-linux-x64-gnu@4.38.0': '@rollup/rollup-linux-x64-gnu@4.39.0':
optional: true optional: true
'@rollup/rollup-linux-x64-musl@4.22.4': '@rollup/rollup-linux-x64-musl@4.22.4':
optional: true optional: true
'@rollup/rollup-linux-x64-musl@4.38.0': '@rollup/rollup-linux-x64-musl@4.39.0':
optional: true optional: true
'@rollup/rollup-win32-arm64-msvc@4.22.4': '@rollup/rollup-win32-arm64-msvc@4.22.4':
optional: true optional: true
'@rollup/rollup-win32-arm64-msvc@4.38.0': '@rollup/rollup-win32-arm64-msvc@4.39.0':
optional: true optional: true
'@rollup/rollup-win32-ia32-msvc@4.22.4': '@rollup/rollup-win32-ia32-msvc@4.22.4':
optional: true optional: true
'@rollup/rollup-win32-ia32-msvc@4.38.0': '@rollup/rollup-win32-ia32-msvc@4.39.0':
optional: true optional: true
'@rollup/rollup-win32-x64-msvc@4.22.4': '@rollup/rollup-win32-x64-msvc@4.22.4':
optional: true optional: true
'@rollup/rollup-win32-x64-msvc@4.38.0': '@rollup/rollup-win32-x64-msvc@4.39.0':
optional: true optional: true
'@stylistic/eslint-plugin-js@1.8.0(eslint@9.9.1)': '@stylistic/eslint-plugin-js@1.8.0(eslint@9.9.1)':
@ -3000,25 +3000,25 @@ snapshots:
typescript: 5.5.4 typescript: 5.5.4
typescript-eslint: 8.26.0(eslint@9.9.1)(typescript@5.5.4) typescript-eslint: 8.26.0(eslint@9.9.1)(typescript@5.5.4)
'@sveltejs/vite-plugin-svelte-inspector@3.0.0-next.2(@sveltejs/vite-plugin-svelte@4.0.0-next.6(svelte@packages+svelte)(vite@5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)))(svelte@packages+svelte)(vite@5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))': '@sveltejs/vite-plugin-svelte-inspector@3.0.0-next.2(@sveltejs/vite-plugin-svelte@4.0.0-next.6(svelte@packages+svelte)(vite@5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)))(svelte@packages+svelte)(vite@5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))':
dependencies: dependencies:
'@sveltejs/vite-plugin-svelte': 4.0.0-next.6(svelte@packages+svelte)(vite@5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) '@sveltejs/vite-plugin-svelte': 4.0.0-next.6(svelte@packages+svelte)(vite@5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))
debug: 4.4.0 debug: 4.4.0
svelte: link:packages/svelte svelte: link:packages/svelte
vite: 5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) vite: 5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@sveltejs/vite-plugin-svelte@4.0.0-next.6(svelte@packages+svelte)(vite@5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))': '@sveltejs/vite-plugin-svelte@4.0.0-next.6(svelte@packages+svelte)(vite@5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))':
dependencies: dependencies:
'@sveltejs/vite-plugin-svelte-inspector': 3.0.0-next.2(@sveltejs/vite-plugin-svelte@4.0.0-next.6(svelte@packages+svelte)(vite@5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)))(svelte@packages+svelte)(vite@5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) '@sveltejs/vite-plugin-svelte-inspector': 3.0.0-next.2(@sveltejs/vite-plugin-svelte@4.0.0-next.6(svelte@packages+svelte)(vite@5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)))(svelte@packages+svelte)(vite@5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))
debug: 4.4.0 debug: 4.4.0
deepmerge: 4.3.1 deepmerge: 4.3.1
kleur: 4.1.5 kleur: 4.1.5
magic-string: 0.30.17 magic-string: 0.30.17
svelte: link:packages/svelte svelte: link:packages/svelte
vite: 5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) vite: 5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
vitefu: 0.2.5(vite@5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)) vitefu: 0.2.5(vite@5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -4292,30 +4292,30 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.22.4 '@rollup/rollup-win32-x64-msvc': 4.22.4
fsevents: 2.3.3 fsevents: 2.3.3
rollup@4.38.0: rollup@4.39.0:
dependencies: dependencies:
'@types/estree': 1.0.7 '@types/estree': 1.0.7
optionalDependencies: optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.38.0 '@rollup/rollup-android-arm-eabi': 4.39.0
'@rollup/rollup-android-arm64': 4.38.0 '@rollup/rollup-android-arm64': 4.39.0
'@rollup/rollup-darwin-arm64': 4.38.0 '@rollup/rollup-darwin-arm64': 4.39.0
'@rollup/rollup-darwin-x64': 4.38.0 '@rollup/rollup-darwin-x64': 4.39.0
'@rollup/rollup-freebsd-arm64': 4.38.0 '@rollup/rollup-freebsd-arm64': 4.39.0
'@rollup/rollup-freebsd-x64': 4.38.0 '@rollup/rollup-freebsd-x64': 4.39.0
'@rollup/rollup-linux-arm-gnueabihf': 4.38.0 '@rollup/rollup-linux-arm-gnueabihf': 4.39.0
'@rollup/rollup-linux-arm-musleabihf': 4.38.0 '@rollup/rollup-linux-arm-musleabihf': 4.39.0
'@rollup/rollup-linux-arm64-gnu': 4.38.0 '@rollup/rollup-linux-arm64-gnu': 4.39.0
'@rollup/rollup-linux-arm64-musl': 4.38.0 '@rollup/rollup-linux-arm64-musl': 4.39.0
'@rollup/rollup-linux-loongarch64-gnu': 4.38.0 '@rollup/rollup-linux-loongarch64-gnu': 4.39.0
'@rollup/rollup-linux-powerpc64le-gnu': 4.38.0 '@rollup/rollup-linux-powerpc64le-gnu': 4.39.0
'@rollup/rollup-linux-riscv64-gnu': 4.38.0 '@rollup/rollup-linux-riscv64-gnu': 4.39.0
'@rollup/rollup-linux-riscv64-musl': 4.38.0 '@rollup/rollup-linux-riscv64-musl': 4.39.0
'@rollup/rollup-linux-s390x-gnu': 4.38.0 '@rollup/rollup-linux-s390x-gnu': 4.39.0
'@rollup/rollup-linux-x64-gnu': 4.38.0 '@rollup/rollup-linux-x64-gnu': 4.39.0
'@rollup/rollup-linux-x64-musl': 4.38.0 '@rollup/rollup-linux-x64-musl': 4.39.0
'@rollup/rollup-win32-arm64-msvc': 4.38.0 '@rollup/rollup-win32-arm64-msvc': 4.39.0
'@rollup/rollup-win32-ia32-msvc': 4.38.0 '@rollup/rollup-win32-ia32-msvc': 4.39.0
'@rollup/rollup-win32-x64-msvc': 4.38.0 '@rollup/rollup-win32-x64-msvc': 4.39.0
fsevents: 2.3.3 fsevents: 2.3.3
rrweb-cssom@0.7.1: {} rrweb-cssom@0.7.1: {}
@ -4562,7 +4562,7 @@ snapshots:
debug: 4.4.0 debug: 4.4.0
es-module-lexer: 1.6.0 es-module-lexer: 1.6.0
pathe: 1.1.2 pathe: 1.1.2
vite: 5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) vite: 5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
transitivePeerDependencies: transitivePeerDependencies:
- '@types/node' - '@types/node'
- less - less
@ -4574,10 +4574,10 @@ snapshots:
- supports-color - supports-color
- terser - terser
vite-plugin-inspect@0.8.4(rollup@4.38.0)(vite@5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)): vite-plugin-inspect@0.8.4(rollup@4.39.0)(vite@5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)):
dependencies: dependencies:
'@antfu/utils': 0.7.8 '@antfu/utils': 0.7.8
'@rollup/pluginutils': 5.1.0(rollup@4.38.0) '@rollup/pluginutils': 5.1.0(rollup@4.39.0)
debug: 4.4.0 debug: 4.4.0
error-stack-parser-es: 0.1.1 error-stack-parser-es: 0.1.1
fs-extra: 11.2.0 fs-extra: 11.2.0
@ -4585,7 +4585,7 @@ snapshots:
perfect-debounce: 1.0.0 perfect-debounce: 1.0.0
picocolors: 1.1.1 picocolors: 1.1.1
sirv: 2.0.4 sirv: 2.0.4
vite: 5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) vite: 5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
transitivePeerDependencies: transitivePeerDependencies:
- rollup - rollup
- supports-color - supports-color
@ -4602,11 +4602,11 @@ snapshots:
sass: 1.70.0 sass: 1.70.0
terser: 5.27.0 terser: 5.27.0
vite@5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0): vite@5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0):
dependencies: dependencies:
esbuild: 0.21.5 esbuild: 0.21.5
postcss: 8.5.3 postcss: 8.5.3
rollup: 4.38.0 rollup: 4.39.0
optionalDependencies: optionalDependencies:
'@types/node': 20.12.7 '@types/node': 20.12.7
fsevents: 2.3.3 fsevents: 2.3.3
@ -4614,9 +4614,9 @@ snapshots:
sass: 1.70.0 sass: 1.70.0
terser: 5.27.0 terser: 5.27.0
vitefu@0.2.5(vite@5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)): vitefu@0.2.5(vite@5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)):
optionalDependencies: optionalDependencies:
vite: 5.4.16(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0) vite: 5.4.17(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
vitest@2.1.9(@types/node@20.12.7)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0): vitest@2.1.9(@types/node@20.12.7)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0):
dependencies: dependencies:

Loading…
Cancel
Save