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