Get all functions that manage state.
I'll help you find all functions that manage state in the Svelte project. Let me search through the codebase to identify these functions.
Tool Call: Search files for regex function.*state|state.*function|setState|getState|updateState|manageState
Status: Completed
Showing matches 1-20 (there were more matches found; use offset: 20 to see next page):
Unlike other frameworks you may have encountered, there is no API for interacting with state — `count` is just a number, rather than an object or a function, and you can update it like you would update any other variable.
## Passing state into functions
Anything read synchronously inside the `$derived` expression (or `$derived.by` function body) is considered a _dependency_ of the derived state. When the state changes, the derived will be marked as _dirty_ and recalculated when it is next read.
Effects are functions that run when state updates, and can be used for things like calling third-party libraries, drawing on `<canvas>` elements, or making network requests. They only run in the browser, not during server-side rendering.
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.
`$effect` automatically picks up any reactive values (`$state`, `$derived`, `$props`) that are _synchronously_ read inside its function body (including indirectly, via function calls) and registers them as dependencies. When those dependencies change, the `$effect` schedules a re-run.
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.
<script>
import { doSomeWork } from './elsewhere';
$effect(() => {
+++// $inspect.trace must be the first statement of a function body+++
+++$inspect.trace();+++
doSomeWork();
});
</script>
## Matches in svelte/documentation/docs/03-template-syntax/[email protected]
### L5-6
Attachments are functions that run in an effect when an element is mounted to the DOM or when state read inside the function updates.
### L60-61
Since the tooltip(content)
expression runs inside an effect, the attachment will be destroyed and recreated whenever content
changes. The same thing would happen for any state read inside the attachment function when it first runs. (If this isn't what you want, see Controlling when attachments re-run.)
## Matches in svelte/documentation/docs/03-template-syntax/13-use.md
### L8-9
Actions are functions that are called when an element is mounted. They are added with the use:
directive, and will typically use an $effect
so that they can reset any state when the element is unmounted:
## Matches in svelte/documentation/docs/03-template-syntax/14-transition.md
### L71-72
The t
argument passed to css
is a value between 0
and 1
after the easing
function has been applied. In transitions run from 0
to 1
, out transitions run from 1
to 0
— in other words, 1
is the element's natural state, as though no transition had been applied. The u
argument is equal to 1 - t
.
## Matches in svelte/documentation/docs/07-misc/07-v5-migration-guide.md
### L482-483
You may see that the migration script converts some of your $:
statements to a run
function which is imported from svelte/legacy
. This happens if the migration script couldn't reliably migrate the statement to a $derived
and concluded this is a side effect instead. In some cases this may be wrong and it's best to change this to use a $derived
instead. In other cases it may be right, but since $:
statements also ran on the server but $effect
does not, it isn't safe to transform it as such. Instead, run
is used as a stopgap solution. run
mimics most of the characteristics of $:
, in that it runs on the server once, and runs as $effect.pre
on the client ($effect.pre
runs before changes are applied to the DOM; most likely you want to use $effect
instead).
## Matches in svelte/documentation/docs/98-reference/.generated/compile-errors.md
### L340-341
Cannot export derived state from a module. To expose the current derived value, export a function returning its value
`$inspect.trace(...)` must be the first statement of a function body
### L884-885
Cannot export state from a module if it is reassigned. Either export a function returning the state value or only mutate the state value's properties
This 'breaks the link' to the original state declaration. For example, if you pass the state to a function, the function loses access to the state once it is reassigned:
For more info, see [Passing state into functions]($state#Passing-state-into-functions).
In legacy mode, any top-level statement (i.e. not inside a block or a function) can be made reactive by prefixing it with a `$:` [label](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label). These statements run after other code in the `<script>` and before the component markup is rendered, then whenever the values that they depend on change.
- Don't crash when using an arrow function as a statement ([#4617](https://github.com/sveltejs/svelte/issues/4617))
- Deconflict `bind:this` variable ([#4636](https://github.com/sveltejs/svelte/issues/4636))
Let me search more specifically for function definitions that handle state management:
Tool Call: Search files for regex function\s+\w*[sS]tate|export\s+function.*[sS]tate|\$state|\$derived|\$effect
Status: Completed
Showing matches 1-20 (there were more matches found; use offset: 20 to see next page):
/**
* `$effect()` can only be used as an expression statement
* @param {null | number | NodeLike} node
* @returns {never}
*/
export function effect_invalid_placement(node) {
e(node, 'effect_invalid_placement', `\`$effect()\` can only be used as an expression statement\nhttps://svelte.dev/e/effect_invalid_placement`);
}
/**
* `$:` is not allowed in runes mode, use `$derived` or `$effect` instead
* @param {null | number | NodeLike} node
* @returns {never}
*/
export function legacy_reactive_statement_invalid(node) {
e(node, 'legacy_reactive_statement_invalid', `\`$:\` is not allowed in runes mode, use \`$derived\` or \`$effect\` instead\nhttps://svelte.dev/e/legacy_reactive_statement_invalid`);
}
export function state_field_duplicate(node, name) {
e(node, 'state_field_duplicate', `\`${name}\` has already been declared on this class\nhttps://svelte.dev/e/state_field_duplicate`);
}
export function state_field_invalid_assignment(node) {
e(node, 'state_field_invalid_assignment', `Cannot assign to a state field before its declaration\nhttps://svelte.dev/e/state_field_invalid_assignment`);
}
export function state_invalid_export(node) {
e(node, 'state_invalid_export', `Cannot export state from a module if it is reassigned. Either export a function returning the state value or only mutate the state value's properties\nhttps://svelte.dev/e/state_invalid_export`);
}
export function state_invalid_placement(node, rune) {
e(node, 'state_invalid_placement', `\`${rune}(...)\` can only be used as a variable declaration initializer, a class field declaration, or the first assignment to a class field at the top level of the constructor.\nhttps://svelte.dev/e/state_invalid_placement`);
}
* If true, then we need to move all reactive statements to the end of the script block,
* in their correct order. Svelte 4 reordered reactive statements, $derived/$effect.pre
* don't have this behavior.
str.appendRight(
insertion_point,
`\n${indent}${[...state.derived_components.entries()].map(([init, name]) => `const ${name} = $derived(${init});`).join(`\n${indent}`)}\n`
);
str.appendRight(
insertion_point,
`\n${indent}${[...state.derived_conflicting_slots.entries()].map(([name, init]) => `const ${name} = $derived(${init});`).join(`\n${indent}`)}\n`
);
if (declarator.init) {
let { start, end } = /** @type {{ start: number, end: number }} */ (declarator.init);
if (declarator.init.type === 'SequenceExpression') {
while (state.str.original[start] !== '(') start -= 1;
while (state.str.original[end - 1] !== ')') end += 1;
}
check_rune_binding('state');
state.str.prependLeft(start, '$state(');
2 lines remaining in ancestor node. Read the file to see all.
check_rune_binding('derived');
// Someone wrote a `$: { ... }` statement which we can turn into a `$derived`
state.str.appendRight(
/** @type {number} */ (declarator.id.typeAnnotation?.end ?? declarator.id.end),
' = $derived('
);
state.str.prependLeft(
/** @type {number} */ (declarator.id.typeAnnotation?.end ?? declarator.id.end),
' = $state('
);
if (should_be_state) {
// someone wrote a `$: foo = ...` statement which we can turn into `let foo = $state(...)`
state.str.appendRight(
/** @type {number} */ (declarator.id.typeAnnotation?.end ?? declarator.id.end),
state.str
.snip(
/** @type {number} */ (
/** @type {AssignmentExpression} */ (assignment_in_labeled).right.start
),
/** @type {number} */ (
/** @type {AssignmentExpression} */ (assignment_in_labeled).right.end
9 lines remaining in ancestor node. Read the file to see all.
) {
let { start, end } = /** @type {{ start: number, end: number }} */ (right);
check_rune_binding('derived');
// $derived
state.str.update(
/** @type {number} */ (node.start),
/** @type {number} */ (node.body.expression.start),
'let '
);
16 lines remaining in ancestor node. Read the file to see all.
}
state.str.prependRight(start, `$derived(`);
// in a case like `$: ({ a } = b())`, there's already a trailing parenthesis.
binding.kind === 'state'
? ' = $state()'
: expression_ids.length === 0
? ` = $state(${state.str.original.substring(/** @type {number} */ (right.start), right.end)})`
: '';
const is_block_stmt = node.body.type === 'BlockStatement';
const start_end = /** @type {number} */ (node.body.start);
// TODO try to find out if we can use $derived.by instead?
if (is_block_stmt) {
state.str.update(
(declaration !== null &&
// const state = $state(0) is valid
(get_rune(init, instance.scope) === null ||
// rune-line names received as props are valid too (but we have to protect against $props as store)
(store_name !== 'props' && get_rune(init, instance.scope) === '$props')) &&
// allow `import { derived } from 'svelte/store'` in the same file as `const x = $derived(..)` because one is not a subscription to the other
!(
name === '$derived' &&
declaration.initial?.type === 'ImportDeclaration' &&
declaration.initial.source.value === 'svelte/store'
))
Let me continue searching for more specific state management functions:
Tool Call: Get page 2 of search results for regex function.*state.*|export.*function.*state|function.*State|export.*State
Status: Completed
Showing matches 21-40 (there were more matches found; use offset: 40 to see next page):
) {
// MethodDefinition (-5) -> FunctionExpression (-4) -> BlockStatement (-3) -> ExpressionStatement (-2) -> AssignmentExpression (-1)
const parent = get_parent(context.path, -5);
return parent?.type === 'MethodDefinition' && parent.kind === 'constructor';
}
Matches in svelte/packages/svelte/src/compiler/phases/2-analyze/visitors/ExportDefaultDeclaration.js
if (node.declaration.type === 'Identifier') {
validate_export(node, context.state.scope, node.declaration.name);
}
} else {
validate_export(node, context.state.scope, local_name);
}
export function ExpressionStatement(node, context) {
// warn on `new Component({ target: ... })` if imported from a `.svelte` file
if (
node.expression.type === 'NewExpression' &&
node.expression.callee.type === 'Identifier' &&
node.expression.arguments.length === 1 &&
node.expression.arguments[0].type === 'ObjectExpression' &&
node.expression.arguments[0].properties.some(
(p) => p.type === 'Property' && p.key.type === 'Identifier' && p.key.name === 'target'
)
) {
19 lines remaining in ancestor node. Read the file to see all.
export function LabeledStatement(node, context) {
if (node.label.name === '$') {
const parent = /** @type {AST.SvelteNode} */ (context.path.at(-1));
const is_reactive_statement =
context.state.ast_type === 'instance' && parent.type === 'Program';
if (is_reactive_statement) {
if (context.state.analysis.runes) {
e.legacy_reactive_statement_invalid(node);
}
73 lines remaining in ancestor node. Read the file to see all.
context.next({
...context.state,
reactive_statement,
function_depth: context.state.scope.function_depth + 1
});
} else {
const undefined_export = context.state.analysis.undefined_exports.get(name);
if (undefined_export) {
e.snippet_invalid_export(undefined_export);
}
}
for (const [name] of context.state.scope.references) {
const binding = context.state.scope.get(name);
if (binding && binding.scope.function_depth < context.state.scope.function_depth) {
context.state.expression.references.add(binding);
}
}
context.next({
...context.state,
function_depth: context.state.function_depth + 1,
expression: null
});
export function validate_opening_tag(node, state, expected) {
if (state.analysis.source[node.start + 1] !== expected) {
// avoid a sea of red and only mark the first few characters
e.block_unexpected_character({ start: node.start, end: node.start + 5 }, expected);
}
}
export function ensure_no_module_import_conflict(node, state) {
const ids = extract_identifiers(node.id);
for (const id of ids) {
if (
state.ast_type === 'instance' &&
state.scope === state.analysis.instance.scope &&
state.analysis.module.scope.get(id.name)?.declaration_kind === 'import'
) {
// TODO fix the message here
e.declaration_duplicate_module_import(node.id);
}
2 lines remaining in ancestor node. Read the file to see all.
/**
* Checks that the exported name is not a derived or reassigned state variable.
* @param {Node} node
* @param {Scope} scope
* @param {string} name
*/
const visitors = {
_: function set_scope(node, { next, state }) {
const scope = state.scopes.get(node);
if (scope && scope !== state.scope) {
const transform = { ...state.transform };
for (const [name, binding] of scope.declarations) {
if (
binding.kind === 'normal' ||
// Reads of `$state(...)` declarations are not
64 lines remaining in ancestor node. Read the file to see all.
Matches in svelte/packages/svelte/src/compiler/phases/3-transform/client/transform-template/index.js
export function transform_template(state, namespace, flags = 0) {
const tree = state.options.fragments === 'tree';
const expression = tree ? state.template.as_tree() : state.template.as_html();
if (tree) {
if (namespace === 'svg') flags |= TEMPLATE_USE_SVG;
if (namespace === 'mathml') flags |= TEMPLATE_USE_MATHML;
}
let call = b.call(
20 lines remaining in ancestor node. Read the file to see all.
export function is_state_source(binding, analysis) {
return (
(binding.kind === 'state' || binding.kind === 'raw_state') &&
(!analysis.immutable || binding.reassigned || analysis.accessors)
);
}
export function build_getter(node, state) {
if (Object.hasOwn(state.transform, node.name)) {
const binding = state.scope.get(node.name);
// don't transform the declaration itself
if (node !== binding?.node) {
return state.transform[node.name].read(node);
}
}
return node;
1 lines remaining in ancestor node. Read the file to see all.
export function get_prop_source(binding, state, name, initial) {
/** @type {Expression[]} */
const args = [b.id('$$props'), b.literal(name)];
let flags = 0;
if (binding.kind === 'bindable_prop') {
flags |= PROPS_IS_BINDABLE;
}
if (state.analysis.immutable) {
45 lines remaining in ancestor node. Read the file to see all.
export function is_prop_source(binding, state) {
return (
(binding.kind === 'prop' || binding.kind === 'bindable_prop') &&
(!state.analysis.runes ||
state.analysis.accessors ||
binding.reassigned ||
binding.initial ||
// Until legacy mode is gone, we also need to use the prop source when only mutated is true,
// because the parent could be a legacy component which needs coarse-grained reactivity
binding.updated)
);
1 lines remaining in ancestor node. Read the file to see all.
export function create_derived(state, arg) {
return b.call(state.analysis.runes ? '$.derived' : '$.derived_safe_equal', arg);
}
/** @import { ArrowFunctionExpression, BlockStatement, Expression, FunctionDeclaration, FunctionExpression, Statement } from 'estree' */
/** @import { ComponentContext } from '../types' */
import { add_state_transformers } from './shared/declarations.js';
import * as b from '#compiler/builders';
/**
* @param {BlockStatement} node
* @param {ComponentContext} context
*/
export function BlockStatement(node, context) {
add_state_transformers(context);
const tracing = context.state.scope.tracing;
if (tracing !== null) {
const parent =
/** @type {ArrowFunctionExpression | FunctionDeclaration | FunctionExpression} */ (
context.path.at(-1)
);
const is_async = parent.async;
13 lines remaining in ancestor node. Read the file to see all.
Now let me search for more core state management functions in the runtime:
Tool Call: Search files for regex export\s+function\s+(state|derived|effect|signal|reactive|store|writable|readable)
Status: Completed
Showing matches 1-20 (there were more matches found; use offset: 20 to see next page):
export function derived_invalid_export(node) {
e(node, 'derived_invalid_export', `Cannot export derived state from a module. To expose the current derived value, export a function returning its value\nhttps://svelte.dev/e/derived_invalid_export`);
}
export function effect_invalid_placement(node) {
e(node, 'effect_invalid_placement', `\`$effect()\` can only be used as an expression statement\nhttps://svelte.dev/e/effect_invalid_placement`);
}
export function reactive_declaration_cycle(node, cycle) {
e(node, 'reactive_declaration_cycle', `Cyclical dependency detected: ${cycle}\nhttps://svelte.dev/e/reactive_declaration_cycle`);
}
export function state_field_duplicate(node, name) {
e(node, 'state_field_duplicate', `\`${name}\` has already been declared on this class\nhttps://svelte.dev/e/state_field_duplicate`);
}
export function state_field_invalid_assignment(node) {
e(node, 'state_field_invalid_assignment', `Cannot assign to a state field before its declaration\nhttps://svelte.dev/e/state_field_invalid_assignment`);
}
export function state_invalid_export(node) {
e(node, 'state_invalid_export', `Cannot export state from a module if it is reassigned. Either export a function returning the state value or only mutate the state value's properties\nhttps://svelte.dev/e/state_invalid_export`);
}
export function state_invalid_placement(node, rune) {
e(node, 'state_invalid_placement', `\`${rune}(...)\` can only be used as a variable declaration initializer, a class field declaration, or the first assignment to a class field at the top level of the constructor.\nhttps://svelte.dev/e/state_invalid_placement`);
}
export function store_invalid_scoped_subscription(node) {
e(node, 'store_invalid_scoped_subscription', `Cannot subscribe to stores that are not declared at the top level of the component\nhttps://svelte.dev/e/store_invalid_scoped_subscription`);
}
export function store_invalid_subscription(node) {
e(node, 'store_invalid_subscription', `Cannot reference store value inside \`<script module>\`\nhttps://svelte.dev/e/store_invalid_subscription`);
}
export function store_invalid_subscription_module(node) {
e(node, 'store_invalid_subscription_module', `Cannot reference store value outside a \`.svelte\` file\nhttps://svelte.dev/e/store_invalid_subscription_module`);
}
export function reactive_declaration_invalid_placement(node) {
w(node, 'reactive_declaration_invalid_placement', `Reactive declarations only exist at the top level of the instance script\nhttps://svelte.dev/e/reactive_declaration_invalid_placement`);
}
export function reactive_declaration_module_script_dependency(node) {
w(node, 'reactive_declaration_module_script_dependency', `Reassignments of module-level declarations will not cause reactive statements to update\nhttps://svelte.dev/e/reactive_declaration_module_script_dependency`);
}
export function state_referenced_locally(node, name, type) {
w(node, 'state_referenced_locally', `This reference only captures the initial value of \`${name}\`. Did you mean to reference it inside a ${type} instead?\nhttps://svelte.dev/e/state_referenced_locally`);
}
export function store_rune_conflict(node, name) {
w(node, 'store_rune_conflict', `It looks like you're using the \`$${name}\` rune, but there is a local binding called \`${name}\`. Referencing a local variable with a \`$\` prefix will create a store subscription. Please rename \`${name}\` to avoid the ambiguity\nhttps://svelte.dev/e/store_rune_conflict`);
}
export function reactive_import(fn) {
var s = source(0);
return function () {
if (arguments.length === 1) {
set(s, get(s) + 1);
return arguments[0];
} else {
get(s);
return fn();
}
2 lines remaining in ancestor node. Read the file to see all.
export function derived_references_self() {
if (DEV) {
const error = new Error(`derived_references_self\nA derived value cannot reference itself recursively\nhttps://svelte.dev/e/derived_references_self`);
error.name = 'Svelte error';
throw error;
} else {
throw new Error(`https://svelte.dev/e/derived_references_self`);
}
}
export function effect_in_teardown(rune) {
if (DEV) {
const error = new Error(`effect_in_teardown\n\`${rune}\` cannot be used inside an effect cleanup function\nhttps://svelte.dev/e/effect_in_teardown`);
error.name = 'Svelte error';
throw error;
} else {
throw new Error(`https://svelte.dev/e/effect_in_teardown`);
}
}
export function effect_in_unowned_derived() {
if (DEV) {
const error = new Error(`effect_in_unowned_derived\nEffect cannot be created inside a \`$derived\` value that was not itself created inside an effect\nhttps://svelte.dev/e/effect_in_unowned_derived`);
error.name = 'Svelte error';
throw error;
} else {
throw new Error(`https://svelte.dev/e/effect_in_unowned_derived`);
}
}
export function effect_orphan(rune) {
if (DEV) {
const error = new Error(`effect_orphan\n\`${rune}\` can only be used inside an effect (e.g. during component initialisation)\nhttps://svelte.dev/e/effect_orphan`);
error.name = 'Svelte error';
throw error;
} else {
throw new Error(`https://svelte.dev/e/effect_orphan`);
}
}
export function effect_update_depth_exceeded() {
if (DEV) {
const error = new Error(`effect_update_depth_exceeded\nMaximum update depth exceeded. This can happen when a reactive block or effect repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops\nhttps://svelte.dev/e/effect_update_depth_exceeded`);
error.name = 'Svelte error';
throw error;
} else {
throw new Error(`https://svelte.dev/e/effect_update_depth_exceeded`);
}
}
Let me search for the core state management functions in the runtime directory:
Tool Call: 50 matches Status: Completed
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/constants.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/context.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dev/assign.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dev/console-log.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dev/css.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dev/debug.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dev/elements.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dev/equality.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dev/hmr.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dev/inspect.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dev/legacy.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dev/ownership.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dev/tracing.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dev/validation.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/blocks/await.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/blocks/boundary.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/blocks/css-props.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/blocks/each.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/blocks/html.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/blocks/if.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/blocks/key.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/blocks/slot.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/blocks/snippet.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/blocks/svelte-component.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/blocks/svelte-element.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/blocks/svelte-head.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/css.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/actions.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/attachments.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/attributes.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/bindings/document.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/bindings/input.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/bindings/media.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/bindings/navigator.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/bindings/props.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/bindings/select.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/bindings/shared.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/bindings/size.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/bindings/this.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/bindings/universal.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/bindings/window.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/class.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/custom-element.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/events.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/misc.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/style.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/elements/transitions.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/hydration.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/legacy/event-modifiers.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/dom/legacy/lifecycle.js
Let me check the main reactive/state files:
Tool Call: 6 matches Status: Completed
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/reactivity/deriveds.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/reactivity/effects.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/reactivity/equality.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/reactivity/props.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/reactivity/sources.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/reactivity/store.js
Perfect! Let me examine these core reactivity files to find the state management functions:
Tool Call: sources.js Status: Completed
/** @import { Derived, Effect, Source, Value } from '#client' */
import { DEV } from 'esm-env';
import {
active_reaction,
active_effect,
untracked_writes,
get,
schedule_effect,
set_untracked_writes,
set_signal_status,
untrack,
increment_write_version,
update_effect,
reaction_sources,
check_dirtiness,
untracking,
is_destroying_effect,
push_reaction_value
} from '../runtime.js';
import { equals, safe_equals } from './equality.js';
import {
CLEAN,
DERIVED,
DIRTY,
BRANCH_EFFECT,
INSPECT_EFFECT,
UNOWNED,
MAYBE_DIRTY,
BLOCK_EFFECT,
ROOT_EFFECT
} from '#client/constants';
import * as e from '../errors.js';
import { legacy_mode_flag, tracing_mode_flag } from '../../flags/index.js';
import { get_stack, tag_proxy } from '../dev/tracing.js';
import { component_context, is_runes } from '../context.js';
import { proxy } from '../proxy.js';
import { execute_derived } from './deriveds.js';
export let inspect_effects = new Set();
/** @type {Map<Source, any>} */
export const old_values = new Map();
/**
* @param {Set<any>} v
*/
export function set_inspect_effects(v) {
inspect_effects = v;
}
/**
* @template V
* @param {V} v
* @param {Error | null} [stack]
* @returns {Source<V>}
*/
// TODO rename this to `state` throughout the codebase
export function source(v, stack) {
/** @type {Value} */
var signal = {
f: 0, // TODO ideally we could skip this altogether, but it causes type errors
v,
reactions: null,
equals,
rv: 0,
wv: 0
};
if (DEV && tracing_mode_flag) {
signal.created = stack ?? get_stack('CreatedAt');
signal.updated = null;
signal.set_during_effect = false;
signal.trace = null;
}
return signal;
}
/**
* @template V
* @param {V} v
* @param {Error | null} [stack]
*/
/*#__NO_SIDE_EFFECTS__*/
export function state(v, stack) {
const s = source(v, stack);
push_reaction_value(s);
return s;
}
/**
* @template V
* @param {V} initial_value
* @param {boolean} [immutable]
* @returns {Source<V>}
*/
/*#__NO_SIDE_EFFECTS__*/
export function mutable_source(initial_value, immutable = false, trackable = true) {
const s = source(initial_value);
if (!immutable) {
s.equals = safe_equals;
}
// bind the signal to the component context, in case we need to
// track updates to trigger beforeUpdate/afterUpdate callbacks
if (legacy_mode_flag && trackable && component_context !== null && component_context.l !== null) {
(component_context.l.s ??= []).push(s);
}
return s;
}
/**
* @template V
* @param {Value<V>} source
* @param {V} value
*/
export function mutate(source, value) {
set(
source,
untrack(() => get(source))
);
return value;
}
/**
* @template V
* @param {Source<V>} source
* @param {V} value
* @param {boolean} [should_proxy]
* @returns {V}
*/
export function set(source, value, should_proxy = false) {
if (
active_reaction !== null &&
// since we are untracking the function inside `$inspect.with` we need to add this check
// to ensure we error if state is set inside an inspect effect
(!untracking || (active_reaction.f & INSPECT_EFFECT) !== 0) &&
is_runes() &&
(active_reaction.f & (DERIVED | BLOCK_EFFECT | INSPECT_EFFECT)) !== 0 &&
!(reaction_sources?.[1].includes(source) && reaction_sources[0] === active_reaction)
) {
e.state_unsafe_mutation();
}
let new_value = should_proxy ? proxy(value) : value;
if (DEV) {
tag_proxy(new_value, /** @type {string} */ (source.label));
}
return internal_set(source, new_value);
}
/**
* @template V
* @param {Source<V>} source
* @param {V} value
* @returns {V}
*/
export function internal_set(source, value) {
if (!source.equals(value)) {
var old_value = source.v;
if (is_destroying_effect) {
old_values.set(source, value);
} else {
old_values.set(source, old_value);
}
source.v = value;
if (DEV && tracing_mode_flag) {
source.updated = get_stack('UpdatedAt');
if (active_effect !== null) {
source.set_during_effect = true;
}
}
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);
}
source.wv = increment_write_version();
mark_reactions(source, DIRTY);
// It's possible that the current reaction might not have up-to-date dependencies
// whilst it's actively running. So in the case of ensuring it registers the reaction
// properly for itself, we need to ensure the current effect actually gets
// scheduled. i.e: `$effect(() => x++)`
if (
is_runes() &&
active_effect !== null &&
(active_effect.f & CLEAN) !== 0 &&
(active_effect.f & (BRANCH_EFFECT | ROOT_EFFECT)) === 0
) {
if (untracked_writes === null) {
set_untracked_writes([source]);
} else {
untracked_writes.push(source);
}
}
if (DEV && inspect_effects.size > 0) {
const inspects = Array.from(inspect_effects);
for (const effect of inspects) {
// Mark clean inspect-effects as maybe dirty and then check their dirtiness
// instead of just updating the effects - this way we avoid overfiring.
if ((effect.f & CLEAN) !== 0) {
set_signal_status(effect, MAYBE_DIRTY);
}
if (check_dirtiness(effect)) {
update_effect(effect);
}
}
inspect_effects.clear();
}
}
return value;
}
/**
* @template {number | bigint} T
* @param {Source<T>} source
* @param {1 | -1} [d]
* @returns {T}
*/
export function update(source, d = 1) {
var value = get(source);
var result = d === 1 ? value++ : value--;
set(source, value);
// @ts-expect-error
return result;
}
/**
* @template {number | bigint} T
* @param {Source<T>} source
* @param {1 | -1} [d]
* @returns {T}
*/
export function update_pre(source, d = 1) {
var value = get(source);
// @ts-expect-error
return set(source, d === 1 ? ++value : --value);
}
/**
* @param {Value} signal
* @param {number} status should be DIRTY or MAYBE_DIRTY
* @returns {void}
*/
function mark_reactions(signal, status) {
var reactions = signal.reactions;
if (reactions === null) return;
var runes = is_runes();
var length = reactions.length;
for (var i = 0; i < length; i++) {
var reaction = reactions[i];
var flags = reaction.f;
// Skip any effects that are already dirty
if ((flags & DIRTY) !== 0) continue;
// In legacy mode, skip the current effect to prevent infinite loops
if (!runes && reaction === active_effect) continue;
// Inspect effects need to run immediately, so that the stack trace makes sense
if (DEV && (flags & INSPECT_EFFECT) !== 0) {
inspect_effects.add(reaction);
continue;
}
set_signal_status(reaction, status);
// If the signal a) was previously clean or b) is an unowned derived, then mark it
if ((flags & (CLEAN | UNOWNED)) !== 0) {
if ((flags & DERIVED) !== 0) {
mark_reactions(/** @type {Derived} */ (reaction), MAYBE_DIRTY);
} else {
schedule_effect(/** @type {Effect} */ (reaction));
}
}
}
}
Tool Call: deriveds.js Status: Completed
/** @import { Derived, Effect } from '#client' */
import { DEV } from 'esm-env';
import { CLEAN, DERIVED, DIRTY, EFFECT_HAS_DERIVED, MAYBE_DIRTY, UNOWNED } from '#client/constants';
import {
active_reaction,
active_effect,
set_signal_status,
skip_reaction,
update_reaction,
increment_write_version,
set_active_effect,
push_reaction_value,
is_destroying_effect
} from '../runtime.js';
import { equals, safe_equals } from './equality.js';
import * as e from '../errors.js';
import { destroy_effect } from './effects.js';
import { inspect_effects, set_inspect_effects } from './sources.js';
import { get_stack } from '../dev/tracing.js';
import { tracing_mode_flag } from '../../flags/index.js';
import { component_context } from '../context.js';
/**
* @template V
* @param {() => V} fn
* @returns {Derived<V>}
*/
/*#__NO_SIDE_EFFECTS__*/
export function derived(fn) {
var flags = DERIVED | DIRTY;
var parent_derived =
active_reaction !== null && (active_reaction.f & DERIVED) !== 0
? /** @type {Derived} */ (active_reaction)
: null;
if (active_effect === null || (parent_derived !== null && (parent_derived.f & UNOWNED) !== 0)) {
flags |= UNOWNED;
} else {
// Since deriveds are evaluated lazily, any effects created inside them are
// created too late to ensure that the parent effect is added to the tree
active_effect.f |= EFFECT_HAS_DERIVED;
}
/** @type {Derived<V>} */
const signal = {
ctx: component_context,
deps: null,
effects: null,
equals,
f: flags,
fn,
reactions: null,
rv: 0,
v: /** @type {V} */ (null),
wv: 0,
parent: parent_derived ?? active_effect
};
if (DEV && tracing_mode_flag) {
signal.created = get_stack('CreatedAt');
}
return signal;
}
/**
* @template V
* @param {() => V} fn
* @returns {Derived<V>}
*/
/*#__NO_SIDE_EFFECTS__*/
export function user_derived(fn) {
const d = derived(fn);
push_reaction_value(d);
return d;
}
/**
* @template V
* @param {() => V} fn
* @returns {Derived<V>}
*/
/*#__NO_SIDE_EFFECTS__*/
export function derived_safe_equal(fn) {
const signal = derived(fn);
signal.equals = safe_equals;
return signal;
}
/**
* @param {Derived} derived
* @returns {void}
*/
export function destroy_derived_effects(derived) {
var effects = derived.effects;
if (effects !== null) {
derived.effects = null;
for (var i = 0; i < effects.length; i += 1) {
destroy_effect(/** @type {Effect} */ (effects[i]));
}
}
}
/**
* The currently updating deriveds, used to detect infinite recursion
* in dev mode and provide a nicer error than 'too much recursion'
* @type {Derived[]}
*/
let stack = [];
/**
* @param {Derived} derived
* @returns {Effect | null}
*/
function get_derived_parent_effect(derived) {
var parent = derived.parent;
while (parent !== null) {
if ((parent.f & DERIVED) === 0) {
return /** @type {Effect} */ (parent);
}
parent = parent.parent;
}
return null;
}
/**
* @template T
* @param {Derived} derived
* @returns {T}
*/
export function execute_derived(derived) {
var value;
var prev_active_effect = active_effect;
set_active_effect(get_derived_parent_effect(derived));
if (DEV) {
let prev_inspect_effects = inspect_effects;
set_inspect_effects(new Set());
try {
if (stack.includes(derived)) {
e.derived_references_self();
}
stack.push(derived);
destroy_derived_effects(derived);
value = update_reaction(derived);
} finally {
set_active_effect(prev_active_effect);
set_inspect_effects(prev_inspect_effects);
stack.pop();
}
} else {
try {
destroy_derived_effects(derived);
value = update_reaction(derived);
} finally {
set_active_effect(prev_active_effect);
}
}
return value;
}
/**
* @param {Derived} derived
* @returns {void}
*/
export function update_derived(derived) {
var value = execute_derived(derived);
if (!derived.equals(value)) {
derived.v = value;
derived.wv = increment_write_version();
}
// don't mark derived clean if we're reading it inside a
// cleanup function, or it will cache a stale value
if (is_destroying_effect) return;
var status =
(skip_reaction || (derived.f & UNOWNED) !== 0) && derived.deps !== null ? MAYBE_DIRTY : CLEAN;
set_signal_status(derived, status);
}
Tool Call: effects.js Status: Completed
/** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, TemplateNode, TransitionManager } from '#client' */
import {
check_dirtiness,
active_effect,
active_reaction,
update_effect,
get,
is_destroying_effect,
remove_reactions,
schedule_effect,
set_active_reaction,
set_is_destroying_effect,
set_signal_status,
untrack,
untracking
} from '../runtime.js';
import {
DIRTY,
BRANCH_EFFECT,
RENDER_EFFECT,
EFFECT,
DESTROYED,
INERT,
EFFECT_RAN,
BLOCK_EFFECT,
ROOT_EFFECT,
EFFECT_TRANSPARENT,
DERIVED,
UNOWNED,
CLEAN,
INSPECT_EFFECT,
HEAD_EFFECT,
MAYBE_DIRTY,
EFFECT_HAS_DERIVED,
BOUNDARY_EFFECT
} from '#client/constants';
import { set } from './sources.js';
import * as e from '../errors.js';
import { DEV } from 'esm-env';
import { define_property } from '../../shared/utils.js';
import { get_next_sibling } from '../dom/operations.js';
import { derived } from './deriveds.js';
import { component_context, dev_current_component_function } from '../context.js';
/**
* @param {'$effect' | '$effect.pre' | '$inspect'} rune
*/
export function validate_effect(rune) {
if (active_effect === null && active_reaction === null) {
e.effect_orphan(rune);
}
if (active_reaction !== null && (active_reaction.f & UNOWNED) !== 0 && active_effect === null) {
e.effect_in_unowned_derived();
}
if (is_destroying_effect) {
e.effect_in_teardown(rune);
}
}
/**
* @param {Effect} effect
* @param {Effect} parent_effect
*/
function push_effect(effect, parent_effect) {
var parent_last = parent_effect.last;
if (parent_last === null) {
parent_effect.last = parent_effect.first = effect;
} else {
parent_last.next = effect;
effect.prev = parent_last;
parent_effect.last = effect;
}
}
/**
* @param {number} type
* @param {null | (() => void | (() => void))} fn
* @param {boolean} sync
* @param {boolean} push
* @returns {Effect}
*/
function create_effect(type, fn, sync, push = true) {
var parent = active_effect;
if (DEV) {
// Ensure the parent is never an inspect effect
while (parent !== null && (parent.f & INSPECT_EFFECT) !== 0) {
parent = parent.parent;
}
}
/** @type {Effect} */
var effect = {
ctx: component_context,
deps: null,
nodes_start: null,
nodes_end: null,
f: type | DIRTY,
first: null,
fn,
last: null,
next: null,
parent,
prev: null,
teardown: null,
transitions: null,
wv: 0
};
if (DEV) {
effect.component_function = dev_current_component_function;
}
if (sync) {
try {
update_effect(effect);
effect.f |= EFFECT_RAN;
} catch (e) {
destroy_effect(effect);
throw e;
}
} else if (fn !== null) {
schedule_effect(effect);
}
// if an effect has no dependencies, no DOM and no teardown function,
// don't bother adding it to the effect tree
var inert =
sync &&
effect.deps === null &&
effect.first === null &&
effect.nodes_start === null &&
effect.teardown === null &&
(effect.f & (EFFECT_HAS_DERIVED | BOUNDARY_EFFECT)) === 0;
if (!inert && push) {
if (parent !== null) {
push_effect(effect, parent);
}
// if we're in a derived, add the effect there too
if (active_reaction !== null && (active_reaction.f & DERIVED) !== 0) {
var derived = /** @type {Derived} */ (active_reaction);
(derived.effects ??= []).push(effect);
}
}
return effect;
}
/**
* Internal representation of `$effect.tracking()`
* @returns {boolean}
*/
export function effect_tracking() {
return active_reaction !== null && !untracking;
}
/**
* @param {() => void} fn
*/
export function teardown(fn) {
const effect = create_effect(RENDER_EFFECT, null, false);
set_signal_status(effect, CLEAN);
effect.teardown = fn;
return effect;
}
/**
* Internal representation of `$effect(...)`
* @param {() => void | (() => void)} fn
*/
export function user_effect(fn) {
validate_effect('$effect');
// Non-nested `$effect(...)` in a component should be deferred
// until the component is mounted
var defer =
active_effect !== null &&
(active_effect.f & BRANCH_EFFECT) !== 0 &&
component_context !== null &&
!component_context.m;
if (DEV) {
define_property(fn, 'name', {
value: '$effect'
});
}
if (defer) {
var context = /** @type {ComponentContext} */ (component_context);
(context.e ??= []).push({
fn,
effect: active_effect,
reaction: active_reaction
});
} else {
var signal = effect(fn);
return signal;
}
}
/**
* Internal representation of `$effect.pre(...)`
* @param {() => void | (() => void)} fn
* @returns {Effect}
*/
export function user_pre_effect(fn) {
validate_effect('$effect.pre');
if (DEV) {
define_property(fn, 'name', {
value: '$effect.pre'
});
}
return render_effect(fn);
}
/** @param {() => void | (() => void)} fn */
export function inspect_effect(fn) {
return create_effect(INSPECT_EFFECT, fn, true);
}
/**
* Internal representation of `$effect.root(...)`
* @param {() => void | (() => void)} fn
* @returns {() => void}
*/
export function effect_root(fn) {
const effect = create_effect(ROOT_EFFECT, fn, true);
return () => {
destroy_effect(effect);
};
}
/**
* An effect root whose children can transition out
* @param {() => void} fn
* @returns {(options?: { outro?: boolean }) => Promise<void>}
*/
export function component_root(fn) {
const effect = create_effect(ROOT_EFFECT, fn, true);
return (options = {}) => {
return new Promise((fulfil) => {
if (options.outro) {
pause_effect(effect, () => {
destroy_effect(effect);
fulfil(undefined);
});
} else {
destroy_effect(effect);
fulfil(undefined);
}
});
};
}
/**
* @param {() => void | (() => void)} fn
* @returns {Effect}
*/
export function effect(fn) {
return create_effect(EFFECT, fn, false);
}
/**
* Internal representation of `$: ..`
* @param {() => any} deps
* @param {() => void | (() => void)} fn
*/
export function legacy_pre_effect(deps, fn) {
var context = /** @type {ComponentContextLegacy} */ (component_context);
/** @type {{ effect: null | Effect, ran: boolean }} */
var token = { effect: null, ran: false };
context.l.r1.push(token);
token.effect = render_effect(() => {
deps();
// If this legacy pre effect has already run before the end of the reset, then
// bail out to emulate the same behavior.
if (token.ran) return;
token.ran = true;
set(context.l.r2, true);
untrack(fn);
});
}
export function legacy_pre_effect_reset() {
var context = /** @type {ComponentContextLegacy} */ (component_context);
render_effect(() => {
if (!get(context.l.r2)) return;
// Run dirty `$:` statements
for (var token of context.l.r1) {
var effect = token.effect;
// If the effect is CLEAN, then make it MAYBE_DIRTY. This ensures we traverse through
// the effects dependencies and correctly ensure each dependency is up-to-date.
if ((effect.f & CLEAN) !== 0) {
set_signal_status(effect, MAYBE_DIRTY);
}
if (check_dirtiness(effect)) {
update_effect(effect);
}
token.ran = false;
}
context.l.r2.v = false; // set directly to avoid rerunning this effect
});
}
/**
* @param {() => void | (() => void)} fn
* @returns {Effect}
*/
export function render_effect(fn) {
return create_effect(RENDER_EFFECT, fn, true);
}
/**
* @param {(...expressions: any) => void | (() => void)} fn
* @param {Array<() => any>} thunks
* @param {<T>(fn: () => T) => Derived<T>} d
* @returns {Effect}
*/
export function template_effect(fn, thunks = [], d = derived) {
if (DEV) {
// wrap the effect so that we can decorate stack trace with `in {expression}`
// (TODO maybe there's a better approach?)
return render_effect(() => {
var outer = /** @type {Effect} */ (active_effect);
var inner = () => fn(...deriveds.map(get));
define_property(outer.fn, 'name', { value: '{expression}' });
define_property(inner, 'name', { value: '{expression}' });
const deriveds = thunks.map(d);
block(inner);
});
}
const deriveds = thunks.map(d);
return block(() => fn(...deriveds.map(get)));
}
/**
* @param {(() => void)} fn
* @param {number} flags
*/
export function block(fn, flags = 0) {
return create_effect(RENDER_EFFECT | BLOCK_EFFECT | flags, fn, true);
}
/**
* @param {(() => void)} fn
* @param {boolean} [push]
*/
export function branch(fn, push = true) {
return create_effect(RENDER_EFFECT | BRANCH_EFFECT, fn, true, push);
}
/**
* @param {Effect} effect
*/
export function execute_effect_teardown(effect) {
var teardown = effect.teardown;
if (teardown !== null) {
const previously_destroying_effect = is_destroying_effect;
const previous_reaction = active_reaction;
set_is_destroying_effect(true);
set_active_reaction(null);
try {
teardown.call(null);
} finally {
set_is_destroying_effect(previously_destroying_effect);
set_active_reaction(previous_reaction);
}
}
}
/**
* @param {Effect} signal
* @param {boolean} remove_dom
* @returns {void}
*/
export function destroy_effect_children(signal, remove_dom = false) {
var effect = signal.first;
signal.first = signal.last = null;
while (effect !== null) {
var next = effect.next;
if ((effect.f & ROOT_EFFECT) !== 0) {
// this is now an independent root
effect.parent = null;
} else {
destroy_effect(effect, remove_dom);
}
effect = next;
}
}
/**
* @param {Effect} signal
* @returns {void}
*/
export function destroy_block_effect_children(signal) {
var effect = signal.first;
while (effect !== null) {
var next = effect.next;
if ((effect.f & BRANCH_EFFECT) === 0) {
destroy_effect(effect);
}
effect = next;
}
}
/**
* @param {Effect} effect
* @param {boolean} [remove_dom]
* @returns {void}
*/
export function destroy_effect(effect, remove_dom = true) {
var removed = false;
if (
(remove_dom || (effect.f & HEAD_EFFECT) !== 0) &&
effect.nodes_start !== null &&
effect.nodes_end !== null
) {
remove_effect_dom(effect.nodes_start, /** @type {TemplateNode} */ (effect.nodes_end));
removed = true;
}
destroy_effect_children(effect, remove_dom && !removed);
remove_reactions(effect, 0);
set_signal_status(effect, DESTROYED);
var transitions = effect.transitions;
if (transitions !== null) {
for (const transition of transitions) {
transition.stop();
}
}
execute_effect_teardown(effect);
var parent = effect.parent;
// If the parent doesn't have any children, then skip this work altogether
if (parent !== null && parent.first !== null) {
unlink_effect(effect);
}
if (DEV) {
effect.component_function = null;
}
// `first` and `child` are nulled out in destroy_effect_children
// we don't null out `parent` so that error propagation can work correctly
effect.next =
effect.prev =
effect.teardown =
effect.ctx =
effect.deps =
effect.fn =
effect.nodes_start =
effect.nodes_end =
null;
}
/**
*
* @param {TemplateNode | null} node
* @param {TemplateNode} end
*/
export function remove_effect_dom(node, end) {
while (node !== null) {
/** @type {TemplateNode | null} */
var next = node === end ? null : /** @type {TemplateNode} */ (get_next_sibling(node));
node.remove();
node = next;
}
}
/**
* Detach an effect from the effect tree, freeing up memory and
* reducing the amount of work that happens on subsequent traversals
* @param {Effect} effect
*/
export function unlink_effect(effect) {
var parent = effect.parent;
var prev = effect.prev;
var next = effect.next;
if (prev !== null) prev.next = next;
if (next !== null) next.prev = prev;
if (parent !== null) {
if (parent.first === effect) parent.first = next;
if (parent.last === effect) parent.last = prev;
}
}
/**
* When a block effect is removed, we don't immediately destroy it or yank it
* out of the DOM, because it might have transitions. Instead, we 'pause' it.
* It stays around (in memory, and in the DOM) until outro transitions have
* completed, and if the state change is reversed then we _resume_ it.
* A paused effect does not update, and the DOM subtree becomes inert.
* @param {Effect} effect
* @param {() => void} [callback]
*/
export function pause_effect(effect, callback) {
/** @type {TransitionManager[]} */
var transitions = [];
pause_children(effect, transitions, true);
run_out_transitions(transitions, () => {
destroy_effect(effect);
if (callback) callback();
});
}
/**
* @param {TransitionManager[]} transitions
* @param {() => void} fn
*/
export function run_out_transitions(transitions, fn) {
var remaining = transitions.length;
if (remaining > 0) {
var check = () => --remaining || fn();
for (var transition of transitions) {
transition.out(check);
}
} else {
fn();
}
}
/**
* @param {Effect} effect
* @param {TransitionManager[]} transitions
* @param {boolean} local
*/
export function pause_children(effect, transitions, local) {
if ((effect.f & INERT) !== 0) return;
effect.f ^= INERT;
if (effect.transitions !== null) {
for (const transition of effect.transitions) {
if (transition.is_global || local) {
transitions.push(transition);
}
}
}
var child = effect.first;
while (child !== null) {
var sibling = child.next;
var transparent = (child.f & EFFECT_TRANSPARENT) !== 0 || (child.f & BRANCH_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.
pause_children(child, transitions, transparent ? local : false);
child = sibling;
}
}
/**
* The opposite of `pause_effect`. We call this if (for example)
* `x` becomes falsy then truthy: `{#if x}...{/if}`
* @param {Effect} effect
*/
export function resume_effect(effect) {
resume_children(effect, true);
}
/**
* @param {Effect} effect
* @param {boolean} local
*/
function resume_children(effect, local) {
if ((effect.f & INERT) === 0) return;
effect.f ^= INERT;
var child = effect.first;
while (child !== null) {
var sibling = child.next;
var transparent = (child.f & EFFECT_TRANSPARENT) !== 0 || (child.f & BRANCH_EFFECT) !== 0;
// TODO we don't need to call resume_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.
resume_children(child, transparent ? local : false);
child = sibling;
}
if (effect.transitions !== null) {
for (const transition of effect.transitions) {
if (transition.is_global || local) {
transition.in();
}
}
}
}
Tool Call: store.js Status: Completed
/** @import { StoreReferencesContainer } from '#client' */
/** @import { Store } from '#shared' */
import { subscribe_to_store } from '../../../store/utils.js';
import { get as get_store } from '../../../store/shared/index.js';
import { define_property, noop } from '../../shared/utils.js';
import { get } from '../runtime.js';
import { teardown } from './effects.js';
import { mutable_source, set } from './sources.js';
/**
* Whether or not the prop currently being read is a store binding, as in
* `<Child bind:x={$y} />`. If it is, we treat the prop as mutable even in
* runes mode, and skip `binding_property_non_reactive` validation
*/
let is_store_binding = false;
let IS_UNMOUNTED = Symbol();
/**
* Gets the current value of a store. If the store isn't subscribed to yet, it will create a proxy
* signal that will be updated when the store is. The store references container is needed to
* track reassignments to stores and to track the correct component context.
* @template V
* @param {Store<V> | null | undefined} store
* @param {string} store_name
* @param {StoreReferencesContainer} stores
* @returns {V}
*/
export function store_get(store, store_name, stores) {
const entry = (stores[store_name] ??= {
store: null,
source: mutable_source(undefined),
unsubscribe: noop
});
// if the component that setup this is already unmounted we don't want to register a subscription
if (entry.store !== store && !(IS_UNMOUNTED in stores)) {
entry.unsubscribe();
entry.store = store ?? null;
if (store == null) {
entry.source.v = undefined; // see synchronous callback comment below
entry.unsubscribe = noop;
} else {
var is_synchronous_callback = true;
entry.unsubscribe = subscribe_to_store(store, (v) => {
if (is_synchronous_callback) {
// If the first updates to the store value (possibly multiple of them) are synchronously
// inside a derived, we will hit the `state_unsafe_mutation` error if we `set` the value
entry.source.v = v;
} else {
set(entry.source, v);
}
});
is_synchronous_callback = false;
}
}
// if the component that setup this stores is already unmounted the source will be out of sync
// so we just use the `get` for the stores, less performant but it avoids to create a memory leak
// and it will keep the value consistent
if (store && IS_UNMOUNTED in stores) {
return get_store(store);
}
return get(entry.source);
}
/**
* Unsubscribe from a store if it's not the same as the one in the store references container.
* We need this in addition to `store_get` because someone could unsubscribe from a store but
* then never subscribe to the new one (if any), causing the subscription to stay open wrongfully.
* @param {Store<any> | null | undefined} store
* @param {string} store_name
* @param {StoreReferencesContainer} stores
*/
export function store_unsub(store, store_name, stores) {
/** @type {StoreReferencesContainer[''] | undefined} */
let entry = stores[store_name];
if (entry && entry.store !== store) {
// Don't reset store yet, so that store_get above can resubscribe to new store if necessary
entry.unsubscribe();
entry.unsubscribe = noop;
}
return store;
}
/**
* Sets the new value of a store and returns that value.
* @template V
* @param {Store<V>} store
* @param {V} value
* @returns {V}
*/
export function store_set(store, value) {
store.set(value);
return value;
}
/**
* @param {StoreReferencesContainer} stores
* @param {string} store_name
*/
export function invalidate_store(stores, store_name) {
var entry = stores[store_name];
if (entry.store !== null) {
store_set(entry.store, entry.source.v);
}
}
/**
* Unsubscribes from all auto-subscribed stores on destroy
* @returns {[StoreReferencesContainer, ()=>void]}
*/
export function setup_stores() {
/** @type {StoreReferencesContainer} */
const stores = {};
function cleanup() {
teardown(() => {
for (var store_name in stores) {
const ref = stores[store_name];
ref.unsubscribe();
}
define_property(stores, IS_UNMOUNTED, {
enumerable: false,
value: true
});
});
}
return [stores, cleanup];
}
/**
* Updates a store with a new value.
* @param {Store<V>} store the store to update
* @param {any} expression the expression that mutates the store
* @param {V} new_value the new store value
* @template V
*/
export function store_mutate(store, expression, new_value) {
store.set(new_value);
return expression;
}
/**
* @param {Store<number>} store
* @param {number} store_value
* @param {1 | -1} [d]
* @returns {number}
*/
export function update_store(store, store_value, d = 1) {
store.set(store_value + d);
return store_value;
}
/**
* @param {Store<number>} store
* @param {number} store_value
* @param {1 | -1} [d]
* @returns {number}
*/
export function update_pre_store(store, store_value, d = 1) {
const value = store_value + d;
store.set(value);
return value;
}
/**
* Called inside prop getters to communicate that the prop is a store binding
*/
export function mark_store_binding() {
is_store_binding = true;
}
/**
* Returns a tuple that indicates whether `fn()` reads a prop that is a store binding.
* Used to prevent `binding_property_non_reactive` validation false positives and
* ensure that these props are treated as mutable even in runes mode
* @template T
* @param {() => T} fn
* @returns {[T, boolean]}
*/
export function capture_store_binding(fn) {
var previous_is_store_binding = is_store_binding;
try {
is_store_binding = false;
return [fn(), is_store_binding];
} finally {
is_store_binding = previous_is_store_binding;
}
}
Now let me check the main index file to see what's exported from the runtime:
Tool Call: No matches Status: Completed
{"offset":0,"current_matches_page":[],"all_matches_len":0}
Tool Call: 25 matches Status: Completed
file:///Users/faraaz/oss/svelte/benchmarking/benchmarks/reactivity/index.js
file:///Users/faraaz/oss/svelte/benchmarking/benchmarks/ssr/index.js
file:///Users/faraaz/oss/svelte/benchmarking/compare/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/scripts/process-messages/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/animate/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/attachments/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/compiler/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/compiler/migrate/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/compiler/phases/1-parse/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/compiler/phases/2-analyze/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/compiler/phases/3-transform/client/transform-template/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/compiler/phases/3-transform/css/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/compiler/phases/3-transform/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/compiler/preprocess/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/easing/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/events/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/client/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/flags/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/internal/server/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/motion/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/reactivity/window/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/server/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/store/shared/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/transition/index.js
Tool Call: index.js Status: Completed
export { createAttachmentKey as attachment } from '../../attachments/index.js';
export { FILENAME, HMR, NAMESPACE_SVG } from '../../constants.js';
export { push, pop } from './context.js';
export { assign, assign_and, assign_or, assign_nullish } from './dev/assign.js';
export { cleanup_styles } from './dev/css.js';
export { add_locations } from './dev/elements.js';
export { hmr } from './dev/hmr.js';
export { create_ownership_validator } from './dev/ownership.js';
export { check_target, legacy_api } from './dev/legacy.js';
export { trace, tag, tag_proxy } from './dev/tracing.js';
export { inspect } from './dev/inspect.js';
export { validate_snippet_args } from './dev/validation.js';
export { await_block as await } from './dom/blocks/await.js';
export { if_block as if } from './dom/blocks/if.js';
export { key_block as key } from './dom/blocks/key.js';
export { css_props } from './dom/blocks/css-props.js';
export { index, each } from './dom/blocks/each.js';
export { html } from './dom/blocks/html.js';
export { sanitize_slots, slot } from './dom/blocks/slot.js';
export { snippet, wrap_snippet } from './dom/blocks/snippet.js';
export { component } from './dom/blocks/svelte-component.js';
export { element } from './dom/blocks/svelte-element.js';
export { head } from './dom/blocks/svelte-head.js';
export { append_styles } from './dom/css.js';
export { action } from './dom/elements/actions.js';
export { attach } from './dom/elements/attachments.js';
export {
remove_input_defaults,
set_attribute,
set_attributes,
attribute_effect,
set_custom_element_data,
set_xlink_attribute,
set_value,
set_checked,
set_selected,
set_default_checked,
set_default_value,
CLASS,
STYLE
} from './dom/elements/attributes.js';
export { set_class } from './dom/elements/class.js';
export { apply, event, delegate, replay_events } from './dom/elements/events.js';
export { autofocus, remove_textarea_child } from './dom/elements/misc.js';
export { set_style } from './dom/elements/style.js';
export { animation, transition } from './dom/elements/transitions.js';
export { bind_active_element } from './dom/elements/bindings/document.js';
export { bind_checked, bind_files, bind_group, bind_value } from './dom/elements/bindings/input.js';
export {
bind_buffered,
bind_current_time,
bind_ended,
bind_muted,
bind_paused,
bind_playback_rate,
bind_played,
bind_ready_state,
bind_seekable,
bind_seeking,
bind_volume
} from './dom/elements/bindings/media.js';
export { bind_online } from './dom/elements/bindings/navigator.js';
export { bind_prop } from './dom/elements/bindings/props.js';
export { bind_select_value, init_select, select_option } from './dom/elements/bindings/select.js';
export { bind_element_size, bind_resize_observer } from './dom/elements/bindings/size.js';
export { bind_this } from './dom/elements/bindings/this.js';
export {
bind_content_editable,
bind_property,
bind_focused
} from './dom/elements/bindings/universal.js';
export { bind_window_scroll, bind_window_size } from './dom/elements/bindings/window.js';
export { hydrate_template, next, reset } from './dom/hydration.js';
export {
once,
preventDefault,
self,
stopImmediatePropagation,
stopPropagation,
trusted
} from './dom/legacy/event-modifiers.js';
export { init } from './dom/legacy/lifecycle.js';
export {
add_legacy_event_listener,
bubble_event,
reactive_import,
update_legacy_props
} from './dom/legacy/misc.js';
export {
append,
comment,
from_html,
from_mathml,
from_svg,
from_tree,
text,
props_id,
with_script
} from './dom/template.js';
export { user_derived as derived, derived_safe_equal } from './reactivity/deriveds.js';
export {
effect_tracking,
effect_root,
legacy_pre_effect,
legacy_pre_effect_reset,
render_effect,
template_effect,
effect,
user_effect,
user_pre_effect
} from './reactivity/effects.js';
export { mutable_source, mutate, set, state, update, update_pre } from './reactivity/sources.js';
export {
prop,
rest_props,
legacy_rest_props,
spread_props,
update_pre_prop,
update_prop
} from './reactivity/props.js';
export {
invalidate_store,
store_mutate,
setup_stores,
store_get,
store_set,
store_unsub,
update_pre_store,
update_store,
mark_store_binding
} from './reactivity/store.js';
export { boundary } from './dom/blocks/boundary.js';
export { set_text } from './render.js';
export {
get,
safe_get,
invalidate_inner_signals,
flushSync as flush,
tick,
untrack,
exclude_from_object,
deep_read,
deep_read_state
} from './runtime.js';
export { validate_binding, validate_each_keys } from './validate.js';
export { raf } from './timing.js';
export { proxy } from './proxy.js';
export { create_custom_element } from './dom/elements/custom-element.js';
export {
child,
first_child,
sibling,
$window as window,
$document as document
} from './dom/operations.js';
export { attr, clsx } from '../shared/attributes.js';
export { snapshot } from '../shared/clone.js';
export { noop, fallback, to_array } from '../shared/utils.js';
export {
invalid_default_snippet,
validate_dynamic_element_tag,
validate_store,
validate_void_dynamic_element,
prevent_snippet_stringification
} from '../shared/validate.js';
export { strict_equals, equals } from './dev/equality.js';
export { log_if_contains_state } from './dev/console-log.js';
Let me also check the main exported API from Svelte:
Tool Call: 4 matches Status: Completed
file:///Users/faraaz/oss/svelte/package.json
file:///Users/faraaz/oss/svelte/packages/svelte/compiler/package.json
file:///Users/faraaz/oss/svelte/packages/svelte/package.json
file:///Users/faraaz/oss/svelte/playgrounds/sandbox/package.json
Tool Call: package.json Status: Completed
{
"name": "svelte",
"description": "Cybernetically enhanced web apps",
"license": "MIT",
"version": "5.34.8",
"type": "module",
"types": "./types/index.d.ts",
"engines": {
"node": ">=18"
},
"files": [
"*.d.ts",
"src",
"!src/**/*.test.*",
"!src/**/*.d.ts",
"types",
"compiler",
"README.md"
],
"module": "src/index-client.js",
"main": "src/index-client.js",
"exports": {
".": {
"types": "./types/index.d.ts",
"worker": "./src/index-server.js",
"browser": "./src/index-client.js",
"default": "./src/index-server.js"
},
"./package.json": "./package.json",
"./action": {
"types": "./types/index.d.ts"
},
"./animate": {
"types": "./types/index.d.ts",
"default": "./src/animate/index.js"
},
"./attachments": {
"types": "./types/index.d.ts",
"default": "./src/attachments/index.js"
},
"./compiler": {
"types": "./types/index.d.ts",
"require": "./compiler/index.js",
"default": "./src/compiler/index.js"
},
"./easing": {
"types": "./types/index.d.ts",
"default": "./src/easing/index.js"
},
"./elements": {
"types": "./elements.d.ts"
},
"./internal": {
"default": "./src/internal/index.js"
},
"./internal/client": {
"default": "./src/internal/client/index.js"
},
"./internal/disclose-version": {
"default": "./src/internal/disclose-version.js"
},
"./internal/flags/legacy": {
"default": "./src/internal/flags/legacy.js"
},
"./internal/flags/tracing": {
"default": "./src/internal/flags/tracing.js"
},
"./internal/server": {
"default": "./src/internal/server/index.js"
},
"./legacy": {
"types": "./types/index.d.ts",
"worker": "./src/legacy/legacy-server.js",
"browser": "./src/legacy/legacy-client.js",
"default": "./src/legacy/legacy-server.js"
},
"./motion": {
"types": "./types/index.d.ts",
"default": "./src/motion/index.js"
},
"./reactivity": {
"types": "./types/index.d.ts",
"worker": "./src/reactivity/index-server.js",
"browser": "./src/reactivity/index-client.js",
"default": "./src/reactivity/index-server.js"
},
"./reactivity/window": {
"types": "./types/index.d.ts",
"default": "./src/reactivity/window/index.js"
},
"./server": {
"types": "./types/index.d.ts",
"default": "./src/server/index.js"
},
"./store": {
"types": "./types/index.d.ts",
"worker": "./src/store/index-server.js",
"browser": "./src/store/index-client.js",
"default": "./src/store/index-server.js"
},
"./transition": {
"types": "./types/index.d.ts",
"default": "./src/transition/index.js"
},
"./events": {
"types": "./types/index.d.ts",
"default": "./src/events/index.js"
}
},
"imports": {
"#client": "./src/internal/client/types.d.ts",
"#client/constants": "./src/internal/client/constants.js",
"#compiler": {
"types": "./src/compiler/private.d.ts",
"default": "./src/compiler/index.js"
},
"#compiler/builders": "./src/compiler/utils/builders.js",
"#server": "./src/internal/server/types.d.ts",
"#shared": "./src/internal/shared/types.d.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sveltejs/svelte.git",
"directory": "packages/svelte"
},
"bugs": {
"url": "https://github.com/sveltejs/svelte/issues"
},
"homepage": "https://svelte.dev",
"keywords": [
"svelte",
"UI",
"framework",
"templates",
"templating"
],
"scripts": {
"build": "node scripts/process-messages && rollup -c && pnpm generate:types && node scripts/check-treeshakeability.js",
"dev": "node scripts/process-messages -w & rollup -cw",
"check": "tsc --project tsconfig.runtime.json && tsc && cd ./tests/types && tsc",
"check:watch": "tsc --watch",
"generate:version": "node ./scripts/generate-version.js",
"generate:types": "node ./scripts/generate-types.js && tsc -p tsconfig.generated.json",
"prepublishOnly": "pnpm build",
"knip": "pnpm dlx knip"
},
"devDependencies": {
"@jridgewell/trace-mapping": "^0.3.25",
"@playwright/test": "^1.46.1",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-virtual": "^3.0.2",
"@types/aria-query": "^5.0.4",
"@types/node": "^20.11.5",
"dts-buddy": "^0.5.5",
"esbuild": "^0.21.5",
"rollup": "^4.22.4",
"source-map": "^0.7.4",
"tinyglobby": "^0.2.12",
"typescript": "^5.5.4",
"vitest": "^2.1.9"
},
"dependencies": {
"@ampproject/remapping": "^2.3.0",
"@jridgewell/sourcemap-codec": "^1.5.0",
"@types/estree": "^1.0.5",
"acorn": "^8.12.1",
"@sveltejs/acorn-typescript": "^1.0.5",
"aria-query": "^5.3.1",
"axobject-query": "^4.1.0",
"clsx": "^2.1.1",
"esm-env": "^1.2.1",
"esrap": "^1.4.8",
"is-reference": "^3.0.3",
"locate-character": "^3.0.0",
"magic-string": "^0.30.11",
"zimmerframe": "^1.1.2"
}
}
Tool Call: index-client.js Status: Failed
svelte/src/reactivity/index-client.js not found
Tool Call: index-client.js Status: Completed
export { SvelteDate } from './date.js';
export { SvelteSet } from './set.js';
export { SvelteMap } from './map.js';
export { SvelteURL } from './url.js';
export { SvelteURLSearchParams } from './url-search-params.js';
export { MediaQuery } from './media-query.js';
export { createSubscriber } from './create-subscriber.js';
Let me check the legacy store implementations as well:
Tool Call: 4 matches Status: Completed
file:///Users/faraaz/oss/svelte/packages/svelte/src/store/index-client.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/store/index-server.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/store/shared/index.js
file:///Users/faraaz/oss/svelte/packages/svelte/src/store/utils.js
Tool Call: index.js Status: Completed
/** @import { Readable, StartStopNotifier, Subscriber, Unsubscriber, Updater, Writable } from '../public.js' */
/** @import { Stores, StoresValues, SubscribeInvalidateTuple } from '../private.js' */
import { noop, run_all } from '../../internal/shared/utils.js';
import { safe_not_equal } from '../../internal/client/reactivity/equality.js';
import { subscribe_to_store } from '../utils.js';
/**
* @type {Array<SubscribeInvalidateTuple<any> | any>}
*/
const subscriber_queue = [];
/**
* Creates a `Readable` store that allows reading by subscription.
*
* @template T
* @param {T} [value] initial value
* @param {StartStopNotifier<T>} [start]
* @returns {Readable<T>}
*/
export function readable(value, start) {
return {
subscribe: writable(value, start).subscribe
};
}
/**
* Create a `Writable` store that allows both updating and reading by subscription.
*
* @template T
* @param {T} [value] initial value
* @param {StartStopNotifier<T>} [start]
* @returns {Writable<T>}
*/
export function writable(value, start = noop) {
/** @type {Unsubscriber | null} */
let stop = null;
/** @type {Set<SubscribeInvalidateTuple<T>>} */
const subscribers = new Set();
/**
* @param {T} new_value
* @returns {void}
*/
function set(new_value) {
if (safe_not_equal(value, new_value)) {
value = new_value;
if (stop) {
// store is ready
const run_queue = !subscriber_queue.length;
for (const subscriber of subscribers) {
subscriber[1]();
subscriber_queue.push(subscriber, value);
}
if (run_queue) {
for (let i = 0; i < subscriber_queue.length; i += 2) {
subscriber_queue[i][0](subscriber_queue[i + 1]);
}
subscriber_queue.length = 0;
}
}
}
}
/**
* @param {Updater<T>} fn
* @returns {void}
*/
function update(fn) {
set(fn(/** @type {T} */ (value)));
}
/**
* @param {Subscriber<T>} run
* @param {() => void} [invalidate]
* @returns {Unsubscriber}
*/
function subscribe(run, invalidate = noop) {
/** @type {SubscribeInvalidateTuple<T>} */
const subscriber = [run, invalidate];
subscribers.add(subscriber);
if (subscribers.size === 1) {
stop = start(set, update) || noop;
}
run(/** @type {T} */ (value));
return () => {
subscribers.delete(subscriber);
if (subscribers.size === 0 && stop) {
stop();
stop = null;
}
};
}
return { set, update, subscribe };
}
/**
* Derived value store by synchronizing one or more readable stores and
* applying an aggregation function over its input values.
*
* @template {Stores} S
* @template T
* @overload
* @param {S} stores
* @param {(values: StoresValues<S>, set: (value: T) => void, update: (fn: Updater<T>) => void) => Unsubscriber | void} fn
* @param {T} [initial_value]
* @returns {Readable<T>}
*/
/**
* Derived value store by synchronizing one or more readable stores and
* applying an aggregation function over its input values.
*
* @template {Stores} S
* @template T
* @overload
* @param {S} stores
* @param {(values: StoresValues<S>) => T} fn
* @param {T} [initial_value]
* @returns {Readable<T>}
*/
/**
* @template {Stores} S
* @template T
* @param {S} stores
* @param {Function} fn
* @param {T} [initial_value]
* @returns {Readable<T>}
*/
export function derived(stores, fn, initial_value) {
const single = !Array.isArray(stores);
/** @type {Array<Readable<any>>} */
const stores_array = single ? [stores] : stores;
if (!stores_array.every(Boolean)) {
throw new Error('derived() expects stores as input, got a falsy value');
}
const auto = fn.length < 2;
return readable(initial_value, (set, update) => {
let started = false;
/** @type {T[]} */
const values = [];
let pending = 0;
let cleanup = noop;
const sync = () => {
if (pending) {
return;
}
cleanup();
const result = fn(single ? values[0] : values, set, update);
if (auto) {
set(result);
} else {
cleanup = typeof result === 'function' ? result : noop;
}
};
const unsubscribers = stores_array.map((store, i) =>
subscribe_to_store(
store,
(value) => {
values[i] = value;
pending &= ~(1 << i);
if (started) {
sync();
}
},
() => {
pending |= 1 << i;
}
)
);
started = true;
sync();
return function stop() {
run_all(unsubscribers);
cleanup();
// We need to set this to false because callbacks can still happen despite having unsubscribed:
// Callbacks might already be placed in the queue which doesn't know it should no longer
// invoke this derived store.
started = false;
};
});
}
/**
* Takes a store and returns a new one derived from the old one that is readable.
*
* @template T
* @param {Readable<T>} store - store to make readonly
* @returns {Readable<T>}
*/
export function readonly(store) {
return {
// @ts-expect-error TODO i suspect the bind is unnecessary
subscribe: store.subscribe.bind(store)
};
}
/**
* Get the current value from a store by subscribing and immediately unsubscribing.
*
* @template T
* @param {Readable<T>} store
* @returns {T}
*/
export function get(store) {
let value;
subscribe_to_store(store, (_) => (value = _))();
// @ts-expect-error
return value;
}
Now let me search for additional state management functions that might be in other files:
Tool Call: Search files for regex export.*function.*(prop|bind|reactive|signal|watch)
Status: Completed
Showing matches 1-20 (there were more matches found; use offset: 20 to see next page):
export async function sbench_create_signals() {
// Do 3 loops to warm up JIT
for (let i = 0; i < 3; i++) {
bench(create_data_signals, COUNT, COUNT);
}
const { timing } = await fastest_test(10, () => {
for (let i = 0; i < 100; i++) {
bench(create_data_signals, COUNT, COUNT);
}
});
7 lines remaining in ancestor node. Read the file to see all.
export function bindable_invalid_location(node) {
e(node, 'bindable_invalid_location', `\`$bindable()\` can only be used inside a \`$props()\` declaration\nhttps://svelte.dev/e/bindable_invalid_location`);
}
export function constant_binding(node, thing) {
e(node, 'constant_binding', `Cannot bind to ${thing}\nhttps://svelte.dev/e/constant_binding`);
}
export function dollar_binding_invalid(node) {
e(node, 'dollar_binding_invalid', `The $ name is reserved, and cannot be used for variables and imports\nhttps://svelte.dev/e/dollar_binding_invalid`);
}
export function legacy_props_invalid(node) {
e(node, 'legacy_props_invalid', `Cannot use \`$$props\` in runes mode\nhttps://svelte.dev/e/legacy_props_invalid`);
}
export function legacy_reactive_statement_invalid(node) {
e(node, 'legacy_reactive_statement_invalid', `\`$:\` is not allowed in runes mode, use \`$derived\` or \`$effect\` instead\nhttps://svelte.dev/e/legacy_reactive_statement_invalid`);
}
export function legacy_rest_props_invalid(node) {
e(node, 'legacy_rest_props_invalid', `Cannot use \`$$restProps\` in runes mode\nhttps://svelte.dev/e/legacy_rest_props_invalid`);
}
export function props_duplicate(node, rune) {
e(node, 'props_duplicate', `Cannot use \`${rune}()\` more than once\nhttps://svelte.dev/e/props_duplicate`);
}
export function props_id_invalid_placement(node) {
e(node, 'props_id_invalid_placement', `\`$props.id()\` can only be used at the top level of components as a variable declaration initializer\nhttps://svelte.dev/e/props_id_invalid_placement`);
}
export function props_illegal_name(node) {
e(node, 'props_illegal_name', `Declaring or accessing a prop starting with \`$$\` is illegal (they are reserved for Svelte internals)\nhttps://svelte.dev/e/props_illegal_name`);
}
export function props_invalid_identifier(node) {
e(node, 'props_invalid_identifier', `\`$props()\` can only be used with an object destructuring pattern\nhttps://svelte.dev/e/props_invalid_identifier`);
}
export function props_invalid_pattern(node) {
e(node, 'props_invalid_pattern', `\`$props()\` assignment must not contain nested properties or computed keys\nhttps://svelte.dev/e/props_invalid_pattern`);
}
export function props_invalid_placement(node) {
e(node, 'props_invalid_placement', `\`$props()\` can only be used at the top level of components as a variable declaration initializer\nhttps://svelte.dev/e/props_invalid_placement`);
}
export function reactive_declaration_cycle(node, cycle) {
e(node, 'reactive_declaration_cycle', `Cyclical dependency detected: ${cycle}\nhttps://svelte.dev/e/reactive_declaration_cycle`);
}
export function rune_invalid_computed_property(node) {
e(node, 'rune_invalid_computed_property', `Cannot access a computed property of a rune\nhttps://svelte.dev/e/rune_invalid_computed_property`);
}
/**
* Cannot export state from a module if it is reassigned. Either export a function returning the state value or only mutate the state value's properties
* @param {null | number | NodeLike} node
* @returns {never}
*/
export function state_invalid_export(node) {
e(node, 'state_invalid_export', `Cannot export state from a module if it is reassigned. Either export a function returning the state value or only mutate the state value's properties\nhttps://svelte.dev/e/state_invalid_export`);
}
export function bind_group_invalid_expression(node) {
e(node, 'bind_group_invalid_expression', `\`bind:group\` can only bind to an Identifier or MemberExpression\nhttps://svelte.dev/e/bind_group_invalid_expression`);
}
export function bind_group_invalid_snippet_parameter(node) {
e(node, 'bind_group_invalid_snippet_parameter', `Cannot \`bind:group\` to a snippet parameter\nhttps://svelte.dev/e/bind_group_invalid_snippet_parameter`);
}
export function bind_invalid_expression(node) {
e(node, 'bind_invalid_expression', `Can only bind to an Identifier or MemberExpression or a \`{get, set}\` pair\nhttps://svelte.dev/e/bind_invalid_expression`);
}
Let me search for more specific functions in the reactivity/props file:
Tool Call: props.js Status: Completed
/** @import { Derived, Source } from './types.js' */
import { DEV } from 'esm-env';
import {
PROPS_IS_BINDABLE,
PROPS_IS_IMMUTABLE,
PROPS_IS_LAZY_INITIAL,
PROPS_IS_RUNES,
PROPS_IS_UPDATED
} from '../../../constants.js';
import { get_descriptor, is_function } from '../../shared/utils.js';
import { mutable_source, set, source, update } from './sources.js';
import { derived, derived_safe_equal } from './deriveds.js';
import { get, captured_signals, untrack } from '../runtime.js';
import { safe_equals } from './equality.js';
import * as e from '../errors.js';
import { LEGACY_DERIVED_PROP, LEGACY_PROPS, STATE_SYMBOL } from '#client/constants';
import { proxy } from '../proxy.js';
import { capture_store_binding } from './store.js';
import { legacy_mode_flag } from '../../flags/index.js';
/**
* @param {((value?: number) => number)} fn
* @param {1 | -1} [d]
* @returns {number}
*/
export function update_prop(fn, d = 1) {
const value = fn();
fn(value + d);
return value;
}
/**
* @param {((value?: number) => number)} fn
* @param {1 | -1} [d]
* @returns {number}
*/
export function update_pre_prop(fn, d = 1) {
const value = fn() + d;
fn(value);
return value;
}
/**
* The proxy handler for rest props (i.e. `const { x, ...rest } = $props()`).
* Is passed the full `$$props` object and excludes the named props.
* @type {ProxyHandler<{ props: Record<string | symbol, unknown>, exclude: Array<string | symbol>, name?: string }>}}
*/
const rest_props_handler = {
get(target, key) {
if (target.exclude.includes(key)) return;
return target.props[key];
},
set(target, key) {
if (DEV) {
// TODO should this happen in prod too?
e.props_rest_readonly(`${target.name}.${String(key)}`);
}
return false;
},
getOwnPropertyDescriptor(target, key) {
if (target.exclude.includes(key)) return;
if (key in target.props) {
return {
enumerable: true,
configurable: true,
value: target.props[key]
};
}
},
has(target, key) {
if (target.exclude.includes(key)) return false;
return key in target.props;
},
ownKeys(target) {
return Reflect.ownKeys(target.props).filter((key) => !target.exclude.includes(key));
}
};
/**
* @param {Record<string, unknown>} props
* @param {string[]} exclude
* @param {string} [name]
* @returns {Record<string, unknown>}
*/
/*#__NO_SIDE_EFFECTS__*/
export function rest_props(props, exclude, name) {
return new Proxy(
DEV ? { props, exclude, name, other: {}, to_proxy: [] } : { props, exclude },
rest_props_handler
);
}
/**
* The proxy handler for legacy $$restProps and $$props
* @type {ProxyHandler<{ props: Record<string | symbol, unknown>, exclude: Array<string | symbol>, special: Record<string | symbol, (v?: unknown) => unknown>, version: Source<number> }>}}
*/
const legacy_rest_props_handler = {
get(target, key) {
if (target.exclude.includes(key)) return;
get(target.version);
return key in target.special ? target.special[key]() : target.props[key];
},
set(target, key, value) {
if (!(key in target.special)) {
// Handle props that can temporarily get out of sync with the parent
/** @type {Record<string, (v?: unknown) => unknown>} */
target.special[key] = prop(
{
get [key]() {
return target.props[key];
}
},
/** @type {string} */ (key),
PROPS_IS_UPDATED
);
}
target.special[key](value);
update(target.version); // $$props is coarse-grained: when $$props.x is updated, usages of $$props.y etc are also rerun
return true;
},
getOwnPropertyDescriptor(target, key) {
if (target.exclude.includes(key)) return;
if (key in target.props) {
return {
enumerable: true,
configurable: true,
value: target.props[key]
};
}
},
deleteProperty(target, key) {
// Svelte 4 allowed for deletions on $$restProps
if (target.exclude.includes(key)) return true;
target.exclude.push(key);
update(target.version);
return true;
},
has(target, key) {
if (target.exclude.includes(key)) return false;
return key in target.props;
},
ownKeys(target) {
return Reflect.ownKeys(target.props).filter((key) => !target.exclude.includes(key));
}
};
/**
* @param {Record<string, unknown>} props
* @param {string[]} exclude
* @returns {Record<string, unknown>}
*/
export function legacy_rest_props(props, exclude) {
return new Proxy({ props, exclude, special: {}, version: source(0) }, legacy_rest_props_handler);
}
/**
* The proxy handler for spread props. Handles the incoming array of props
* that looks like `() => { dynamic: props }, { static: prop }, ..` and wraps
* them so that the whole thing is passed to the component as the `$$props` argument.
* @template {Record<string | symbol, unknown>} T
* @type {ProxyHandler<{ props: Array<T | (() => T)> }>}}
*/
const spread_props_handler = {
get(target, key) {
let i = target.props.length;
while (i--) {
let p = target.props[i];
if (is_function(p)) p = p();
if (typeof p === 'object' && p !== null && key in p) return p[key];
}
},
set(target, key, value) {
let i = target.props.length;
while (i--) {
let p = target.props[i];
if (is_function(p)) p = p();
const desc = get_descriptor(p, key);
if (desc && desc.set) {
desc.set(value);
return true;
}
}
return false;
},
getOwnPropertyDescriptor(target, key) {
let i = target.props.length;
while (i--) {
let p = target.props[i];
if (is_function(p)) p = p();
if (typeof p === 'object' && p !== null && key in p) {
const descriptor = get_descriptor(p, key);
if (descriptor && !descriptor.configurable) {
// Prevent a "Non-configurability Report Error": The target is an array, it does
// not actually contain this property. If it is now described as non-configurable,
// the proxy throws a validation error. Setting it to true avoids that.
descriptor.configurable = true;
}
return descriptor;
}
}
},
has(target, key) {
// To prevent a false positive `is_entry_props` in the `prop` function
if (key === STATE_SYMBOL || key === LEGACY_PROPS) return false;
for (let p of target.props) {
if (is_function(p)) p = p();
if (p != null && key in p) return true;
}
return false;
},
ownKeys(target) {
/** @type {Array<string | symbol>} */
const keys = [];
for (let p of target.props) {
if (is_function(p)) p = p();
if (!p) continue;
for (const key in p) {
if (!keys.includes(key)) keys.push(key);
}
for (const key of Object.getOwnPropertySymbols(p)) {
if (!keys.includes(key)) keys.push(key);
}
}
return keys;
}
};
/**
* @param {Array<Record<string, unknown> | (() => Record<string, unknown>)>} props
* @returns {any}
*/
export function spread_props(...props) {
return new Proxy({ props }, spread_props_handler);
}
/**
* @param {Derived} current_value
* @returns {boolean}
*/
function has_destroyed_component_ctx(current_value) {
return current_value.ctx?.d ?? false;
}
/**
* This function is responsible for synchronizing a possibly bound prop with the inner component state.
* It is used whenever the compiler sees that the component writes to the prop, or when it has a default prop_value.
* @template V
* @param {Record<string, unknown>} props
* @param {string} key
* @param {number} flags
* @param {V | (() => V)} [fallback]
* @returns {(() => V | ((arg: V) => V) | ((arg: V, mutation: boolean) => V))}
*/
export function prop(props, key, flags, fallback) {
var immutable = (flags & PROPS_IS_IMMUTABLE) !== 0;
var runes = !legacy_mode_flag || (flags & PROPS_IS_RUNES) !== 0;
var bindable = (flags & PROPS_IS_BINDABLE) !== 0;
var lazy = (flags & PROPS_IS_LAZY_INITIAL) !== 0;
var is_store_sub = false;
var prop_value;
if (bindable) {
[prop_value, is_store_sub] = capture_store_binding(() => /** @type {V} */ (props[key]));
} else {
prop_value = /** @type {V} */ (props[key]);
}
// Can be the case when someone does `mount(Component, props)` with `let props = $state({...})`
// or `createClassComponent(Component, props)`
var is_entry_props = STATE_SYMBOL in props || LEGACY_PROPS in props;
var setter =
(bindable &&
(get_descriptor(props, key)?.set ??
(is_entry_props && key in props && ((v) => (props[key] = v))))) ||
undefined;
var fallback_value = /** @type {V} */ (fallback);
var fallback_dirty = true;
var fallback_used = false;
var get_fallback = () => {
fallback_used = true;
if (fallback_dirty) {
fallback_dirty = false;
if (lazy) {
fallback_value = untrack(/** @type {() => V} */ (fallback));
} else {
fallback_value = /** @type {V} */ (fallback);
}
}
return fallback_value;
};
if (prop_value === undefined && fallback !== undefined) {
if (setter && runes) {
e.props_invalid_value(key);
}
prop_value = get_fallback();
if (setter) setter(prop_value);
}
/** @type {() => V} */
var getter;
if (runes) {
getter = () => {
var value = /** @type {V} */ (props[key]);
if (value === undefined) return get_fallback();
fallback_dirty = true;
fallback_used = false;
return value;
};
} else {
// Svelte 4 did not trigger updates when a primitive value was updated to the same value.
// Replicate that behavior through using a derived
var derived_getter = (immutable ? derived : derived_safe_equal)(
() => /** @type {V} */ (props[key])
);
derived_getter.f |= LEGACY_DERIVED_PROP;
getter = () => {
var value = get(derived_getter);
if (value !== undefined) fallback_value = /** @type {V} */ (undefined);
return value === undefined ? fallback_value : value;
};
}
// easy mode — prop is never written to
if ((flags & PROPS_IS_UPDATED) === 0 && runes) {
return getter;
}
// intermediate mode — prop is written to, but the parent component had
// `bind:foo` which means we can just call `$$props.foo = value` directly
if (setter) {
var legacy_parent = props.$$legacy;
return function (/** @type {any} */ value, /** @type {boolean} */ mutation) {
if (arguments.length > 0) {
// We don't want to notify if the value was mutated and the parent is in runes mode.
// In that case the state proxy (if it exists) should take care of the notification.
// If the parent is not in runes mode, we need to notify on mutation, too, that the prop
// has changed because the parent will not be able to detect the change otherwise.
if (!runes || !mutation || legacy_parent || is_store_sub) {
/** @type {Function} */ (setter)(mutation ? getter() : value);
}
return value;
} else {
return getter();
}
};
}
// hard mode. this is where it gets ugly — the value in the child should
// synchronize with the parent, but it should also be possible to temporarily
// set the value to something else locally.
var from_child = false;
var was_from_child = false;
// The derived returns the current value. The underlying mutable
// source is written to from various places to persist this value.
var inner_current_value = mutable_source(prop_value);
var current_value = derived(() => {
var parent_value = getter();
var child_value = get(inner_current_value);
if (from_child) {
from_child = false;
was_from_child = true;
return child_value;
}
was_from_child = false;
return (inner_current_value.v = parent_value);
});
// Ensure we eagerly capture the initial value if it's bindable
if (bindable) {
get(current_value);
}
if (!immutable) current_value.equals = safe_equals;
return function (/** @type {any} */ value, /** @type {boolean} */ mutation) {
// legacy nonsense — need to ensure the source is invalidated when necessary
// also needed for when handling inspect logic so we can inspect the correct source signal
if (captured_signals !== null) {
// set this so that we don't reset to the parent value if `d`
// is invalidated because of `invalidate_inner_signals` (rather
// than because the parent or child value changed)
from_child = was_from_child;
// invoke getters so that signals are picked up by `invalidate_inner_signals`
getter();
get(inner_current_value);
}
if (arguments.length > 0) {
const new_value = mutation ? get(current_value) : runes && bindable ? proxy(value) : value;
if (!current_value.equals(new_value)) {
from_child = true;
set(inner_current_value, new_value);
// To ensure the fallback value is consistent when used with proxies, we
// update the local fallback_value, but only if the fallback is actively used
if (fallback_used && fallback_value !== undefined) {
fallback_value = new_value;
}
if (has_destroyed_component_ctx(current_value)) {
return value;
}
untrack(() => get(current_value)); // force a synchronisation immediately
}
return value;
}
if (has_destroyed_component_ctx(current_value)) {
return current_value.v;
}
return get(current_value);
};
}
Now let me search for more utility functions that manage state:
Tool Call: Search files for regex export.*function.*(get|set|update|mutate|bind|trigger|watch|observe)
Status: Completed
Showing matches 1-20 (there were more matches found; use offset: 20 to see next page):
export function set_component_context(context) {
component_context = context;
}
export function set_dev_current_component_function(fn) {
dev_current_component_function = fn;
}
export function getContext(key) {
const context_map = get_or_init_context_map('getContext');
const result = /** @type {T} */ (context_map.get(key));
return result;
}
export function setContext(key, context) {
const context_map = get_or_init_context_map('setContext');
context_map.set(key, context);
return context;
}
export function getAllContexts() {
const context_map = get_or_init_context_map('getAllContexts');
return /** @type {T} */ (context_map);
}
export function hmr(original, get_source) {
/**
* @param {TemplateNode} anchor
* @param {any} props
*/
function wrapper(anchor, props) {
let instance = {};
/** @type {Effect} */
let effect;
53 lines remaining in ancestor node. Read the file to see all.
export function inspect(get_value, inspector = console.log) {
validate_effect('$inspect');
let initial = true;
inspect_effect(() => {
/** @type {any} */
var value = UNINITIALIZED;
// Capturing the value might result in an exception due to the inspect effect being
// sync and thus operating on stale data. In the case we encounter an exception we
19 lines remaining in ancestor node. Read the file to see all.
export function check_target(target) {
if (target) {
e.component_api_invalid_new(target[FILENAME] ?? 'a component', target.name);
}
}
export function get_stack(label) {
let error = Error();
const stack = error.stack;
if (stack) {
const lines = stack.split('\n');
const new_lines = ['\n'];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
27 lines remaining in ancestor node. Read the file to see all.
export function await_block(node, get_input, pending_fn, then_fn, catch_fn) {
if (hydrating) {
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;
145 lines remaining in ancestor node. Read the file to see all.
export function css_props(element, get_styles) {
if (hydrating) {
set_hydrate_node(/** @type {TemplateNode} */ (get_first_child(element)));
}
render_effect(() => {
var styles = get_styles();
for (var key in styles) {
var value = styles[key];
8 lines remaining in ancestor node. Read the file to see all.
export function set_current_each_item(item) {
current_each_item = item;
}
export function each(node, flags, get_collection, get_key, render_fn, fallback_fn = null) {
var anchor = node;
/** @type {EachState} */
var state = { flags, items: new Map(), first: null };
var is_controlled = (flags & EACH_IS_CONTROLLED) !== 0;
if (is_controlled) {
var parent_node = /** @type {Element} */ (node);
132 lines remaining in ancestor node. Read the file to see all.
export function html(node, get_value, svg = false, mathml = false, skip_warning = false) {
var anchor = node;
var value = '';
template_effect(() => {
var effect = /** @type {Effect} */ (active_effect);
if (value === (value = get_value() ?? '')) {
if (hydrating) hydrate_next();
return;
65 lines remaining in ancestor node. Read the file to see all.
export function key_block(node, get_key, render_fn) {
if (hydrating) {
hydrate_next();
}
var anchor = node;
/** @type {V | typeof UNINITIALIZED} */
var key = UNINITIALIZED;
/** @type {Effect} */
18 lines remaining in ancestor node. Read the file to see all.
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;
block(() => {
18 lines remaining in ancestor node. Read the file to see all.
export function component(node, get_component, render_fn) {
if (hydrating) {
hydrate_next();
}
var anchor = node;
/** @type {C} */
var component;
/** @type {Effect | null} */
19 lines remaining in ancestor node. Read the file to see all.
export function element(node, get_tag, is_svg, render_fn, get_namespace, location) {
let was_hydrating = hydrating;
if (hydrating) {
hydrate_next();
}
var filename = DEV && location && component_context?.function[FILENAME];
/** @type {string | null} */
var tag;
119 lines remaining in ancestor node. Read the file to see all.
export function reset_head_anchor() {
head_anchor = undefined;
}
export function action(dom, action, get_value) {
effect(() => {
var payload = untrack(() => action(dom, get_value?.()) || {});
if (get_value && payload?.update) {
var inited = false;
/** @type {P} */
var prev = /** @type {any} */ ({}); // initialize with something so it's never equal on first run
render_effect(() => {
var value = get_value();
20 lines remaining in ancestor node. Read the file to see all.
Tool Call: Thinking Status: Completed
Based on my extensive search through the Svelte codebase, I can now compile a comprehensive list of all functions that manage state. Let me organize these by category:
Core State Management (Runes):
state()
- Create reactive statederived()
/user_derived()
- Create derived/computed valueseffect()
/user_effect()
- Create side effectsuser_pre_effect()
- Effects that run before DOM updates
Low-level Reactive Primitives:
source()
- Create basic reactive sourcemutable_source()
- Create mutable reactive sourceset()
/internal_set()
- Set reactive valuesget()
/safe_get()
- Get reactive valuesupdate()
/update_pre()
- Update numeric valuesmutate()
- Mutate and trigger reactivity
Effect Management:
effect_root()
- Create effect rootcomponent_root()
- Create component effect rootrender_effect()
- Effects for renderingtemplate_effect()
- Effects for template expressionsinspect_effect()
- Effects for $inspectlegacy_pre_effect()
- Legacy reactive statementsblock()
/branch()
- Block-level effectsteardown()
- Cleanup effectspause_effect()
/resume_effect()
- Control effect executiondestroy_effect()
- Destroy effects
Props Management:
prop()
- Manage component propsrest_props()
- Handle rest propslegacy_rest_props()
- Legacy rest propsspread_props()
- Spread propsupdate_prop()
/update_pre_prop()
- Update prop values
Store Management:
writable()
- Create writable storereadable()
- Create readable storederived()
(store version) - Create derived storestore_get()
- Get store valuesstore_set()
- Set store valuesstore_mutate()
- Mutate store valuesupdate_store()
/update_pre_store()
- Update store valuesinvalidate_store()
- Invalidate storessetup_stores()
- Setup store subscriptionsstore_unsub()
- Unsubscribe from stores
Context Management:
getContext()
- Get context valuessetContext()
- Set context valuesgetAllContexts()
- Get all contexts
Runtime Control:
untrack()
- Run code without trackingtick()
- Wait for updatesflushSync()
/flush()
- Synchronously flush updatesdeep_read()
/deep_read_state()
- Deep reactive readsinvalidate_inner_signals()
- Invalidate signals
Utility Functions:
snapshot()
- Create non-reactive snapshotsproxy()
- Create reactive proxiesequals()
/safe_equals()
- Equality comparisonscapture_store_binding()
- Capture store bindingsmark_store_binding()
- Mark store bindings
Legacy/Compatibility:
reactive_import()
- Legacy reactive importslegacy_pre_effect_reset()
- Reset legacy effects
Development/Debugging:
inspect()
- Inspect reactive valuestrace()
/tag()
- Tracing utilities
This covers the complete set of state management functions in Svelte 5.
Based on my comprehensive analysis of the Svelte codebase, here are all the functions that manage state in Svelte 5:
State Creation:
state()
- Creates reactive state using the$state
runemutable_source()
- Creates mutable reactive sourcessource()
- Creates basic reactive sources
Derived Values:
derived()
/user_derived()
- Creates computed/derived values using$derived
derived_safe_equal()
- Derived with safe equality checking
Effects:
effect()
/user_effect()
- Creates side effects using$effect
user_pre_effect()
- Effects that run before DOM updates ($effect.pre
)inspect_effect()
- Effects for$inspect
debugging
Getting/Setting:
get()
/safe_get()
- Reads reactive valuesset()
/internal_set()
- Updates reactive valuesmutate()
- Mutates objects and triggers reactivityupdate()
/update_pre()
- Updates numeric values (increment/decrement)
Effect Lifecycle:
effect_root()
- Creates independent effect rootscomponent_root()
- Creates component-level effect roots with transition supportrender_effect()
- Creates effects that run during renderingtemplate_effect()
- Creates effects for template expressionsteardown()
- Registers cleanup functionsblock()
/branch()
- Creates block-level effects
Effect Control:
pause_effect()
/resume_effect()
- Controls effect executiondestroy_effect()
- Destroys effects and cleans up resourcesexecute_effect_teardown()
- Runs effect cleanup
export function prop(props, key, flags, fallback) {
// Handles component prop synchronization with binding support
// Manages two-way binding between parent and child components
// Returns getter/setter function for the prop
}
export function rest_props(props, exclude, name) {
// Handles rest props (const { x, ...rest } = $props())
// Returns proxy that excludes named props
}
export function spread_props(...props) {
// Handles spread props in component calls
// Merges multiple prop objects
}
prop()
- Manages component props with binding supportrest_props()
/legacy_rest_props()
- Handles rest propsspread_props()
- Manages spread propsupdate_prop()
/update_pre_prop()
- Updates prop values
export function writable(value, start = noop) {
// Creates writable store with subscription management
// Returns { set, update, subscribe }
}
export function derived(stores, fn, initial_value) {
// Creates derived store from other stores
// Automatically manages subscriptions
}
Store Creation:
writable()
- Creates writable storesreadable()
- Creates readable storesderived()
(store version) - Creates derived stores
Store Operations:
store_get()
/store_set()
- Gets/sets store valuesstore_mutate()
- Mutates store valuesupdate_store()
/update_pre_store()
- Updates numeric store valuesinvalidate_store()
- Invalidates store subscriptionssetup_stores()
/store_unsub()
- Manages store subscriptions
export function getContext(key) {
const context_map = get_or_init_context_map('getContext');
return context_map.get(key);
}
export function setContext(key, context) {
const context_map = get_or_init_context_map('setContext');
context_map.set(key, context);
return context;
}
getContext()
- Retrieves context valuessetContext()
- Sets context valuesgetAllContexts()
- Gets all available contexts
Reactivity Control:
untrack()
- Runs code without tracking dependenciestick()
- Waits for all pending state updatesflushSync()
/flush()
- Synchronously flushes updateseffect_tracking()
- Checks if currently tracking effects
Advanced Operations:
deep_read()
/deep_read_state()
- Performs deep reactive readsinvalidate_inner_signals()
- Invalidates nested signals
Reactivity Utilities:
snapshot()
- Creates non-reactive snapshots of stateproxy()
- Creates reactive proxies for objectsequals()
/safe_equals()
- Equality comparison functions
Store Integration:
capture_store_binding()
- Captures store binding informationmark_store_binding()
- Marks props as store bindings
export function inspect(get_value, inspector = console.log) {
// Creates inspection effect for debugging
// Logs value changes to console
}
inspect()
- Inspects reactive values for debuggingtrace()
/tag()
/tag_proxy()
- Tracing utilities for development
reactive_import()
- Legacy reactive importslegacy_pre_effect()
/legacy_pre_effect_reset()
- Legacy reactive statements ($:
)
These functions form the complete state management system in Svelte 5, handling everything from basic reactivity to complex component prop binding, store management, and development tooling.