aa-coordination
Rich Harris 8 months ago
commit 4642b499bb

@ -1,5 +1,13 @@
# svelte
## 5.19.5
### Patch Changes
- fix: improve derived connection to ownership graph ([#15137](https://github.com/sveltejs/svelte/pull/15137))
- fix: correctly look for sibling elements inside blocks and components when pruning CSS ([#15106](https://github.com/sveltejs/svelte/pull/15106))
## 5.19.4
### Patch Changes

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

@ -638,19 +638,30 @@ function get_following_sibling_elements(element, include_self) {
/** @type {Array<Compiler.AST.RegularElement | Compiler.AST.SvelteElement>} */
const siblings = [];
// ...then walk them, starting from the node after the one
// containing the element in question
// ...then walk them, starting from the node containing the element in question
// skipping nodes that appears before the element
const seen = new Set();
let skip = true;
/** @param {Compiler.AST.SvelteNode} node */
function get_siblings(node) {
walk(node, null, {
RegularElement(node) {
siblings.push(node);
if (node === element) {
skip = false;
if (include_self) siblings.push(node);
} else if (!skip) {
siblings.push(node);
}
},
SvelteElement(node) {
siblings.push(node);
if (node === element) {
skip = false;
if (include_self) siblings.push(node);
} else if (!skip) {
siblings.push(node);
}
},
RenderTag(node) {
for (const snippet of node.metadata.snippets) {
@ -663,14 +674,10 @@ function get_following_sibling_elements(element, include_self) {
});
}
for (const node of nodes.slice(nodes.indexOf(start) + 1)) {
for (const node of nodes.slice(nodes.indexOf(start))) {
get_siblings(node);
}
if (include_self) {
siblings.push(element);
}
return siblings;
}

@ -1,12 +1,48 @@
/** @import { ComponentContext, ComponentContextLegacy } from '#client' */
/** @import { EventDispatcher } from './index.js' */
/** @import { NotFunction } from './internal/types.js' */
import { component_context, flush_sync, untrack } from './internal/client/runtime.js';
import { flush_sync, untrack } from './internal/client/runtime.js';
import { is_array } from './internal/shared/utils.js';
import { user_effect } from './internal/client/index.js';
import * as e from './internal/client/errors.js';
import { lifecycle_outside_component } from './internal/shared/errors.js';
import { legacy_mode_flag } from './internal/flags/index.js';
import { component_context } from './internal/client/context.js';
import { DEV } from 'esm-env';
if (DEV) {
/**
* @param {string} rune
*/
function throw_rune_error(rune) {
if (!(rune in globalThis)) {
// TODO if people start adjusting the "this can contain runes" config through v-p-s more, adjust this message
/** @type {any} */
let value; // let's hope noone modifies this global, but belts and braces
Object.defineProperty(globalThis, rune, {
configurable: true,
// eslint-disable-next-line getter-return
get: () => {
if (value !== undefined) {
return value;
}
e.rune_outside_svelte(rune);
},
set: (v) => {
value = v;
}
});
}
}
throw_rune_error('$state');
throw_rune_error('$effect');
throw_rune_error('$derived');
throw_rune_error('$inspect');
throw_rune_error('$props');
throw_rune_error('$bindable');
}
/**
* The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM.
@ -179,15 +215,7 @@ export function flushSync(fn) {
flush_sync(fn);
}
export { getContext, getAllContexts, hasContext, setContext } from './internal/client/context.js';
export { hydrate, mount, unmount } from './internal/client/render.js';
export {
getContext,
getAllContexts,
hasContext,
setContext,
tick,
untrack
} from './internal/client/runtime.js';
export { tick, untrack } from './internal/client/runtime.js';
export { createRawSnippet } from './internal/client/dom/blocks/snippet.js';

@ -0,0 +1,219 @@
/** @import { ComponentContext } from '#client' */
import { DEV } from 'esm-env';
import { add_owner } from './dev/ownership.js';
import { lifecycle_outside_component } from '../shared/errors.js';
import { source } from './reactivity/sources.js';
import {
active_effect,
active_reaction,
set_active_effect,
set_active_reaction
} from './runtime.js';
import { effect } from './reactivity/effects.js';
import { legacy_mode_flag } from '../flags/index.js';
/** @type {ComponentContext | null} */
export let component_context = null;
/** @param {ComponentContext | null} context */
export function set_component_context(context) {
component_context = context;
}
/**
* The current component function. Different from current component context:
* ```html
* <!-- App.svelte -->
* <Foo>
* <Bar /> <!-- context == Foo.svelte, function == App.svelte -->
* </Foo>
* ```
* @type {ComponentContext['function']}
*/
export let dev_current_component_function = null;
/** @param {ComponentContext['function']} fn */
export function set_dev_current_component_function(fn) {
dev_current_component_function = fn;
}
/**
* Retrieves the context that belongs to the closest parent component with the specified `key`.
* Must be called during component initialisation.
*
* @template T
* @param {any} key
* @returns {T}
*/
export function getContext(key) {
const context_map = get_or_init_context_map('getContext');
const result = /** @type {T} */ (context_map.get(key));
if (DEV) {
const fn = /** @type {ComponentContext} */ (component_context).function;
if (fn) {
add_owner(result, fn, true);
}
}
return result;
}
/**
* Associates an arbitrary `context` object with the current component and the specified `key`
* and returns that object. The context is then available to children of the component
* (including slotted content) with `getContext`.
*
* Like lifecycle functions, this must be called during component initialisation.
*
* @template T
* @param {any} key
* @param {T} context
* @returns {T}
*/
export function setContext(key, context) {
const context_map = get_or_init_context_map('setContext');
context_map.set(key, context);
return context;
}
/**
* Checks whether a given `key` has been set in the context of a parent component.
* Must be called during component initialisation.
*
* @param {any} key
* @returns {boolean}
*/
export function hasContext(key) {
const context_map = get_or_init_context_map('hasContext');
return context_map.has(key);
}
/**
* Retrieves the whole context map that belongs to the closest parent component.
* Must be called during component initialisation. Useful, for example, if you
* programmatically create a component and want to pass the existing context to it.
*
* @template {Map<any, any>} [T=Map<any, any>]
* @returns {T}
*/
export function getAllContexts() {
const context_map = get_or_init_context_map('getAllContexts');
if (DEV) {
const fn = component_context?.function;
if (fn) {
for (const value of context_map.values()) {
add_owner(value, fn, true);
}
}
}
return /** @type {T} */ (context_map);
}
/**
* @param {Record<string, unknown>} props
* @param {any} runes
* @param {Function} [fn]
* @returns {void}
*/
export function push(props, runes = false, fn) {
component_context = {
p: component_context,
c: null,
e: null,
m: false,
s: props,
x: null,
l: null
};
if (legacy_mode_flag && !runes) {
component_context.l = {
s: null,
u: null,
r1: [],
r2: source(false)
};
}
if (DEV) {
// component function
component_context.function = fn;
dev_current_component_function = fn;
}
}
/**
* @template {Record<string, any>} T
* @param {T} [component]
* @returns {T}
*/
export function pop(component) {
const context_stack_item = component_context;
if (context_stack_item !== null) {
if (component !== undefined) {
context_stack_item.x = component;
}
const component_effects = context_stack_item.e;
if (component_effects !== null) {
var previous_effect = active_effect;
var previous_reaction = active_reaction;
context_stack_item.e = null;
try {
for (var i = 0; i < component_effects.length; i++) {
var component_effect = component_effects[i];
set_active_effect(component_effect.effect);
set_active_reaction(component_effect.reaction);
effect(component_effect.fn);
}
} finally {
set_active_effect(previous_effect);
set_active_reaction(previous_reaction);
}
}
component_context = context_stack_item.p;
if (DEV) {
dev_current_component_function = context_stack_item.p?.function ?? null;
}
context_stack_item.m = true;
}
// Micro-optimization: Don't set .a above to the empty object
// so it can be garbage-collected when the return here is unused
return component || /** @type {T} */ ({});
}
/** @returns {boolean} */
export function is_runes() {
return !legacy_mode_flag || (component_context !== null && component_context.l === null);
}
/**
* @param {string} name
* @returns {Map<unknown, unknown>}
*/
function get_or_init_context_map(name) {
if (component_context === null) {
lifecycle_outside_component(name);
}
return (component_context.c ??= new Map(get_parent_context(component_context) || undefined));
}
/**
* @param {ComponentContext} component_context
* @returns {Map<unknown, unknown> | null}
*/
function get_parent_context(component_context) {
let parent = component_context.p;
while (parent !== null) {
const context_map = parent.c;
if (context_map !== null) {
return context_map;
}
parent = parent.p;
}
return null;
}

@ -1,5 +1,5 @@
import * as e from '../errors.js';
import { component_context } from '../runtime.js';
import { component_context } from '../context.js';
import { FILENAME } from '../../../constants.js';
import { get_component } from './ownership.js';

@ -3,7 +3,7 @@
import { STATE_SYMBOL_METADATA } from '../constants.js';
import { render_effect, user_pre_effect } from '../reactivity/effects.js';
import { dev_current_component_function } from '../runtime.js';
import { dev_current_component_function } from '../context.js';
import { get_prototype_of } from '../../shared/utils.js';
import * as w from '../warnings.js';
import { FILENAME } from '../../../constants.js';

@ -3,18 +3,16 @@ import { DEV } from 'esm-env';
import { is_promise } from '../../../shared/utils.js';
import { block, branch, pause_effect, resume_effect } from '../../reactivity/effects.js';
import { internal_set, mutable_source, source } from '../../reactivity/sources.js';
import { flush_sync, set_active_effect, set_active_reaction } from '../../runtime.js';
import { hydrate_next, hydrate_node, hydrating } from '../hydration.js';
import { queue_micro_task } from '../task.js';
import { UNINITIALIZED } from '../../../../constants.js';
import {
component_context,
flush_sync,
is_runes,
set_active_effect,
set_active_reaction,
set_component_context,
set_dev_current_component_function
} from '../../runtime.js';
import { hydrate_next, hydrate_node, hydrating } from '../hydration.js';
import { queue_micro_task } from '../task.js';
import { UNINITIALIZED } from '../../../../constants.js';
} from '../../context.js';
const PENDING = 0;
const THEN = 1;

@ -1,21 +1,14 @@
/** @import { Effect, TemplateNode, } from '#client' */
import { BOUNDARY_EFFECT, BOUNDARY_SUSPENDED, EFFECT_TRANSPARENT } from '../../constants.js';
import {
block,
branch,
destroy_effect,
pause_effect,
resume_effect
} from '../../reactivity/effects.js';
import { component_context, set_component_context } from '../../context.js';
import { block, branch, destroy_effect, pause_effect } from '../../reactivity/effects.js';
import {
active_effect,
active_reaction,
component_context,
handle_error,
set_active_effect,
set_active_reaction,
set_component_context,
reset_is_throwing_error,
schedule_effect
} from '../../runtime.js';

@ -7,7 +7,7 @@ import { assign_nodes } from '../template.js';
import * as w from '../../warnings.js';
import { hash, sanitize_location } from '../../../../utils.js';
import { DEV } from 'esm-env';
import { dev_current_component_function } from '../../runtime.js';
import { dev_current_component_function } from '../../context.js';
import { get_first_child, get_next_sibling } from '../operations.js';
/**

@ -1,8 +1,9 @@
/** @import { Effect, TemplateNode } from '#client' */
import { UNINITIALIZED } from '../../../../constants.js';
import { block, branch, pause_effect, resume_effect } from '../../reactivity/effects.js';
import { block, branch, pause_effect } from '../../reactivity/effects.js';
import { not_equal, safe_not_equal } from '../../reactivity/equality.js';
import { active_effect, is_runes, suspended } from '../../runtime.js';
import { active_effect, suspended } from '../../runtime.js';
import { is_runes } from '../../context.js';
import { hydrate_next, hydrate_node, hydrating } from '../hydration.js';
import { add_boundary_callback, find_boundary } from './boundary.js';

@ -6,7 +6,7 @@ import { branch, block, destroy_effect, teardown } from '../../reactivity/effect
import {
dev_current_component_function,
set_dev_current_component_function
} from '../../runtime.js';
} from '../../context.js';
import { hydrate_next, hydrate_node, hydrating } from '../hydration.js';
import { create_fragment_from_html } from '../reconciler.js';
import { assign_nodes } from '../template.js';

@ -17,7 +17,8 @@ import {
} from '../../reactivity/effects.js';
import { set_should_intro } from '../../render.js';
import { current_each_item, set_current_each_item } from './each.js';
import { component_context, active_effect } from '../../runtime.js';
import { active_effect } from '../../runtime.js';
import { component_context } from '../../context.js';
import { DEV } from 'esm-env';
import { EFFECT_TRANSPARENT } from '../../constants.js';
import { assign_nodes } from '../template.js';

@ -5,7 +5,8 @@ import * as e from '../../../errors.js';
import { is } from '../../../proxy.js';
import { queue_micro_task } from '../../task.js';
import { hydrating } from '../../hydration.js';
import { is_runes, untrack } from '../../../runtime.js';
import { untrack } from '../../../runtime.js';
import { is_runes } from '../../../context.js';
/**
* @param {HTMLInputElement} input

@ -1,8 +1,9 @@
/** @import { ComponentContextLegacy } from '#client' */
import { run, run_all } from '../../../shared/utils.js';
import { component_context } from '../../context.js';
import { derived } from '../../reactivity/deriveds.js';
import { user_pre_effect, user_effect } from '../../reactivity/effects.js';
import { component_context, deep_read_state, get, untrack } from '../../runtime.js';
import { deep_read_state, get, untrack } from '../../runtime.js';
/**
* Legacy-mode only: Call `onMount` callbacks and set up `beforeUpdate`/`afterUpdate` effects

@ -1,4 +1,5 @@
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';
@ -110,7 +111,7 @@ export {
user_effect,
user_pre_effect
} from './reactivity/effects.js';
export { mutable_state, mutate, set, state } from './reactivity/sources.js';
export { mutable_state, mutate, set, state, update, update_pre } from './reactivity/sources.js';
export {
prop,
rest_props,
@ -139,17 +140,9 @@ export {
flush_sync,
tick,
untrack,
update,
update_pre,
exclude_from_object,
pop,
push,
deep_read,
deep_read_state,
getAllContexts,
getContext,
setContext,
hasContext
deep_read_state
} from './runtime.js';
export { validate_binding, validate_each_keys } from './validate.js';
export { raf } from './timing.js';

@ -1,6 +1,7 @@
/** @import { ProxyMetadata, ProxyStateObject, Source } from '#client' */
/** @import { ProxyMetadata, Source } from '#client' */
import { DEV } from 'esm-env';
import { get, component_context, active_effect } from './runtime.js';
import { get, active_effect } from './runtime.js';
import { component_context } from './context.js';
import {
array_prototype,
get_descriptor,

@ -19,9 +19,7 @@ import {
update_reaction,
increment_write_version,
set_active_effect,
component_context,
handle_error,
get
handle_error
} from '../runtime.js';
import { equals, safe_equals } from './equality.js';
import * as e from '../errors.js';
@ -30,6 +28,7 @@ import { inspect_effects, internal_set, set_inspect_effects, source } from './so
import { get_stack } from '../dev/tracing.js';
import { tracing_mode_flag } from '../../flags/index.js';
import { capture, suspend } from '../dom/blocks/boundary.js';
import { component_context } from '../context.js';
/**
* @template V
@ -39,8 +38,12 @@ import { capture, suspend } from '../dom/blocks/boundary.js';
/*#__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) {
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
@ -48,16 +51,11 @@ export function derived(fn) {
active_effect.f |= EFFECT_HAS_DERIVED;
}
var parent_derived =
active_reaction !== null && (active_reaction.f & DERIVED) !== 0
? /** @type {Derived} */ (active_reaction)
: null;
/** @type {Derived<V>} */
const signal = {
children: null,
ctx: component_context,
deps: null,
effects: null,
equals,
f: flags,
fn,
@ -137,19 +135,14 @@ export function derived_safe_equal(fn) {
* @param {Derived} derived
* @returns {void}
*/
function destroy_derived_children(derived) {
var children = derived.children;
if (children !== null) {
derived.children = null;
for (var i = 0; i < children.length; i += 1) {
var child = children[i];
if ((child.f & DERIVED) !== 0) {
destroy_derived(/** @type {Derived} */ (child));
} else {
destroy_effect(/** @type {Effect} */ (child));
}
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]));
}
}
}
@ -197,7 +190,7 @@ export function execute_derived(derived) {
stack.push(derived);
destroy_derived_children(derived);
destroy_derived_effects(derived);
value = update_reaction(derived);
} finally {
set_active_effect(prev_active_effect);
@ -206,7 +199,7 @@ export function execute_derived(derived) {
}
} else {
try {
destroy_derived_children(derived);
destroy_derived_effects(derived);
value = update_reaction(derived);
} finally {
set_active_effect(prev_active_effect);
@ -238,9 +231,9 @@ export function update_derived(derived) {
* @returns {void}
*/
export function destroy_derived(derived) {
destroy_derived_children(derived);
destroy_derived_effects(derived);
remove_reactions(derived, 0);
set_signal_status(derived, DESTROYED);
derived.v = derived.children = derived.deps = derived.ctx = derived.reactions = null;
derived.v = derived.deps = derived.ctx = derived.reactions = null;
}

@ -1,10 +1,8 @@
/** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, TemplateNode, TransitionManager, Value } from '#client' */
import {
check_dirtiness,
component_context,
active_effect,
active_reaction,
dev_current_component_function,
update_effect,
get,
is_destroying_effect,
@ -46,8 +44,9 @@ 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 { async_derived, derived, destroy_derived } from './deriveds.js';
import { async_derived, derived } from './deriveds.js';
import { capture, suspend } from '../dom/blocks/boundary.js';
import { component_context, dev_current_component_function } from '../context.js';
/**
* @param {'$effect' | '$effect.pre' | '$inspect'} rune
@ -57,7 +56,7 @@ export function validate_effect(rune) {
e.effect_orphan(rune);
}
if (active_reaction !== null && (active_reaction.f & UNOWNED) !== 0) {
if (active_reaction !== null && (active_reaction.f & UNOWNED) !== 0 && active_effect === null) {
e.effect_in_unowned_derived();
}
@ -107,7 +106,6 @@ function create_effect(type, fn, sync, push = true) {
var effect = {
ctx: component_context,
deps: null,
deriveds: null,
nodes_start: null,
nodes_end: null,
f: type | DIRTY,
@ -161,7 +159,7 @@ function create_effect(type, fn, sync, push = true) {
// 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.children ??= []).push(effect);
(derived.effects ??= []).push(effect);
}
}
@ -429,22 +427,6 @@ export function execute_effect_teardown(effect) {
}
}
/**
* @param {Effect} signal
* @returns {void}
*/
export function destroy_effect_deriveds(signal) {
var deriveds = signal.deriveds;
if (deriveds !== null) {
signal.deriveds = null;
for (var i = 0; i < deriveds.length; i += 1) {
destroy_derived(deriveds[i]);
}
}
}
/**
* @param {Effect} signal
* @param {boolean} remove_dom
@ -502,7 +484,6 @@ export function destroy_effect(effect, remove_dom = true) {
}
destroy_effect_children(effect, remove_dom && !removed);
destroy_effect_deriveds(effect);
remove_reactions(effect, 0);
set_signal_status(effect, DESTROYED);

@ -8,16 +8,9 @@ import {
PROPS_IS_UPDATED
} from '../../../constants.js';
import { get_descriptor, is_function } from '../../shared/utils.js';
import { mutable_source, set, source } from './sources.js';
import { mutable_source, set, source, update } from './sources.js';
import { derived, derived_safe_equal } from './deriveds.js';
import {
active_effect,
get,
captured_signals,
set_active_effect,
untrack,
update
} from '../runtime.js';
import { active_effect, get, captured_signals, set_active_effect, untrack } from '../runtime.js';
import { safe_equals } from './equality.js';
import * as e from '../errors.js';
import {

@ -1,12 +1,10 @@
/** @import { Derived, Effect, Reaction, Source, Value } from '#client' */
import { DEV } from 'esm-env';
import {
component_context,
active_reaction,
active_effect,
untracked_writes,
get,
is_runes,
schedule_effect,
set_untracked_writes,
set_signal_status,
@ -38,6 +36,7 @@ import {
import * as e from '../errors.js';
import { legacy_mode_flag, tracing_mode_flag } from '../../flags/index.js';
import { get_stack } from '../dev/tracing.js';
import { component_context, is_runes } from '../context.js';
export let inspect_effects = new Set();
@ -229,6 +228,35 @@ export function internal_set(source, value) {
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

@ -36,8 +36,8 @@ export interface Reaction extends Signal {
export interface Derived<V = unknown> extends Value<V>, Reaction {
/** The derived function */
fn: () => V;
/** Reactions created inside this signal */
children: null | Reaction[];
/** Effects created inside this signal */
effects: null | Effect[];
/** Parent effect or derived */
parent: Effect | Derived | null;
}
@ -51,8 +51,6 @@ export interface Effect extends Reaction {
*/
nodes_start: null | TemplateNode;
nodes_end: null | TemplateNode;
/** Reactions created inside this signal */
deriveds: null | Derived[];
/** The effect function */
fn: null | (() => void | (() => void));
/** The teardown function returned from the effect function */

@ -9,7 +9,8 @@ import {
init_operations
} from './dom/operations.js';
import { HYDRATION_END, HYDRATION_ERROR, HYDRATION_START } from '../../constants.js';
import { push, pop, component_context, active_effect } from './runtime.js';
import { active_effect } from './runtime.js';
import { push, pop, component_context } from './context.js';
import { component_root, branch } from './reactivity/effects.js';
import {
hydrate_next,

@ -4,8 +4,6 @@ import { define_property, get_descriptors, get_prototype_of, index_of } from '..
import {
destroy_block_effect_children,
destroy_effect_children,
destroy_effect_deriveds,
effect,
execute_effect_teardown,
unlink_effect
} from './reactivity/effects.js';
@ -35,14 +33,24 @@ import {
flush_boundary_micro_tasks,
flush_post_micro_tasks
} from './dom/task.js';
import { add_owner } from './dev/ownership.js';
import { internal_set, set, source } from './reactivity/sources.js';
import { destroy_derived, execute_derived, update_derived } from './reactivity/deriveds.js';
import { internal_set } from './reactivity/sources.js';
import {
destroy_derived,
destroy_derived_effects,
execute_derived,
update_derived
} from './reactivity/deriveds.js';
import * as e from './errors.js';
import { lifecycle_outside_component } from '../shared/errors.js';
import { FILENAME } from '../../constants.js';
import { legacy_mode_flag, tracing_mode_flag } from '../flags/index.js';
import { tracing_mode_flag } from '../flags/index.js';
import { tracing_expressions, get_stack } from './dev/tracing.js';
import {
component_context,
dev_current_component_function,
is_runes,
set_component_context,
set_dev_current_component_function
} from './context.js';
const FLUSH_MICROTASK = 0;
const FLUSH_SYNC = 1;
@ -168,41 +176,10 @@ export function set_captured_signals(value) {
captured_signals = value;
}
// Handling runtime component context
/** @type {ComponentContext | null} */
export let component_context = null;
/** @param {ComponentContext | null} context */
export function set_component_context(context) {
component_context = context;
}
/**
* The current component function. Different from current component context:
* ```html
* <!-- App.svelte -->
* <Foo>
* <Bar /> <!-- context == Foo.svelte, function == App.svelte -->
* </Foo>
* ```
* @type {ComponentContext['function']}
*/
export let dev_current_component_function = null;
/** @param {ComponentContext['function']} fn */
export function set_dev_current_component_function(fn) {
dev_current_component_function = fn;
}
export function increment_write_version() {
return ++write_version;
}
/** @returns {boolean} */
export function is_runes() {
return !legacy_mode_flag || (component_context !== null && component_context.l === null);
}
/**
* Determines whether a derived or effect is dirty.
* If it is MAYBE_DIRTY, will set the status to CLEAN
@ -450,9 +427,18 @@ export function update_reaction(reaction) {
skipped_deps = 0;
untracked_writes = null;
active_reaction = (flags & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null;
skip_reaction = !is_flushing_effect && (flags & UNOWNED) !== 0;
// prettier-ignore
skip_reaction =
(flags & UNOWNED) !== 0 &&
(!is_flushing_effect ||
// If we were previously not in a reactive context and we're reading an unowned derived
// that was created inside another reaction, then we don't fully know the real owner and thus
// we need to skip adding any reactions for this unowned
((previous_reaction === null || previous_untracking) &&
/** @type {Derived} */ (reaction).parent !== null));
derived_sources = null;
component_context = reaction.ctx;
set_component_context(reaction.ctx);
untracking = false;
read_version++;
@ -518,7 +504,7 @@ export function update_reaction(reaction) {
active_reaction = previous_reaction;
skip_reaction = previous_skip_reaction;
derived_sources = prev_derived_sources;
component_context = previous_component_context;
set_component_context(previous_component_context);
untracking = previous_untracking;
}
}
@ -560,6 +546,8 @@ function remove_reaction(signal, dependency) {
if ((dependency.f & (UNOWNED | DISCONNECTED)) === 0) {
dependency.f ^= DISCONNECTED;
}
// Disconnect any reactions owned by this reaction
destroy_derived_effects(/** @type {Derived} **/ (dependency));
remove_reactions(/** @type {Derived} **/ (dependency), 0);
}
}
@ -598,7 +586,7 @@ export function update_effect(effect) {
if (DEV) {
var previous_component_fn = dev_current_component_function;
dev_current_component_function = effect.component_function;
set_dev_current_component_function(effect.component_function);
}
try {
@ -607,7 +595,6 @@ export function update_effect(effect) {
} else {
destroy_effect_children(effect);
}
destroy_effect_deriveds(effect);
execute_effect_teardown(effect);
var teardown = update_reaction(effect);
@ -640,7 +627,7 @@ export function update_effect(effect) {
active_effect = previous_effect;
if (DEV) {
dev_current_component_function = previous_component_fn;
set_dev_current_component_function(previous_component_fn);
}
}
}
@ -1027,30 +1014,20 @@ export function get(signal) {
signal.reactions.push(active_reaction);
}
}
}
if (
} else if (
is_derived &&
/** @type {Derived} */ (signal).deps === null &&
(active_reaction === null || untracking || (active_reaction.f & DERIVED) !== 0)
/** @type {Derived} */ (signal).effects === null
) {
var derived = /** @type {Derived} */ (signal);
var parent = derived.parent;
if (parent !== null) {
// Attach the derived to the nearest parent effect or derived
if ((parent.f & DERIVED) !== 0) {
var parent_derived = /** @type {Derived} */ (parent);
if (!parent_derived.children?.includes(derived)) {
(parent_derived.children ??= []).push(derived);
}
} else {
var parent_effect = /** @type {Effect} */ (parent);
if (!parent_effect.deriveds?.includes(derived)) {
(parent_effect.deriveds ??= []).push(derived);
}
// If the derived is owned by another derived then mark it as unowned
// as the derived value might have been referenced in a different context
// since and thus its parent might not be its true owner anymore
if ((parent.f & UNOWNED) === 0) {
derived.f ^= UNOWNED;
}
}
}
@ -1184,138 +1161,6 @@ export function set_signal_status(signal, status) {
signal.f = (signal.f & STATUS_MASK) | status;
}
/**
* Retrieves the context that belongs to the closest parent component with the specified `key`.
* Must be called during component initialisation.
*
* @template T
* @param {any} key
* @returns {T}
*/
export function getContext(key) {
const context_map = get_or_init_context_map('getContext');
const result = /** @type {T} */ (context_map.get(key));
if (DEV) {
const fn = /** @type {ComponentContext} */ (component_context).function;
if (fn) {
add_owner(result, fn, true);
}
}
return result;
}
/**
* Associates an arbitrary `context` object with the current component and the specified `key`
* and returns that object. The context is then available to children of the component
* (including slotted content) with `getContext`.
*
* Like lifecycle functions, this must be called during component initialisation.
*
* @template T
* @param {any} key
* @param {T} context
* @returns {T}
*/
export function setContext(key, context) {
const context_map = get_or_init_context_map('setContext');
context_map.set(key, context);
return context;
}
/**
* Checks whether a given `key` has been set in the context of a parent component.
* Must be called during component initialisation.
*
* @param {any} key
* @returns {boolean}
*/
export function hasContext(key) {
const context_map = get_or_init_context_map('hasContext');
return context_map.has(key);
}
/**
* Retrieves the whole context map that belongs to the closest parent component.
* Must be called during component initialisation. Useful, for example, if you
* programmatically create a component and want to pass the existing context to it.
*
* @template {Map<any, any>} [T=Map<any, any>]
* @returns {T}
*/
export function getAllContexts() {
const context_map = get_or_init_context_map('getAllContexts');
if (DEV) {
const fn = component_context?.function;
if (fn) {
for (const value of context_map.values()) {
add_owner(value, fn, true);
}
}
}
return /** @type {T} */ (context_map);
}
/**
* @param {string} name
* @returns {Map<unknown, unknown>}
*/
function get_or_init_context_map(name) {
if (component_context === null) {
lifecycle_outside_component(name);
}
return (component_context.c ??= new Map(get_parent_context(component_context) || undefined));
}
/**
* @param {ComponentContext} component_context
* @returns {Map<unknown, unknown> | null}
*/
function get_parent_context(component_context) {
let parent = component_context.p;
while (parent !== null) {
const context_map = parent.c;
if (context_map !== null) {
return context_map;
}
parent = parent.p;
}
return null;
}
/**
* @template {number | bigint} T
* @param {Value<T>} signal
* @param {1 | -1} [d]
* @returns {T}
*/
export function update(signal, d = 1) {
var value = get(signal);
var result = d === 1 ? value++ : value--;
set(signal, value);
// @ts-expect-error
return result;
}
/**
* @template {number | bigint} T
* @param {Value<T>} signal
* @param {1 | -1} [d]
* @returns {T}
*/
export function update_pre(signal, d = 1) {
var value = get(signal);
// @ts-expect-error
return set(signal, d === 1 ? ++value : --value);
}
/**
* @param {Record<string, unknown>} obj
* @param {string[]} keys
@ -1334,78 +1179,6 @@ export function exclude_from_object(obj, keys) {
return result;
}
/**
* @param {Record<string, unknown>} props
* @param {any} runes
* @param {Function} [fn]
* @returns {void}
*/
export function push(props, runes = false, fn) {
component_context = {
p: component_context,
c: null,
e: null,
m: false,
s: props,
x: null,
l: null
};
if (legacy_mode_flag && !runes) {
component_context.l = {
s: null,
u: null,
r1: [],
r2: source(false)
};
}
if (DEV) {
// component function
component_context.function = fn;
dev_current_component_function = fn;
}
}
/**
* @template {Record<string, any>} T
* @param {T} [component]
* @returns {T}
*/
export function pop(component) {
const context_stack_item = component_context;
if (context_stack_item !== null) {
if (component !== undefined) {
context_stack_item.x = component;
}
const component_effects = context_stack_item.e;
if (component_effects !== null) {
var previous_effect = active_effect;
var previous_reaction = active_reaction;
context_stack_item.e = null;
try {
for (var i = 0; i < component_effects.length; i++) {
var component_effect = component_effects[i];
set_active_effect(component_effect.effect);
set_active_reaction(component_effect.reaction);
effect(component_effect.fn);
}
} finally {
set_active_effect(previous_effect);
set_active_reaction(previous_reaction);
}
}
component_context = context_stack_item.p;
if (DEV) {
dev_current_component_function = context_stack_item.p?.function ?? null;
}
context_stack_item.m = true;
}
// Micro-optimization: Don't set .a above to the empty object
// so it can be garbage-collected when the return here is unused
return component || /** @type {T} */ ({});
}
/**
* Possibly traverse an object and read all its properties so that they're all reactive in case this is `$state`.
* Does only check first level of an object for performance reasons (heuristic should be good for 99% of all cases).
@ -1479,37 +1252,3 @@ export function deep_read(value, visited = new Set()) {
}
}
}
if (DEV) {
/**
* @param {string} rune
*/
function throw_rune_error(rune) {
if (!(rune in globalThis)) {
// TODO if people start adjusting the "this can contain runes" config through v-p-s more, adjust this message
/** @type {any} */
let value; // let's hope noone modifies this global, but belts and braces
Object.defineProperty(globalThis, rune, {
configurable: true,
// eslint-disable-next-line getter-return
get: () => {
if (value !== undefined) {
return value;
}
e.rune_outside_svelte(rune);
},
set: (v) => {
value = v;
}
});
}
}
throw_rune_error('$state');
throw_rune_error('$effect');
throw_rune_error('$derived');
throw_rune_error('$inspect');
throw_rune_error('$props');
throw_rune_error('$bindable');
}

@ -1,4 +1,4 @@
import { dev_current_component_function } from './runtime.js';
import { dev_current_component_function } from './context.js';
import { is_array } from '../shared/utils.js';
import * as e from './errors.js';
import { FILENAME } from '../../constants.js';

@ -3,19 +3,13 @@ import { DIRTY, LEGACY_PROPS, MAYBE_DIRTY } from '../internal/client/constants.j
import { user_pre_effect } from '../internal/client/reactivity/effects.js';
import { mutable_source, set } from '../internal/client/reactivity/sources.js';
import { hydrate, mount, unmount } from '../internal/client/render.js';
import {
active_effect,
component_context,
dev_current_component_function,
flush_sync,
get,
set_signal_status
} from '../internal/client/runtime.js';
import { active_effect, flush_sync, get, set_signal_status } from '../internal/client/runtime.js';
import { lifecycle_outside_component } from '../internal/shared/errors.js';
import { define_property, is_array } from '../internal/shared/utils.js';
import * as w from '../internal/client/warnings.js';
import { DEV } from 'esm-env';
import { FILENAME } from '../constants.js';
import { component_context, dev_current_component_function } from '../internal/client/context.js';
/**
* Takes the same options as a Svelte 4 component and the component function and returns a Svelte 4 compatible component.

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

@ -6,182 +6,196 @@ export default test({
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused:has(y)"',
start: {
line: 31,
line: 33,
column: 1,
character: 308
character: 330
},
end: {
line: 31,
line: 33,
column: 15,
character: 322
character: 344
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused:has(:global(y))"',
start: {
line: 34,
line: 36,
column: 1,
character: 343
character: 365
},
end: {
line: 34,
line: 36,
column: 24,
character: 366
character: 388
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "x:has(.unused)"',
start: {
line: 37,
line: 39,
column: 1,
character: 387
character: 409
},
end: {
line: 37,
line: 39,
column: 15,
character: 401
character: 423
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector ":global(.foo):has(.unused)"',
start: {
line: 40,
line: 42,
column: 1,
character: 422
character: 444
},
end: {
line: 40,
line: 42,
column: 27,
character: 448
character: 470
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "x:has(y):has(.unused)"',
start: {
line: 50,
line: 52,
column: 1,
character: 556
character: 578
},
end: {
line: 50,
line: 52,
column: 22,
character: 577
character: 599
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused"',
start: {
line: 69,
line: 71,
column: 2,
character: 782
character: 804
},
end: {
line: 69,
line: 71,
column: 9,
character: 789
character: 811
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused x:has(y)"',
start: {
line: 85,
line: 87,
column: 1,
character: 936
character: 958
},
end: {
line: 85,
line: 87,
column: 17,
character: 952
character: 974
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused:has(.unused)"',
start: {
line: 88,
line: 90,
column: 1,
character: 973
character: 995
},
end: {
line: 88,
line: 90,
column: 21,
character: 993
character: 1015
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "x:has(> z)"',
start: {
line: 98,
line: 100,
column: 1,
character: 1093
character: 1115
},
end: {
line: 98,
line: 100,
column: 11,
character: 1103
character: 1125
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "x:has(> d)"',
start: {
line: 101,
line: 103,
column: 1,
character: 1124
character: 1146
},
end: {
line: 101,
line: 103,
column: 11,
character: 1134
character: 1156
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "x:has(~ y)"',
start: {
line: 121,
line: 123,
column: 1,
character: 1326
character: 1348
},
end: {
line: 121,
line: 123,
column: 11,
character: 1336
character: 1358
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "f:has(~ d)"',
start: {
line: 133,
column: 1,
character: 1446
},
end: {
line: 133,
column: 11,
character: 1456
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector ":has(.unused)"',
start: {
line: 129,
line: 141,
column: 2,
character: 1409
character: 1529
},
end: {
line: 129,
line: 141,
column: 15,
character: 1422
character: 1542
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "&:has(.unused)"',
start: {
line: 135,
line: 147,
column: 2,
character: 1480
character: 1600
},
end: {
line: 135,
line: 147,
column: 16,
character: 1494
character: 1614
}
}
]

@ -112,6 +112,16 @@
color: red;
}*/
d.svelte-xyz:has(+ e:where(.svelte-xyz)) {
color: green;
}
d.svelte-xyz:has(~ f:where(.svelte-xyz)) {
color: green;
}
/* (unused) f:has(~ d) {
color: red;
}*/
.foo {
.svelte-xyz:has(x:where(.svelte-xyz)) {
color: green;

@ -3,6 +3,8 @@
<z></z>
{#if foo}
<d></d>
<e></e>
<f></f>
{/if}
</y>
</x>
@ -122,6 +124,16 @@
color: red;
}
d:has(+ e) {
color: green;
}
d:has(~ f) {
color: green;
}
f:has(~ d) {
color: red;
}
:global(.foo) {
:has(x) {
color: green;

@ -1,18 +1,20 @@
import { describe, assert, it } from 'vitest';
import { flushSync } from '../../src/index-client';
import * as $ from '../../src/internal/client/runtime';
import { push, pop } from '../../src/internal/client/context';
import {
effect,
effect_root,
render_effect,
user_effect
} from '../../src/internal/client/reactivity/effects';
import { state, set } from '../../src/internal/client/reactivity/sources';
import type { Derived, Value } from '../../src/internal/client/types';
import { state, set, update, update_pre } from '../../src/internal/client/reactivity/sources';
import type { Derived, Effect, Value } from '../../src/internal/client/types';
import { proxy } from '../../src/internal/client/proxy';
import { derived } from '../../src/internal/client/reactivity/deriveds';
import { snapshot } from '../../src/internal/shared/clone.js';
import { SvelteSet } from '../../src/reactivity/set';
import { DESTROYED } from '../../src/internal/client/constants';
/**
* @param runes runes mode
@ -22,13 +24,13 @@ import { SvelteSet } from '../../src/reactivity/set';
function run_test(runes: boolean, fn: (runes: boolean) => () => void) {
return () => {
// Create a component context to test runes vs legacy mode
$.push({}, runes);
push({}, runes);
// Create a render context so that effect validations etc don't fail
let execute: any;
const destroy = effect_root(() => {
execute = fn(runes);
});
$.pop();
pop();
execute();
destroy();
};
@ -67,7 +69,7 @@ describe('signals', () => {
};
});
test('multiple effects with state and derived in it#1', () => {
test('multiple effects with state and derived in it #1', () => {
const log: string[] = [];
let count = state(0);
@ -88,7 +90,7 @@ describe('signals', () => {
};
});
test('multiple effects with state and derived in it#2', () => {
test('multiple effects with state and derived in it #2', () => {
const log: string[] = [];
let count = state(0);
@ -255,12 +257,16 @@ describe('signals', () => {
const a = state(0);
const b = state(0);
const c = derived(() => {
const a_2 = derived(() => $.get(a) + '!');
const b_2 = derived(() => $.get(b) + '?');
nested.push(a_2, b_2);
let c: any;
const destroy = effect_root(() => {
c = derived(() => {
const a_2 = derived(() => $.get(a) + '!');
const b_2 = derived(() => $.get(b) + '?');
nested.push(a_2, b_2);
return { a: $.get(a_2), b: $.get(b_2) };
return { a: $.get(a_2), b: $.get(b_2) };
});
});
$.get(c);
@ -273,11 +279,10 @@ describe('signals', () => {
$.get(c);
// Ensure we're not leaking dependencies
assert.deepEqual(
nested.slice(0, -2).map((s) => s.deps),
[null, null, null, null]
);
destroy();
assert.equal(a.reactions, null);
assert.equal(b.reactions, null);
};
});
@ -476,6 +481,7 @@ describe('signals', () => {
effect(() => {
log.push('inner', $.get(inner));
});
return $.get(outer);
});
});
});
@ -529,6 +535,103 @@ describe('signals', () => {
};
});
test('mixed nested deriveds correctly cleanup when no longer connected to graph #1', () => {
let a: Derived<unknown>;
let b: Derived<unknown>;
let s = state(0);
const destroy = effect_root(() => {
render_effect(() => {
a = derived(() => {
b = derived(() => {
$.get(s);
});
$.untrack(() => {
$.get(b);
});
$.get(s);
});
$.get(a);
});
});
return () => {
flushSync();
assert.equal(a?.deps?.length, 1);
assert.equal(s?.reactions?.length, 1);
destroy();
assert.equal(s?.reactions, null);
};
});
test('mixed nested deriveds correctly cleanup when no longer connected to graph #2', () => {
let a: Derived<unknown>;
let b: Derived<unknown>;
let s = state(0);
const destroy = effect_root(() => {
render_effect(() => {
a = derived(() => {
b = derived(() => {
$.get(s);
});
effect_root(() => {
$.get(b);
});
$.get(s);
});
$.get(a);
});
});
return () => {
flushSync();
assert.equal(a?.deps?.length, 1);
assert.equal(s?.reactions?.length, 1);
destroy();
assert.equal(s?.reactions, null);
};
});
test('mixed nested deriveds correctly cleanup when no longer connected to graph #3', () => {
let a: Derived<unknown>;
let b: Derived<unknown>;
let s = state(0);
let logs: any[] = [];
const destroy = effect_root(() => {
render_effect(() => {
a = derived(() => {
b = derived(() => {
return $.get(s);
});
effect_root(() => {
$.get(b);
});
render_effect(() => {
logs.push($.get(b));
});
$.get(s);
});
$.get(a);
});
});
return () => {
flushSync();
assert.equal(a?.deps?.length, 1);
assert.equal(s?.reactions?.length, 2);
set(s, 1);
flushSync();
assert.deepEqual(logs, [0, 1]);
destroy();
assert.equal(s?.reactions, null);
};
});
test('deriveds update upon reconnection #1', () => {
let a = state(false);
let b = state(false);
@ -777,56 +880,44 @@ describe('signals', () => {
};
});
test('nested deriveds clean up the relationships when used with untrack', () => {
test('deriveds containing effects work correctly', () => {
return () => {
let a = render_effect(() => {});
let b = state(0);
let c;
let effects: Effect[] = [];
const destroy = effect_root(() => {
a = render_effect(() => {
$.untrack(() => {
const b = derived(() => {
const c = derived(() => {});
$.untrack(() => {
$.get(c);
});
});
c = derived(() => {
effects.push(
effect(() => {
$.get(b);
})
);
$.get(b);
});
$.get(c);
});
});
assert.deepEqual(a.deriveds?.length, 1);
destroy();
assert.equal(c!.effects?.length, 1);
assert.equal(a.first, a.last);
assert.deepEqual(a.deriveds, null);
};
});
test('nested deriveds do not connect inside parent deriveds if unused', () => {
return () => {
let a = render_effect(() => {});
let b: Derived<void> | undefined;
set(b, 1);
const destroy = effect_root(() => {
a = render_effect(() => {
$.untrack(() => {
b = derived(() => {
derived(() => {});
derived(() => {});
derived(() => {});
});
$.get(b);
});
});
});
flushSync();
assert.deepEqual(a.deriveds?.length, 1);
assert.deepEqual(b?.children, null);
assert.equal(c!.effects?.length, 1);
assert.equal(a.first, a.last);
destroy();
assert.deepEqual(a.deriveds, null);
assert.equal(a.first, null);
assert.equal(effects.length, 2);
assert.equal((effects[0].f & DESTROYED) !== 0, true);
assert.equal((effects[1].f & DESTROYED) !== 0, true);
};
});
@ -835,7 +926,7 @@ describe('signals', () => {
let a = render_effect(() => {});
let b = state(0);
let c;
let effects = [];
let effects: Effect[] = [];
const destroy = effect_root(() => {
a = render_effect(() => {
@ -853,20 +944,23 @@ describe('signals', () => {
});
});
assert.deepEqual(c!.children?.length, 1);
assert.deepEqual(a.first, a.last);
assert.equal(c!.effects?.length, 1);
assert.equal(a.first, a.last);
set(b, 1);
flushSync();
assert.deepEqual(c!.children?.length, 1);
assert.deepEqual(a.first, a.last);
assert.equal(c!.effects?.length, 1);
assert.equal(a.first, a.last);
destroy();
assert.deepEqual(a.deriveds, null);
assert.deepEqual(a.first, null);
assert.equal(a.first, null);
assert.equal(effects.length, 2);
assert.equal((effects[0].f & DESTROYED) !== 0, true);
assert.equal((effects[1].f & DESTROYED) !== 0, true);
};
});
@ -874,14 +968,14 @@ describe('signals', () => {
return () => {
const count = state(0n);
assert.doesNotThrow(() => $.update(count));
assert.doesNotThrow(() => update(count));
assert.equal($.get(count), 1n);
assert.doesNotThrow(() => $.update(count, -1));
assert.doesNotThrow(() => update(count, -1));
assert.equal($.get(count), 0n);
assert.doesNotThrow(() => $.update_pre(count));
assert.doesNotThrow(() => update_pre(count));
assert.equal($.get(count), 1n);
assert.doesNotThrow(() => $.update_pre(count, -1));
assert.doesNotThrow(() => update_pre(count, -1));
assert.equal($.get(count), 0n);
};
});

@ -421,6 +421,34 @@ declare module 'svelte' {
}): Snippet<Params>;
/** Anything except a function */
type NotFunction<T> = T extends Function ? never : T;
/**
* Retrieves the context that belongs to the closest parent component with the specified `key`.
* Must be called during component initialisation.
*
* */
export function getContext<T>(key: any): T;
/**
* Associates an arbitrary `context` object with the current component and the specified `key`
* and returns that object. The context is then available to children of the component
* (including slotted content) with `getContext`.
*
* Like lifecycle functions, this must be called during component initialisation.
*
* */
export function setContext<T>(key: any, context: T): T;
/**
* Checks whether a given `key` has been set in the context of a parent component.
* Must be called during component initialisation.
*
* */
export function hasContext(key: any): boolean;
/**
* Retrieves the whole context map that belongs to the closest parent component.
* Must be called during component initialisation. Useful, for example, if you
* programmatically create a component and want to pass the existing context to it.
*
* */
export function getAllContexts<T extends Map<any, any> = Map<any, any>>(): T;
/**
* Mounts a component to the given target and returns the exports and potentially the props (if compiled with `accessors: true`) of the component.
* Transitions will play during the initial render unless the `intro` option is set to `false`.
@ -484,34 +512,6 @@ declare module 'svelte' {
* ```
* */
export function untrack<T>(fn: () => T): T;
/**
* Retrieves the context that belongs to the closest parent component with the specified `key`.
* Must be called during component initialisation.
*
* */
export function getContext<T>(key: any): T;
/**
* Associates an arbitrary `context` object with the current component and the specified `key`
* and returns that object. The context is then available to children of the component
* (including slotted content) with `getContext`.
*
* Like lifecycle functions, this must be called during component initialisation.
*
* */
export function setContext<T>(key: any, context: T): T;
/**
* Checks whether a given `key` has been set in the context of a parent component.
* Must be called during component initialisation.
*
* */
export function hasContext(key: any): boolean;
/**
* Retrieves the whole context map that belongs to the closest parent component.
* Must be called during component initialisation. Useful, for example, if you
* programmatically create a component and want to pass the existing context to it.
*
* */
export function getAllContexts<T extends Map<any, any> = Map<any, any>>(): T;
type Getters<T> = {
[K in keyof T]: () => T[K];
};

Loading…
Cancel
Save