Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions packages/svelte/src/index-client.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/** @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';

/**
* The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM.
Expand Down Expand Up @@ -179,15 +180,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';
214 changes: 214 additions & 0 deletions packages/svelte/src/internal/client/context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/** @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} */ ({});
}

/**
* @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;
}
2 changes: 1 addition & 1 deletion packages/svelte/src/internal/client/dev/legacy.js
Original file line number Diff line number Diff line change
@@ -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';

Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/src/internal/client/dev/ownership.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
13 changes: 5 additions & 8 deletions packages/svelte/src/internal/client/dom/blocks/await.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,15 @@ 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, is_runes, 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;
Expand Down
3 changes: 1 addition & 2 deletions packages/svelte/src/internal/client/dom/blocks/boundary.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
/** @import { Effect, TemplateNode, } from '#client' */

import { BOUNDARY_EFFECT, EFFECT_TRANSPARENT } from '../../constants.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
} from '../../runtime.js';
import {
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/src/internal/client/dom/blocks/html.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/src/internal/client/dom/blocks/snippet.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
3 changes: 2 additions & 1 deletion packages/svelte/src/internal/client/dom/legacy/lifecycle.js
Original file line number Diff line number Diff line change
@@ -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
Expand Down
9 changes: 2 additions & 7 deletions packages/svelte/src/internal/client/index.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -141,14 +142,8 @@ export {
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';
Expand Down
5 changes: 3 additions & 2 deletions packages/svelte/src/internal/client/proxy.js
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
4 changes: 2 additions & 2 deletions packages/svelte/src/internal/client/reactivity/deriveds.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ import {
skip_reaction,
update_reaction,
increment_write_version,
set_active_effect,
component_context
set_active_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
Expand Down
Loading