mirror of https://github.com/sveltejs/svelte
chore: tidy up server exports (#10972)
* tidy up server exports * tidy up server exports * docs are unnecessary here * eliminate client dependencies from server code * lintpull/10974/head
parent
d49e2aeb15
commit
f303d82043
@ -0,0 +1,84 @@
|
|||||||
|
import { DEV } from 'esm-env';
|
||||||
|
import { on_destroy } from './index.js';
|
||||||
|
|
||||||
|
/** @type {import('#server').Component | null} */
|
||||||
|
export var current_component = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @template T
|
||||||
|
* @param {any} key
|
||||||
|
* @returns {T}
|
||||||
|
*/
|
||||||
|
export function getContext(key) {
|
||||||
|
const context_map = getAllContexts();
|
||||||
|
const result = /** @type {T} */ (context_map.get(key));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @template T
|
||||||
|
* @param {any} key
|
||||||
|
* @param {T} context
|
||||||
|
* @returns {T}
|
||||||
|
*/
|
||||||
|
export function setContext(key, context) {
|
||||||
|
getAllContexts().set(key, context);
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} key
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function hasContext(key) {
|
||||||
|
return getAllContexts().has(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {Map<any, any>} */
|
||||||
|
export function getAllContexts() {
|
||||||
|
const context = current_component;
|
||||||
|
|
||||||
|
if (context === null) {
|
||||||
|
throw new Error(
|
||||||
|
'ERR_SVELTE_ORPHAN_CONTEXT' +
|
||||||
|
(DEV ? 'Context can only be used during component initialisation.' : '')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (context.c ??= new Map(get_parent_context(context) || undefined));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function push() {
|
||||||
|
current_component = { p: current_component, c: null, d: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pop() {
|
||||||
|
var component = /** @type {import('#server').Component} */ (current_component);
|
||||||
|
|
||||||
|
var ondestroy = component.d;
|
||||||
|
|
||||||
|
if (ondestroy) {
|
||||||
|
on_destroy.push(...ondestroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
current_component = component.p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('#server').Component} 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;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
export interface Component {
|
||||||
|
/** parent */
|
||||||
|
p: null | Component;
|
||||||
|
/** context */
|
||||||
|
c: null | Map<unknown, unknown>;
|
||||||
|
/** ondestroy */
|
||||||
|
d: null | Array<() => void>;
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
export type Store<V> = {
|
||||||
|
subscribe: (run: (value: V) => void) => () => void;
|
||||||
|
set(value: V): void;
|
||||||
|
};
|
@ -0,0 +1,57 @@
|
|||||||
|
import { is_void } from '../../compiler/phases/1-parse/utils/names.js';
|
||||||
|
|
||||||
|
const snippet_symbol = Symbol.for('svelte.snippet');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} fn
|
||||||
|
*/
|
||||||
|
export function add_snippet_symbol(fn) {
|
||||||
|
fn[snippet_symbol] = true;
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that the function handed to `{@render ...}` is a snippet function, and not some other kind of function.
|
||||||
|
* @param {any} snippet_fn
|
||||||
|
*/
|
||||||
|
export function validate_snippet(snippet_fn) {
|
||||||
|
if (snippet_fn && snippet_fn[snippet_symbol] !== true) {
|
||||||
|
throw new Error(
|
||||||
|
'The argument to `{@render ...}` must be a snippet function, not a component or some other kind of function. ' +
|
||||||
|
'If you want to dynamically render one snippet or another, use `$derived` and pass its result to `{@render ...}`.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return snippet_fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that the function behind `<Component />` isn't a snippet.
|
||||||
|
* @param {any} component_fn
|
||||||
|
*/
|
||||||
|
export function validate_component(component_fn) {
|
||||||
|
if (component_fn?.[snippet_symbol] === true) {
|
||||||
|
throw new Error('A snippet must be rendered with `{@render ...}`');
|
||||||
|
}
|
||||||
|
return component_fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {() => string} tag_fn
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
export function validate_void_dynamic_element(tag_fn) {
|
||||||
|
const tag = tag_fn();
|
||||||
|
if (tag && is_void(tag)) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.warn(`<svelte:element this="${tag}"> is self-closing and cannot have content.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {() => unknown} tag_fn */
|
||||||
|
export function validate_dynamic_element_tag(tag_fn) {
|
||||||
|
const tag = tag_fn();
|
||||||
|
const is_string = typeof tag === 'string';
|
||||||
|
if (tag && !is_string) {
|
||||||
|
throw new Error('<svelte:element> expects "this" attribute to be a string.');
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue