Add js web stuff to landing page + documentation

This commit is contained in:
2026-07-14 10:33:12 -04:00
parent fec8ef4a3e
commit 02a6dc6c48
435 changed files with 69567 additions and 1522 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020-2022 Ryan Carniato
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
import type { JSX } from "solid-js";
import type { Location, Navigator } from "./types.js";
declare module "solid-js" {
namespace JSX {
interface AnchorHTMLAttributes<T> {
state?: string;
noScroll?: boolean;
replace?: boolean;
preload?: boolean;
link?: boolean;
}
}
}
export interface AnchorProps extends Omit<JSX.AnchorHTMLAttributes<HTMLAnchorElement>, "state"> {
href: string;
replace?: boolean | undefined;
noScroll?: boolean | undefined;
state?: unknown | undefined;
inactiveClass?: string | undefined;
activeClass?: string | undefined;
end?: boolean | undefined;
}
export declare function A(props: AnchorProps): JSX.Element;
export interface NavigateProps {
href: ((args: {
navigate: Navigator;
location: Location;
}) => string) | string;
state?: unknown;
}
export declare function Navigate(props: NavigateProps): null;

View File

@@ -0,0 +1,39 @@
import { createMemo, mergeProps, splitProps } from "solid-js";
import { useHref, useLocation, useNavigate, useResolvedPath } from "./routing.js";
import { normalizePath } from "./utils.js";
export function A(props) {
props = mergeProps({ inactiveClass: "inactive", activeClass: "active" }, props);
const [, rest] = splitProps(props, [
"href",
"state",
"class",
"activeClass",
"inactiveClass",
"end"
]);
const to = useResolvedPath(() => props.href);
const href = useHref(to);
const location = useLocation();
const isActive = createMemo(() => {
const to_ = to();
if (to_ === undefined)
return [false, false];
const path = normalizePath(to_.split(/[?#]/, 1)[0]).toLowerCase();
const loc = decodeURI(normalizePath(location.pathname).toLowerCase());
return [props.end ? path === loc : loc.startsWith(path + "/") || loc === path, path === loc];
});
return (<a {...rest} href={href() || props.href} state={JSON.stringify(props.state)} classList={{
...(props.class && { [props.class]: true }),
[props.inactiveClass]: !isActive()[0],
[props.activeClass]: isActive()[0],
...rest.classList
}} link aria-current={isActive()[1] ? "page" : undefined}/>);
}
export function Navigate(props) {
const navigate = useNavigate();
const location = useLocation();
const { href, state } = props;
const path = typeof href === "function" ? href({ navigate, location }) : href;
navigate(path, { replace: true, state });
return null;
}

View File

@@ -0,0 +1,17 @@
import { JSX } from "solid-js";
import type { Submission, SubmissionStub, NarrowResponse } from "../types.js";
export type Action<T extends Array<any>, U, V = T> = (T extends [FormData | URLSearchParams] | [] ? JSX.SerializableAttributeValue : unknown) & ((...vars: T) => Promise<NarrowResponse<U>>) & {
url: string;
with<A extends any[], B extends any[]>(this: (this: any, ...args: [...A, ...B]) => Promise<NarrowResponse<U>>, ...args: A): Action<B, U, V>;
};
export declare const actions: Map<string, Action<any, any, any>>;
export declare function useSubmissions<T extends Array<any>, U, V>(fn: Action<T, U, V>, filter?: (input: V) => boolean): Submission<T, NarrowResponse<U>>[] & {
pending: boolean;
};
export declare function useSubmission<T extends Array<any>, U, V>(fn: Action<T, U, V>, filter?: (input: V) => boolean): Submission<T, NarrowResponse<U>> | SubmissionStub;
export declare function useAction<T extends Array<any>, U, V>(action: Action<T, U, V>): (...args: Parameters<Action<T, U, V>>) => Promise<NarrowResponse<U>>;
export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, name?: string): Action<T, U>;
export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, options?: {
name?: string;
onComplete?: (s: Submission<T, U>) => void;
}): Action<T, U>;

View File

@@ -0,0 +1,163 @@
import { $TRACK, createMemo, createSignal, onCleanup, getOwner } from "solid-js";
import { isServer } from "solid-js/web";
import { useRouter } from "../routing.js";
import { mockBase, setFunctionName } from "../utils.js";
import { cacheKeyOp, hashKey, revalidate, query } from "./query.js";
export const actions = /* #__PURE__ */ new Map();
export function useSubmissions(fn, filter) {
const router = useRouter();
const subs = createMemo(() => router.submissions[0]().filter(s => s.url === fn.base && (!filter || filter(s.input))));
return new Proxy([], {
get(_, property) {
if (property === $TRACK)
return subs();
if (property === "pending")
return subs().some(sub => !sub.result);
return subs()[property];
},
has(_, property) {
return property in subs();
}
});
}
export function useSubmission(fn, filter) {
const submissions = useSubmissions(fn, filter);
return new Proxy({}, {
get(_, property) {
if ((submissions.length === 0 && property === "clear") || property === "retry")
return () => { };
return submissions[submissions.length - 1]?.[property];
}
});
}
export function useAction(action) {
const r = useRouter();
return (...args) => action.apply({ r }, args);
}
export function action(fn, options = {}) {
function mutate(...variables) {
const router = this.r;
const form = this.f;
const p = (router.singleFlight && fn.withOptions
? fn.withOptions({ headers: { "X-Single-Flight": "true" } })
: fn)(...variables);
const [result, setResult] = createSignal();
let submission;
function handler(error) {
return async (res) => {
const result = await handleResponse(res, error, router.navigatorFactory());
let retry = null;
o.onComplete?.({
...submission,
result: result?.data,
error: result?.error,
pending: false,
retry() {
return (retry = submission.retry());
}
});
if (retry)
return retry;
if (!result)
return submission.clear();
setResult(result);
if (result.error && !form)
throw result.error;
return result.data;
};
}
router.submissions[1](s => [
...s,
(submission = {
input: variables,
url,
get result() {
return result()?.data;
},
get error() {
return result()?.error;
},
get pending() {
return !result();
},
clear() {
router.submissions[1](v => v.filter(i => i !== submission));
},
retry() {
setResult(undefined);
const p = fn(...variables);
return p.then(handler(), handler(true));
}
})
]);
return p.then(handler(), handler(true));
}
const o = typeof options === "string" ? { name: options } : options;
const name = o.name || (!isServer ? String(hashString(fn.toString())) : undefined);
const url = fn.url || (name && `https://action/${name}`) || "";
mutate.base = url;
if (name)
setFunctionName(mutate, name);
return toAction(mutate, url);
}
function toAction(fn, url) {
fn.toString = () => {
if (!url)
throw new Error("Client Actions need explicit names if server rendered");
return url;
};
fn.with = function (...args) {
const newFn = function (...passedArgs) {
return fn.call(this, ...args, ...passedArgs);
};
newFn.base = fn.base;
const uri = new URL(url, mockBase);
uri.searchParams.set("args", hashKey(args));
return toAction(newFn, (uri.origin === "https://action" ? uri.origin : "") + uri.pathname + uri.search);
};
fn.url = url;
if (!isServer) {
actions.set(url, fn);
getOwner() && onCleanup(() => actions.delete(url));
}
return fn;
}
const hashString = (s) => s.split("").reduce((a, b) => ((a << 5) - a + b.charCodeAt(0)) | 0, 0);
async function handleResponse(response, error, navigate) {
let data;
let custom;
let keys;
let flightKeys;
if (response instanceof Response) {
if (response.headers.has("X-Revalidate"))
keys = response.headers.get("X-Revalidate").split(",");
if (response.customBody) {
data = custom = await response.customBody();
if (response.headers.has("X-Single-Flight")) {
data = data._$value;
delete custom._$value;
flightKeys = Object.keys(custom);
}
}
if (response.headers.has("Location")) {
const locationUrl = response.headers.get("Location") || "/";
if (locationUrl.startsWith("http")) {
window.location.href = locationUrl;
}
else {
navigate(locationUrl);
}
}
}
else if (error)
return { error: response };
else
data = response;
// invalidate
cacheKeyOp(keys, entry => (entry[0] = 0));
// set cache
flightKeys && flightKeys.forEach(k => query.set(k, custom[k]));
// trigger revalidation
await revalidate(keys, false);
return data != null ? { data } : undefined;
}

View File

@@ -0,0 +1,32 @@
import { type ReconcileOptions } from "solid-js/store";
/**
* As `createAsync` and `createAsyncStore` are wrappers for `createResource`,
* this type allows to support `latest` field for these primitives.
* It will be removed in the future.
*/
export type AccessorWithLatest<T> = {
(): T;
latest: T;
};
export declare function createAsync<T>(fn: (prev: T) => Promise<T>, options: {
name?: string;
initialValue: T;
deferStream?: boolean;
}): AccessorWithLatest<T>;
export declare function createAsync<T>(fn: (prev: T | undefined) => Promise<T>, options?: {
name?: string;
initialValue?: T;
deferStream?: boolean;
}): AccessorWithLatest<T | undefined>;
export declare function createAsyncStore<T>(fn: (prev: T) => Promise<T>, options: {
name?: string;
initialValue: T;
deferStream?: boolean;
reconcile?: ReconcileOptions;
}): AccessorWithLatest<T>;
export declare function createAsyncStore<T>(fn: (prev: T | undefined) => Promise<T>, options?: {
name?: string;
initialValue?: T;
deferStream?: boolean;
reconcile?: ReconcileOptions;
}): AccessorWithLatest<T | undefined>;

View File

@@ -0,0 +1,96 @@
/**
* This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
*/
import { createResource, sharedConfig, untrack, catchError } from "solid-js";
import { createStore, reconcile, unwrap } from "solid-js/store";
import { isServer } from "solid-js/web";
import { setFunctionName } from "../utils.js";
export function createAsync(fn, options) {
let resource;
let prev = () => !resource || resource.state === "unresolved" ? undefined : resource.latest;
[resource] = createResource(() => subFetch(fn, catchError(() => untrack(prev), () => undefined)), v => v, options);
const resultAccessor = (() => resource());
if (options?.name)
setFunctionName(resultAccessor, options.name);
Object.defineProperty(resultAccessor, "latest", {
get() {
return resource.latest;
}
});
return resultAccessor;
}
export function createAsyncStore(fn, options = {}) {
let resource;
let prev = () => !resource || resource.state === "unresolved"
? undefined
: unwrap(resource.latest);
[resource] = createResource(() => subFetch(fn, catchError(() => untrack(prev), () => undefined)), v => v, {
...options,
storage: (init) => createDeepSignal(init, options.reconcile)
});
const resultAccessor = (() => resource());
Object.defineProperty(resultAccessor, "latest", {
get() {
return resource.latest;
}
});
return resultAccessor;
}
function createDeepSignal(value, options) {
const [store, setStore] = createStore({
value: structuredClone(value)
});
return [
() => store.value,
(v) => {
typeof v === "function" && (v = v());
setStore("value", reconcile(structuredClone(v), options));
return store.value;
}
];
}
// mock promise while hydrating to prevent fetching
class MockPromise {
static all() {
return new MockPromise();
}
static allSettled() {
return new MockPromise();
}
static any() {
return new MockPromise();
}
static race() {
return new MockPromise();
}
static reject() {
return new MockPromise();
}
static resolve() {
return new MockPromise();
}
catch() {
return new MockPromise();
}
then() {
return new MockPromise();
}
finally() {
return new MockPromise();
}
}
function subFetch(fn, prev) {
if (isServer || !sharedConfig.context)
return fn(prev);
const ogFetch = fetch;
const ogPromise = Promise;
try {
window.fetch = () => new MockPromise();
Promise = MockPromise;
return fn(prev);
}
finally {
window.fetch = ogFetch;
Promise = ogPromise;
}
}

View File

@@ -0,0 +1,9 @@
import type { RouterContext } from "../types.js";
type NativeEventConfig = {
preload?: boolean;
explicitLinks?: boolean;
actionBase?: string;
transformUrl?: (url: string) => string;
};
export declare function setupNativeEvents({ preload, explicitLinks, actionBase, transformUrl }?: NativeEventConfig): (router: RouterContext) => void;
export {};

View File

@@ -0,0 +1,123 @@
import { delegateEvents } from "solid-js/web";
import { onCleanup } from "solid-js";
import { actions } from "./action.js";
import { mockBase } from "../utils.js";
export function setupNativeEvents({ preload = true, explicitLinks = false, actionBase = "/_server", transformUrl } = {}) {
return (router) => {
const basePath = router.base.path();
const navigateFromRoute = router.navigatorFactory(router.base);
let preloadTimeout;
let lastElement;
function isSvg(el) {
return el.namespaceURI === "http://www.w3.org/2000/svg";
}
function handleAnchor(evt) {
if (evt.defaultPrevented ||
evt.button !== 0 ||
evt.metaKey ||
evt.altKey ||
evt.ctrlKey ||
evt.shiftKey)
return;
const a = evt
.composedPath()
.find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
if (!a || (explicitLinks && !a.hasAttribute("link")))
return;
const svg = isSvg(a);
const href = svg ? a.href.baseVal : a.href;
const target = svg ? a.target.baseVal : a.target;
if (target || (!href && !a.hasAttribute("state")))
return;
const rel = (a.getAttribute("rel") || "").split(/\s+/);
if (a.hasAttribute("download") || (rel && rel.includes("external")))
return;
const url = svg ? new URL(href, document.baseURI) : new URL(href);
if (url.origin !== window.location.origin ||
(basePath && url.pathname && !url.pathname.toLowerCase().startsWith(basePath.toLowerCase())))
return;
return [a, url];
}
function handleAnchorClick(evt) {
const res = handleAnchor(evt);
if (!res)
return;
const [a, url] = res;
const to = router.parsePath(url.pathname + url.search + url.hash);
const state = a.getAttribute("state");
evt.preventDefault();
navigateFromRoute(to, {
resolve: false,
replace: a.hasAttribute("replace"),
scroll: !a.hasAttribute("noscroll"),
state: state ? JSON.parse(state) : undefined
});
}
function handleAnchorPreload(evt) {
const res = handleAnchor(evt);
if (!res)
return;
const [a, url] = res;
transformUrl && (url.pathname = transformUrl(url.pathname));
router.preloadRoute(url, a.getAttribute("preload") !== "false");
}
function handleAnchorMove(evt) {
clearTimeout(preloadTimeout);
const res = handleAnchor(evt);
if (!res)
return (lastElement = null);
const [a, url] = res;
if (lastElement === a)
return;
transformUrl && (url.pathname = transformUrl(url.pathname));
preloadTimeout = setTimeout(() => {
router.preloadRoute(url, a.getAttribute("preload") !== "false");
lastElement = a;
}, 20);
}
function handleFormSubmit(evt) {
if (evt.defaultPrevented)
return;
let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction")
? evt.submitter.getAttribute("formaction")
: evt.target.getAttribute("action");
if (!actionRef)
return;
if (!actionRef.startsWith("https://action/")) {
// normalize server actions
const url = new URL(actionRef, mockBase);
actionRef = router.parsePath(url.pathname + url.search);
if (!actionRef.startsWith(actionBase))
return;
}
if (evt.target.method.toUpperCase() !== "POST")
throw new Error("Only POST forms are supported for Actions");
const handler = actions.get(actionRef);
if (handler) {
evt.preventDefault();
const data = new FormData(evt.target, evt.submitter);
handler.call({ r: router, f: evt.target }, evt.target.enctype === "multipart/form-data"
? data
: new URLSearchParams(data));
}
}
// ensure delegated event run first
delegateEvents(["click", "submit"]);
document.addEventListener("click", handleAnchorClick);
if (preload) {
document.addEventListener("mousemove", handleAnchorMove, { passive: true });
document.addEventListener("focusin", handleAnchorPreload, { passive: true });
document.addEventListener("touchstart", handleAnchorPreload, { passive: true });
}
document.addEventListener("submit", handleFormSubmit);
onCleanup(() => {
document.removeEventListener("click", handleAnchorClick);
if (preload) {
document.removeEventListener("mousemove", handleAnchorMove);
document.removeEventListener("focusin", handleAnchorPreload);
document.removeEventListener("touchstart", handleAnchorPreload);
}
document.removeEventListener("submit", handleFormSubmit);
});
};
}

View File

@@ -0,0 +1,4 @@
export { createAsync, createAsyncStore, type AccessorWithLatest } from "./createAsync.js";
export { action, useSubmission, useSubmissions, useAction, type Action } from "./action.js";
export { query, revalidate, cache, type CachedFunction } from "./query.js";
export { redirect, reload, json } from "./response.js";

View File

@@ -0,0 +1,4 @@
export { createAsync, createAsyncStore } from "./createAsync.js";
export { action, useSubmission, useSubmissions, useAction } from "./action.js";
export { query, revalidate, cache } from "./query.js";
export { redirect, reload, json } from "./response.js";

View File

@@ -0,0 +1,23 @@
import type { CacheEntry, NarrowResponse } from "../types.js";
/**
* Revalidates the given cache entry/entries.
*/
export declare function revalidate(key?: string | string[] | void, force?: boolean): Promise<void>;
export declare function cacheKeyOp(key: string | string[] | void, fn: (cacheEntry: CacheEntry) => void): void;
export type CachedFunction<T extends (...args: any) => any> = T extends (...args: infer A) => infer R ? ([] extends {
[K in keyof A]-?: A[K];
} ? (...args: never[]) => R extends Promise<infer P> ? Promise<NarrowResponse<P>> : NarrowResponse<R> : (...args: A) => R extends Promise<infer P> ? Promise<NarrowResponse<P>> : NarrowResponse<R>) & {
keyFor: (...args: A) => string;
key: string;
} : never;
export declare function query<T extends (...args: any) => any>(fn: T, name: string): CachedFunction<T>;
export declare namespace query {
export var get: (key: string) => any;
export var set: <T>(key: string, value: T extends Promise<any> ? never : T) => void;
var _a: (key: string) => boolean;
export var clear: () => void;
export { _a as delete };
}
/** @deprecated use query instead */
export declare const cache: typeof query;
export declare function hashKey<T extends Array<any>>(args: T): string;

View File

@@ -0,0 +1,232 @@
import { createSignal, getListener, getOwner, onCleanup, sharedConfig, startTransition } from "solid-js";
import { getRequestEvent, isServer } from "solid-js/web";
import { useNavigate, getIntent, getInPreloadFn } from "../routing.js";
const LocationHeader = "Location";
const PRELOAD_TIMEOUT = 5000;
const CACHE_TIMEOUT = 180000;
let cacheMap = new Map();
// cleanup forward/back cache
if (!isServer) {
setInterval(() => {
const now = Date.now();
for (let [k, v] of cacheMap.entries()) {
if (!v[4].count && now - v[0] > CACHE_TIMEOUT) {
cacheMap.delete(k);
}
}
}, 300000);
}
function getCache() {
if (!isServer)
return cacheMap;
const req = getRequestEvent();
if (!req)
throw new Error("Cannot find cache context");
return (req.router || (req.router = {})).cache || (req.router.cache = new Map());
}
/**
* Revalidates the given cache entry/entries.
*/
export function revalidate(key, force = true) {
return startTransition(() => {
const now = Date.now();
cacheKeyOp(key, entry => {
force && (entry[0] = 0); //force cache miss
entry[4][1](now); // retrigger live signals
});
});
}
export function cacheKeyOp(key, fn) {
key && !Array.isArray(key) && (key = [key]);
for (let k of cacheMap.keys()) {
if (key === undefined || matchKey(k, key))
fn(cacheMap.get(k));
}
}
export function query(fn, name) {
// prioritize GET for server functions
if (fn.GET)
fn = fn.GET;
const cachedFn = ((...args) => {
const cache = getCache();
const intent = getIntent();
const inPreloadFn = getInPreloadFn();
const owner = getOwner();
const navigate = owner ? useNavigate() : undefined;
const now = Date.now();
const key = name + hashKey(args);
let cached = cache.get(key);
let tracking;
if (isServer) {
const e = getRequestEvent();
if (e) {
const dataOnly = (e.router || (e.router = {})).dataOnly;
if (dataOnly) {
const data = e && (e.router.data || (e.router.data = {}));
if (data && key in data)
return data[key];
if (Array.isArray(dataOnly) && !matchKey(key, dataOnly)) {
data[key] = undefined;
return Promise.resolve();
}
}
}
}
if (getListener() && !isServer) {
tracking = true;
onCleanup(() => cached[4].count--);
}
if (cached &&
cached[0] &&
(isServer ||
intent === "native" ||
cached[4].count ||
Date.now() - cached[0] < PRELOAD_TIMEOUT)) {
if (tracking) {
cached[4].count++;
cached[4][0](); // track
}
if (cached[3] === "preload" && intent !== "preload") {
cached[0] = now;
}
let res = cached[1];
if (intent !== "preload") {
res =
"then" in cached[1]
? cached[1].then(handleResponse(false), handleResponse(true))
: handleResponse(false)(cached[1]);
!isServer && intent === "navigate" && startTransition(() => cached[4][1](cached[0])); // update version
}
inPreloadFn && "then" in res && res.catch(() => { });
return res;
}
let res;
if (!isServer && sharedConfig.has && sharedConfig.has(key)) {
res = sharedConfig.load(key); // hydrating
// @ts-ignore at least until we add a delete method to sharedConfig
delete globalThis._$HY.r[key];
}
else
res = fn(...args);
if (cached) {
cached[0] = now;
cached[1] = res;
cached[3] = intent;
!isServer && intent === "navigate" && startTransition(() => cached[4][1](cached[0])); // update version
}
else {
cache.set(key, (cached = [now, res, , intent, createSignal(now)]));
cached[4].count = 0;
}
if (tracking) {
cached[4].count++;
cached[4][0](); // track
}
if (isServer) {
const e = getRequestEvent();
if (e && e.router.dataOnly)
return (e.router.data[key] = res);
}
if (intent !== "preload") {
res =
"then" in res
? res.then(handleResponse(false), handleResponse(true))
: handleResponse(false)(res);
}
inPreloadFn && "then" in res && res.catch(() => { });
// serialize on server
if (isServer &&
sharedConfig.context &&
sharedConfig.context.async &&
!sharedConfig.context.noHydrate) {
const e = getRequestEvent();
(!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
}
return res;
function handleResponse(error) {
return async (v) => {
if (v instanceof Response) {
const e = getRequestEvent();
if (e) {
for (const [key, value] of v.headers) {
if (key == "set-cookie")
e.response.headers.append("set-cookie", value);
else
e.response.headers.set(key, value);
}
}
const url = v.headers.get(LocationHeader);
if (url !== null) {
// client + server relative redirect
if (navigate && url.startsWith("/"))
startTransition(() => {
navigate(url, { replace: true });
});
else if (!isServer)
window.location.href = url;
else if (e)
e.response.status = 302;
return;
}
if (v.customBody)
v = await v.customBody();
}
if (error)
throw v;
cached[2] = v;
return v;
};
}
});
cachedFn.keyFor = (...args) => name + hashKey(args);
cachedFn.key = name;
return cachedFn;
}
query.get = (key) => {
const cached = getCache().get(key);
return cached[2];
};
query.set = (key, value) => {
const cache = getCache();
const now = Date.now();
let cached = cache.get(key);
if (cached) {
cached[0] = now;
cached[1] = Promise.resolve(value);
cached[2] = value;
cached[3] = "preload";
}
else {
cache.set(key, (cached = [now, Promise.resolve(value), value, "preload", createSignal(now)]));
cached[4].count = 0;
}
};
query.delete = (key) => getCache().delete(key);
query.clear = () => getCache().clear();
/** @deprecated use query instead */
export const cache = query;
function matchKey(key, keys) {
for (let k of keys) {
if (k && key.startsWith(k))
return true;
}
return false;
}
// Modified from the amazing Tanstack Query library (MIT)
// https://github.com/TanStack/query/blob/main/packages/query-core/src/utils.ts#L168
export function hashKey(args) {
return JSON.stringify(args, (_, val) => isPlainObject(val)
? Object.keys(val)
.sort()
.reduce((result, key) => {
result[key] = val[key];
return result;
}, {})
: val);
}
function isPlainObject(obj) {
let proto;
return (obj != null &&
typeof obj === "object" &&
(!(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype));
}

View File

@@ -0,0 +1,4 @@
import type { RouterResponseInit, CustomResponse } from "../types.js";
export declare function redirect(url: string, init?: number | RouterResponseInit): CustomResponse<never>;
export declare function reload(init?: RouterResponseInit): CustomResponse<never>;
export declare function json<T>(data: T, init?: RouterResponseInit): CustomResponse<T>;

View File

@@ -0,0 +1,42 @@
export function redirect(url, init = 302) {
let responseInit;
let revalidate;
if (typeof init === "number") {
responseInit = { status: init };
}
else {
({ revalidate, ...responseInit } = init);
if (typeof responseInit.status === "undefined") {
responseInit.status = 302;
}
}
const headers = new Headers(responseInit.headers);
headers.set("Location", url);
revalidate !== undefined && headers.set("X-Revalidate", revalidate.toString());
const response = new Response(null, {
...responseInit,
headers: headers
});
return response;
}
export function reload(init = {}) {
const { revalidate, ...responseInit } = init;
const headers = new Headers(responseInit.headers);
revalidate !== undefined && headers.set("X-Revalidate", revalidate.toString());
return new Response(null, {
...responseInit,
headers
});
}
export function json(data, init = {}) {
const { revalidate, ...responseInit } = init;
const headers = new Headers(responseInit.headers);
revalidate !== undefined && headers.set("X-Revalidate", revalidate.toString());
headers.set("Content-Type", "application/json");
const response = new Response(JSON.stringify(data), {
...responseInit,
headers
});
response.customBody = () => data;
return response;
}

View File

@@ -0,0 +1,7 @@
export * from "./routers/index.js";
export * from "./components.js";
export * from "./lifecycle.js";
export { useHref, useIsRouting, useLocation, useMatch, useCurrentMatches, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, usePreloadRoute, RouterContextObj as RouterContext } from "./routing.js";
export { mergeSearchString as _mergeSearchString } from "./utils.js";
export * from "./data/index.js";
export type { Location, LocationChange, SearchParams, MatchFilter, MatchFilters, NavigateOptions, Navigator, OutputMatch, Params, PathMatch, RouteSectionProps, RoutePreloadFunc, RoutePreloadFuncArgs, RouteDefinition, RouteDescription, RouteMatch, RouterIntegration, RouterUtils, SetParams, Submission, BeforeLeaveEventArgs, RouteLoadFunc, RouteLoadFuncArgs, RouterResponseInit, CustomResponse } from "./types.js";

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
export * from "./routers/index.js";
export * from "./components.jsx";
export * from "./lifecycle.js";
export { useHref, useIsRouting, useLocation, useMatch, useCurrentMatches, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, usePreloadRoute, RouterContextObj as RouterContext } from "./routing.js";
export { mergeSearchString as _mergeSearchString } from "./utils.js";
export * from "./data/index.js";

View File

@@ -0,0 +1,5 @@
import { BeforeLeaveLifecycle, LocationChange } from "./types.js";
export declare function createBeforeLeave(): BeforeLeaveLifecycle;
export declare function saveCurrentDepth(): void;
export declare function keepDepth(state: any): any;
export declare function notifyIfNotBlocked(notify: (value?: string | LocationChange) => void, block: (delta: number | null) => boolean): () => void;

View File

@@ -0,0 +1,69 @@
import { isServer } from "solid-js/web";
export function createBeforeLeave() {
let listeners = new Set();
function subscribe(listener) {
listeners.add(listener);
return () => listeners.delete(listener);
}
let ignore = false;
function confirm(to, options) {
if (ignore)
return !(ignore = false);
const e = {
to,
options,
defaultPrevented: false,
preventDefault: () => (e.defaultPrevented = true)
};
for (const l of listeners)
l.listener({
...e,
from: l.location,
retry: (force) => {
force && (ignore = true);
l.navigate(to, { ...options, resolve: false });
}
});
return !e.defaultPrevented;
}
return {
subscribe,
confirm
};
}
// The following supports browser initiated blocking (eg back/forward)
let depth;
export function saveCurrentDepth() {
if (!window.history.state || window.history.state._depth == null) {
window.history.replaceState({ ...window.history.state, _depth: window.history.length - 1 }, "");
}
depth = window.history.state._depth;
}
if (!isServer) {
saveCurrentDepth();
}
export function keepDepth(state) {
return {
...state,
_depth: window.history.state && window.history.state._depth
};
}
export function notifyIfNotBlocked(notify, block) {
let ignore = false;
return () => {
const prevDepth = depth;
saveCurrentDepth();
const delta = prevDepth == null ? null : depth - prevDepth;
if (ignore) {
ignore = false;
return;
}
if (delta && block(delta)) {
ignore = true;
window.history.go(-delta);
}
else {
notify();
}
};
}

View File

@@ -0,0 +1,9 @@
import type { JSX } from "solid-js";
import type { BaseRouterProps } from "./components.js";
export declare function hashParser(str: string): string;
export type HashRouterProps = BaseRouterProps & {
actionBase?: string;
explicitLinks?: boolean;
preload?: boolean;
};
export declare function HashRouter(props: HashRouterProps): JSX.Element;

View File

@@ -0,0 +1,41 @@
import { setupNativeEvents } from "../data/events.js";
import { createRouter, scrollToHash, bindEvent } from "./createRouter.js";
import { createBeforeLeave, keepDepth, notifyIfNotBlocked, saveCurrentDepth } from "../lifecycle.js";
export function hashParser(str) {
const to = str.replace(/^.*?#/, "");
// Hash-only hrefs like `#foo` from plain anchors will come in as `/#foo` whereas a link to
// `/foo` will be `/#/foo`. Check if the to starts with a `/` and if not append it as a hash
// to the current path so we can handle these in-page anchors correctly.
if (!to.startsWith("/")) {
const [, path = "/"] = window.location.hash.split("#", 2);
return `${path}#${to}`;
}
return to;
}
export function HashRouter(props) {
const getSource = () => window.location.hash.slice(1);
const beforeLeave = createBeforeLeave();
return createRouter({
get: getSource,
set({ value, replace, scroll, state }) {
if (replace) {
window.history.replaceState(keepDepth(state), "", "#" + value);
}
else {
window.history.pushState(state, "", "#" + value);
}
const hashIndex = value.indexOf("#");
const hash = hashIndex >= 0 ? value.slice(hashIndex + 1) : "";
scrollToHash(hash, scroll);
saveCurrentDepth();
},
init: notify => bindEvent(window, "hashchange", notifyIfNotBlocked(notify, delta => !beforeLeave.confirm(delta && delta < 0 ? delta : getSource()))),
create: setupNativeEvents({ preload: props.preload, explicitLinks: props.explicitLinks, actionBase: props.actionBase }),
utils: {
go: delta => window.history.go(delta),
renderPath: path => `#${path}`,
parsePath: hashParser,
beforeLeave
}
})(props);
}

View File

@@ -0,0 +1,24 @@
import type { LocationChange } from "../types.js";
import type { BaseRouterProps } from "./components.js";
import type { JSX } from "solid-js";
export type MemoryHistory = {
get: () => string;
set: (change: LocationChange) => void;
go: (delta: number) => void;
listen: (listener: (value: string) => void) => () => void;
};
export declare function createMemoryHistory(): {
get: () => string;
set: ({ value, scroll, replace }: LocationChange) => void;
back: () => void;
forward: () => void;
go: (n: number) => void;
listen: (listener: (value: string) => void) => () => void;
};
export type MemoryRouterProps = BaseRouterProps & {
history?: MemoryHistory;
actionBase?: string;
explicitLinks?: boolean;
preload?: boolean;
};
export declare function MemoryRouter(props: MemoryRouterProps): JSX.Element;

View File

@@ -0,0 +1,57 @@
import { createRouter, scrollToHash } from "./createRouter.js";
import { setupNativeEvents } from "../data/events.js";
export function createMemoryHistory() {
const entries = ["/"];
let index = 0;
const listeners = [];
const go = (n) => {
// https://github.com/remix-run/react-router/blob/682810ca929d0e3c64a76f8d6e465196b7a2ac58/packages/router/history.ts#L245
index = Math.max(0, Math.min(index + n, entries.length - 1));
const value = entries[index];
listeners.forEach(listener => listener(value));
};
return {
get: () => entries[index],
set: ({ value, scroll, replace }) => {
if (replace) {
entries[index] = value;
}
else {
entries.splice(index + 1, entries.length - index, value);
index++;
}
listeners.forEach(listener => listener(value));
setTimeout(() => {
if (scroll) {
scrollToHash(value.split("#")[1] || "", true);
}
}, 0);
},
back: () => {
go(-1);
},
forward: () => {
go(1);
},
go,
listen: (listener) => {
listeners.push(listener);
return () => {
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
};
}
};
}
export function MemoryRouter(props) {
const memoryHistory = props.history || createMemoryHistory();
return createRouter({
get: memoryHistory.get,
set: memoryHistory.set,
init: memoryHistory.listen,
create: setupNativeEvents({ preload: props.preload, explicitLinks: props.explicitLinks, actionBase: props.actionBase }),
utils: {
go: memoryHistory.go
}
})(props);
}

View File

@@ -0,0 +1,9 @@
import type { BaseRouterProps } from "./components.js";
import type { JSX } from "solid-js";
export type RouterProps = BaseRouterProps & {
url?: string;
actionBase?: string;
explicitLinks?: boolean;
preload?: boolean;
};
export declare function Router(props: RouterProps): JSX.Element;

View File

@@ -0,0 +1,45 @@
import { isServer } from "solid-js/web";
import { createRouter, scrollToHash, bindEvent } from "./createRouter.js";
import { StaticRouter } from "./StaticRouter.js";
import { setupNativeEvents } from "../data/events.js";
import { createBeforeLeave, keepDepth, notifyIfNotBlocked, saveCurrentDepth } from "../lifecycle.js";
export function Router(props) {
if (isServer)
return StaticRouter(props);
const getSource = () => {
const url = window.location.pathname.replace(/^\/+/, "/") + window.location.search;
const state = window.history.state && window.history.state._depth && Object.keys(window.history.state).length === 1 ? undefined : window.history.state;
return {
value: url + window.location.hash,
state
};
};
const beforeLeave = createBeforeLeave();
return createRouter({
get: getSource,
set({ value, replace, scroll, state }) {
if (replace) {
window.history.replaceState(keepDepth(state), "", value);
}
else {
window.history.pushState(state, "", value);
}
scrollToHash(decodeURIComponent(window.location.hash.slice(1)), scroll);
saveCurrentDepth();
},
init: notify => bindEvent(window, "popstate", notifyIfNotBlocked(notify, delta => {
if (delta) {
return !beforeLeave.confirm(delta);
}
else {
const s = getSource();
return !beforeLeave.confirm(s.value, { state: s.state });
}
})),
create: setupNativeEvents({ preload: props.preload, explicitLinks: props.explicitLinks, actionBase: props.actionBase, transformUrl: props.transformUrl }),
utils: {
go: delta => window.history.go(delta),
beforeLeave
}
})(props);
}

View File

@@ -0,0 +1,6 @@
import { type BaseRouterProps } from "./components.js";
import type { JSX } from "solid-js";
export type StaticRouterProps = BaseRouterProps & {
url?: string;
};
export declare function StaticRouter(props: StaticRouterProps): JSX.Element;

View File

@@ -0,0 +1,15 @@
import { getRequestEvent } from "solid-js/web";
import { createRouterComponent } from "./components.js";
function getPath(url) {
const u = new URL(url);
return u.pathname + u.search;
}
export function StaticRouter(props) {
let e;
const obj = {
value: props.url || ((e = getRequestEvent()) && getPath(e.request.url)) || "",
};
return createRouterComponent({
signal: [() => obj, next => Object.assign(obj, next)]
})(props);
}

View File

@@ -0,0 +1,27 @@
import type { Component, JSX } from "solid-js";
import type { MatchFilters, RouteDefinition, RoutePreloadFunc, RouterIntegration, RouteSectionProps } from "../types.js";
export type BaseRouterProps = {
base?: string;
/**
* A component that wraps the content of every route.
*/
root?: Component<RouteSectionProps>;
rootPreload?: RoutePreloadFunc;
singleFlight?: boolean;
children?: JSX.Element | RouteDefinition | RouteDefinition[];
transformUrl?: (url: string) => string;
/** @deprecated use rootPreload */
rootLoad?: RoutePreloadFunc;
};
export declare const createRouterComponent: (router: RouterIntegration) => (props: BaseRouterProps) => JSX.Element;
export type RouteProps<S extends string, T = unknown> = {
path?: S | S[];
children?: JSX.Element;
preload?: RoutePreloadFunc<T>;
matchFilters?: MatchFilters<S>;
component?: Component<RouteSectionProps<T>>;
info?: Record<string, any>;
/** @deprecated use preload */
load?: RoutePreloadFunc<T>;
};
export declare const Route: <S extends string, T = unknown>(props: RouteProps<S, T>) => JSX.Element;

View File

@@ -0,0 +1,118 @@
/*@refresh skip*/
import { children, createMemo, createRoot, getOwner, mergeProps, on, Show, untrack } from "solid-js";
import { getRequestEvent, isServer } from "solid-js/web";
import { createBranches, createRouteContext, createRouterContext, getIntent, getRouteMatches, RouteContextObj, RouterContextObj, setInPreloadFn } from "../routing.js";
export const createRouterComponent = (router) => (props) => {
const { base } = props;
const routeDefs = children(() => props.children);
const branches = createMemo(() => createBranches(routeDefs(), props.base || ""));
let context;
const routerState = createRouterContext(router, branches, () => context, {
base,
singleFlight: props.singleFlight,
transformUrl: props.transformUrl,
});
router.create && router.create(routerState);
return (<RouterContextObj.Provider value={routerState}>
<Root routerState={routerState} root={props.root} preload={props.rootPreload || props.rootLoad}>
{(context = getOwner()) && null}
<Routes routerState={routerState} branches={branches()}/>
</Root>
</RouterContextObj.Provider>);
};
function Root(props) {
const location = props.routerState.location;
const params = props.routerState.params;
const data = createMemo(() => props.preload &&
untrack(() => {
setInPreloadFn(true);
props.preload({ params, location, intent: getIntent() || "initial" });
setInPreloadFn(false);
}));
return (<Show when={props.root} keyed fallback={props.children}>
{Root => (<Root params={params} location={location} data={data()}>
{props.children}
</Root>)}
</Show>);
}
function Routes(props) {
if (isServer) {
const e = getRequestEvent();
if (e && e.router && e.router.dataOnly) {
dataOnly(e, props.routerState, props.branches);
return;
}
e &&
((e.router || (e.router = {})).matches ||
(e.router.matches = props.routerState.matches().map(({ route, path, params }) => ({
path: route.originalPath,
pattern: route.pattern,
match: path,
params,
info: route.info
}))));
}
const disposers = [];
let root;
const routeStates = createMemo(on(props.routerState.matches, (nextMatches, prevMatches, prev) => {
let equal = prevMatches && nextMatches.length === prevMatches.length;
const next = [];
for (let i = 0, len = nextMatches.length; i < len; i++) {
const prevMatch = prevMatches && prevMatches[i];
const nextMatch = nextMatches[i];
if (prev && prevMatch && nextMatch.route.key === prevMatch.route.key) {
next[i] = prev[i];
}
else {
equal = false;
if (disposers[i]) {
disposers[i]();
}
createRoot(dispose => {
disposers[i] = dispose;
next[i] = createRouteContext(props.routerState, next[i - 1] || props.routerState.base, createOutlet(() => routeStates()[i + 1]), () => {
const routeMatches = props.routerState.matches();
return routeMatches[i] ?? routeMatches[0];
});
});
}
}
disposers.splice(nextMatches.length).forEach(dispose => dispose());
if (prev && equal) {
return prev;
}
root = next[0];
return next;
}));
return createOutlet(() => routeStates() && root)();
}
const createOutlet = (child) => {
return () => (<Show when={child()} keyed>
{child => <RouteContextObj.Provider value={child}>{child.outlet()}</RouteContextObj.Provider>}
</Show>);
};
export const Route = (props) => {
const childRoutes = children(() => props.children);
return mergeProps(props, {
get children() {
return childRoutes();
}
});
};
// for data only mode with single flight mutations
function dataOnly(event, routerState, branches) {
const url = new URL(event.request.url);
const prevMatches = getRouteMatches(branches, new URL(event.router.previousUrl || event.request.url).pathname);
const matches = getRouteMatches(branches, url.pathname);
for (let match = 0; match < matches.length; match++) {
if (!prevMatches[match] || matches[match].route !== prevMatches[match].route)
event.router.dataOnly = true;
const { route, params } = matches[match];
route.preload &&
route.preload({
params,
location: routerState.location,
intent: "preload"
});
}
}

View File

@@ -0,0 +1,10 @@
import type { LocationChange, RouterContext, RouterUtils } from "../types.js";
export declare function createRouter(config: {
get: () => string | LocationChange;
set: (next: LocationChange) => void;
init?: (notify: (value?: string | LocationChange) => void) => () => void;
create?: (router: RouterContext) => void;
utils?: Partial<RouterUtils>;
}): (props: import("./components.js").BaseRouterProps) => import("solid-js").JSX.Element;
export declare function bindEvent(target: EventTarget, type: string, handler: EventListener): () => void;
export declare function scrollToHash(hash: string, fallbackTop?: boolean): void;

View File

@@ -0,0 +1,41 @@
import { createSignal, onCleanup, sharedConfig } from "solid-js";
import { createRouterComponent } from "./components.js";
function intercept([value, setValue], get, set) {
return [get ? () => get(value()) : value, set ? (v) => setValue(set(v)) : setValue];
}
export function createRouter(config) {
let ignore = false;
const wrap = (value) => (typeof value === "string" ? { value } : value);
const signal = intercept(createSignal(wrap(config.get()), {
equals: (a, b) => a.value === b.value && a.state === b.state
}), undefined, next => {
!ignore && config.set(next);
if (sharedConfig.registry && !sharedConfig.done)
sharedConfig.done = true;
return next;
});
config.init &&
onCleanup(config.init((value = config.get()) => {
ignore = true;
signal[1](wrap(value));
ignore = false;
}));
return createRouterComponent({
signal,
create: config.create,
utils: config.utils
});
}
export function bindEvent(target, type, handler) {
target.addEventListener(type, handler);
return () => target.removeEventListener(type, handler);
}
export function scrollToHash(hash, fallbackTop) {
const el = hash && document.getElementById(hash);
if (el) {
el.scrollIntoView();
}
else if (fallbackTop) {
window.scrollTo(0, 0);
}
}

View File

@@ -0,0 +1,11 @@
export { Route } from "./components.js";
export type { BaseRouterProps, RouteProps } from "./components.js";
export { createRouter } from "./createRouter.js";
export { Router } from "./Router.js";
export type { RouterProps } from "./Router.js";
export { HashRouter } from "./HashRouter.js";
export type { HashRouterProps } from "./HashRouter.js";
export { MemoryRouter, createMemoryHistory } from "./MemoryRouter.js";
export type { MemoryRouterProps, MemoryHistory } from "./MemoryRouter.js";
export { StaticRouter } from "./StaticRouter.js";
export type { StaticRouterProps } from "./StaticRouter.js";

View File

@@ -0,0 +1,6 @@
export { Route } from "./components.js";
export { createRouter } from "./createRouter.js";
export { Router } from "./Router.js";
export { HashRouter } from "./HashRouter.js";
export { MemoryRouter, createMemoryHistory } from "./MemoryRouter.js";
export { StaticRouter } from "./StaticRouter.js";

View File

@@ -0,0 +1,175 @@
import { JSX, Accessor } from "solid-js";
import type { BeforeLeaveEventArgs, Branch, Intent, Location, MatchFilters, NavigateOptions, Navigator, Params, RouteDescription, RouteContext, RouteDefinition, RouteMatch, RouterContext, RouterIntegration, SearchParams, SetSearchParams } from "./types.js";
/** Consider this API opaque and internal. It is likely to change in the future. */
export declare const RouterContextObj: import("solid-js").Context<RouterContext | undefined>;
export declare const RouteContextObj: import("solid-js").Context<RouteContext | undefined>;
export declare const useRouter: () => RouterContext;
export declare const useRoute: () => RouteContext;
export declare const useResolvedPath: (path: () => string) => Accessor<string | undefined>;
export declare const useHref: <T extends string | undefined>(to: () => T) => () => string | T;
/**
* Retrieves method to do navigation. The method accepts a path to navigate to and an optional object with the following options:
*
* - resolve (*boolean*, default `true`): resolve the path against the current route
* - replace (*boolean*, default `false`): replace the history entry
* - scroll (*boolean*, default `true`): scroll to top after navigation
* - state (*any*, default `undefined`): pass custom state to `location.state`
*
* **Note**: The state is serialized using the structured clone algorithm which does not support all object types.
*
* @example
* ```js
* const navigate = useNavigate();
*
* if (unauthorized) {
* navigate("/login", { replace: true });
* }
* ```
*/
export declare const useNavigate: () => Navigator;
/**
* Retrieves reactive `location` object useful for getting things like `pathname`.
*
* @example
* ```js
* const location = useLocation();
*
* const pathname = createMemo(() => parsePath(location.pathname));
* ```
*/
export declare const useLocation: <S = unknown>() => Location<S>;
/**
* Retrieves signal that indicates whether the route is currently in a *Transition*.
* Useful for showing stale/pending state when the route resolution is *Suspended* during concurrent rendering.
*
* @example
* ```js
* const isRouting = useIsRouting();
*
* return (
* <div classList={{ "grey-out": isRouting() }}>
* <MyAwesomeContent />
* </div>
* );
* ```
*/
export declare const useIsRouting: () => () => boolean;
/**
* usePreloadRoute returns a function that can be used to preload a route manual.
* This is what happens automatically with link hovering and similar focus based behavior, but it is available here as an API.
*
* @example
* ```js
* const preload = usePreloadRoute();
*
* preload(`/users/settings`, { preloadData: true });
* ```
*/
export declare const usePreloadRoute: () => (url: string | URL, options?: {
preloadData?: boolean;
}) => void;
/**
* `useMatch` takes an accessor that returns the path and creates a `Memo` that returns match information if the current path matches the provided path.
* Useful for determining if a given path matches the current route.
*
* @example
* ```js
* const match = useMatch(() => props.href);
*
* return <div classList={{ active: Boolean(match()) }} />;
* ```
*/
export declare const useMatch: <S extends string>(path: () => S, matchFilters?: MatchFilters<S>) => Accessor<import("./types.js").PathMatch | undefined>;
/**
* `useCurrentMatches` returns all the matches for the current matched route.
* Useful for getting all the route information.
*
* @example
* ```js
* const matches = useCurrentMatches();
*
* const breadcrumbs = createMemo(() => matches().map(m => m.route.info.breadcrumb))
* ```
*/
export declare const useCurrentMatches: () => () => RouteMatch[];
/**
* Retrieves a reactive, store-like object containing the current route path parameters as defined in the Route.
*
* @example
* ```js
* const params = useParams();
*
* // fetch user based on the id path parameter
* const [user] = createResource(() => params.id, fetchUser);
* ```
*/
export declare const useParams: <T extends Params>() => T;
/**
* Retrieves a tuple containing a reactive object to read the current location's query parameters and a method to update them.
* The object is a proxy so you must access properties to subscribe to reactive updates.
* **Note** that values will be strings and property names will retain their casing.
*
* The setter method accepts an object whose entries will be merged into the current query string.
* Values `''`, `undefined` and `null` will remove the key from the resulting query string.
* Updates will behave just like a navigation and the setter accepts the same optional second parameter as `navigate` and auto-scrolling is disabled by default.
*
* @examples
* ```js
* const [searchParams, setSearchParams] = useSearchParams();
*
* return (
* <div>
* <span>Page: {searchParams.page}</span>
* <button
* onClick={() =>
* setSearchParams({ page: (parseInt(searchParams.page) || 0) + 1 })
* }
* >
* Next Page
* </button>
* </div>
* );
* ```
*/
export declare const useSearchParams: <T extends SearchParams>() => [Partial<T>, (params: SetSearchParams, options?: Partial<NavigateOptions>) => void];
/**
* useBeforeLeave takes a function that will be called prior to leaving a route.
* The function will be called with:
*
* - from (*Location*): current location (before change).
* - to (*string | number*): path passed to `navigate`.
* - options (*NavigateOptions*): options passed to navigate.
* - preventDefault (*function*): call to block the route change.
* - defaultPrevented (*readonly boolean*): `true` if any previously called leave handlers called `preventDefault`.
* - retry (*function*, force?: boolean ): call to retry the same navigation, perhaps after confirming with the user. Pass `true` to skip running the leave handlers again (i.e. force navigate without confirming).
*
* @example
* ```js
* useBeforeLeave((e: BeforeLeaveEventArgs) => {
* if (form.isDirty && !e.defaultPrevented) {
* // preventDefault to block immediately and prompt user async
* e.preventDefault();
* setTimeout(() => {
* if (window.confirm("Discard unsaved changes - are you sure?")) {
* // user wants to proceed anyway so retry with force=true
* e.retry(true);
* }
* }, 100);
* }
* });
* ```
*/
export declare const useBeforeLeave: (listener: (e: BeforeLeaveEventArgs) => void) => void;
export declare function createRoutes(routeDef: RouteDefinition, base?: string): RouteDescription[];
export declare function createBranch(routes: RouteDescription[], index?: number): Branch;
export declare function createBranches(routeDef: RouteDefinition | RouteDefinition[], base?: string, stack?: RouteDescription[], branches?: Branch[]): Branch[];
export declare function getRouteMatches(branches: Branch[], location: string): RouteMatch[];
export declare function getIntent(): Intent | undefined;
export declare function getInPreloadFn(): boolean;
export declare function setInPreloadFn(value: boolean): void;
export declare function createRouterContext(integration: RouterIntegration, branches: () => Branch[], getContext?: () => any, options?: {
base?: string;
singleFlight?: boolean;
transformUrl?: (url: string) => string;
}): RouterContext;
export declare function createRouteContext(router: RouterContext, parent: RouteContext, outlet: () => JSX.Element, match: () => RouteMatch): RouteContext;

View File

@@ -0,0 +1,560 @@
import { runWithOwner, batch } from "solid-js";
import { createComponent, createContext, createMemo, createRenderEffect, createSignal, on, onCleanup, untrack, useContext, startTransition, resetErrorBoundaries } from "solid-js";
import { isServer, getRequestEvent } from "solid-js/web";
import { createBeforeLeave } from "./lifecycle.js";
import { mockBase, createMemoObject, extractSearchParams, invariant, resolvePath, createMatcher, joinPaths, scoreRoute, mergeSearchString, expandOptionals } from "./utils.js";
const MAX_REDIRECTS = 100;
/** Consider this API opaque and internal. It is likely to change in the future. */
export const RouterContextObj = createContext();
export const RouteContextObj = createContext();
export const useRouter = () => invariant(useContext(RouterContextObj), "<A> and 'use' router primitives can be only used inside a Route.");
let TempRoute;
export const useRoute = () => TempRoute || useContext(RouteContextObj) || useRouter().base;
export const useResolvedPath = (path) => {
const route = useRoute();
return createMemo(() => route.resolvePath(path()));
};
export const useHref = (to) => {
const router = useRouter();
return createMemo(() => {
const to_ = to();
return to_ !== undefined ? router.renderPath(to_) : to_;
});
};
/**
* Retrieves method to do navigation. The method accepts a path to navigate to and an optional object with the following options:
*
* - resolve (*boolean*, default `true`): resolve the path against the current route
* - replace (*boolean*, default `false`): replace the history entry
* - scroll (*boolean*, default `true`): scroll to top after navigation
* - state (*any*, default `undefined`): pass custom state to `location.state`
*
* **Note**: The state is serialized using the structured clone algorithm which does not support all object types.
*
* @example
* ```js
* const navigate = useNavigate();
*
* if (unauthorized) {
* navigate("/login", { replace: true });
* }
* ```
*/
export const useNavigate = () => useRouter().navigatorFactory();
/**
* Retrieves reactive `location` object useful for getting things like `pathname`.
*
* @example
* ```js
* const location = useLocation();
*
* const pathname = createMemo(() => parsePath(location.pathname));
* ```
*/
export const useLocation = () => useRouter().location;
/**
* Retrieves signal that indicates whether the route is currently in a *Transition*.
* Useful for showing stale/pending state when the route resolution is *Suspended* during concurrent rendering.
*
* @example
* ```js
* const isRouting = useIsRouting();
*
* return (
* <div classList={{ "grey-out": isRouting() }}>
* <MyAwesomeContent />
* </div>
* );
* ```
*/
export const useIsRouting = () => useRouter().isRouting;
/**
* usePreloadRoute returns a function that can be used to preload a route manual.
* This is what happens automatically with link hovering and similar focus based behavior, but it is available here as an API.
*
* @example
* ```js
* const preload = usePreloadRoute();
*
* preload(`/users/settings`, { preloadData: true });
* ```
*/
export const usePreloadRoute = () => {
const pre = useRouter().preloadRoute;
return (url, options = {}) => pre(url instanceof URL ? url : new URL(url, mockBase), options.preloadData);
};
/**
* `useMatch` takes an accessor that returns the path and creates a `Memo` that returns match information if the current path matches the provided path.
* Useful for determining if a given path matches the current route.
*
* @example
* ```js
* const match = useMatch(() => props.href);
*
* return <div classList={{ active: Boolean(match()) }} />;
* ```
*/
export const useMatch = (path, matchFilters) => {
const location = useLocation();
const matchers = createMemo(() => expandOptionals(path()).map(path => createMatcher(path, undefined, matchFilters)));
return createMemo(() => {
for (const matcher of matchers()) {
const match = matcher(location.pathname);
if (match)
return match;
}
});
};
/**
* `useCurrentMatches` returns all the matches for the current matched route.
* Useful for getting all the route information.
*
* @example
* ```js
* const matches = useCurrentMatches();
*
* const breadcrumbs = createMemo(() => matches().map(m => m.route.info.breadcrumb))
* ```
*/
export const useCurrentMatches = () => useRouter().matches;
/**
* Retrieves a reactive, store-like object containing the current route path parameters as defined in the Route.
*
* @example
* ```js
* const params = useParams();
*
* // fetch user based on the id path parameter
* const [user] = createResource(() => params.id, fetchUser);
* ```
*/
export const useParams = () => useRouter().params;
/**
* Retrieves a tuple containing a reactive object to read the current location's query parameters and a method to update them.
* The object is a proxy so you must access properties to subscribe to reactive updates.
* **Note** that values will be strings and property names will retain their casing.
*
* The setter method accepts an object whose entries will be merged into the current query string.
* Values `''`, `undefined` and `null` will remove the key from the resulting query string.
* Updates will behave just like a navigation and the setter accepts the same optional second parameter as `navigate` and auto-scrolling is disabled by default.
*
* @examples
* ```js
* const [searchParams, setSearchParams] = useSearchParams();
*
* return (
* <div>
* <span>Page: {searchParams.page}</span>
* <button
* onClick={() =>
* setSearchParams({ page: (parseInt(searchParams.page) || 0) + 1 })
* }
* >
* Next Page
* </button>
* </div>
* );
* ```
*/
export const useSearchParams = () => {
const location = useLocation();
const navigate = useNavigate();
const setSearchParams = (params, options) => {
const searchString = untrack(() => mergeSearchString(location.search, params) + location.hash);
navigate(searchString, {
scroll: false,
resolve: false,
...options
});
};
return [location.query, setSearchParams];
};
/**
* useBeforeLeave takes a function that will be called prior to leaving a route.
* The function will be called with:
*
* - from (*Location*): current location (before change).
* - to (*string | number*): path passed to `navigate`.
* - options (*NavigateOptions*): options passed to navigate.
* - preventDefault (*function*): call to block the route change.
* - defaultPrevented (*readonly boolean*): `true` if any previously called leave handlers called `preventDefault`.
* - retry (*function*, force?: boolean ): call to retry the same navigation, perhaps after confirming with the user. Pass `true` to skip running the leave handlers again (i.e. force navigate without confirming).
*
* @example
* ```js
* useBeforeLeave((e: BeforeLeaveEventArgs) => {
* if (form.isDirty && !e.defaultPrevented) {
* // preventDefault to block immediately and prompt user async
* e.preventDefault();
* setTimeout(() => {
* if (window.confirm("Discard unsaved changes - are you sure?")) {
* // user wants to proceed anyway so retry with force=true
* e.retry(true);
* }
* }, 100);
* }
* });
* ```
*/
export const useBeforeLeave = (listener) => {
const s = useRouter().beforeLeave.subscribe({
listener,
location: useLocation(),
navigate: useNavigate()
});
onCleanup(s);
};
export function createRoutes(routeDef, base = "") {
const { component, preload, load, children, info } = routeDef;
const isLeaf = !children || (Array.isArray(children) && !children.length);
const shared = {
key: routeDef,
component,
preload: preload || load,
info
};
return asArray(routeDef.path).reduce((acc, originalPath) => {
for (const expandedPath of expandOptionals(originalPath)) {
const path = joinPaths(base, expandedPath);
let pattern = isLeaf ? path : path.split("/*", 1)[0];
pattern = pattern
.split("/")
.map((s) => {
return s.startsWith(":") || s.startsWith("*") ? s : encodeURIComponent(s);
})
.join("/");
acc.push({
...shared,
originalPath,
pattern,
matcher: createMatcher(pattern, !isLeaf, routeDef.matchFilters)
});
}
return acc;
}, []);
}
export function createBranch(routes, index = 0) {
return {
routes,
score: scoreRoute(routes[routes.length - 1]) * 10000 - index,
matcher(location) {
const matches = [];
for (let i = routes.length - 1; i >= 0; i--) {
const route = routes[i];
const match = route.matcher(location);
if (!match) {
return null;
}
matches.unshift({
...match,
route
});
}
return matches;
}
};
}
function asArray(value) {
return Array.isArray(value) ? value : [value];
}
export function createBranches(routeDef, base = "", stack = [], branches = []) {
const routeDefs = asArray(routeDef);
for (let i = 0, len = routeDefs.length; i < len; i++) {
const def = routeDefs[i];
if (def && typeof def === "object") {
if (!def.hasOwnProperty("path"))
def.path = "";
const routes = createRoutes(def, base);
for (const route of routes) {
stack.push(route);
const isEmptyArray = Array.isArray(def.children) && def.children.length === 0;
if (def.children && !isEmptyArray) {
createBranches(def.children, route.pattern, stack, branches);
}
else {
const branch = createBranch([...stack], branches.length);
branches.push(branch);
}
stack.pop();
}
}
}
// Stack will be empty on final return
return stack.length ? branches : branches.sort((a, b) => b.score - a.score);
}
export function getRouteMatches(branches, location) {
for (let i = 0, len = branches.length; i < len; i++) {
const match = branches[i].matcher(location);
if (match) {
return match;
}
}
return [];
}
function createLocation(path, state, queryWrapper) {
const origin = new URL(mockBase);
const url = createMemo(prev => {
const path_ = path();
try {
return new URL(path_, origin);
}
catch (err) {
console.error(`Invalid path ${path_}`);
return prev;
}
}, origin, {
equals: (a, b) => a.href === b.href
});
const pathname = createMemo(() => url().pathname);
const search = createMemo(() => url().search, true);
const hash = createMemo(() => url().hash);
const key = () => "";
const queryFn = on(search, () => extractSearchParams(url()));
return {
get pathname() {
return pathname();
},
get search() {
return search();
},
get hash() {
return hash();
},
get state() {
return state();
},
get key() {
return key();
},
query: queryWrapper ? queryWrapper(queryFn) : createMemoObject(queryFn)
};
}
let intent;
export function getIntent() {
return intent;
}
let inPreloadFn = false;
export function getInPreloadFn() {
return inPreloadFn;
}
export function setInPreloadFn(value) {
inPreloadFn = value;
}
export function createRouterContext(integration, branches, getContext, options = {}) {
const { signal: [source, setSource], utils = {} } = integration;
const parsePath = utils.parsePath || (p => p);
const renderPath = utils.renderPath || (p => p);
const beforeLeave = utils.beforeLeave || createBeforeLeave();
const basePath = resolvePath("", options.base || "");
if (basePath === undefined) {
throw new Error(`${basePath} is not a valid base path`);
}
else if (basePath && !source().value) {
setSource({ value: basePath, replace: true, scroll: false });
}
const [isRouting, setIsRouting] = createSignal(false);
// Keep track of last target, so that last call to transition wins
let lastTransitionTarget;
// Transition the location to a new value
const transition = (newIntent, newTarget) => {
if (newTarget.value === reference() && newTarget.state === state())
return;
if (lastTransitionTarget === undefined)
setIsRouting(true);
intent = newIntent;
lastTransitionTarget = newTarget;
startTransition(() => {
if (lastTransitionTarget !== newTarget)
return;
setReference(lastTransitionTarget.value);
setState(lastTransitionTarget.state);
resetErrorBoundaries();
if (!isServer)
submissions[1](subs => subs.filter(s => s.pending));
}).finally(() => {
if (lastTransitionTarget !== newTarget)
return;
// Batch, in order for isRouting and final source update to happen together
batch(() => {
intent = undefined;
if (newIntent === "navigate")
navigateEnd(lastTransitionTarget);
setIsRouting(false);
lastTransitionTarget = undefined;
});
});
};
const [reference, setReference] = createSignal(source().value);
const [state, setState] = createSignal(source().state);
const location = createLocation(reference, state, utils.queryWrapper);
const referrers = [];
const submissions = createSignal(isServer ? initFromFlash() : []);
const matches = createMemo(() => {
if (typeof options.transformUrl === "function") {
return getRouteMatches(branches(), options.transformUrl(location.pathname));
}
return getRouteMatches(branches(), location.pathname);
});
const buildParams = () => {
const m = matches();
const params = {};
for (let i = 0; i < m.length; i++) {
Object.assign(params, m[i].params);
}
return params;
};
const params = utils.paramsWrapper
? utils.paramsWrapper(buildParams, branches)
: createMemoObject(buildParams);
const baseRoute = {
pattern: basePath,
path: () => basePath,
outlet: () => null,
resolvePath(to) {
return resolvePath(basePath, to);
}
};
// Create a native transition, when source updates
createRenderEffect(on(source, source => transition("native", source), { defer: true }));
return {
base: baseRoute,
location,
params,
isRouting,
renderPath,
parsePath,
navigatorFactory,
matches,
beforeLeave,
preloadRoute,
singleFlight: options.singleFlight === undefined ? true : options.singleFlight,
submissions
};
function navigateFromRoute(route, to, options) {
// Untrack in case someone navigates in an effect - don't want to track `reference` or route paths
untrack(() => {
if (typeof to === "number") {
if (!to) {
// A delta of 0 means stay at the current location, so it is ignored
}
else if (utils.go) {
utils.go(to);
}
else {
console.warn("Router integration does not support relative routing");
}
return;
}
const queryOnly = !to || to[0] === "?";
const { replace, resolve, scroll, state: nextState } = {
replace: false,
resolve: !queryOnly,
scroll: true,
...options
};
const resolvedTo = resolve
? route.resolvePath(to)
: resolvePath((queryOnly && location.pathname) || "", to);
if (resolvedTo === undefined) {
throw new Error(`Path '${to}' is not a routable path`);
}
else if (referrers.length >= MAX_REDIRECTS) {
throw new Error("Too many redirects");
}
const current = reference();
if (resolvedTo !== current || nextState !== state()) {
if (isServer) {
const e = getRequestEvent();
e && (e.response = { status: 302, headers: new Headers({ Location: resolvedTo }) });
setSource({ value: resolvedTo, replace, scroll, state: nextState });
}
else if (beforeLeave.confirm(resolvedTo, options)) {
referrers.push({ value: current, replace, scroll, state: state() });
transition("navigate", {
value: resolvedTo,
state: nextState
});
}
}
});
}
function navigatorFactory(route) {
// Workaround for vite issue (https://github.com/vitejs/vite/issues/3803)
route = route || useContext(RouteContextObj) || baseRoute;
return (to, options) => navigateFromRoute(route, to, options);
}
function navigateEnd(next) {
const first = referrers[0];
if (first) {
setSource({
...next,
replace: first.replace,
scroll: first.scroll
});
referrers.length = 0;
}
}
function preloadRoute(url, preloadData) {
const matches = getRouteMatches(branches(), url.pathname);
const prevIntent = intent;
intent = "preload";
for (let match in matches) {
const { route, params } = matches[match];
route.component &&
route.component.preload &&
route.component.preload();
const { preload } = route;
inPreloadFn = true;
preloadData &&
preload &&
runWithOwner(getContext(), () => preload({
params,
location: {
pathname: url.pathname,
search: url.search,
hash: url.hash,
query: extractSearchParams(url),
state: null,
key: ""
},
intent: "preload"
}));
inPreloadFn = false;
}
intent = prevIntent;
}
function initFromFlash() {
const e = getRequestEvent();
return (e && e.router && e.router.submission ? [e.router.submission] : []);
}
}
export function createRouteContext(router, parent, outlet, match) {
const { base, location, params } = router;
const { pattern, component, preload } = match().route;
const path = createMemo(() => match().path);
component &&
component.preload &&
component.preload();
inPreloadFn = true;
const data = preload ? preload({ params, location, intent: intent || "initial" }) : undefined;
inPreloadFn = false;
const route = {
parent,
pattern,
path,
outlet: () => component
? createComponent(component, {
params,
location,
data,
get children() {
return outlet();
}
})
: outlet(),
resolvePath(to) {
return resolvePath(base.path(), to, path());
}
};
return route;
}

View File

@@ -0,0 +1,200 @@
import type { Component, JSX, Signal } from "solid-js";
declare module "solid-js/web" {
interface RequestEvent {
response: {
status?: number;
statusText?: string;
headers: Headers;
};
router?: {
matches?: OutputMatch[];
cache?: Map<string, CacheEntry>;
submission?: {
input: any;
result: any;
url: string;
};
dataOnly?: boolean | string[];
data?: Record<string, any>;
previousUrl?: string;
};
serverOnly?: boolean;
}
}
export type Params = Record<string, string | undefined>;
export type SearchParams = Record<string, string | string[] | undefined>;
export type SetParams = Record<string, string | number | boolean | null | undefined>;
export type SetSearchParams = Record<string, string | string[] | number | number[] | boolean | boolean[] | null | undefined>;
export interface Path {
pathname: string;
search: string;
hash: string;
}
export interface Location<S = unknown> extends Path {
query: SearchParams;
state: Readonly<Partial<S>> | null;
key: string;
}
export interface NavigateOptions<S = unknown> {
resolve: boolean;
replace: boolean;
scroll: boolean;
state: S;
}
export interface Navigator {
(to: string | number, options?: Partial<NavigateOptions>): void;
(delta: number): void;
}
export type NavigatorFactory = (route?: RouteContext) => Navigator;
export interface LocationChange<S = unknown> {
value: string;
replace?: boolean;
scroll?: boolean;
state?: S;
rawPath?: string;
}
export interface RouterIntegration {
signal: Signal<LocationChange>;
create?: (router: RouterContext) => void;
utils?: Partial<RouterUtils>;
}
export type Intent = "initial" | "native" | "navigate" | "preload";
export interface RoutePreloadFuncArgs {
params: Params;
location: Location;
intent: Intent;
}
export type RoutePreloadFunc<T = unknown> = (args: RoutePreloadFuncArgs) => T;
export interface RouteSectionProps<T = unknown> {
params: Params;
location: Location;
data: T;
children?: JSX.Element;
}
export type RouteDefinition<S extends string | string[] = any, T = unknown> = {
path?: S;
matchFilters?: MatchFilters<S>;
preload?: RoutePreloadFunc<T>;
children?: RouteDefinition | RouteDefinition[];
component?: Component<RouteSectionProps<T>>;
info?: Record<string, any>;
/** @deprecated use preload */
load?: RoutePreloadFunc;
};
export type MatchFilter = readonly string[] | RegExp | ((s: string) => boolean);
export type PathParams<P extends string | readonly string[]> = P extends `${infer Head}/${infer Tail}` ? [...PathParams<Head>, ...PathParams<Tail>] : P extends `:${infer S}?` ? [S] : P extends `:${infer S}` ? [S] : P extends `*${infer S}` ? [S] : [];
export type MatchFilters<P extends string | readonly string[] = any> = P extends string ? {
[K in PathParams<P>[number]]?: MatchFilter;
} : Record<string, MatchFilter>;
export interface PathMatch {
params: Params;
path: string;
}
export interface RouteMatch extends PathMatch {
route: RouteDescription;
}
export interface OutputMatch {
path: string;
pattern: string;
match: string;
params: Params;
info?: Record<string, any>;
}
export interface RouteDescription {
key: unknown;
originalPath: string;
pattern: string;
component?: Component<RouteSectionProps>;
preload?: RoutePreloadFunc;
matcher: (location: string) => PathMatch | null;
matchFilters?: MatchFilters;
info?: Record<string, any>;
}
export interface Branch {
routes: RouteDescription[];
score: number;
matcher: (location: string) => RouteMatch[] | null;
}
export interface RouteContext {
parent?: RouteContext;
child?: RouteContext;
pattern: string;
path: () => string;
outlet: () => JSX.Element;
resolvePath(to: string): string | undefined;
}
export interface RouterUtils {
renderPath(path: string): string;
parsePath(str: string): string;
go(delta: number): void;
beforeLeave: BeforeLeaveLifecycle;
paramsWrapper: (getParams: () => Params, branches: () => Branch[]) => Params;
queryWrapper: (getQuery: () => SearchParams) => SearchParams;
}
export interface RouterContext {
base: RouteContext;
location: Location;
params: Params;
navigatorFactory: NavigatorFactory;
isRouting: () => boolean;
matches: () => RouteMatch[];
renderPath(path: string): string;
parsePath(str: string): string;
beforeLeave: BeforeLeaveLifecycle;
preloadRoute: (url: URL, preloadData?: boolean) => void;
singleFlight: boolean;
submissions: Signal<Submission<any, any>[]>;
}
export interface BeforeLeaveEventArgs {
from: Location;
to: string | number;
options?: Partial<NavigateOptions>;
readonly defaultPrevented: boolean;
preventDefault(): void;
retry(force?: boolean): void;
}
export interface BeforeLeaveListener {
listener(e: BeforeLeaveEventArgs): void;
location: Location;
navigate: Navigator;
}
export interface BeforeLeaveLifecycle {
subscribe(listener: BeforeLeaveListener): () => void;
confirm(to: string | number, options?: Partial<NavigateOptions>): boolean;
}
export type Submission<T, U> = {
readonly input: T;
readonly result?: U;
readonly error: any;
readonly pending: boolean;
readonly url: string;
clear: () => void;
retry: () => void;
};
export type SubmissionStub = {
readonly input: undefined;
readonly result: undefined;
readonly error: undefined;
readonly pending: undefined;
readonly url: undefined;
clear: () => void;
retry: () => void;
};
export interface MaybePreloadableComponent extends Component {
preload?: () => void;
}
export type CacheEntry = [number, Promise<any>, any, Intent | undefined, Signal<number> & {
count: number;
}];
export type NarrowResponse<T> = T extends CustomResponse<infer U> ? U : Exclude<T, Response>;
export type RouterResponseInit = Omit<ResponseInit, "body"> & {
revalidate?: string | string[];
};
export type CustomResponse<T> = Omit<Response, "clone"> & {
customBody: () => T;
clone(...args: readonly unknown[]): CustomResponse<T>;
};
/** @deprecated */
export type RouteLoadFunc = RoutePreloadFunc;
/** @deprecated */
export type RouteLoadFuncArgs = RoutePreloadFuncArgs;

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,13 @@
import type { MatchFilters, PathMatch, RouteDescription, SearchParams, SetSearchParams } from "./types.js";
export declare const mockBase = "http://sr";
export declare function normalizePath(path: string, omitSlash?: boolean): string;
export declare function resolvePath(base: string, path: string, from?: string): string | undefined;
export declare function invariant<T>(value: T | null | undefined, message: string): T;
export declare function joinPaths(from: string, to: string): string;
export declare function extractSearchParams(url: URL): SearchParams;
export declare function createMatcher<S extends string>(path: S, partial?: boolean, matchFilters?: MatchFilters<S>): (location: string) => PathMatch | null;
export declare function scoreRoute(route: RouteDescription): number;
export declare function createMemoObject<T extends Record<string | symbol, unknown>>(fn: () => T): T;
export declare function mergeSearchString(search: string, params: SetSearchParams): string;
export declare function expandOptionals(pattern: string): string[];
export declare function setFunctionName<T>(obj: T, value: string): T;

View File

@@ -0,0 +1,185 @@
import { createMemo, getOwner, runWithOwner } from "solid-js";
const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
const trimPathRegex = /^\/+|(\/)\/+$/g;
export const mockBase = "http://sr";
export function normalizePath(path, omitSlash = false) {
const s = path.replace(trimPathRegex, "$1");
return s ? (omitSlash || /^[?#]/.test(s) ? s : "/" + s) : "";
}
export function resolvePath(base, path, from) {
if (hasSchemeRegex.test(path)) {
return undefined;
}
const basePath = normalizePath(base);
const fromPath = from && normalizePath(from);
let result = "";
if (!fromPath || path.startsWith("/")) {
result = basePath;
}
else if (fromPath.toLowerCase().indexOf(basePath.toLowerCase()) !== 0) {
result = basePath + fromPath;
}
else {
result = fromPath;
}
return (result || "/") + normalizePath(path, !result);
}
export function invariant(value, message) {
if (value == null) {
throw new Error(message);
}
return value;
}
export function joinPaths(from, to) {
return normalizePath(from).replace(/\/*(\*.*)?$/g, "") + normalizePath(to);
}
export function extractSearchParams(url) {
const params = {};
url.searchParams.forEach((value, key) => {
if (key in params) {
if (Array.isArray(params[key]))
params[key].push(value);
else
params[key] = [params[key], value];
}
else
params[key] = value;
});
return params;
}
export function createMatcher(path, partial, matchFilters) {
const [pattern, splat] = path.split("/*", 2);
const segments = pattern.split("/").filter(Boolean);
const len = segments.length;
return (location) => {
const locSegments = location.split("/").filter(Boolean);
const lenDiff = locSegments.length - len;
if (lenDiff < 0 || (lenDiff > 0 && splat === undefined && !partial)) {
return null;
}
const match = {
path: len ? "" : "/",
params: {}
};
const matchFilter = (s) => matchFilters === undefined ? undefined : matchFilters[s];
for (let i = 0; i < len; i++) {
const segment = segments[i];
const dynamic = segment[0] === ":";
const locSegment = dynamic ? locSegments[i] : locSegments[i].toLowerCase();
const key = dynamic ? segment.slice(1) : segment.toLowerCase();
if (dynamic && matchSegment(locSegment, matchFilter(key))) {
match.params[key] = locSegment;
}
else if (dynamic || !matchSegment(locSegment, key)) {
return null;
}
match.path += `/${locSegment}`;
}
if (splat) {
const remainder = lenDiff ? locSegments.slice(-lenDiff).join("/") : "";
if (matchSegment(remainder, matchFilter(splat))) {
match.params[splat] = remainder;
}
else {
return null;
}
}
return match;
};
}
function matchSegment(input, filter) {
const isEqual = (s) => s === input;
if (filter === undefined) {
return true;
}
else if (typeof filter === "string") {
return isEqual(filter);
}
else if (typeof filter === "function") {
return filter(input);
}
else if (Array.isArray(filter)) {
return filter.some(isEqual);
}
else if (filter instanceof RegExp) {
return filter.test(input);
}
return false;
}
export function scoreRoute(route) {
const [pattern, splat] = route.pattern.split("/*", 2);
const segments = pattern.split("/").filter(Boolean);
return segments.reduce((score, segment) => score + (segment.startsWith(":") ? 2 : 3), segments.length - (splat === undefined ? 0 : 1));
}
export function createMemoObject(fn) {
const map = new Map();
const owner = getOwner();
return new Proxy({}, {
get(_, property) {
if (!map.has(property)) {
runWithOwner(owner, () => map.set(property, createMemo(() => fn()[property])));
}
return map.get(property)();
},
getOwnPropertyDescriptor() {
return {
enumerable: true,
configurable: true
};
},
ownKeys() {
return Reflect.ownKeys(fn());
},
has(_, property) {
return property in fn();
}
});
}
export function mergeSearchString(search, params) {
const merged = new URLSearchParams(search);
Object.entries(params).forEach(([key, value]) => {
if (value == null || value === "" || (value instanceof Array && !value.length)) {
merged.delete(key);
}
else {
if (value instanceof Array) {
// Delete all instances of the key before appending
merged.delete(key);
value.forEach(v => {
merged.append(key, String(v));
});
}
else {
merged.set(key, String(value));
}
}
});
const s = merged.toString();
return s ? `?${s}` : "";
}
export function expandOptionals(pattern) {
let match = /(\/?\:[^\/]+)\?/.exec(pattern);
if (!match)
return [pattern];
let prefix = pattern.slice(0, match.index);
let suffix = pattern.slice(match.index + match[0].length);
const prefixes = [prefix, (prefix += match[1])];
// This section handles adjacent optional params. We don't actually want all permuations since
// that will lead to equivalent routes which have the same number of params. For example
// `/:a?/:b?/:c`? only has the unique expansion: `/`, `/:a`, `/:a/:b`, `/:a/:b/:c` and we can
// discard `/:b`, `/:c`, `/:b/:c` by building them up in order and not recursing. This also helps
// ensure predictability where earlier params have precidence.
while ((match = /^(\/\:[^\/]+)\?/.exec(suffix))) {
prefixes.push((prefix += match[1]));
suffix = suffix.slice(match[0].length);
}
return expandOptionals(suffix).reduce((results, expansion) => [...results, ...prefixes.map(p => p + expansion)], []);
}
export function setFunctionName(obj, value) {
Object.defineProperty(obj, "name", {
value,
writable: false,
configurable: false
});
return obj;
}

View File

@@ -0,0 +1,61 @@
{
"name": "@solidjs/router",
"description": "Universal router for SolidJS",
"author": "Ryan Carniato",
"contributors": [
"Ryan Turnquist"
],
"license": "MIT",
"version": "0.16.1",
"homepage": "https://github.com/solidjs/solid-router#readme",
"repository": {
"type": "git",
"url": "https://github.com/solidjs/solid-router"
},
"publishConfig": {
"access": "public"
},
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"solid": "./dist/index.jsx",
"default": "./dist/index.js"
}
},
"files": [
"dist"
],
"sideEffects": false,
"devDependencies": {
"@babel/core": "^7.26.0",
"@babel/preset-typescript": "^7.26.0",
"@changesets/cli": "^2.27.10",
"@rollup/plugin-babel": "6.0.4",
"@rollup/plugin-node-resolve": "15.3.0",
"@rollup/plugin-terser": "0.4.4",
"@types/jest": "^29.5.14",
"@types/node": "^22.10.0",
"babel-preset-solid": "^1.9.3",
"jsdom": "^25.0.1",
"prettier": "^3.4.1",
"rollup": "^4.27.4",
"solid-js": "^1.9.3",
"typescript": "^5.7.2",
"vite": "^6.0.0",
"vite-plugin-solid": "^2.11.0",
"vitest": "^2.1.6"
},
"peerDependencies": {
"solid-js": "^1.8.6"
},
"scripts": {
"build": "rm -rf dist && tsc && rollup -c",
"test": "vitest run && npm run test:types",
"test:watch": "vitest",
"test:types": "tsc --project tsconfig.test.json",
"pretty": "prettier --write \"{src,test}/**/*.{ts,tsx}\"",
"release": "pnpm build && changeset publish"
}
}

View File

@@ -0,0 +1,19 @@
Copyright (c) 2017-2018 Fredrik Nicol
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,291 @@
# CSSType
[![npm](https://img.shields.io/npm/v/csstype.svg)](https://www.npmjs.com/package/csstype)
TypeScript and Flow definitions for CSS, generated by [data from MDN](https://github.com/mdn/data). It provides autocompletion and type checking for CSS properties and values.
**TypeScript**
```ts
import type * as CSS from 'csstype';
const style: CSS.Properties = {
colour: 'white', // Type error on property
textAlign: 'middle', // Type error on value
};
```
**Flow**
```js
// @flow strict
import * as CSS from 'csstype';
const style: CSS.Properties<> = {
colour: 'white', // Type error on property
textAlign: 'middle', // Type error on value
};
```
_Further examples below will be in TypeScript!_
## Getting started
```sh
$ npm install csstype
```
## Table of content
- [Style types](#style-types)
- [At-rule types](#at-rule-types)
- [Pseudo types](#pseudo-types)
- [Generics](#generics)
- [Usage](#usage)
- [What should I do when I get type errors?](#what-should-i-do-when-i-get-type-errors)
- [Version 3.0](#version-30)
- [Contributing](#contributing)
## Style types
Properties are categorized in different uses and in several technical variations to provide typings that suits as many as possible.
| | Default | `Hyphen` | `Fallback` | `HyphenFallback` |
| -------------- | -------------------- | -------------------------- | ---------------------------- | ---------------------------------- |
| **All** | `Properties` | `PropertiesHyphen` | `PropertiesFallback` | `PropertiesHyphenFallback` |
| **`Standard`** | `StandardProperties` | `StandardPropertiesHyphen` | `StandardPropertiesFallback` | `StandardPropertiesHyphenFallback` |
| **`Vendor`** | `VendorProperties` | `VendorPropertiesHyphen` | `VendorPropertiesFallback` | `VendorPropertiesHyphenFallback` |
| **`Obsolete`** | `ObsoleteProperties` | `ObsoletePropertiesHyphen` | `ObsoletePropertiesFallback` | `ObsoletePropertiesHyphenFallback` |
| **`Svg`** | `SvgProperties` | `SvgPropertiesHyphen` | `SvgPropertiesFallback` | `SvgPropertiesHyphenFallback` |
Categories:
- **All** - Includes `Standard`, `Vendor`, `Obsolete` and `Svg`
- **`Standard`** - Current properties and extends subcategories `StandardLonghand` and `StandardShorthand` _(e.g. `StandardShorthandProperties`)_
- **`Vendor`** - Vendor prefixed properties and extends subcategories `VendorLonghand` and `VendorShorthand` _(e.g. `VendorShorthandProperties`)_
- **`Obsolete`** - Removed or deprecated properties
- **`Svg`** - SVG-specific properties
Variations:
- **Default** - JavaScript (camel) cased property names
- **`Hyphen`** - CSS (kebab) cased property names
- **`Fallback`** - Also accepts array of values e.g. `string | string[]`
## At-rule types
At-rule interfaces with descriptors.
**TypeScript**: These will be found in the `AtRule` namespace, e.g. `AtRule.Viewport`.
**Flow**: These will be prefixed with `AtRule$`, e.g. `AtRule$Viewport`.
| | Default | `Hyphen` | `Fallback` | `HyphenFallback` |
| -------------------- | -------------- | -------------------- | ---------------------- | ---------------------------- |
| **`@counter-style`** | `CounterStyle` | `CounterStyleHyphen` | `CounterStyleFallback` | `CounterStyleHyphenFallback` |
| **`@font-face`** | `FontFace` | `FontFaceHyphen` | `FontFaceFallback` | `FontFaceHyphenFallback` |
| **`@viewport`** | `Viewport` | `ViewportHyphen` | `ViewportFallback` | `ViewportHyphenFallback` |
## Pseudo types
String literals of pseudo classes and pseudo elements
- `Pseudos`
Extends:
- `AdvancedPseudos`
Function-like pseudos e.g. `:not(:first-child)`. The string literal contains the value excluding the parenthesis: `:not`. These are separated because they require an argument that results in infinite number of variations.
- `SimplePseudos`
Plain pseudos e.g. `:hover` that can only be **one** variation.
## Generics
All interfaces has two optional generic argument to define length and time: `CSS.Properties<TLength = string | 0, TTime = string>`
- **Length** is the first generic parameter and defaults to `string | 0` because `0` is the only [length where the unit identifier is optional](https://drafts.csswg.org/css-values-3/#lengths). You can specify this, e.g. `string | number`, for platforms and libraries that accepts any numeric value as length with a specific unit.
```tsx
const style: CSS.Properties<string | number> = {
width: 100,
};
```
- **Time** is the second generic argument and defaults to `string`. You can specify this, e.g. `string | number`, for platforms and libraries that accepts any numeric value as length with a specific unit.
```tsx
const style: CSS.Properties<string | number, number> = {
transitionDuration: 1000,
};
```
## Usage
```ts
import type * as CSS from 'csstype';
const style: CSS.Properties = {
width: '10px',
margin: '1em',
};
```
In some cases, like for CSS-in-JS libraries, an array of values is a way to provide fallback values in CSS. Using `CSS.PropertiesFallback` instead of `CSS.Properties` will add the possibility to use any property value as an array of values.
```ts
import type * as CSS from 'csstype';
const style: CSS.PropertiesFallback = {
display: ['-webkit-flex', 'flex'],
color: 'white',
};
```
There's even string literals for pseudo selectors and elements.
```ts
import type * as CSS from 'csstype';
const pseudos: { [P in CSS.SimplePseudos]?: CSS.Properties } = {
':hover': {
display: 'flex',
},
};
```
Hyphen cased (kebab cased) properties are provided in `CSS.PropertiesHyphen` and `CSS.PropertiesHyphenFallback`. It's not **not** added by default in `CSS.Properties`. To allow both of them, you can simply extend with `CSS.PropertiesHyphen` or/and `CSS.PropertiesHyphenFallback`.
```ts
import type * as CSS from 'csstype';
interface Style extends CSS.Properties, CSS.PropertiesHyphen {}
const style: Style = {
'flex-grow': 1,
'flex-shrink': 0,
'font-weight': 'normal',
backgroundColor: 'white',
};
```
Adding type checked CSS properties to a `HTMLElement`.
```ts
import type * as CSS from 'csstype';
const style: CSS.Properties = {
color: 'red',
margin: '1em',
};
let button = document.createElement('button');
Object.assign(button.style, style);
```
## What should I do when I get type errors?
The goal is to have as perfect types as possible and we're trying to do our best. But with CSS Custom Properties, the CSS specification changing frequently and vendors implementing their own specifications with new releases sometimes causes type errors even if it should work. Here's some steps you could take to get it fixed:
_If you're using CSS Custom Properties you can step directly to step 3._
1. **First of all, make sure you're doing it right.** A type error could also indicate that you're not :wink:
- Some CSS specs that some vendors has implemented could have been officially rejected or haven't yet received any official acceptance and are therefor not included
- If you're using TypeScript, [type widening](https://blog.mariusschulz.com/2017/02/04/TypeScript-2-1-literal-type-widening) could be the reason you get `Type 'string' is not assignable to...` errors
2. **Have a look in [issues](https://github.com/frenic/csstype/issues) to see if an issue already has been filed. If not, create a new one.** To help us out, please refer to any information you have found.
3. Fix the issue locally with **TypeScript** (Flow further down):
- The recommended way is to use **module augmentation**. Here's a few examples:
```ts
// My css.d.ts file
import type * as CSS from 'csstype';
declare module 'csstype' {
interface Properties {
// Add a missing property
WebkitRocketLauncher?: string;
// Add a CSS Custom Property
'--theme-color'?: 'black' | 'white';
// Allow namespaced CSS Custom Properties
[index: `--theme-${string}`]: any;
// Allow any CSS Custom Properties
[index: `--${string}`]: any;
// ...or allow any other property
[index: string]: any;
}
}
```
- The alternative way is to use **type assertion**. Here's a few examples:
```ts
const style: CSS.Properties = {
// Add a missing property
['WebkitRocketLauncher' as any]: 'launching',
// Add a CSS Custom Property
['--theme-color' as any]: 'black',
};
```
Fix the issue locally with **Flow**:
- Use **type assertion**. Here's a few examples:
```js
const style: $Exact<CSS.Properties<*>> = {
// Add a missing property
[('WebkitRocketLauncher': any)]: 'launching',
// Add a CSS Custom Property
[('--theme-color': any)]: 'black',
};
```
## Version 3.2
- **No longer compatible with version 2**
Conflicts may occur when both version ^3.2.0 and ^2.0.0 are installed. Potential fix for Npm would be to force resolution in `package.json`:
```json
{
"overrides": {
"csstype": "^3.2.0"
}
}
```
## Version 3.1
- **Data types are exposed**
TypeScript: `DataType.Color`
Flow: `DataType$Color`
## Version 3.0
- **All property types are exposed with namespace**
TypeScript: `Property.AlignContent` (was `AlignContentProperty` before)
Flow: `Property$AlignContent`
- **All at-rules are exposed with namespace**
TypeScript: `AtRule.FontFace` (was `FontFace` before)
Flow: `AtRule$FontFace`
- **Data types are NOT exposed**
E.g. `Color` and `Box`. Because the generation of data types may suddenly be removed or renamed.
- **TypeScript hack for autocompletion**
Uses `(string & {})` for literal string unions and `(number & {})` for literal number unions ([related issue](https://github.com/microsoft/TypeScript/issues/29729)). Utilize `PropertyValue<T>` to unpack types from e.g. `(string & {})` to `string`.
- **New generic for time**
Read more on the ["Generics"](#generics) section.
- **Flow types improvements**
Flow Strict enabled and exact types are used.
## Contributing
**Never modify `index.d.ts` and `index.js.flow` directly. They are generated automatically and committed so that we can easily follow any change it results in.** Therefor it's important that you run `$ git config merge.ours.driver true` after you've forked and cloned. That setting prevents merge conflicts when doing rebase.
### Commands
- `npm run build` Generates typings and type checks them
- `npm run watch` Runs build on each save
- `npm run test` Runs the tests
- `npm run lazy` Type checks, lints and formats everything

22569
go/jsruntime/runtime/csstype/index.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,70 @@
{
"name": "csstype",
"version": "3.2.3",
"main": "",
"types": "index.d.ts",
"description": "Strict TypeScript and Flow types for style based on MDN data",
"repository": "https://github.com/frenic/csstype",
"author": "Fredrik Nicol <fredrik.nicol@gmail.com>",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.28.5",
"@babel/preset-env": "^7.28.5",
"@babel/preset-typescript": "^7.28.5",
"@eslint/js": "^9.39.1",
"@mdn/browser-compat-data": "7.1.21",
"@tsconfig/node24": "^24.0.2",
"@types/chokidar": "^2.1.7",
"@types/css-tree": "^2.3.11",
"@types/jest": "^30.0.0",
"@types/jsdom": "^27.0.0",
"@types/node": "^24.10.1",
"@types/prettier": "^3.0.0",
"@types/turndown": "^5.0.6",
"babel-jest": "^30.2.0",
"chalk": "^5.6.2",
"chokidar": "^4.0.3",
"css-tree": "^3.1.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.4",
"flow-bin": "^0.291.0",
"jest": "^30.2.0",
"jsdom": "^27.2.0",
"mdn-data": "2.25.0",
"prettier": "^3.6.2",
"release-it": "^19.0.6",
"tsx": "^4.20.6",
"turndown": "^7.2.2",
"typescript": "~5.9.3",
"typescript-eslint": "^8.46.4"
},
"overrides": {
"js-yaml": ">=4.1.1"
},
"scripts": {
"prepublish": "npm install --no-save --prefix __tests__ && npm install --no-save --prefix __tests__/__fixtures__",
"release": "release-it",
"update": "tsx update.ts",
"build": "tsx --inspect build.ts --start",
"watch": "tsx build.ts --watch",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
"pretty": "prettier --write build.ts **/*.{ts,js,json,md}",
"lazy": "tsc && npm run lint",
"test": "jest --runInBand",
"test:src": "jest src.*.ts",
"test:dist": "jest dist.*.ts --runInBand"
},
"files": [
"index.d.ts",
"index.js.flow"
],
"keywords": [
"css",
"style",
"typescript",
"flow",
"typings",
"types",
"definitions"
]
}

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016-2025 Ryan Carniato
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,223 @@
<p>
<img src="https://assets.solidjs.com/banner?project=Library&type=core" alt="SolidJS" />
</p>
[![Build Status](https://img.shields.io/github/actions/workflow/status/solidjs/solid/main-ci.yml?branch=main&logo=github&style=for-the-badge)](https://github.com/solidjs/solid/actions/workflows/main-ci.yml)
[![Coverage Status](https://img.shields.io/coveralls/github/solidjs/solid.svg?style=for-the-badge)](https://coveralls.io/github/solidjs/solid?branch=main)
[![NPM Version](https://img.shields.io/npm/v/solid-js.svg?style=for-the-badge)](https://www.npmjs.com/package/solid-js)
[![](https://img.shields.io/npm/dm/solid-js.svg?style=for-the-badge)](https://www.npmjs.com/package/solid-js)
[![Discord](https://img.shields.io/discord/722131463138705510?style=for-the-badge)](https://discord.com/invite/solidjs)
[![Subreddit subscribers](https://img.shields.io/reddit/subreddit-subscribers/solidjs?style=for-the-badge)](https://www.reddit.com/r/solidjs/)
**[Website](https://www.solidjs.com/) • [API Docs](https://docs.solidjs.com/) • [Features Tutorial](https://www.solidjs.com/tutorial/introduction_basics) • [Playground](https://playground.solidjs.com/?version=1.3.13#NobwRAdghgtgpmAXGGUCWEwBowBcCeADgsrgM4Ae2YZA9gK4BOAxiWGjIbY7gAQi9GcCABM4jXgF9eAM0a0YvADo1aAGzQiAtACsyAegDucAEYqA3EogcuPfr2ZCouOAGU0Ac2hqps+YpU6DW09CysrGXoIZlw0WgheAGEGCBdGAAoASn4rXgd4sj5gZhTcLF4yOFxkqNwAXV4AXgcnF3cvKDV0gAZMywT8iELeDEc4eFSm3iymgD4KqprU9JLamYBqXgBGPvCBoVwmBPTcvN4AHhN6XFx43gJiRpUrm-iVXnjEjWYAa0aQUZCCa4SSzU5nfirZaZSTgi76F63CBgga7CCwiBWISicTpGaNebnJZpXj6WblES0Zj0YEAOg8VQAompxsJcAAhfAASREJzAUEIhBUmTRYEkdSAA) • [Discord](https://discord.com/invite/solidjs)**
Solid is a declarative JavaScript library for creating user interfaces. Instead of using a Virtual DOM, it compiles its templates to real DOM nodes and updates them with fine-grained reactions. Declare your state and use it throughout your app, and when a piece of state changes, only the code that depends on it will rerun. Check out our [intro video](https://www.youtube.com/watch?v=cELFZQAMdhQ) or read on!
## Key Features
- Fine-grained updates to the real DOM
- Declarative data: model your state as a system with reactive primitives
- Render-once mental model: your components are regular JavaScript functions that run once to set up your view
- Automatic dependency tracking: accessing your reactive state subscribes to it
- [Small](https://dev.to/this-is-learning/javascript-framework-todomvc-size-comparison-504f) and [fast](https://krausest.github.io/js-framework-benchmark/current.html)
- Simple: learn a few powerful concepts that can be reused, combined, and built on top of
- Provides modern framework features like JSX, fragments, Context, Portals, Suspense, streaming SSR, progressive hydration, Error Boundaries and concurrent rendering.
- Naturally debuggable: A `<div>` is a real div, so you can use your browser's devtools to inspect the rendering
- [Web component friendly](https://github.com/solidjs/solid/tree/main/packages/solid-element#readme) and can author custom elements
- Isomorphic: render your components on the client and the server
- Universal: write [custom renderers](https://github.com/solidjs/solid/releases/tag/v1.2.0) to use Solid anywhere
- A growing community and ecosystem with active core team support
<details>
<summary>Quick Start</summary>
You can get started with a simple app by running the following in your terminal:
```sh
> npx degit solidjs/templates/js my-app
> cd my-app
> npm i # or yarn or pnpm
> npm run dev # or yarn or pnpm
```
Or for TypeScript:
```sh
> npx degit solidjs/templates/ts my-app
> cd my-app
> npm i # or yarn or pnpm
> npm run dev # or yarn or pnpm
```
This will create a minimal, client-rendered application powered by [Vite](https://vitejs.dev/).
Or you can install the dependencies in your own setup. To use Solid with JSX (_recommended_), run:
```sh
> npm i -D babel-preset-solid
> npm i solid-js
```
The easiest way to get set up is to add `babel-preset-solid` to your `.babelrc`, babel config for webpack, or rollup configuration:
```js
"presets": ["solid"]
```
For TypeScript to work, remember to set your `.tsconfig` to handle Solid's JSX:
```js
"compilerOptions": {
"jsx": "preserve",
"jsxImportSource": "solid-js",
}
```
</details>
## Why Solid?
### Performant
Meticulously engineered for performance and with half a decade of research behind it, Solid's performance is almost indistinguishable from optimized vanilla JavaScript (See Solid on the [JS Framework Benchmark](https://krausest.github.io/js-framework-benchmark/current.html)). Solid is [small](https://bundlephobia.com/package/solid-js@1.3.15) and completely tree-shakable, and [fast](https://levelup.gitconnected.com/how-we-wrote-the-fastest-javascript-ui-framework-again-db097ddd99b6) when rendering on the server, too. Whether you're writing a fully client-rendered SPA or a server-rendered app, your users see it faster than ever. ([Read more about Solid's performance](https://dev.to/ryansolid/thinking-granular-how-is-solidjs-so-performant-4g37) from the library's creator.)
### Powerful
Solid is fully-featured with everything you can expect from a modern framework. Performant state management is built-in with Context and Stores: you don't have to reach for a third party library to manage global state (if you don't want to). With Resources, you can use data loaded from the server like any other piece of state and build a responsive UI for it thanks to Suspense and concurrent rendering. And when you're ready to move to the server, Solid has full SSR and serverless support, with streaming and progressive hydration to get to interactive as quickly as possible. (Check out our full [interactive features walkthrough](https://www.solidjs.com/tutorial/introduction_basics).)
### Pragmatic
Do more with less: use simple, composable primitives without hidden rules and gotchas. In Solid, components are just functions - rendering is determined purely by how your state is used - so you're free to organize your code how you like and you don't have to learn a new rendering system. Solid encourages patterns like declarative code and read-write segregation that help keep your project maintainable, but isn't opinionated enough to get in your way.
### Productive
Solid is built on established tools like JSX and TypeScript and integrates with the Vite ecosystem. Solid's bare-metal, minimal abstractions give you direct access to the DOM, making it easy to use your favorite native JavaScript libraries like D3. And the Solid ecosystem is growing fast, with [custom primitives](https://github.com/solidjs-community/solid-primitives), [component libraries](https://github.com/hope-ui/hope-ui), and build-time utilities that let you [write Solid code in new ways](https://github.com/LXSMNSYC/solid-labels).
<details>
<summary>Show Me!</summary>
```jsx
import { render } from "solid-js/web";
import { createSignal } from "solid-js";
// A component is just a function that (optionally) accepts properties and returns a DOM node
const Counter = props => {
// Create a piece of reactive state, giving us a accessor, count(), and a setter, setCount()
const [count, setCount] = createSignal(props.startingCount || 1);
// The increment function calls the setter
const increment = () => setCount(count() + 1);
console.log(
"The body of the function runs once, like you'd expect from calling any other function, so you only ever see this console log once."
);
// JSX allows us to write HTML within our JavaScript function and include dynamic expressions using the { } syntax
// The only part of this that will ever rerender is the count() text.
return (
<button type="button" onClick={increment}>
Increment {count()}
</button>
);
};
// The render function mounts a component onto your page
render(() => <Counter startingCount={2} />, document.getElementById("app"));
```
See it in action in our interactive [Playground](https://playground.solidjs.com/?hash=-894962706&version=1.3.13)!
Solid compiles our JSX down to efficient real DOM expressions updates, still using the same reactive primitives (`createSignal`) at runtime but making sure there's as little rerendering as possible. Here's what that looks like in this example:
```js
import { render, createComponent, delegateEvents, insert, template } from "solid-js/web";
import { createSignal } from "solid-js";
const _tmpl$ = /*#__PURE__*/ template(`<button type="button">Increment </button>`, 2);
const Counter = props => {
const [count, setCount] = createSignal(props.startingCount || 1);
const increment = () => setCount(count() + 1);
console.log("The body of the function runs once . . .");
return (() => {
//_el$ is a real DOM node!
const _el$ = _tmpl$.cloneNode(true);
_el$.firstChild;
_el$.$$click = increment;
//This inserts the count as a child of the button in a way that allows count to update without rerendering the whole button
insert(_el$, count, null);
return _el$;
})();
};
render(
() =>
createComponent(Counter, {
startingCount: 2
}),
document.getElementById("app")
);
delegateEvents(["click"]);
```
</details>
## More
Check out our official [documentation](https://www.solidjs.com/guide) or browse some [examples](https://github.com/solidjs/solid/blob/main/documentation/resources/examples.md)
## Browser Support
SolidJS Core is committed to supporting the last 2 years of modern browsers including Firefox, Safari, Chrome and Edge (for desktop and mobile devices). We do not support IE or similar sunset browsers. For server environments, we support Node LTS and the latest Deno and Cloudflare Worker runtimes.
<img src="https://saucelabs.github.io/images/opensauce/powered-by-saucelabs-badge-gray.svg?sanitize=true" alt="Testing Powered By SauceLabs" width="300"/>
## Community
Come chat with us on [Discord](https://discord.com/invite/solidjs)! Solid's creator and the rest of the core team are active there, and we're always looking for contributions.
### Contributors
<a href="https://github.com/solidjs/solid/graphs/contributors"><img src="https://contrib.rocks/image?repo=solidjs/solid" style="max-width:100%;"></a>
### Open Collective
Support us with a donation and help us continue our activities. [[Contribute](https://opencollective.com/solid)]
<a href="https://opencollective.com/solid/backer/0/website" target="_blank"><img src="https://opencollective.com/solid/backer/0/avatar.svg"></a>
<a href="https://opencollective.com/solid/backer/1/website" target="_blank"><img src="https://opencollective.com/solid/backer/1/avatar.svg"></a>
<a href="https://opencollective.com/solid/backer/2/website" target="_blank"><img src="https://opencollective.com/solid/backer/2/avatar.svg"></a>
<a href="https://opencollective.com/solid/backer/3/website" target="_blank"><img src="https://opencollective.com/solid/backer/3/avatar.svg"></a>
<a href="https://opencollective.com/solid/backer/4/website" target="_blank"><img src="https://opencollective.com/solid/backer/4/avatar.svg"></a>
<a href="https://opencollective.com/solid/backer/5/website" target="_blank"><img src="https://opencollective.com/solid/backer/5/avatar.svg"></a>
<a href="https://opencollective.com/solid/backer/6/website" target="_blank"><img src="https://opencollective.com/solid/backer/6/avatar.svg"></a>
<a href="https://opencollective.com/solid/backer/7/website" target="_blank"><img src="https://opencollective.com/solid/backer/7/avatar.svg"></a>
<a href="https://opencollective.com/solid/backer/8/website" target="_blank"><img src="https://opencollective.com/solid/backer/8/avatar.svg"></a>
<a href="https://opencollective.com/solid/backer/9/website" target="_blank"><img src="https://opencollective.com/solid/backer/9/avatar.svg"></a>
<a href="https://opencollective.com/solid/backer/10/website" target="_blank"><img src="https://opencollective.com/solid/backer/10/avatar.svg"></a>
### Sponsors
Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor](https://opencollective.com/solid#sponsor)]
<a href="https://opencollective.com/solid/sponsor/0/website" target="_blank"><img src="https://opencollective.com/solid/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/solid/sponsor/1/website" target="_blank"><img src="https://opencollective.com/solid/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/solid/sponsor/2/website" target="_blank"><img src="https://opencollective.com/solid/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/solid/sponsor/3/website" target="_blank"><img src="https://opencollective.com/solid/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/solid/sponsor/4/website" target="_blank"><img src="https://opencollective.com/solid/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/solid/sponsor/5/website" target="_blank"><img src="https://opencollective.com/solid/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/solid/sponsor/6/website" target="_blank"><img src="https://opencollective.com/solid/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/solid/sponsor/7/website" target="_blank"><img src="https://opencollective.com/solid/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/solid/sponsor/8/website" target="_blank"><img src="https://opencollective.com/solid/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/solid/sponsor/9/website" target="_blank"><img src="https://opencollective.com/solid/sponsor/9/avatar.svg"></a>
<a href="https://opencollective.com/solid/sponsor/10/website" target="_blank"><img src="https://opencollective.com/solid/sponsor/10/avatar.svg"></a>
<a href="https://opencollective.com/solid/sponsor/11/website" target="_blank"><img src="https://opencollective.com/solid/sponsor/11/avatar.svg"></a>
<a href="https://opencollective.com/solid/sponsor/12/website" target="_blank"><img src="https://opencollective.com/solid/sponsor/12/avatar.svg"></a>

1863
go/jsruntime/runtime/solid-js/dist/dev.cjs vendored Normal file

File diff suppressed because it is too large Load Diff

1808
go/jsruntime/runtime/solid-js/dist/dev.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,817 @@
'use strict';
const equalFn = (a, b) => a === b;
const $PROXY = Symbol("solid-proxy");
const $TRACK = Symbol("solid-track");
const $DEVCOMP = Symbol("solid-dev-component");
const DEV = undefined;
const ERROR = Symbol("error");
function castError(err) {
if (err instanceof Error) return err;
return new Error(typeof err === "string" ? err : "Unknown error", {
cause: err
});
}
function handleError(err, owner = Owner) {
const fns = owner && owner.context && owner.context[ERROR];
const error = castError(err);
if (!fns) throw error;
try {
for (const f of fns) f(error);
} catch (e) {
handleError(e, owner && owner.owner || null);
}
}
const UNOWNED = {
context: null,
owner: null,
owned: null,
cleanups: null
};
let Owner = null;
function createOwner() {
const o = {
owner: Owner,
context: Owner ? Owner.context : null,
owned: null,
cleanups: null
};
if (Owner) {
if (!Owner.owned) Owner.owned = [o];else Owner.owned.push(o);
}
return o;
}
function createRoot(fn, detachedOwner) {
const owner = Owner,
current = detachedOwner === undefined ? owner : detachedOwner,
root = fn.length === 0 ? UNOWNED : {
context: current ? current.context : null,
owner: current,
owned: null,
cleanups: null
};
Owner = root;
let result;
try {
result = fn(fn.length === 0 ? () => {} : () => cleanNode(root));
} catch (err) {
handleError(err);
} finally {
Owner = owner;
}
return result;
}
function createSignal(value, options) {
return [() => value, v => {
return value = typeof v === "function" ? v(value) : v;
}];
}
function createComputed(fn, value) {
Owner = createOwner();
try {
fn(value);
} catch (err) {
handleError(err);
} finally {
Owner = Owner.owner;
}
}
const createRenderEffect = createComputed;
function createEffect(fn, value) {}
function createReaction(fn) {
return fn => {
fn();
};
}
function createMemo(fn, value) {
Owner = createOwner();
let v;
try {
v = fn(value);
} catch (err) {
handleError(err);
} finally {
Owner = Owner.owner;
}
return () => v;
}
function createDeferred(source) {
return source;
}
function createSelector(source, fn = equalFn) {
return k => fn(k, source());
}
function batch(fn) {
return fn();
}
const untrack = batch;
function on(deps, fn, options = {}) {
const isArray = Array.isArray(deps);
const defer = options.defer;
return () => {
if (defer) return undefined;
let value;
if (isArray) {
value = [];
for (let i = 0; i < deps.length; i++) value.push(deps[i]());
} else value = deps();
return fn(value);
};
}
function onMount(fn) {}
function onCleanup(fn) {
if (Owner) {
if (!Owner.cleanups) Owner.cleanups = [fn];else Owner.cleanups.push(fn);
}
return fn;
}
function cleanNode(node) {
if (node.owned) {
for (let i = 0; i < node.owned.length; i++) cleanNode(node.owned[i]);
node.owned = null;
}
if (node.cleanups) {
for (let i = 0; i < node.cleanups.length; i++) node.cleanups[i]();
node.cleanups = null;
}
}
function catchError(fn, handler) {
const owner = createOwner();
owner.context = {
...owner.context,
[ERROR]: [handler]
};
Owner = owner;
try {
return fn();
} catch (err) {
handleError(err);
} finally {
Owner = Owner.owner;
}
}
function getListener() {
return null;
}
function createContext(defaultValue) {
const id = Symbol("context");
return {
id,
Provider: createProvider(id),
defaultValue
};
}
function useContext(context) {
return Owner && Owner.context && Owner.context[context.id] !== undefined ? Owner.context[context.id] : context.defaultValue;
}
function getOwner() {
return Owner;
}
function children(fn) {
const memo = createMemo(() => resolveChildren(fn()));
memo.toArray = () => {
const c = memo();
return Array.isArray(c) ? c : c != null ? [c] : [];
};
return memo;
}
function runWithOwner(o, fn) {
const prev = Owner;
Owner = o;
try {
return fn();
} catch (err) {
handleError(err);
} finally {
Owner = prev;
}
}
function resolveChildren(children) {
if (typeof children === "function" && !children.length) return resolveChildren(children());
if (Array.isArray(children)) {
const results = [];
for (let i = 0; i < children.length; i++) {
const result = resolveChildren(children[i]);
if (Array.isArray(result)) {
if (result.length < 32768) results.push.apply(results, result);else for (let j = 0; j < result.length; j++) results.push(result[j]);
} else {
results.push(result);
}
}
return results;
}
return children;
}
function createProvider(id) {
return function provider(props) {
return createMemo(() => {
Owner.context = {
...Owner.context,
[id]: props.value
};
return children(() => props.children);
});
};
}
function requestCallback(fn, options) {
return {
id: 0,
fn: () => {},
startTime: 0,
expirationTime: 0
};
}
function mapArray(list, mapFn, options = {}) {
const items = list();
let s = [];
if (items && items.length) {
for (let i = 0, len = items.length; i < len; i++) s.push(mapFn(items[i], () => i));
} else if (options.fallback) s = [options.fallback()];
return () => s;
}
function indexArray(list, mapFn, options = {}) {
const items = list();
let s = [];
if (items && items.length) {
for (let i = 0, len = items.length; i < len; i++) s.push(mapFn(() => items[i], i));
} else if (options.fallback) s = [options.fallback()];
return () => s;
}
function observable(input) {
return {
subscribe(observer) {
if (!(observer instanceof Object) || observer == null) {
throw new TypeError("Expected the observer to be an object.");
}
const handler = typeof observer === "function" ? observer : observer.next && observer.next.bind(observer);
if (!handler) {
return {
unsubscribe() {}
};
}
const dispose = createRoot(disposer => {
createEffect(() => {
const v = input();
untrack(() => handler(v));
});
return disposer;
});
if (getOwner()) onCleanup(dispose);
return {
unsubscribe() {
dispose();
}
};
},
[Symbol.observable || "@@observable"]() {
return this;
}
};
}
function from(producer) {
const [s, set] = createSignal(undefined);
if ("subscribe" in producer) {
const unsub = producer.subscribe(v => set(() => v));
onCleanup(() => "unsubscribe" in unsub ? unsub.unsubscribe() : unsub());
} else {
const clean = producer(set);
onCleanup(clean);
}
return s;
}
function enableExternalSource(factory) {}
function onError(fn) {
if (Owner) {
if (Owner.context === null || !Owner.context[ERROR]) {
Owner.context = {
...Owner.context,
[ERROR]: [fn]
};
mutateContext(Owner, ERROR, [fn]);
} else Owner.context[ERROR].push(fn);
}
}
function mutateContext(o, key, value) {
if (o.owned) {
for (let i = 0; i < o.owned.length; i++) {
if (o.owned[i].context === o.context) mutateContext(o.owned[i], key, value);
if (!o.owned[i].context) {
o.owned[i].context = o.context;
mutateContext(o.owned[i], key, value);
} else if (!o.owned[i].context[key]) {
o.owned[i].context[key] = value;
mutateContext(o.owned[i], key, value);
}
}
}
}
function escape(s, attr) {
const t = typeof s;
if (t !== "string") {
if (t === "function") return escape(s());
if (Array.isArray(s)) {
for (let i = 0; i < s.length; i++) s[i] = escape(s[i]);
return s;
}
return s;
}
const delim = "<";
const escDelim = "&lt;";
let iDelim = s.indexOf(delim);
let iAmp = s.indexOf("&");
if (iDelim < 0 && iAmp < 0) return s;
let left = 0,
out = "";
while (iDelim >= 0 && iAmp >= 0) {
if (iDelim < iAmp) {
if (left < iDelim) out += s.substring(left, iDelim);
out += escDelim;
left = iDelim + 1;
iDelim = s.indexOf(delim, left);
} else {
if (left < iAmp) out += s.substring(left, iAmp);
out += "&amp;";
left = iAmp + 1;
iAmp = s.indexOf("&", left);
}
}
if (iDelim >= 0) {
do {
if (left < iDelim) out += s.substring(left, iDelim);
out += escDelim;
left = iDelim + 1;
iDelim = s.indexOf(delim, left);
} while (iDelim >= 0);
} else while (iAmp >= 0) {
if (left < iAmp) out += s.substring(left, iAmp);
out += "&amp;";
left = iAmp + 1;
iAmp = s.indexOf("&", left);
}
return left < s.length ? out + s.substring(left) : out;
}
function resolveSSRNode(node) {
const t = typeof node;
if (t === "string") return node;
if (node == null || t === "boolean") return "";
if (Array.isArray(node)) {
let prev = {};
let mapped = "";
for (let i = 0, len = node.length; i < len; i++) {
if (typeof prev !== "object" && typeof node[i] !== "object") mapped += `<!--!$-->`;
mapped += resolveSSRNode(prev = node[i]);
}
return mapped;
}
if (t === "object") return node.t;
if (t === "function") return resolveSSRNode(node());
return String(node);
}
const sharedConfig = {
context: undefined,
getContextId() {
if (!this.context) throw new Error(`getContextId cannot be used under non-hydrating context`);
return getContextId(this.context.count);
},
getNextContextId() {
if (!this.context) throw new Error(`getNextContextId cannot be used under non-hydrating context`);
return getContextId(this.context.count++);
}
};
function getContextId(count) {
const num = String(count),
len = num.length - 1;
return sharedConfig.context.id + (len ? String.fromCharCode(96 + len) : "") + num;
}
function setHydrateContext(context) {
sharedConfig.context = context;
}
function nextHydrateContext() {
return sharedConfig.context ? {
...sharedConfig.context,
id: sharedConfig.getNextContextId(),
count: 0
} : undefined;
}
function createUniqueId() {
return sharedConfig.getNextContextId();
}
function createComponent(Comp, props) {
if (sharedConfig.context && !sharedConfig.context.noHydrate) {
const c = sharedConfig.context;
setHydrateContext(nextHydrateContext());
const r = Comp(props || {});
setHydrateContext(c);
return r;
}
return Comp(props || {});
}
function mergeProps(...sources) {
const target = {};
for (let i = 0; i < sources.length; i++) {
let source = sources[i];
if (typeof source === "function") source = source();
if (source) {
const descriptors = Object.getOwnPropertyDescriptors(source);
for (const key in descriptors) {
if (key === "__proto__" || key === "constructor" || Object.prototype.hasOwnProperty.call(target, key)) continue;
Object.defineProperty(target, key, {
enumerable: true,
get() {
for (let i = sources.length - 1; i >= 0; i--) {
let v,
s = sources[i];
if (typeof s === "function") s = s();
v = (s || {})[key];
if (v !== undefined) return v;
}
}
});
}
}
}
return target;
}
function splitProps(props, ...keys) {
const descriptors = Object.getOwnPropertyDescriptors(props),
split = k => {
const clone = {};
for (let i = 0; i < k.length; i++) {
const key = k[i];
if (descriptors[key]) {
Object.defineProperty(clone, key, descriptors[key]);
delete descriptors[key];
}
}
return clone;
};
return keys.map(split).concat(split(Object.keys(descriptors)));
}
function simpleMap(props, wrap) {
const list = props.each || [],
len = list.length,
fn = props.children;
if (len) {
let mapped = Array(len);
for (let i = 0; i < len; i++) mapped[i] = wrap(fn, list[i], i);
return mapped;
}
return props.fallback;
}
function For(props) {
return simpleMap(props, (fn, item, i) => fn(item, () => i));
}
function Index(props) {
return simpleMap(props, (fn, item, i) => fn(() => item, i));
}
function Show(props) {
let c;
return props.when ? typeof (c = props.children) === "function" && c.length > 0 ? c(props.keyed ? props.when : () => props.when) : c : props.fallback || "";
}
function Switch(props) {
let conditions = props.children;
Array.isArray(conditions) || (conditions = [conditions]);
for (let i = 0; i < conditions.length; i++) {
const w = conditions[i].when;
if (w) {
const c = conditions[i].children;
return typeof c === "function" && c.length > 0 ? c(conditions[i].keyed ? w : () => w) : c;
}
}
return props.fallback || "";
}
function Match(props) {
return props;
}
function resetErrorBoundaries() {}
function ErrorBoundary(props) {
let error,
res,
clean,
sync = true;
const ctx = sharedConfig.context;
const id = sharedConfig.getContextId();
function displayFallback() {
cleanNode(clean);
ctx.serialize(id, error);
setHydrateContext({
...ctx,
count: 0
});
const f = props.fallback;
return typeof f === "function" && f.length ? f(error, () => {}) : f;
}
createMemo(() => {
clean = Owner;
return catchError(() => res = props.children, err => {
error = err;
!sync && ctx.replace("e" + id, displayFallback);
sync = true;
});
});
if (error) return displayFallback();
sync = false;
return {
t: `<!--!$e${id}-->${resolveSSRNode(escape(res))}<!--!$/e${id}-->`
};
}
const SuspenseContext = createContext();
let resourceContext = null;
function createResource(source, fetcher, options = {}) {
if (typeof fetcher !== "function") {
options = fetcher || {};
fetcher = source;
source = true;
}
const contexts = new Set();
const id = sharedConfig.getNextContextId();
let resource = {};
let value = options.storage ? options.storage(options.initialValue)[0]() : options.initialValue;
let p;
let error;
if (sharedConfig.context.async && options.ssrLoadFrom !== "initial") {
resource = sharedConfig.context.resources[id] || (sharedConfig.context.resources[id] = {});
if (resource.ref) {
if (!resource.data && !resource.ref[0]._loading && !resource.ref[0].error) resource.ref[1].refetch();
return resource.ref;
}
}
const prepareResource = () => {
if (error) throw error;
const resolved = options.ssrLoadFrom !== "initial" && sharedConfig.context.async && "data" in sharedConfig.context.resources[id];
if (!resolved && resourceContext) resourceContext.push(id);
if (!resolved && read._loading) {
const ctx = useContext(SuspenseContext);
if (ctx) {
ctx.resources.set(id, read);
contexts.add(ctx);
}
}
return resolved;
};
const read = () => {
return prepareResource() ? sharedConfig.context.resources[id].data : value;
};
const loading = () => {
prepareResource();
return read._loading;
};
read._loading = false;
read.error = undefined;
read.state = "initialValue" in options ? "ready" : "unresolved";
Object.defineProperties(read, {
latest: {
get() {
return read();
}
},
loading: {
get() {
return loading();
}
}
});
function load() {
const ctx = sharedConfig.context;
if (!ctx.async) return read._loading = !!(typeof source === "function" ? source() : source);
if (ctx.resources && id in ctx.resources && "data" in ctx.resources[id]) {
value = ctx.resources[id].data;
return;
}
let lookup;
try {
resourceContext = [];
lookup = typeof source === "function" ? source() : source;
if (resourceContext.length) return;
} finally {
resourceContext = null;
}
if (!p) {
if (lookup == null || lookup === false) return;
p = fetcher(lookup, {
value
});
}
if (p != undefined && typeof p === "object" && "then" in p) {
read._loading = true;
read.state = "pending";
p = p.then(res => {
read._loading = false;
read.state = "ready";
ctx.resources[id].data = res;
p = null;
notifySuspense(contexts);
return res;
}).catch(err => {
read._loading = false;
read.state = "errored";
read.error = error = castError(err);
p = null;
notifySuspense(contexts);
throw error;
});
if (ctx.serialize) ctx.serialize(id, p, options.deferStream);
return p;
}
ctx.resources[id].data = p;
if (ctx.serialize) ctx.serialize(id, p);
p = null;
return ctx.resources[id].data;
}
if (options.ssrLoadFrom !== "initial") load();
const ref = [read, {
refetch: load,
mutate: v => value = v
}];
if (p) resource.ref = ref;
return ref;
}
function lazy(fn) {
let p;
let load = id => {
if (!p) {
p = fn();
p.then(mod => p.resolved = mod.default);
if (id) sharedConfig.context.lazy[id] = p;
}
return p;
};
const contexts = new Set();
const wrap = props => {
const id = sharedConfig.context.id;
let ref = sharedConfig.context.lazy[id];
if (ref) p = ref;else load(id);
if (p.resolved) return p.resolved(props);
const ctx = useContext(SuspenseContext);
const track = {
_loading: true,
error: undefined
};
if (ctx) {
ctx.resources.set(id, track);
contexts.add(ctx);
}
if (sharedConfig.context.async) {
sharedConfig.context.block(p.then(() => {
track._loading = false;
notifySuspense(contexts);
}));
}
return "";
};
wrap.preload = load;
return wrap;
}
function suspenseComplete(c) {
for (const r of c.resources.values()) {
if (r._loading) return false;
}
return true;
}
function notifySuspense(contexts) {
for (const c of contexts) {
if (!suspenseComplete(c)) {
continue;
}
c.completed();
contexts.delete(c);
}
}
function enableScheduling() {}
function enableHydration() {}
function startTransition(fn) {
fn();
}
function useTransition() {
return [() => false, fn => {
fn();
}];
}
function SuspenseList(props) {
if (sharedConfig.context && !sharedConfig.context.noHydrate) {
const c = sharedConfig.context;
setHydrateContext(nextHydrateContext());
const result = props.children;
setHydrateContext(c);
return result;
}
return props.children;
}
function Suspense(props) {
let done;
const ctx = sharedConfig.context;
const id = sharedConfig.getContextId();
const o = createOwner();
const value = ctx.suspense[id] || (ctx.suspense[id] = {
resources: new Map(),
completed: () => {
const res = runSuspense();
if (suspenseComplete(value)) {
done(resolveSSRNode(escape(res)));
}
}
});
function suspenseError(err) {
if (!done || !done(undefined, err)) {
runWithOwner(o.owner, () => {
throw err;
});
}
}
function runSuspense() {
setHydrateContext({
...ctx,
count: 0
});
cleanNode(o);
return runWithOwner(o, () => createComponent(SuspenseContext.Provider, {
value,
get children() {
return catchError(() => props.children, suspenseError);
}
}));
}
const res = runSuspense();
if (suspenseComplete(value)) {
delete ctx.suspense[id];
return res;
}
done = ctx.async ? ctx.registerFragment(id) : undefined;
return catchError(() => {
if (ctx.async) {
setHydrateContext({
...ctx,
count: 0,
id: ctx.id + "0F",
noHydrate: true
});
const res = {
t: `<template id="pl-${id}"></template>${resolveSSRNode(escape(props.fallback))}<!--pl-${id}-->`
};
setHydrateContext(ctx);
return res;
}
setHydrateContext({
...ctx,
count: 0,
id: ctx.id + "0F"
});
ctx.serialize(id, "$$f");
return props.fallback;
}, suspenseError);
}
exports.$DEVCOMP = $DEVCOMP;
exports.$PROXY = $PROXY;
exports.$TRACK = $TRACK;
exports.DEV = DEV;
exports.ErrorBoundary = ErrorBoundary;
exports.For = For;
exports.Index = Index;
exports.Match = Match;
exports.Show = Show;
exports.Suspense = Suspense;
exports.SuspenseList = SuspenseList;
exports.Switch = Switch;
exports.batch = batch;
exports.catchError = catchError;
exports.children = children;
exports.createComponent = createComponent;
exports.createComputed = createComputed;
exports.createContext = createContext;
exports.createDeferred = createDeferred;
exports.createEffect = createEffect;
exports.createMemo = createMemo;
exports.createReaction = createReaction;
exports.createRenderEffect = createRenderEffect;
exports.createResource = createResource;
exports.createRoot = createRoot;
exports.createSelector = createSelector;
exports.createSignal = createSignal;
exports.createUniqueId = createUniqueId;
exports.enableExternalSource = enableExternalSource;
exports.enableHydration = enableHydration;
exports.enableScheduling = enableScheduling;
exports.equalFn = equalFn;
exports.from = from;
exports.getListener = getListener;
exports.getOwner = getOwner;
exports.indexArray = indexArray;
exports.lazy = lazy;
exports.mapArray = mapArray;
exports.mergeProps = mergeProps;
exports.observable = observable;
exports.on = on;
exports.onCleanup = onCleanup;
exports.onError = onError;
exports.onMount = onMount;
exports.requestCallback = requestCallback;
exports.resetErrorBoundaries = resetErrorBoundaries;
exports.runWithOwner = runWithOwner;
exports.sharedConfig = sharedConfig;
exports.splitProps = splitProps;
exports.startTransition = startTransition;
exports.untrack = untrack;
exports.useContext = useContext;
exports.useTransition = useTransition;

View File

@@ -0,0 +1,763 @@
const equalFn = (a, b) => a === b;
const $PROXY = Symbol("solid-proxy");
const $TRACK = Symbol("solid-track");
const $DEVCOMP = Symbol("solid-dev-component");
const DEV = undefined;
const ERROR = Symbol("error");
function castError(err) {
if (err instanceof Error) return err;
return new Error(typeof err === "string" ? err : "Unknown error", {
cause: err
});
}
function handleError(err, owner = Owner) {
const fns = owner && owner.context && owner.context[ERROR];
const error = castError(err);
if (!fns) throw error;
try {
for (const f of fns) f(error);
} catch (e) {
handleError(e, owner && owner.owner || null);
}
}
const UNOWNED = {
context: null,
owner: null,
owned: null,
cleanups: null
};
let Owner = null;
function createOwner() {
const o = {
owner: Owner,
context: Owner ? Owner.context : null,
owned: null,
cleanups: null
};
if (Owner) {
if (!Owner.owned) Owner.owned = [o];else Owner.owned.push(o);
}
return o;
}
function createRoot(fn, detachedOwner) {
const owner = Owner,
current = detachedOwner === undefined ? owner : detachedOwner,
root = fn.length === 0 ? UNOWNED : {
context: current ? current.context : null,
owner: current,
owned: null,
cleanups: null
};
Owner = root;
let result;
try {
result = fn(fn.length === 0 ? () => {} : () => cleanNode(root));
} catch (err) {
handleError(err);
} finally {
Owner = owner;
}
return result;
}
function createSignal(value, options) {
return [() => value, v => {
return value = typeof v === "function" ? v(value) : v;
}];
}
function createComputed(fn, value) {
Owner = createOwner();
try {
fn(value);
} catch (err) {
handleError(err);
} finally {
Owner = Owner.owner;
}
}
const createRenderEffect = createComputed;
function createEffect(fn, value) {}
function createReaction(fn) {
return fn => {
fn();
};
}
function createMemo(fn, value) {
Owner = createOwner();
let v;
try {
v = fn(value);
} catch (err) {
handleError(err);
} finally {
Owner = Owner.owner;
}
return () => v;
}
function createDeferred(source) {
return source;
}
function createSelector(source, fn = equalFn) {
return k => fn(k, source());
}
function batch(fn) {
return fn();
}
const untrack = batch;
function on(deps, fn, options = {}) {
const isArray = Array.isArray(deps);
const defer = options.defer;
return () => {
if (defer) return undefined;
let value;
if (isArray) {
value = [];
for (let i = 0; i < deps.length; i++) value.push(deps[i]());
} else value = deps();
return fn(value);
};
}
function onMount(fn) {}
function onCleanup(fn) {
if (Owner) {
if (!Owner.cleanups) Owner.cleanups = [fn];else Owner.cleanups.push(fn);
}
return fn;
}
function cleanNode(node) {
if (node.owned) {
for (let i = 0; i < node.owned.length; i++) cleanNode(node.owned[i]);
node.owned = null;
}
if (node.cleanups) {
for (let i = 0; i < node.cleanups.length; i++) node.cleanups[i]();
node.cleanups = null;
}
}
function catchError(fn, handler) {
const owner = createOwner();
owner.context = {
...owner.context,
[ERROR]: [handler]
};
Owner = owner;
try {
return fn();
} catch (err) {
handleError(err);
} finally {
Owner = Owner.owner;
}
}
function getListener() {
return null;
}
function createContext(defaultValue) {
const id = Symbol("context");
return {
id,
Provider: createProvider(id),
defaultValue
};
}
function useContext(context) {
return Owner && Owner.context && Owner.context[context.id] !== undefined ? Owner.context[context.id] : context.defaultValue;
}
function getOwner() {
return Owner;
}
function children(fn) {
const memo = createMemo(() => resolveChildren(fn()));
memo.toArray = () => {
const c = memo();
return Array.isArray(c) ? c : c != null ? [c] : [];
};
return memo;
}
function runWithOwner(o, fn) {
const prev = Owner;
Owner = o;
try {
return fn();
} catch (err) {
handleError(err);
} finally {
Owner = prev;
}
}
function resolveChildren(children) {
if (typeof children === "function" && !children.length) return resolveChildren(children());
if (Array.isArray(children)) {
const results = [];
for (let i = 0; i < children.length; i++) {
const result = resolveChildren(children[i]);
if (Array.isArray(result)) {
if (result.length < 32768) results.push.apply(results, result);else for (let j = 0; j < result.length; j++) results.push(result[j]);
} else {
results.push(result);
}
}
return results;
}
return children;
}
function createProvider(id) {
return function provider(props) {
return createMemo(() => {
Owner.context = {
...Owner.context,
[id]: props.value
};
return children(() => props.children);
});
};
}
function requestCallback(fn, options) {
return {
id: 0,
fn: () => {},
startTime: 0,
expirationTime: 0
};
}
function mapArray(list, mapFn, options = {}) {
const items = list();
let s = [];
if (items && items.length) {
for (let i = 0, len = items.length; i < len; i++) s.push(mapFn(items[i], () => i));
} else if (options.fallback) s = [options.fallback()];
return () => s;
}
function indexArray(list, mapFn, options = {}) {
const items = list();
let s = [];
if (items && items.length) {
for (let i = 0, len = items.length; i < len; i++) s.push(mapFn(() => items[i], i));
} else if (options.fallback) s = [options.fallback()];
return () => s;
}
function observable(input) {
return {
subscribe(observer) {
if (!(observer instanceof Object) || observer == null) {
throw new TypeError("Expected the observer to be an object.");
}
const handler = typeof observer === "function" ? observer : observer.next && observer.next.bind(observer);
if (!handler) {
return {
unsubscribe() {}
};
}
const dispose = createRoot(disposer => {
createEffect(() => {
const v = input();
untrack(() => handler(v));
});
return disposer;
});
if (getOwner()) onCleanup(dispose);
return {
unsubscribe() {
dispose();
}
};
},
[Symbol.observable || "@@observable"]() {
return this;
}
};
}
function from(producer) {
const [s, set] = createSignal(undefined);
if ("subscribe" in producer) {
const unsub = producer.subscribe(v => set(() => v));
onCleanup(() => "unsubscribe" in unsub ? unsub.unsubscribe() : unsub());
} else {
const clean = producer(set);
onCleanup(clean);
}
return s;
}
function enableExternalSource(factory) {}
function onError(fn) {
if (Owner) {
if (Owner.context === null || !Owner.context[ERROR]) {
Owner.context = {
...Owner.context,
[ERROR]: [fn]
};
mutateContext(Owner, ERROR, [fn]);
} else Owner.context[ERROR].push(fn);
}
}
function mutateContext(o, key, value) {
if (o.owned) {
for (let i = 0; i < o.owned.length; i++) {
if (o.owned[i].context === o.context) mutateContext(o.owned[i], key, value);
if (!o.owned[i].context) {
o.owned[i].context = o.context;
mutateContext(o.owned[i], key, value);
} else if (!o.owned[i].context[key]) {
o.owned[i].context[key] = value;
mutateContext(o.owned[i], key, value);
}
}
}
}
function escape(s, attr) {
const t = typeof s;
if (t !== "string") {
if (t === "function") return escape(s());
if (Array.isArray(s)) {
for (let i = 0; i < s.length; i++) s[i] = escape(s[i]);
return s;
}
return s;
}
const delim = "<";
const escDelim = "&lt;";
let iDelim = s.indexOf(delim);
let iAmp = s.indexOf("&");
if (iDelim < 0 && iAmp < 0) return s;
let left = 0,
out = "";
while (iDelim >= 0 && iAmp >= 0) {
if (iDelim < iAmp) {
if (left < iDelim) out += s.substring(left, iDelim);
out += escDelim;
left = iDelim + 1;
iDelim = s.indexOf(delim, left);
} else {
if (left < iAmp) out += s.substring(left, iAmp);
out += "&amp;";
left = iAmp + 1;
iAmp = s.indexOf("&", left);
}
}
if (iDelim >= 0) {
do {
if (left < iDelim) out += s.substring(left, iDelim);
out += escDelim;
left = iDelim + 1;
iDelim = s.indexOf(delim, left);
} while (iDelim >= 0);
} else while (iAmp >= 0) {
if (left < iAmp) out += s.substring(left, iAmp);
out += "&amp;";
left = iAmp + 1;
iAmp = s.indexOf("&", left);
}
return left < s.length ? out + s.substring(left) : out;
}
function resolveSSRNode(node) {
const t = typeof node;
if (t === "string") return node;
if (node == null || t === "boolean") return "";
if (Array.isArray(node)) {
let prev = {};
let mapped = "";
for (let i = 0, len = node.length; i < len; i++) {
if (typeof prev !== "object" && typeof node[i] !== "object") mapped += `<!--!$-->`;
mapped += resolveSSRNode(prev = node[i]);
}
return mapped;
}
if (t === "object") return node.t;
if (t === "function") return resolveSSRNode(node());
return String(node);
}
const sharedConfig = {
context: undefined,
getContextId() {
if (!this.context) throw new Error(`getContextId cannot be used under non-hydrating context`);
return getContextId(this.context.count);
},
getNextContextId() {
if (!this.context) throw new Error(`getNextContextId cannot be used under non-hydrating context`);
return getContextId(this.context.count++);
}
};
function getContextId(count) {
const num = String(count),
len = num.length - 1;
return sharedConfig.context.id + (len ? String.fromCharCode(96 + len) : "") + num;
}
function setHydrateContext(context) {
sharedConfig.context = context;
}
function nextHydrateContext() {
return sharedConfig.context ? {
...sharedConfig.context,
id: sharedConfig.getNextContextId(),
count: 0
} : undefined;
}
function createUniqueId() {
return sharedConfig.getNextContextId();
}
function createComponent(Comp, props) {
if (sharedConfig.context && !sharedConfig.context.noHydrate) {
const c = sharedConfig.context;
setHydrateContext(nextHydrateContext());
const r = Comp(props || {});
setHydrateContext(c);
return r;
}
return Comp(props || {});
}
function mergeProps(...sources) {
const target = {};
for (let i = 0; i < sources.length; i++) {
let source = sources[i];
if (typeof source === "function") source = source();
if (source) {
const descriptors = Object.getOwnPropertyDescriptors(source);
for (const key in descriptors) {
if (key === "__proto__" || key === "constructor" || Object.prototype.hasOwnProperty.call(target, key)) continue;
Object.defineProperty(target, key, {
enumerable: true,
get() {
for (let i = sources.length - 1; i >= 0; i--) {
let v,
s = sources[i];
if (typeof s === "function") s = s();
v = (s || {})[key];
if (v !== undefined) return v;
}
}
});
}
}
}
return target;
}
function splitProps(props, ...keys) {
const descriptors = Object.getOwnPropertyDescriptors(props),
split = k => {
const clone = {};
for (let i = 0; i < k.length; i++) {
const key = k[i];
if (descriptors[key]) {
Object.defineProperty(clone, key, descriptors[key]);
delete descriptors[key];
}
}
return clone;
};
return keys.map(split).concat(split(Object.keys(descriptors)));
}
function simpleMap(props, wrap) {
const list = props.each || [],
len = list.length,
fn = props.children;
if (len) {
let mapped = Array(len);
for (let i = 0; i < len; i++) mapped[i] = wrap(fn, list[i], i);
return mapped;
}
return props.fallback;
}
function For(props) {
return simpleMap(props, (fn, item, i) => fn(item, () => i));
}
function Index(props) {
return simpleMap(props, (fn, item, i) => fn(() => item, i));
}
function Show(props) {
let c;
return props.when ? typeof (c = props.children) === "function" && c.length > 0 ? c(props.keyed ? props.when : () => props.when) : c : props.fallback || "";
}
function Switch(props) {
let conditions = props.children;
Array.isArray(conditions) || (conditions = [conditions]);
for (let i = 0; i < conditions.length; i++) {
const w = conditions[i].when;
if (w) {
const c = conditions[i].children;
return typeof c === "function" && c.length > 0 ? c(conditions[i].keyed ? w : () => w) : c;
}
}
return props.fallback || "";
}
function Match(props) {
return props;
}
function resetErrorBoundaries() {}
function ErrorBoundary(props) {
let error,
res,
clean,
sync = true;
const ctx = sharedConfig.context;
const id = sharedConfig.getContextId();
function displayFallback() {
cleanNode(clean);
ctx.serialize(id, error);
setHydrateContext({
...ctx,
count: 0
});
const f = props.fallback;
return typeof f === "function" && f.length ? f(error, () => {}) : f;
}
createMemo(() => {
clean = Owner;
return catchError(() => res = props.children, err => {
error = err;
!sync && ctx.replace("e" + id, displayFallback);
sync = true;
});
});
if (error) return displayFallback();
sync = false;
return {
t: `<!--!$e${id}-->${resolveSSRNode(escape(res))}<!--!$/e${id}-->`
};
}
const SuspenseContext = createContext();
let resourceContext = null;
function createResource(source, fetcher, options = {}) {
if (typeof fetcher !== "function") {
options = fetcher || {};
fetcher = source;
source = true;
}
const contexts = new Set();
const id = sharedConfig.getNextContextId();
let resource = {};
let value = options.storage ? options.storage(options.initialValue)[0]() : options.initialValue;
let p;
let error;
if (sharedConfig.context.async && options.ssrLoadFrom !== "initial") {
resource = sharedConfig.context.resources[id] || (sharedConfig.context.resources[id] = {});
if (resource.ref) {
if (!resource.data && !resource.ref[0]._loading && !resource.ref[0].error) resource.ref[1].refetch();
return resource.ref;
}
}
const prepareResource = () => {
if (error) throw error;
const resolved = options.ssrLoadFrom !== "initial" && sharedConfig.context.async && "data" in sharedConfig.context.resources[id];
if (!resolved && resourceContext) resourceContext.push(id);
if (!resolved && read._loading) {
const ctx = useContext(SuspenseContext);
if (ctx) {
ctx.resources.set(id, read);
contexts.add(ctx);
}
}
return resolved;
};
const read = () => {
return prepareResource() ? sharedConfig.context.resources[id].data : value;
};
const loading = () => {
prepareResource();
return read._loading;
};
read._loading = false;
read.error = undefined;
read.state = "initialValue" in options ? "ready" : "unresolved";
Object.defineProperties(read, {
latest: {
get() {
return read();
}
},
loading: {
get() {
return loading();
}
}
});
function load() {
const ctx = sharedConfig.context;
if (!ctx.async) return read._loading = !!(typeof source === "function" ? source() : source);
if (ctx.resources && id in ctx.resources && "data" in ctx.resources[id]) {
value = ctx.resources[id].data;
return;
}
let lookup;
try {
resourceContext = [];
lookup = typeof source === "function" ? source() : source;
if (resourceContext.length) return;
} finally {
resourceContext = null;
}
if (!p) {
if (lookup == null || lookup === false) return;
p = fetcher(lookup, {
value
});
}
if (p != undefined && typeof p === "object" && "then" in p) {
read._loading = true;
read.state = "pending";
p = p.then(res => {
read._loading = false;
read.state = "ready";
ctx.resources[id].data = res;
p = null;
notifySuspense(contexts);
return res;
}).catch(err => {
read._loading = false;
read.state = "errored";
read.error = error = castError(err);
p = null;
notifySuspense(contexts);
throw error;
});
if (ctx.serialize) ctx.serialize(id, p, options.deferStream);
return p;
}
ctx.resources[id].data = p;
if (ctx.serialize) ctx.serialize(id, p);
p = null;
return ctx.resources[id].data;
}
if (options.ssrLoadFrom !== "initial") load();
const ref = [read, {
refetch: load,
mutate: v => value = v
}];
if (p) resource.ref = ref;
return ref;
}
function lazy(fn) {
let p;
let load = id => {
if (!p) {
p = fn();
p.then(mod => p.resolved = mod.default);
if (id) sharedConfig.context.lazy[id] = p;
}
return p;
};
const contexts = new Set();
const wrap = props => {
const id = sharedConfig.context.id;
let ref = sharedConfig.context.lazy[id];
if (ref) p = ref;else load(id);
if (p.resolved) return p.resolved(props);
const ctx = useContext(SuspenseContext);
const track = {
_loading: true,
error: undefined
};
if (ctx) {
ctx.resources.set(id, track);
contexts.add(ctx);
}
if (sharedConfig.context.async) {
sharedConfig.context.block(p.then(() => {
track._loading = false;
notifySuspense(contexts);
}));
}
return "";
};
wrap.preload = load;
return wrap;
}
function suspenseComplete(c) {
for (const r of c.resources.values()) {
if (r._loading) return false;
}
return true;
}
function notifySuspense(contexts) {
for (const c of contexts) {
if (!suspenseComplete(c)) {
continue;
}
c.completed();
contexts.delete(c);
}
}
function enableScheduling() {}
function enableHydration() {}
function startTransition(fn) {
fn();
}
function useTransition() {
return [() => false, fn => {
fn();
}];
}
function SuspenseList(props) {
if (sharedConfig.context && !sharedConfig.context.noHydrate) {
const c = sharedConfig.context;
setHydrateContext(nextHydrateContext());
const result = props.children;
setHydrateContext(c);
return result;
}
return props.children;
}
function Suspense(props) {
let done;
const ctx = sharedConfig.context;
const id = sharedConfig.getContextId();
const o = createOwner();
const value = ctx.suspense[id] || (ctx.suspense[id] = {
resources: new Map(),
completed: () => {
const res = runSuspense();
if (suspenseComplete(value)) {
done(resolveSSRNode(escape(res)));
}
}
});
function suspenseError(err) {
if (!done || !done(undefined, err)) {
runWithOwner(o.owner, () => {
throw err;
});
}
}
function runSuspense() {
setHydrateContext({
...ctx,
count: 0
});
cleanNode(o);
return runWithOwner(o, () => createComponent(SuspenseContext.Provider, {
value,
get children() {
return catchError(() => props.children, suspenseError);
}
}));
}
const res = runSuspense();
if (suspenseComplete(value)) {
delete ctx.suspense[id];
return res;
}
done = ctx.async ? ctx.registerFragment(id) : undefined;
return catchError(() => {
if (ctx.async) {
setHydrateContext({
...ctx,
count: 0,
id: ctx.id + "0F",
noHydrate: true
});
const res = {
t: `<template id="pl-${id}"></template>${resolveSSRNode(escape(props.fallback))}<!--pl-${id}-->`
};
setHydrateContext(ctx);
return res;
}
setHydrateContext({
...ctx,
count: 0,
id: ctx.id + "0F"
});
ctx.serialize(id, "$$f");
return props.fallback;
}, suspenseError);
}
export { $DEVCOMP, $PROXY, $TRACK, DEV, ErrorBoundary, For, Index, Match, Show, Suspense, SuspenseList, Switch, batch, catchError, children, createComponent, createComputed, createContext, createDeferred, createEffect, createMemo, createReaction, createRenderEffect, createResource, createRoot, createSelector, createSignal, createUniqueId, enableExternalSource, enableHydration, enableScheduling, equalFn, from, getListener, getOwner, indexArray, lazy, mapArray, mergeProps, observable, on, onCleanup, onError, onMount, requestCallback, resetErrorBoundaries, runWithOwner, sharedConfig, splitProps, startTransition, untrack, useContext, useTransition };

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,115 @@
'use strict';
var web = require('solid-js/web');
const $ELEMENT = Symbol("hyper-element");
function createHyperScript(r) {
function h() {
let args = [].slice.call(arguments),
e,
classes = [],
multiExpression = false;
while (Array.isArray(args[0])) args = args[0];
if (args[0][$ELEMENT]) args.unshift(h.Fragment);
typeof args[0] === "string" && detectMultiExpression(args);
const ret = () => {
while (args.length) item(args.shift());
if (e instanceof Element && classes.length) e.classList.add(...classes);
return e;
};
ret[$ELEMENT] = true;
return ret;
function item(l) {
const type = typeof l;
if (l == null) ;else if ("string" === type) {
if (!e) parseClass(l);else e.appendChild(document.createTextNode(l));
} else if ("number" === type || "boolean" === type || "bigint" === type || "symbol" === type || l instanceof Date || l instanceof RegExp) {
e.appendChild(document.createTextNode(l.toString()));
} else if (Array.isArray(l)) {
for (let i = 0; i < l.length; i++) item(l[i]);
} else if (l instanceof Element) {
r.insert(e, l, multiExpression ? null : undefined);
} else if ("object" === type) {
let dynamic = false;
const d = Object.getOwnPropertyDescriptors(l);
for (const k in d) {
if (k === "class" && classes.length !== 0) {
const fixedClasses = classes.join(" "),
value = typeof d["class"].value === "function" ? () => fixedClasses + " " + d["class"].value() : fixedClasses + " " + l["class"];
Object.defineProperty(l, "class", {
...d[k],
value
});
classes = [];
}
if (k !== "ref" && k.slice(0, 2) !== "on" && typeof d[k].value === "function") {
r.dynamicProperty(l, k);
dynamic = true;
} else if (d[k].get) dynamic = true;
}
dynamic ? r.spread(e, l, e instanceof SVGElement, !!args.length) : r.assign(e, l, e instanceof SVGElement, !!args.length);
} else if ("function" === type) {
if (!e) {
let props,
next = args[0];
if (next == null || typeof next === "object" && !Array.isArray(next) && !(next instanceof Element)) props = args.shift();
props || (props = {});
if (args.length) {
props.children = args.length > 1 ? args : args[0];
}
const d = Object.getOwnPropertyDescriptors(props);
for (const k in d) {
if (Array.isArray(d[k].value)) {
const list = d[k].value;
props[k] = () => {
for (let i = 0; i < list.length; i++) {
while (list[i][$ELEMENT]) list[i] = list[i]();
}
return list;
};
r.dynamicProperty(props, k);
} else if (typeof d[k].value === "function" && !d[k].value.length) r.dynamicProperty(props, k);
}
e = r.createComponent(l, props);
args = [];
} else {
while (l[$ELEMENT]) l = l();
r.insert(e, l, multiExpression ? null : undefined);
}
}
}
function parseClass(string) {
const m = string.split(/([\.#]?[^\s#.]+)/);
if (/^\.|#/.test(m[1])) e = document.createElement("div");
for (let i = 0; i < m.length; i++) {
const v = m[i],
s = v.substring(1, v.length);
if (!v) continue;
if (!e) e = r.SVGElements.has(v) ? document.createElementNS("http://www.w3.org/2000/svg", v) : document.createElement(v);else if (v[0] === ".") classes.push(s);else if (v[0] === "#") e.setAttribute("id", s);
}
}
function detectMultiExpression(list) {
for (let i = 1; i < list.length; i++) {
if (typeof list[i] === "function") {
multiExpression = true;
return;
} else if (Array.isArray(list[i])) {
detectMultiExpression(list[i]);
}
}
}
}
h.Fragment = props => props.children;
return h;
}
const h = createHyperScript({
spread: web.spread,
assign: web.assign,
insert: web.insert,
createComponent: web.createComponent,
dynamicProperty: web.dynamicProperty,
SVGElements: web.SVGElements
});
module.exports = h;

View File

@@ -0,0 +1,113 @@
import { SVGElements, dynamicProperty, createComponent, insert, assign, spread } from 'solid-js/web';
const $ELEMENT = Symbol("hyper-element");
function createHyperScript(r) {
function h() {
let args = [].slice.call(arguments),
e,
classes = [],
multiExpression = false;
while (Array.isArray(args[0])) args = args[0];
if (args[0][$ELEMENT]) args.unshift(h.Fragment);
typeof args[0] === "string" && detectMultiExpression(args);
const ret = () => {
while (args.length) item(args.shift());
if (e instanceof Element && classes.length) e.classList.add(...classes);
return e;
};
ret[$ELEMENT] = true;
return ret;
function item(l) {
const type = typeof l;
if (l == null) ;else if ("string" === type) {
if (!e) parseClass(l);else e.appendChild(document.createTextNode(l));
} else if ("number" === type || "boolean" === type || "bigint" === type || "symbol" === type || l instanceof Date || l instanceof RegExp) {
e.appendChild(document.createTextNode(l.toString()));
} else if (Array.isArray(l)) {
for (let i = 0; i < l.length; i++) item(l[i]);
} else if (l instanceof Element) {
r.insert(e, l, multiExpression ? null : undefined);
} else if ("object" === type) {
let dynamic = false;
const d = Object.getOwnPropertyDescriptors(l);
for (const k in d) {
if (k === "class" && classes.length !== 0) {
const fixedClasses = classes.join(" "),
value = typeof d["class"].value === "function" ? () => fixedClasses + " " + d["class"].value() : fixedClasses + " " + l["class"];
Object.defineProperty(l, "class", {
...d[k],
value
});
classes = [];
}
if (k !== "ref" && k.slice(0, 2) !== "on" && typeof d[k].value === "function") {
r.dynamicProperty(l, k);
dynamic = true;
} else if (d[k].get) dynamic = true;
}
dynamic ? r.spread(e, l, e instanceof SVGElement, !!args.length) : r.assign(e, l, e instanceof SVGElement, !!args.length);
} else if ("function" === type) {
if (!e) {
let props,
next = args[0];
if (next == null || typeof next === "object" && !Array.isArray(next) && !(next instanceof Element)) props = args.shift();
props || (props = {});
if (args.length) {
props.children = args.length > 1 ? args : args[0];
}
const d = Object.getOwnPropertyDescriptors(props);
for (const k in d) {
if (Array.isArray(d[k].value)) {
const list = d[k].value;
props[k] = () => {
for (let i = 0; i < list.length; i++) {
while (list[i][$ELEMENT]) list[i] = list[i]();
}
return list;
};
r.dynamicProperty(props, k);
} else if (typeof d[k].value === "function" && !d[k].value.length) r.dynamicProperty(props, k);
}
e = r.createComponent(l, props);
args = [];
} else {
while (l[$ELEMENT]) l = l();
r.insert(e, l, multiExpression ? null : undefined);
}
}
}
function parseClass(string) {
const m = string.split(/([\.#]?[^\s#.]+)/);
if (/^\.|#/.test(m[1])) e = document.createElement("div");
for (let i = 0; i < m.length; i++) {
const v = m[i],
s = v.substring(1, v.length);
if (!v) continue;
if (!e) e = r.SVGElements.has(v) ? document.createElementNS("http://www.w3.org/2000/svg", v) : document.createElement(v);else if (v[0] === ".") classes.push(s);else if (v[0] === "#") e.setAttribute("id", s);
}
}
function detectMultiExpression(list) {
for (let i = 1; i < list.length; i++) {
if (typeof list[i] === "function") {
multiExpression = true;
return;
} else if (Array.isArray(list[i])) {
detectMultiExpression(list[i]);
}
}
}
}
h.Fragment = props => props.children;
return h;
}
const h = createHyperScript({
spread,
assign,
insert,
createComponent,
dynamicProperty,
SVGElements
});
export { h as default };

View File

@@ -0,0 +1,8 @@
{
"name": "solid-js/h/jsx-dev-runtime",
"main": "../jsx-runtime/dist/jsx.cjs",
"module": "../jsx-runtime/dist/jsx.js",
"types": "../jsx-runtime/types/index.d.ts",
"type": "module",
"sideEffects": false
}

View File

@@ -0,0 +1,15 @@
'use strict';
var h = require('solid-js/h');
function Fragment(props) {
return props.children;
}
function jsx(type, props) {
return h(type, props);
}
exports.Fragment = Fragment;
exports.jsx = jsx;
exports.jsxDEV = jsx;
exports.jsxs = jsx;

View File

@@ -0,0 +1,10 @@
import h from 'solid-js/h';
function Fragment(props) {
return props.children;
}
function jsx(type, props) {
return h(type, props);
}
export { Fragment, jsx, jsx as jsxDEV, jsx as jsxs };

View File

@@ -0,0 +1,8 @@
{
"name": "solid-js/h/jsx-runtime",
"main": "./dist/jsx.cjs",
"module": "./dist/jsx.js",
"types": "./types/index.d.ts",
"type": "module",
"sideEffects": false
}

View File

@@ -0,0 +1,11 @@
export type { JSX } from "./jsx.d.ts";
import type { JSX } from "./jsx.d.ts";
declare function Fragment(props: {
children: JSX.Element;
}): JSX.Element;
declare function jsx(type: any, props: any): () => (Node & {
[key: string]: any;
}) | (Node & {
[key: string]: any;
})[];
export { jsx, jsx as jsxs, jsx as jsxDEV, Fragment };

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
{
"name": "solid-js/h",
"main": "./dist/h.cjs",
"module": "./dist/h.js",
"types": "./types/index.d.ts",
"type": "module",
"sideEffects": false
}

View File

@@ -0,0 +1,20 @@
type MountableElement = Element | Document | ShadowRoot | DocumentFragment | Node;
interface Runtime {
insert(parent: MountableElement, accessor: any, marker?: Node | null, init?: any): any;
spread(node: Element, accessor: any, isSVG?: Boolean, skipChildren?: Boolean): void;
assign(node: Element, props: any, isSVG?: Boolean, skipChildren?: Boolean): void;
createComponent(Comp: (props: any) => any, props: any): any;
dynamicProperty(props: any, key: string): any;
SVGElements: Set<string>;
}
type ExpandableNode = Node & {
[key: string]: any;
};
export type HyperScript = {
(...args: any[]): () => ExpandableNode | ExpandableNode[];
Fragment: (props: {
children: (() => ExpandableNode) | (() => ExpandableNode)[];
}) => ExpandableNode[];
};
export declare function createHyperScript(r: Runtime): HyperScript;
export {};

View File

@@ -0,0 +1,3 @@
import type { HyperScript } from "./hyperscript.js";
declare const h: HyperScript;
export default h;

View File

@@ -0,0 +1,583 @@
'use strict';
var web = require('solid-js/web');
const tagRE = /(?:<!--[\S\s]*?-->|<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>)/g;
const attrRE = /(?:\s(?<boolean>[^/\s><=]+?)(?=[\s/>]))|(?:(?<name>\S+?)(?:\s*=\s*(?:(['"])(?<quotedValue>[\s\S]*?)\3|(?<unquotedValue>[^\s>]+))))/g;
const lookup = {
area: true,
base: true,
br: true,
col: true,
embed: true,
hr: true,
img: true,
input: true,
keygen: true,
link: true,
menuitem: true,
meta: true,
param: true,
source: true,
track: true,
wbr: true
};
function parseTag(tag) {
const res = {
type: 'tag',
name: '',
voidElement: false,
attrs: [],
children: []
};
const tagMatch = tag.match(/<\/?([^\s]+?)[/\s>]/);
if (tagMatch) {
res.name = tagMatch[1];
if (lookup[tagMatch[1].toLowerCase()] || tag.charAt(tag.length - 2) === '/') {
res.voidElement = true;
}
if (res.name.startsWith('!--')) {
const endIndex = tag.indexOf('-->');
return {
type: 'comment',
comment: endIndex !== -1 ? tag.slice(4, endIndex) : ''
};
}
}
const reg = new RegExp(attrRE);
for (const match of tag.matchAll(reg)) {
if ((match[1] || match[2]).startsWith('use:')) {
res.attrs.push({
type: 'directive',
name: match[1] || match[2],
value: match[4] || match[5] || ''
});
} else {
res.attrs.push({
type: 'attr',
name: match[1] || match[2],
value: match[4] || match[5] || ''
});
}
}
return res;
}
function pushTextNode(list, html, start) {
const end = html.indexOf('<', start);
const content = html.slice(start, end === -1 ? void 0 : end);
if (!/^\s*$/.test(content)) {
list.push({
type: 'text',
content: content
});
}
}
function pushCommentNode(list, tag) {
const content = tag.replace('<!--', '').replace('-->', '');
if (!/^\s*$/.test(content)) {
list.push({
type: 'comment',
content: content
});
}
}
function parse(html) {
const result = [];
let current = void 0;
let level = -1;
const arr = [];
const byTag = {};
html.replace(tagRE, (tag, index) => {
const isOpen = tag.charAt(1) !== '/';
const isComment = tag.slice(0, 4) === '<!--';
const start = index + tag.length;
const nextChar = html.charAt(start);
let parent = void 0;
if (isOpen && !isComment) {
level++;
current = parseTag(tag);
if (!current.voidElement && nextChar && nextChar !== '<') {
pushTextNode(current.children, html, start);
}
byTag[current.tagName] = current;
if (level === 0) {
result.push(current);
}
parent = arr[level - 1];
if (parent) {
parent.children.push(current);
}
arr[level] = current;
}
if (isComment) {
if (level < 0) {
pushCommentNode(result, tag);
} else {
pushCommentNode(arr[level].children, tag);
}
}
if (isComment || !isOpen || current.voidElement) {
if (!isComment) {
level--;
}
if (nextChar !== '<' && nextChar) {
parent = level === -1 ? result : arr[level].children;
pushTextNode(parent, html, start);
}
}
});
return result;
}
function attrString(attrs) {
const buff = [];
for (const attr of attrs) {
buff.push(attr.name + '="' + attr.value.replace(/"/g, '&quot;') + '"');
}
if (!buff.length) {
return '';
}
return ' ' + buff.join(' ');
}
function stringifier(buff, doc) {
switch (doc.type) {
case 'text':
return buff + doc.content;
case 'tag':
buff += '<' + doc.name + (doc.attrs ? attrString(doc.attrs) : '') + (doc.voidElement ? '/>' : '>');
if (doc.voidElement) {
return buff;
}
return buff + doc.children.reduce(stringifier, '') + '</' + doc.name + '>';
case 'comment':
return buff += '<!--' + doc.content + '-->';
}
}
function stringify(doc) {
return doc.reduce(function (token, rootEl) {
return token + stringifier('', rootEl);
}, '');
}
const cache = new Map();
const VOID_ELEMENTS = /^(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)$/i;
const spaces = " \\f\\n\\r\\t";
const almostEverything = "[^" + spaces + "\\/>\"'=]+";
const attrName = "[ " + spaces + "]+(?:use:<!--#-->|" + almostEverything + ')';
const tagName = "<([A-Za-z$#]+[A-Za-z0-9:_-]*)((?:";
const attrPartials = "(?:\\s*=\\s*(?:'[^']*?'|\"[^\"]*?\"|\\([^)]*?\\)|<[^>]*?>|" + almostEverything + "))?)";
const attrSeeker = new RegExp(tagName + attrName + attrPartials + "+)([ " + spaces + "]*/?>)", "g");
const findAttributes = new RegExp("(" + attrName + "\\s*=\\s*)(<!--#-->|['\"(]([\\w\\s]*<!--#-->[\\w\\s]*)*['\")])", "gi");
const selfClosing = new RegExp(tagName + attrName + attrPartials + "*)([ " + spaces + "]*/>)", "g");
const marker = "<!--#-->";
const reservedNameSpaces = new Set(["class", "on", "oncapture", "style", "use", "prop", "attr"]);
function attrReplacer($0, $1, $2, $3) {
return "<" + $1 + $2.replace(findAttributes, replaceAttributes) + $3;
}
function replaceAttributes($0, $1, $2) {
return $1.replace(/<!--#-->/g, "###") + ($2[0] === '"' || $2[0] === "'" ? $2.replace(/<!--#-->/g, "###") : '"###"');
}
function fullClosing($0, $1, $2) {
return VOID_ELEMENTS.test($1) ? $0 : "<" + $1 + $2 + "></" + $1 + ">";
}
function toPropertyName(name) {
return name.toLowerCase().replace(/-([a-z])/g, (_, w) => w.toUpperCase());
}
function parseDirective(name, value, tag, options) {
if (name === 'use:###' && value === '###') {
const count = options.counter++;
options.exprs.push(`typeof exprs[${count}] === "function" ? r.use(exprs[${count}], ${tag}, exprs[${options.counter++}]) : (()=>{throw new Error("use:### must be a function")})()`);
} else {
throw new Error(`Not support syntax ${name} must be use:{function}`);
}
}
function createHTML(r, {
delegateEvents = true,
functionBuilder = (...args) => new Function(...args)
} = {}) {
let uuid = 1;
r.wrapProps = props => {
const d = Object.getOwnPropertyDescriptors(props);
for (const k in d) {
if (typeof d[k].value === "function" && !d[k].value.length) r.dynamicProperty(props, k);
}
return props;
};
function createTemplate(statics, opt) {
let i = 0,
markup = "";
for (; i < statics.length - 1; i++) {
markup = markup + statics[i] + "<!--#-->";
}
markup = markup + statics[i];
const replaceList = [[selfClosing, fullClosing], [/<(<!--#-->)/g, "<###"], [/\.\.\.(<!--#-->)/g, "###"], [attrSeeker, attrReplacer], [/>\n+\s*/g, ">"], [/\n+\s*</g, "<"], [/\s+</g, " <"], [/>\s+/g, "> "]];
markup = replaceList.reduce((acc, x) => {
return acc.replace(x[0], x[1]);
}, markup);
const pars = parse(markup);
const [html, code] = parseTemplate(pars, opt.funcBuilder),
templates = [];
for (let i = 0; i < html.length; i++) {
templates.push(document.createElement("template"));
templates[i].innerHTML = html[i];
const nomarkers = templates[i].content.querySelectorAll("script,style");
for (let j = 0; j < nomarkers.length; j++) {
const d = nomarkers[j].firstChild?.data || "";
if (d.indexOf(marker) > -1) {
const parts = d.split(marker).reduce((memo, p, i) => {
i && memo.push("");
memo.push(p);
return memo;
}, []);
nomarkers[i].firstChild.replaceWith(...parts);
}
}
}
templates[0].create = code;
cache.set(statics, templates);
return templates;
}
function parseKeyValue(node, tag, name, value, isSVG, isCE, options) {
let expr = value === "###" ? `!doNotWrap ? exprs[${options.counter}]() : exprs[${options.counter++}]` : value.split("###").map((v, i) => i ? ` + (typeof exprs[${options.counter}] === "function" ? exprs[${options.counter}]() : exprs[${options.counter++}]) + "${v}"` : `"${v}"`).join(""),
parts,
namespace;
if ((parts = name.split(":")) && parts[1] && reservedNameSpaces.has(parts[0])) {
name = parts[1];
namespace = parts[0];
}
const isChildProp = r.ChildProperties.has(name);
const isProp = r.Properties.has(name);
if (name === "style") {
const prev = `_$v${uuid++}`;
options.decl.push(`${prev}={}`);
options.exprs.push(`r.style(${tag},${expr},${prev})`);
} else if (name === "classList") {
const prev = `_$v${uuid++}`;
options.decl.push(`${prev}={}`);
options.exprs.push(`r.classList(${tag},${expr},${prev})`);
} else if (namespace !== "attr" && (isChildProp || !isSVG && (r.getPropAlias(name, node.name.toUpperCase()) || isProp) || isCE || namespace === "prop")) {
if (isCE && !isChildProp && !isProp && namespace !== "prop") name = toPropertyName(name);
options.exprs.push(`${tag}.${r.getPropAlias(name, node.name.toUpperCase()) || name} = ${expr}`);
} else {
const ns = isSVG && name.indexOf(":") > -1 && r.SVGNamespace[name.split(":")[0]];
if (ns) options.exprs.push(`r.setAttributeNS(${tag},"${ns}","${name}",${expr})`);else options.exprs.push(`r.setAttribute(${tag},"${r.Aliases[name] || name}",${expr})`);
}
}
function parseAttribute(node, tag, name, value, isSVG, isCE, options) {
if (name.slice(0, 2) === "on") {
if (!name.includes(":")) {
const lc = name.slice(2).toLowerCase();
const delegate = delegateEvents && r.DelegatedEvents.has(lc);
options.exprs.push(`r.addEventListener(${tag},"${lc}",exprs[${options.counter++}],${delegate})`);
delegate && options.delegatedEvents.add(lc);
} else {
let capture = name.startsWith("oncapture:");
options.exprs.push(`${tag}.addEventListener("${name.slice(capture ? 10 : 3)}",exprs[${options.counter++}]${capture ? ",true" : ""})`);
}
} else if (name === "ref") {
options.exprs.push(`exprs[${options.counter++}](${tag})`);
} else {
const childOptions = Object.assign({}, options, {
exprs: []
}),
count = options.counter;
parseKeyValue(node, tag, name, value, isSVG, isCE, childOptions);
options.decl.push(`_fn${count} = (${value === "###" ? "doNotWrap" : ""}) => {\n${childOptions.exprs.join(";\n")};\n}`);
if (value === "###") {
options.exprs.push(`typeof exprs[${count}] === "function" ? r.effect(_fn${count}) : _fn${count}(true)`);
} else {
let check = "";
for (let i = count; i < childOptions.counter; i++) {
i !== count && (check += " || ");
check += `typeof exprs[${i}] === "function"`;
}
options.exprs.push(check + ` ? r.effect(_fn${count}) : _fn${count}()`);
}
options.counter = childOptions.counter;
options.wrap = false;
}
}
function processChildren(node, options) {
const childOptions = Object.assign({}, options, {
first: true,
multi: false,
parent: options.path
});
if (node.children.length > 1) {
for (let i = 0; i < node.children.length; i++) {
const child = node.children[i];
if (child.type === "comment" && child.content === "#" || child.type === "tag" && child.name === "###") {
childOptions.multi = true;
break;
}
}
}
let i = 0;
while (i < node.children.length) {
const child = node.children[i];
if (child.name === "###") {
if (childOptions.multi) {
node.children[i] = {
type: "comment",
content: "#"
};
i++;
} else node.children.splice(i, 1);
processComponent(child, childOptions);
continue;
}
parseNode(child, childOptions);
if (!childOptions.multi && child.type === "comment" && child.content === "#") node.children.splice(i, 1);else i++;
}
options.counter = childOptions.counter;
options.templateId = childOptions.templateId;
options.hasCustomElement = options.hasCustomElement || childOptions.hasCustomElement;
options.isImportNode = options.isImportNode || childOptions.isImportNode;
}
function processComponentProps(propGroups) {
let result = [];
for (const props of propGroups) {
if (Array.isArray(props)) {
if (!props.length) continue;
result.push(`r.wrapProps({${props.join(",") || ""}})`);
} else result.push(props);
}
return result.length > 1 ? `r.mergeProps(${result.join(",")})` : result[0];
}
function processComponent(node, options) {
let props = [];
const keys = Object.keys(node.attrs),
propGroups = [props],
componentIdentifier = options.counter++;
for (let i = 0; i < keys.length; i++) {
const {
type,
name,
value
} = node.attrs[i];
if (type === 'attr') {
if (name === "###") {
propGroups.push(`exprs[${options.counter++}]`);
propGroups.push(props = []);
} else if (value === "###") {
props.push(`"${name}": exprs[${options.counter++}]`);
} else props.push(`"${name}": "${value}"`);
} else if (type === 'directive') {
const tag = `_$el${uuid++}`;
const topDecl = !options.decl.length;
options.decl.push(topDecl ? "" : `${tag} = ${options.path}.${options.first ? "firstChild" : "nextSibling"}`);
parseDirective(name, value, tag, options);
}
}
if (node.children.length === 1 && node.children[0].type === "comment" && node.children[0].content === "#") {
props.push(`children: () => exprs[${options.counter++}]`);
} else if (node.children.length) {
const children = {
type: "fragment",
children: node.children
},
childOptions = Object.assign({}, options, {
first: true,
decl: [],
exprs: [],
parent: false
});
parseNode(children, childOptions);
props.push(`children: () => { ${childOptions.exprs.join(";\n")}}`);
options.templateId = childOptions.templateId;
options.counter = childOptions.counter;
}
let tag;
if (options.multi) {
tag = `_$el${uuid++}`;
options.decl.push(`${tag} = ${options.path}.${options.first ? "firstChild" : "nextSibling"}`);
}
if (options.parent) options.exprs.push(`r.insert(${options.parent}, r.createComponent(exprs[${componentIdentifier}],${processComponentProps(propGroups)})${tag ? `, ${tag}` : ""})`);else options.exprs.push(`${options.fragment ? "" : "return "}r.createComponent(exprs[${componentIdentifier}],${processComponentProps(propGroups)})`);
options.path = tag;
options.first = false;
}
function parseNode(node, options) {
if (node.type === "fragment") {
const parts = [];
node.children.forEach(child => {
if (child.type === "tag") {
if (child.name === "###") {
const childOptions = Object.assign({}, options, {
first: true,
fragment: true,
decl: [],
exprs: []
});
processComponent(child, childOptions);
parts.push(childOptions.exprs[0]);
options.counter = childOptions.counter;
options.templateId = childOptions.templateId;
return;
}
options.templateId++;
const id = uuid;
const childOptions = Object.assign({}, options, {
first: true,
decl: [],
exprs: []
});
options.templateNodes.push([child]);
parseNode(child, childOptions);
parts.push(`function() { ${childOptions.decl.join(",\n") + ";\n" + childOptions.exprs.join(";\n") + `;\nreturn _$el${id};\n`}}()`);
options.counter = childOptions.counter;
options.templateId = childOptions.templateId;
} else if (child.type === "text") {
parts.push(`"${child.content}"`);
} else if (child.type === "comment") {
if (child.content === "#") parts.push(`exprs[${options.counter++}]`);else if (child.content) {
for (let i = 0; i < child.content.split("###").length - 1; i++) {
parts.push(`exprs[${options.counter++}]`);
}
}
}
});
options.exprs.push(`return [${parts.join(", \n")}]`);
} else if (node.type === "tag") {
const tag = `_$el${uuid++}`;
const topDecl = !options.decl.length;
const templateId = options.templateId;
options.decl.push(topDecl ? "" : `${tag} = ${options.path}.${options.first ? "firstChild" : "nextSibling"}`);
const isSVG = r.SVGElements.has(node.name);
const isCE = node.name.includes("-") || node.attrs.some(e => e.name === "is");
options.hasCustomElement = isCE;
options.isImportNode = (node.name === 'img' || node.name === 'iframe') && node.attrs.some(e => e.name === "loading" && e.value === 'lazy');
if (node.attrs.some(e => e.name === "###")) {
const spreadArgs = [];
let current = "";
const newAttrs = [];
for (let i = 0; i < node.attrs.length; i++) {
const {
type,
name,
value
} = node.attrs[i];
if (type === 'attr') {
if (value.includes("###")) {
let count = options.counter++;
current += `${name}: ${name !== "ref" ? `typeof exprs[${count}] === "function" ? exprs[${count}]() : ` : ""}exprs[${count}],`;
} else if (name === "###") {
if (current.length) {
spreadArgs.push(`()=>({${current}})`);
current = "";
}
spreadArgs.push(`exprs[${options.counter++}]`);
} else {
newAttrs.push(node.attrs[i]);
}
} else if (type === 'directive') {
parseDirective(name, value, tag, options);
}
}
node.attrs = newAttrs;
if (current.length) {
spreadArgs.push(`()=>({${current}})`);
}
options.exprs.push(`r.spread(${tag},${spreadArgs.length === 1 ? `typeof ${spreadArgs[0]} === "function" ? r.mergeProps(${spreadArgs[0]}) : ${spreadArgs[0]}` : `r.mergeProps(${spreadArgs.join(",")})`},${isSVG},${!!node.children.length})`);
} else {
for (let i = 0; i < node.attrs.length; i++) {
const {
type,
name,
value
} = node.attrs[i];
if (type === 'directive') {
parseDirective(name, value, tag, options);
node.attrs.splice(i, 1);
i--;
} else if (type === "attr") {
if (value.includes("###")) {
node.attrs.splice(i, 1);
i--;
parseAttribute(node, tag, name, value, isSVG, isCE, options);
}
}
}
}
options.path = tag;
options.first = false;
processChildren(node, options);
if (topDecl) {
options.decl[0] = options.hasCustomElement || options.isImportNode ? `const ${tag} = r.untrack(() => document.importNode(tmpls[${templateId}].content.firstChild, true))` : `const ${tag} = tmpls[${templateId}].content.firstChild.cloneNode(true)`;
}
} else if (node.type === "text") {
const tag = `_$el${uuid++}`;
options.decl.push(`${tag} = ${options.path}.${options.first ? "firstChild" : "nextSibling"}`);
options.path = tag;
options.first = false;
} else if (node.type === "comment") {
const tag = `_$el${uuid++}`;
options.decl.push(`${tag} = ${options.path}.${options.first ? "firstChild" : "nextSibling"}`);
if (node.content === "#") {
if (options.multi) {
options.exprs.push(`r.insert(${options.parent}, exprs[${options.counter++}], ${tag})`);
} else options.exprs.push(`r.insert(${options.parent}, exprs[${options.counter++}])`);
}
options.path = tag;
options.first = false;
}
}
function parseTemplate(nodes, funcBuilder) {
const options = {
path: "",
decl: [],
exprs: [],
delegatedEvents: new Set(),
counter: 0,
first: true,
multi: false,
templateId: 0,
templateNodes: []
},
id = uuid,
origNodes = nodes;
let toplevel;
if (nodes.length > 1) {
nodes = [{
type: "fragment",
children: nodes
}];
}
if (nodes[0].name === "###") {
toplevel = true;
processComponent(nodes[0], options);
} else parseNode(nodes[0], options);
r.delegateEvents(Array.from(options.delegatedEvents));
const templateNodes = [origNodes].concat(options.templateNodes);
return [templateNodes.map(t => stringify(t)), funcBuilder("tmpls", "exprs", "r", options.decl.join(",\n") + ";\n" + options.exprs.join(";\n") + (toplevel ? "" : `;\nreturn _$el${id};\n`))];
}
function html(statics, ...args) {
const templates = cache.get(statics) || createTemplate(statics, {
funcBuilder: functionBuilder
});
return templates[0].create(templates, args, r);
}
return html;
}
const html = createHTML({
effect: web.effect,
style: web.style,
insert: web.insert,
untrack: web.untrack,
spread: web.spread,
createComponent: web.createComponent,
delegateEvents: web.delegateEvents,
classList: web.classList,
mergeProps: web.mergeProps,
dynamicProperty: web.dynamicProperty,
setAttribute: web.setAttribute,
setAttributeNS: web.setAttributeNS,
addEventListener: web.addEventListener,
Aliases: web.Aliases,
getPropAlias: web.getPropAlias,
Properties: web.Properties,
ChildProperties: web.ChildProperties,
DelegatedEvents: web.DelegatedEvents,
SVGElements: web.SVGElements,
SVGNamespace: web.SVGNamespace
});
module.exports = html;

View File

@@ -0,0 +1,581 @@
import { SVGNamespace, SVGElements, DelegatedEvents, ChildProperties, Properties, getPropAlias, Aliases, addEventListener, setAttributeNS, setAttribute, dynamicProperty, mergeProps, classList, delegateEvents, createComponent, spread, untrack, insert, style, effect } from 'solid-js/web';
const tagRE = /(?:<!--[\S\s]*?-->|<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>)/g;
const attrRE = /(?:\s(?<boolean>[^/\s><=]+?)(?=[\s/>]))|(?:(?<name>\S+?)(?:\s*=\s*(?:(['"])(?<quotedValue>[\s\S]*?)\3|(?<unquotedValue>[^\s>]+))))/g;
const lookup = {
area: true,
base: true,
br: true,
col: true,
embed: true,
hr: true,
img: true,
input: true,
keygen: true,
link: true,
menuitem: true,
meta: true,
param: true,
source: true,
track: true,
wbr: true
};
function parseTag(tag) {
const res = {
type: 'tag',
name: '',
voidElement: false,
attrs: [],
children: []
};
const tagMatch = tag.match(/<\/?([^\s]+?)[/\s>]/);
if (tagMatch) {
res.name = tagMatch[1];
if (lookup[tagMatch[1].toLowerCase()] || tag.charAt(tag.length - 2) === '/') {
res.voidElement = true;
}
if (res.name.startsWith('!--')) {
const endIndex = tag.indexOf('-->');
return {
type: 'comment',
comment: endIndex !== -1 ? tag.slice(4, endIndex) : ''
};
}
}
const reg = new RegExp(attrRE);
for (const match of tag.matchAll(reg)) {
if ((match[1] || match[2]).startsWith('use:')) {
res.attrs.push({
type: 'directive',
name: match[1] || match[2],
value: match[4] || match[5] || ''
});
} else {
res.attrs.push({
type: 'attr',
name: match[1] || match[2],
value: match[4] || match[5] || ''
});
}
}
return res;
}
function pushTextNode(list, html, start) {
const end = html.indexOf('<', start);
const content = html.slice(start, end === -1 ? void 0 : end);
if (!/^\s*$/.test(content)) {
list.push({
type: 'text',
content: content
});
}
}
function pushCommentNode(list, tag) {
const content = tag.replace('<!--', '').replace('-->', '');
if (!/^\s*$/.test(content)) {
list.push({
type: 'comment',
content: content
});
}
}
function parse(html) {
const result = [];
let current = void 0;
let level = -1;
const arr = [];
const byTag = {};
html.replace(tagRE, (tag, index) => {
const isOpen = tag.charAt(1) !== '/';
const isComment = tag.slice(0, 4) === '<!--';
const start = index + tag.length;
const nextChar = html.charAt(start);
let parent = void 0;
if (isOpen && !isComment) {
level++;
current = parseTag(tag);
if (!current.voidElement && nextChar && nextChar !== '<') {
pushTextNode(current.children, html, start);
}
byTag[current.tagName] = current;
if (level === 0) {
result.push(current);
}
parent = arr[level - 1];
if (parent) {
parent.children.push(current);
}
arr[level] = current;
}
if (isComment) {
if (level < 0) {
pushCommentNode(result, tag);
} else {
pushCommentNode(arr[level].children, tag);
}
}
if (isComment || !isOpen || current.voidElement) {
if (!isComment) {
level--;
}
if (nextChar !== '<' && nextChar) {
parent = level === -1 ? result : arr[level].children;
pushTextNode(parent, html, start);
}
}
});
return result;
}
function attrString(attrs) {
const buff = [];
for (const attr of attrs) {
buff.push(attr.name + '="' + attr.value.replace(/"/g, '&quot;') + '"');
}
if (!buff.length) {
return '';
}
return ' ' + buff.join(' ');
}
function stringifier(buff, doc) {
switch (doc.type) {
case 'text':
return buff + doc.content;
case 'tag':
buff += '<' + doc.name + (doc.attrs ? attrString(doc.attrs) : '') + (doc.voidElement ? '/>' : '>');
if (doc.voidElement) {
return buff;
}
return buff + doc.children.reduce(stringifier, '') + '</' + doc.name + '>';
case 'comment':
return buff += '<!--' + doc.content + '-->';
}
}
function stringify(doc) {
return doc.reduce(function (token, rootEl) {
return token + stringifier('', rootEl);
}, '');
}
const cache = new Map();
const VOID_ELEMENTS = /^(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)$/i;
const spaces = " \\f\\n\\r\\t";
const almostEverything = "[^" + spaces + "\\/>\"'=]+";
const attrName = "[ " + spaces + "]+(?:use:<!--#-->|" + almostEverything + ')';
const tagName = "<([A-Za-z$#]+[A-Za-z0-9:_-]*)((?:";
const attrPartials = "(?:\\s*=\\s*(?:'[^']*?'|\"[^\"]*?\"|\\([^)]*?\\)|<[^>]*?>|" + almostEverything + "))?)";
const attrSeeker = new RegExp(tagName + attrName + attrPartials + "+)([ " + spaces + "]*/?>)", "g");
const findAttributes = new RegExp("(" + attrName + "\\s*=\\s*)(<!--#-->|['\"(]([\\w\\s]*<!--#-->[\\w\\s]*)*['\")])", "gi");
const selfClosing = new RegExp(tagName + attrName + attrPartials + "*)([ " + spaces + "]*/>)", "g");
const marker = "<!--#-->";
const reservedNameSpaces = new Set(["class", "on", "oncapture", "style", "use", "prop", "attr"]);
function attrReplacer($0, $1, $2, $3) {
return "<" + $1 + $2.replace(findAttributes, replaceAttributes) + $3;
}
function replaceAttributes($0, $1, $2) {
return $1.replace(/<!--#-->/g, "###") + ($2[0] === '"' || $2[0] === "'" ? $2.replace(/<!--#-->/g, "###") : '"###"');
}
function fullClosing($0, $1, $2) {
return VOID_ELEMENTS.test($1) ? $0 : "<" + $1 + $2 + "></" + $1 + ">";
}
function toPropertyName(name) {
return name.toLowerCase().replace(/-([a-z])/g, (_, w) => w.toUpperCase());
}
function parseDirective(name, value, tag, options) {
if (name === 'use:###' && value === '###') {
const count = options.counter++;
options.exprs.push(`typeof exprs[${count}] === "function" ? r.use(exprs[${count}], ${tag}, exprs[${options.counter++}]) : (()=>{throw new Error("use:### must be a function")})()`);
} else {
throw new Error(`Not support syntax ${name} must be use:{function}`);
}
}
function createHTML(r, {
delegateEvents = true,
functionBuilder = (...args) => new Function(...args)
} = {}) {
let uuid = 1;
r.wrapProps = props => {
const d = Object.getOwnPropertyDescriptors(props);
for (const k in d) {
if (typeof d[k].value === "function" && !d[k].value.length) r.dynamicProperty(props, k);
}
return props;
};
function createTemplate(statics, opt) {
let i = 0,
markup = "";
for (; i < statics.length - 1; i++) {
markup = markup + statics[i] + "<!--#-->";
}
markup = markup + statics[i];
const replaceList = [[selfClosing, fullClosing], [/<(<!--#-->)/g, "<###"], [/\.\.\.(<!--#-->)/g, "###"], [attrSeeker, attrReplacer], [/>\n+\s*/g, ">"], [/\n+\s*</g, "<"], [/\s+</g, " <"], [/>\s+/g, "> "]];
markup = replaceList.reduce((acc, x) => {
return acc.replace(x[0], x[1]);
}, markup);
const pars = parse(markup);
const [html, code] = parseTemplate(pars, opt.funcBuilder),
templates = [];
for (let i = 0; i < html.length; i++) {
templates.push(document.createElement("template"));
templates[i].innerHTML = html[i];
const nomarkers = templates[i].content.querySelectorAll("script,style");
for (let j = 0; j < nomarkers.length; j++) {
const d = nomarkers[j].firstChild?.data || "";
if (d.indexOf(marker) > -1) {
const parts = d.split(marker).reduce((memo, p, i) => {
i && memo.push("");
memo.push(p);
return memo;
}, []);
nomarkers[i].firstChild.replaceWith(...parts);
}
}
}
templates[0].create = code;
cache.set(statics, templates);
return templates;
}
function parseKeyValue(node, tag, name, value, isSVG, isCE, options) {
let expr = value === "###" ? `!doNotWrap ? exprs[${options.counter}]() : exprs[${options.counter++}]` : value.split("###").map((v, i) => i ? ` + (typeof exprs[${options.counter}] === "function" ? exprs[${options.counter}]() : exprs[${options.counter++}]) + "${v}"` : `"${v}"`).join(""),
parts,
namespace;
if ((parts = name.split(":")) && parts[1] && reservedNameSpaces.has(parts[0])) {
name = parts[1];
namespace = parts[0];
}
const isChildProp = r.ChildProperties.has(name);
const isProp = r.Properties.has(name);
if (name === "style") {
const prev = `_$v${uuid++}`;
options.decl.push(`${prev}={}`);
options.exprs.push(`r.style(${tag},${expr},${prev})`);
} else if (name === "classList") {
const prev = `_$v${uuid++}`;
options.decl.push(`${prev}={}`);
options.exprs.push(`r.classList(${tag},${expr},${prev})`);
} else if (namespace !== "attr" && (isChildProp || !isSVG && (r.getPropAlias(name, node.name.toUpperCase()) || isProp) || isCE || namespace === "prop")) {
if (isCE && !isChildProp && !isProp && namespace !== "prop") name = toPropertyName(name);
options.exprs.push(`${tag}.${r.getPropAlias(name, node.name.toUpperCase()) || name} = ${expr}`);
} else {
const ns = isSVG && name.indexOf(":") > -1 && r.SVGNamespace[name.split(":")[0]];
if (ns) options.exprs.push(`r.setAttributeNS(${tag},"${ns}","${name}",${expr})`);else options.exprs.push(`r.setAttribute(${tag},"${r.Aliases[name] || name}",${expr})`);
}
}
function parseAttribute(node, tag, name, value, isSVG, isCE, options) {
if (name.slice(0, 2) === "on") {
if (!name.includes(":")) {
const lc = name.slice(2).toLowerCase();
const delegate = delegateEvents && r.DelegatedEvents.has(lc);
options.exprs.push(`r.addEventListener(${tag},"${lc}",exprs[${options.counter++}],${delegate})`);
delegate && options.delegatedEvents.add(lc);
} else {
let capture = name.startsWith("oncapture:");
options.exprs.push(`${tag}.addEventListener("${name.slice(capture ? 10 : 3)}",exprs[${options.counter++}]${capture ? ",true" : ""})`);
}
} else if (name === "ref") {
options.exprs.push(`exprs[${options.counter++}](${tag})`);
} else {
const childOptions = Object.assign({}, options, {
exprs: []
}),
count = options.counter;
parseKeyValue(node, tag, name, value, isSVG, isCE, childOptions);
options.decl.push(`_fn${count} = (${value === "###" ? "doNotWrap" : ""}) => {\n${childOptions.exprs.join(";\n")};\n}`);
if (value === "###") {
options.exprs.push(`typeof exprs[${count}] === "function" ? r.effect(_fn${count}) : _fn${count}(true)`);
} else {
let check = "";
for (let i = count; i < childOptions.counter; i++) {
i !== count && (check += " || ");
check += `typeof exprs[${i}] === "function"`;
}
options.exprs.push(check + ` ? r.effect(_fn${count}) : _fn${count}()`);
}
options.counter = childOptions.counter;
options.wrap = false;
}
}
function processChildren(node, options) {
const childOptions = Object.assign({}, options, {
first: true,
multi: false,
parent: options.path
});
if (node.children.length > 1) {
for (let i = 0; i < node.children.length; i++) {
const child = node.children[i];
if (child.type === "comment" && child.content === "#" || child.type === "tag" && child.name === "###") {
childOptions.multi = true;
break;
}
}
}
let i = 0;
while (i < node.children.length) {
const child = node.children[i];
if (child.name === "###") {
if (childOptions.multi) {
node.children[i] = {
type: "comment",
content: "#"
};
i++;
} else node.children.splice(i, 1);
processComponent(child, childOptions);
continue;
}
parseNode(child, childOptions);
if (!childOptions.multi && child.type === "comment" && child.content === "#") node.children.splice(i, 1);else i++;
}
options.counter = childOptions.counter;
options.templateId = childOptions.templateId;
options.hasCustomElement = options.hasCustomElement || childOptions.hasCustomElement;
options.isImportNode = options.isImportNode || childOptions.isImportNode;
}
function processComponentProps(propGroups) {
let result = [];
for (const props of propGroups) {
if (Array.isArray(props)) {
if (!props.length) continue;
result.push(`r.wrapProps({${props.join(",") || ""}})`);
} else result.push(props);
}
return result.length > 1 ? `r.mergeProps(${result.join(",")})` : result[0];
}
function processComponent(node, options) {
let props = [];
const keys = Object.keys(node.attrs),
propGroups = [props],
componentIdentifier = options.counter++;
for (let i = 0; i < keys.length; i++) {
const {
type,
name,
value
} = node.attrs[i];
if (type === 'attr') {
if (name === "###") {
propGroups.push(`exprs[${options.counter++}]`);
propGroups.push(props = []);
} else if (value === "###") {
props.push(`"${name}": exprs[${options.counter++}]`);
} else props.push(`"${name}": "${value}"`);
} else if (type === 'directive') {
const tag = `_$el${uuid++}`;
const topDecl = !options.decl.length;
options.decl.push(topDecl ? "" : `${tag} = ${options.path}.${options.first ? "firstChild" : "nextSibling"}`);
parseDirective(name, value, tag, options);
}
}
if (node.children.length === 1 && node.children[0].type === "comment" && node.children[0].content === "#") {
props.push(`children: () => exprs[${options.counter++}]`);
} else if (node.children.length) {
const children = {
type: "fragment",
children: node.children
},
childOptions = Object.assign({}, options, {
first: true,
decl: [],
exprs: [],
parent: false
});
parseNode(children, childOptions);
props.push(`children: () => { ${childOptions.exprs.join(";\n")}}`);
options.templateId = childOptions.templateId;
options.counter = childOptions.counter;
}
let tag;
if (options.multi) {
tag = `_$el${uuid++}`;
options.decl.push(`${tag} = ${options.path}.${options.first ? "firstChild" : "nextSibling"}`);
}
if (options.parent) options.exprs.push(`r.insert(${options.parent}, r.createComponent(exprs[${componentIdentifier}],${processComponentProps(propGroups)})${tag ? `, ${tag}` : ""})`);else options.exprs.push(`${options.fragment ? "" : "return "}r.createComponent(exprs[${componentIdentifier}],${processComponentProps(propGroups)})`);
options.path = tag;
options.first = false;
}
function parseNode(node, options) {
if (node.type === "fragment") {
const parts = [];
node.children.forEach(child => {
if (child.type === "tag") {
if (child.name === "###") {
const childOptions = Object.assign({}, options, {
first: true,
fragment: true,
decl: [],
exprs: []
});
processComponent(child, childOptions);
parts.push(childOptions.exprs[0]);
options.counter = childOptions.counter;
options.templateId = childOptions.templateId;
return;
}
options.templateId++;
const id = uuid;
const childOptions = Object.assign({}, options, {
first: true,
decl: [],
exprs: []
});
options.templateNodes.push([child]);
parseNode(child, childOptions);
parts.push(`function() { ${childOptions.decl.join(",\n") + ";\n" + childOptions.exprs.join(";\n") + `;\nreturn _$el${id};\n`}}()`);
options.counter = childOptions.counter;
options.templateId = childOptions.templateId;
} else if (child.type === "text") {
parts.push(`"${child.content}"`);
} else if (child.type === "comment") {
if (child.content === "#") parts.push(`exprs[${options.counter++}]`);else if (child.content) {
for (let i = 0; i < child.content.split("###").length - 1; i++) {
parts.push(`exprs[${options.counter++}]`);
}
}
}
});
options.exprs.push(`return [${parts.join(", \n")}]`);
} else if (node.type === "tag") {
const tag = `_$el${uuid++}`;
const topDecl = !options.decl.length;
const templateId = options.templateId;
options.decl.push(topDecl ? "" : `${tag} = ${options.path}.${options.first ? "firstChild" : "nextSibling"}`);
const isSVG = r.SVGElements.has(node.name);
const isCE = node.name.includes("-") || node.attrs.some(e => e.name === "is");
options.hasCustomElement = isCE;
options.isImportNode = (node.name === 'img' || node.name === 'iframe') && node.attrs.some(e => e.name === "loading" && e.value === 'lazy');
if (node.attrs.some(e => e.name === "###")) {
const spreadArgs = [];
let current = "";
const newAttrs = [];
for (let i = 0; i < node.attrs.length; i++) {
const {
type,
name,
value
} = node.attrs[i];
if (type === 'attr') {
if (value.includes("###")) {
let count = options.counter++;
current += `${name}: ${name !== "ref" ? `typeof exprs[${count}] === "function" ? exprs[${count}]() : ` : ""}exprs[${count}],`;
} else if (name === "###") {
if (current.length) {
spreadArgs.push(`()=>({${current}})`);
current = "";
}
spreadArgs.push(`exprs[${options.counter++}]`);
} else {
newAttrs.push(node.attrs[i]);
}
} else if (type === 'directive') {
parseDirective(name, value, tag, options);
}
}
node.attrs = newAttrs;
if (current.length) {
spreadArgs.push(`()=>({${current}})`);
}
options.exprs.push(`r.spread(${tag},${spreadArgs.length === 1 ? `typeof ${spreadArgs[0]} === "function" ? r.mergeProps(${spreadArgs[0]}) : ${spreadArgs[0]}` : `r.mergeProps(${spreadArgs.join(",")})`},${isSVG},${!!node.children.length})`);
} else {
for (let i = 0; i < node.attrs.length; i++) {
const {
type,
name,
value
} = node.attrs[i];
if (type === 'directive') {
parseDirective(name, value, tag, options);
node.attrs.splice(i, 1);
i--;
} else if (type === "attr") {
if (value.includes("###")) {
node.attrs.splice(i, 1);
i--;
parseAttribute(node, tag, name, value, isSVG, isCE, options);
}
}
}
}
options.path = tag;
options.first = false;
processChildren(node, options);
if (topDecl) {
options.decl[0] = options.hasCustomElement || options.isImportNode ? `const ${tag} = r.untrack(() => document.importNode(tmpls[${templateId}].content.firstChild, true))` : `const ${tag} = tmpls[${templateId}].content.firstChild.cloneNode(true)`;
}
} else if (node.type === "text") {
const tag = `_$el${uuid++}`;
options.decl.push(`${tag} = ${options.path}.${options.first ? "firstChild" : "nextSibling"}`);
options.path = tag;
options.first = false;
} else if (node.type === "comment") {
const tag = `_$el${uuid++}`;
options.decl.push(`${tag} = ${options.path}.${options.first ? "firstChild" : "nextSibling"}`);
if (node.content === "#") {
if (options.multi) {
options.exprs.push(`r.insert(${options.parent}, exprs[${options.counter++}], ${tag})`);
} else options.exprs.push(`r.insert(${options.parent}, exprs[${options.counter++}])`);
}
options.path = tag;
options.first = false;
}
}
function parseTemplate(nodes, funcBuilder) {
const options = {
path: "",
decl: [],
exprs: [],
delegatedEvents: new Set(),
counter: 0,
first: true,
multi: false,
templateId: 0,
templateNodes: []
},
id = uuid,
origNodes = nodes;
let toplevel;
if (nodes.length > 1) {
nodes = [{
type: "fragment",
children: nodes
}];
}
if (nodes[0].name === "###") {
toplevel = true;
processComponent(nodes[0], options);
} else parseNode(nodes[0], options);
r.delegateEvents(Array.from(options.delegatedEvents));
const templateNodes = [origNodes].concat(options.templateNodes);
return [templateNodes.map(t => stringify(t)), funcBuilder("tmpls", "exprs", "r", options.decl.join(",\n") + ";\n" + options.exprs.join(";\n") + (toplevel ? "" : `;\nreturn _$el${id};\n`))];
}
function html(statics, ...args) {
const templates = cache.get(statics) || createTemplate(statics, {
funcBuilder: functionBuilder
});
return templates[0].create(templates, args, r);
}
return html;
}
const html = createHTML({
effect,
style,
insert,
untrack,
spread,
createComponent,
delegateEvents,
classList,
mergeProps,
dynamicProperty,
setAttribute,
setAttributeNS,
addEventListener,
Aliases,
getPropAlias,
Properties,
ChildProperties,
DelegatedEvents,
SVGElements,
SVGNamespace
});
export { html as default };

View File

@@ -0,0 +1,8 @@
{
"name": "solid-js/html",
"main": "./dist/html.cjs",
"module": "./dist/html.js",
"types": "./types/index.d.ts",
"type": "module",
"sideEffects": false
}

View File

@@ -0,0 +1,3 @@
import type { HTMLTag } from "./lit.js";
declare const html: HTMLTag;
export default html;

View File

@@ -0,0 +1,38 @@
type MountableElement = Element | Document | ShadowRoot | DocumentFragment | Node;
export type ClassList = {
[k: string]: boolean | undefined;
};
interface Runtime {
effect<T>(fn: (prev?: T) => T, init?: T): any;
untrack<T>(fn: () => T): T;
insert(parent: MountableElement, accessor: any, marker?: Node | null, init?: any): any;
spread<T>(node: Element, accessor: (() => T) | T, isSVG?: Boolean, skipChildren?: Boolean): void;
createComponent(Comp: (props: any) => any, props: any): any;
addEventListener(node: Element, name: string, handler: EventListener | EventListenerObject | (EventListenerObject & AddEventListenerOptions), delegate: boolean): void;
delegateEvents(eventNames: string[]): void;
classList(node: Element, value: ClassList, prev?: ClassList): ClassList;
style(node: Element, value: {
[k: string]: string;
}, prev?: {
[k: string]: string;
}): void;
mergeProps(...sources: unknown[]): unknown;
dynamicProperty(props: any, key: string): any;
setAttribute(node: Element, name: string, value: any): void;
setAttributeNS(node: Element, namespace: string, name: string, value: any): void;
Aliases: Record<string, string>;
getPropAlias(prop: string, tagName: string): string | undefined;
Properties: Set<string>;
ChildProperties: Set<string>;
DelegatedEvents: Set<string>;
SVGElements: Set<string>;
SVGNamespace: Record<string, string>;
}
export type HTMLTag = {
(statics: TemplateStringsArray, ...args: unknown[]): Node | Node[];
};
export declare function createHTML(r: Runtime, { delegateEvents, functionBuilder }?: {
delegateEvents?: boolean;
functionBuilder?: (...args: string[]) => Function;
}): HTMLTag;
export {};

View File

@@ -0,0 +1 @@
export * from "./types/jsx";

View File

@@ -0,0 +1,243 @@
{
"name": "solid-js",
"description": "A declarative JavaScript library for building user interfaces.",
"version": "1.9.14",
"author": "Ryan Carniato",
"license": "MIT",
"homepage": "https://solidjs.com",
"repository": {
"type": "git",
"url": "https://github.com/solidjs/solid"
},
"main": "./dist/server.cjs",
"module": "./dist/server.js",
"unpkg": "./dist/solid.cjs",
"types": "types/index.d.ts",
"sideEffects": false,
"type": "module",
"files": [
"dist",
"store/dist",
"store/types",
"store/package.json",
"web/dist",
"web/types",
"web/package.json",
"web/storage/dist",
"web/storage/types",
"web/storage/package.json",
"h/dist",
"h/types",
"h/package.json",
"h/jsx-runtime/dist",
"h/jsx-runtime/types",
"h/jsx-runtime/package.json",
"h/jsx-dev-runtime/package.json",
"html/dist",
"html/types",
"html/package.json",
"universal/dist",
"universal/types",
"universal/package.json",
"types",
"jsx-runtime.d.ts"
],
"exports": {
".": {
"worker": {
"types": "./types/index.d.ts",
"import": "./dist/server.js",
"require": "./dist/server.cjs"
},
"browser": {
"development": {
"types": "./types/index.d.ts",
"import": "./dist/dev.js",
"require": "./dist/dev.cjs"
},
"types": "./types/index.d.ts",
"import": "./dist/solid.js",
"require": "./dist/solid.cjs"
},
"deno": {
"types": "./types/index.d.ts",
"import": "./dist/server.js",
"require": "./dist/server.cjs"
},
"node": {
"types": "./types/index.d.ts",
"import": "./dist/server.js",
"require": "./dist/server.cjs"
},
"development": {
"types": "./types/index.d.ts",
"import": "./dist/dev.js",
"require": "./dist/dev.cjs"
},
"types": "./types/index.d.ts",
"import": "./dist/solid.js",
"require": "./dist/solid.cjs"
},
"./dist/*": "./dist/*",
"./types/*": "./types/*",
"./jsx-runtime": {
"types": "./types/jsx.d.ts",
"default": "./dist/solid.js"
},
"./jsx-dev-runtime": {
"types": "./types/jsx.d.ts",
"default": "./dist/solid.js"
},
"./store": {
"worker": {
"types": "./store/types/index.d.ts",
"import": "./store/dist/server.js",
"require": "./store/dist/server.cjs"
},
"browser": {
"development": {
"types": "./store/types/index.d.ts",
"import": "./store/dist/dev.js",
"require": "./store/dist/dev.cjs"
},
"types": "./store/types/index.d.ts",
"import": "./store/dist/store.js",
"require": "./store/dist/store.cjs"
},
"deno": {
"types": "./store/types/index.d.ts",
"import": "./store/dist/server.js",
"require": "./store/dist/server.cjs"
},
"node": {
"types": "./store/types/index.d.ts",
"import": "./store/dist/server.js",
"require": "./store/dist/server.cjs"
},
"development": {
"types": "./store/types/index.d.ts",
"import": "./store/dist/dev.js",
"require": "./store/dist/dev.cjs"
},
"types": "./store/types/index.d.ts",
"import": "./store/dist/store.js",
"require": "./store/dist/store.cjs"
},
"./store/dist/*": "./store/dist/*",
"./store/types/*": "./store/types/*",
"./web": {
"worker": {
"types": "./web/types/index.d.ts",
"import": "./web/dist/server.js",
"require": "./web/dist/server.cjs"
},
"browser": {
"development": {
"types": "./web/types/index.d.ts",
"import": "./web/dist/dev.js",
"require": "./web/dist/dev.cjs"
},
"types": "./web/types/index.d.ts",
"import": "./web/dist/web.js",
"require": "./web/dist/web.cjs"
},
"deno": {
"types": "./web/types/index.d.ts",
"import": "./web/dist/server.js",
"require": "./web/dist/server.cjs"
},
"node": {
"types": "./web/types/index.d.ts",
"import": "./web/dist/server.js",
"require": "./web/dist/server.cjs"
},
"development": {
"types": "./web/types/index.d.ts",
"import": "./web/dist/dev.js",
"require": "./web/dist/dev.cjs"
},
"types": "./web/types/index.d.ts",
"import": "./web/dist/web.js",
"require": "./web/dist/web.cjs"
},
"./web/storage": {
"types": "./web/storage/types/index.d.ts",
"import": "./web/storage/dist/storage.js",
"require": "./web/storage/dist/storage.cjs"
},
"./web/dist/*": "./web/dist/*",
"./web/types/*": "./web/types/*",
"./universal": {
"development": {
"types": "./universal/types/index.d.ts",
"import": "./universal/dist/dev.js",
"require": "./universal/dist/dev.cjs"
},
"types": "./universal/types/index.d.ts",
"import": "./universal/dist/universal.js",
"require": "./universal/dist/universal.cjs"
},
"./universal/dist/*": "./universal/dist/*",
"./universal/types/*": "./universal/types/*",
"./h": {
"types": "./h/types/index.d.ts",
"import": "./h/dist/h.js",
"require": "./h/dist/h.cjs"
},
"./h/jsx-runtime": {
"types": "./h/jsx-runtime/types/index.d.ts",
"import": "./h/jsx-runtime/dist/jsx.js",
"require": "./h/jsx-runtime/dist/jsx.cjs"
},
"./h/jsx-dev-runtime": {
"types": "./h/jsx-runtime/types/index.d.ts",
"import": "./h/jsx-runtime/dist/jsx.js",
"require": "./h/jsx-runtime/dist/jsx.cjs"
},
"./h/dist/*": "./h/dist/*",
"./h/types/*": "./h/types/*",
"./html": {
"types": "./html/types/index.d.ts",
"import": "./html/dist/html.js",
"require": "./html/dist/html.cjs"
},
"./html/dist/*": "./html/dist/*",
"./package.json": "./package.json"
},
"keywords": [
"solid",
"solidjs",
"ui",
"reactive",
"components",
"compiler",
"performance"
],
"dependencies": {
"csstype": "^3.1.0",
"seroval": "~1.5.4",
"seroval-plugins": "~1.5.4"
},
"scripts": {
"build": "npm-run-all -nl build:*",
"build:clean": "rimraf dist/ coverage/ store/dist/ web/dist/ web/storage/dist h/dist/ h/jsx-runtime/dist html/dist/ universal/dist/",
"build:js": "rollup -c",
"types": "npm-run-all -nl types:*",
"types:clean": "rimraf types/ store/types/ web/types/ web/storage/types/ h/types/ h/jsx-runtime/types html/types/ universal/types/ src/jsx.d.ts h/jsx-runtime/src/jsx.d.ts",
"types:copy": "ncp ../../node_modules/dom-expressions/src/jsx.d.ts ./src/jsx.d.ts && ncp ../../node_modules/dom-expressions/src/jsx-h.d.ts ./h/jsx-runtime/src/jsx.d.ts",
"types:src": "tsc --project ./tsconfig.build.json && ncp ../../node_modules/dom-expressions/src/jsx.d.ts ./types/jsx.d.ts",
"types:web": "tsc --project ./web/tsconfig.build.json",
"types:web-storage": "tsc --project ./web/storage/tsconfig.build.json",
"types:copy-web": "ncp ../../node_modules/dom-expressions/src/client.d.ts ./web/types/client.d.ts && ncp ../../node_modules/dom-expressions/src/server.d.ts ./web/types/server.d.ts",
"types:store": "tsc --project ./store/tsconfig.build.json",
"types:html": "tsc --project ./html/tsconfig.json && ncp ../../node_modules/lit-dom-expressions/types/index.d.ts ./html/types/lit.d.ts",
"types:h": "tsc --project ./h/tsconfig.json && ncp ../../node_modules/hyper-dom-expressions/types/index.d.ts ./h/types/hyperscript.d.ts",
"types:jsx": "rimraf ./h/jsx-runtime/types && tsc --project ./h/jsx-runtime/tsconfig.json && ncp ../../node_modules/dom-expressions/src/jsx-h.d.ts ./h/jsx-runtime/types/jsx.d.ts",
"types:universal": "tsc --project ./universal/tsconfig.json && ncp ../../node_modules/dom-expressions/src/universal.d.ts ./universal/types/universal.d.ts",
"bench": "node --allow-natives-syntax bench/bench.cjs",
"link": "symlink-dir . node_modules/solid-js",
"test": "vitest run",
"coverage": "vitest run --coverage",
"test-types": "tsc --project tsconfig.test.json"
}
}

View File

@@ -0,0 +1,485 @@
'use strict';
var solidJs = require('solid-js');
const $RAW = Symbol("store-raw"),
$NODE = Symbol("store-node"),
$HAS = Symbol("store-has"),
$SELF = Symbol("store-self");
const DevHooks = {
onStoreNodeUpdate: null
};
function wrap$1(value) {
let p = value[solidJs.$PROXY];
if (!p) {
Object.defineProperty(value, solidJs.$PROXY, {
value: p = new Proxy(value, proxyTraps$1)
});
if (!Array.isArray(value)) {
const keys = Object.keys(value),
desc = Object.getOwnPropertyDescriptors(value),
proto = Object.getPrototypeOf(value);
const isClass = proto !== null && value !== null && typeof value === "object" && !Array.isArray(value) && proto !== Object.prototype;
if (isClass) {
const descriptors = Object.getOwnPropertyDescriptors(proto);
keys.push(...Object.keys(descriptors));
Object.assign(desc, descriptors);
}
for (let i = 0, l = keys.length; i < l; i++) {
const prop = keys[i];
if (isClass && prop === "constructor") continue;
if (desc[prop].get) {
Object.defineProperty(value, prop, {
configurable: true,
enumerable: desc[prop].enumerable,
get: desc[prop].get.bind(p)
});
}
}
}
}
return p;
}
function isWrappable(obj) {
let proto;
return obj != null && typeof obj === "object" && (obj[solidJs.$PROXY] || !(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype || Array.isArray(obj));
}
function unwrap(item, set = new Set()) {
let result, unwrapped, v, prop;
if (result = item != null && item[$RAW]) return result;
if (!isWrappable(item) || set.has(item)) return item;
if (Array.isArray(item)) {
if (Object.isFrozen(item)) item = item.slice(0);else set.add(item);
for (let i = 0, l = item.length; i < l; i++) {
v = item[i];
if ((unwrapped = unwrap(v, set)) !== v) item[i] = unwrapped;
}
} else {
if (Object.isFrozen(item)) item = Object.assign({}, item);else set.add(item);
const keys = Object.keys(item),
desc = Object.getOwnPropertyDescriptors(item);
for (let i = 0, l = keys.length; i < l; i++) {
prop = keys[i];
if (desc[prop].get) continue;
v = item[prop];
if ((unwrapped = unwrap(v, set)) !== v) item[prop] = unwrapped;
}
}
return item;
}
function getNodes(target, symbol) {
let nodes = target[symbol];
if (!nodes) Object.defineProperty(target, symbol, {
value: nodes = Object.create(null)
});
return nodes;
}
function getNode(nodes, property, value) {
if (nodes[property]) return nodes[property];
const [s, set] = solidJs.createSignal(value, {
equals: false,
internal: true
});
s.$ = set;
return nodes[property] = s;
}
function proxyDescriptor$1(target, property) {
const desc = Reflect.getOwnPropertyDescriptor(target, property);
if (!desc || desc.get || !desc.configurable || property === solidJs.$PROXY || property === $NODE) return desc;
delete desc.value;
delete desc.writable;
desc.get = () => target[solidJs.$PROXY][property];
return desc;
}
function trackSelf(target) {
solidJs.getListener() && getNode(getNodes(target, $NODE), $SELF)();
}
function ownKeys(target) {
trackSelf(target);
return Reflect.ownKeys(target);
}
const proxyTraps$1 = {
get(target, property, receiver) {
if (property === $RAW) return target;
if (property === solidJs.$PROXY) return receiver;
if (property === solidJs.$TRACK) {
trackSelf(target);
return receiver;
}
const nodes = getNodes(target, $NODE);
const tracked = nodes[property];
let value = tracked ? tracked() : target[property];
if (property === $NODE || property === $HAS || property === "__proto__") return value;
if (!tracked) {
const desc = Object.getOwnPropertyDescriptor(target, property);
if (solidJs.getListener() && (typeof value !== "function" || Object.prototype.hasOwnProperty.call(target, property)) && !(desc && desc.get)) value = getNode(nodes, property, value)();
}
return isWrappable(value) ? wrap$1(value) : value;
},
has(target, property) {
if (property === $RAW || property === solidJs.$PROXY || property === solidJs.$TRACK || property === $NODE || property === $HAS || property === "__proto__") return true;
solidJs.getListener() && getNode(getNodes(target, $HAS), property)();
return property in target;
},
set() {
console.warn("Cannot mutate a Store directly");
return true;
},
deleteProperty() {
console.warn("Cannot mutate a Store directly");
return true;
},
ownKeys: ownKeys,
getOwnPropertyDescriptor: proxyDescriptor$1
};
function setProperty(state, property, value, deleting = false) {
if (property === "__proto__") {
console.warn(`Refusing to set "__proto__" on a store.`);
return;
}
if (!deleting && state[property] === value) return;
const prev = state[property],
len = state.length;
DevHooks.onStoreNodeUpdate && DevHooks.onStoreNodeUpdate(state, property, value, prev);
if (value === undefined) {
delete state[property];
if (state[$HAS] && state[$HAS][property] && prev !== undefined) state[$HAS][property].$();
} else {
state[property] = value;
if (state[$HAS] && state[$HAS][property] && prev === undefined) state[$HAS][property].$();
}
let nodes = getNodes(state, $NODE),
node;
if (node = getNode(nodes, property, prev)) node.$(() => value);
if (Array.isArray(state) && state.length !== len) {
for (let i = state.length; i < len; i++) (node = nodes[i]) && node.$();
(node = getNode(nodes, "length", len)) && node.$(state.length);
}
(node = nodes[$SELF]) && node.$();
}
function mergeStoreNode(state, value) {
const keys = Object.keys(value);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
if (isUnsafeKey$1(key)) continue;
setProperty(state, key, value[key]);
}
}
function isUnsafeKey$1(property) {
return property === "__proto__" || property === "constructor" || property === "prototype";
}
function updateArray(current, next) {
if (typeof next === "function") next = next(current);
next = unwrap(next);
if (Array.isArray(next)) {
if (current === next) return;
let i = 0,
len = next.length;
for (; i < len; i++) {
const value = next[i];
if (current[i] !== value) setProperty(current, i, value);
}
setProperty(current, "length", len);
} else mergeStoreNode(current, next);
}
function updatePath(current, path, traversed = []) {
let part,
prev = current;
if (path.length > 1) {
part = path.shift();
const partType = typeof part,
isArray = Array.isArray(current);
if (partType === "string" && (part === "__proto__" || path.length > 1 && isUnsafeKey$1(part))) {
console.warn(`Refusing to traverse unsafe key "${part}" on a store.`);
return;
}
if (Array.isArray(part)) {
for (let i = 0; i < part.length; i++) {
updatePath(current, [part[i]].concat(path), traversed);
}
return;
} else if (isArray && partType === "function") {
for (let i = 0; i < current.length; i++) {
if (part(current[i], i)) updatePath(current, [i].concat(path), traversed);
}
return;
} else if (isArray && partType === "object") {
const {
from = 0,
to = current.length - 1,
by = 1
} = part;
for (let i = from; i <= to; i += by) {
updatePath(current, [i].concat(path), traversed);
}
return;
} else if (path.length > 1) {
updatePath(current[part], path, [part].concat(traversed));
return;
}
prev = current[part];
traversed = [part].concat(traversed);
}
let value = path[0];
if (typeof value === "function") {
value = value(prev, traversed);
if (value === prev) return;
}
if (part === undefined && value == undefined) return;
value = unwrap(value);
if (part === undefined || isWrappable(prev) && isWrappable(value) && !Array.isArray(value)) {
mergeStoreNode(prev, value);
} else setProperty(current, part, value);
}
function createStore(...[store, options]) {
const unwrappedStore = unwrap(store || {});
const isArray = Array.isArray(unwrappedStore);
if (typeof unwrappedStore !== "object" && typeof unwrappedStore !== "function") throw new Error(`Unexpected type ${typeof unwrappedStore} received when initializing 'createStore'. Expected an object.`);
const wrappedStore = wrap$1(unwrappedStore);
solidJs.DEV.registerGraph({
value: unwrappedStore,
name: options && options.name
});
function setStore(...args) {
solidJs.batch(() => {
isArray && args.length === 1 ? updateArray(unwrappedStore, args[0]) : updatePath(unwrappedStore, args);
});
}
return [wrappedStore, setStore];
}
function proxyDescriptor(target, property) {
const desc = Reflect.getOwnPropertyDescriptor(target, property);
if (!desc || desc.get || desc.set || !desc.configurable || property === solidJs.$PROXY || property === $NODE) return desc;
delete desc.value;
delete desc.writable;
desc.get = () => target[solidJs.$PROXY][property];
desc.set = v => target[solidJs.$PROXY][property] = v;
return desc;
}
const proxyTraps = {
get(target, property, receiver) {
if (property === $RAW) return target;
if (property === solidJs.$PROXY) return receiver;
if (property === solidJs.$TRACK) {
trackSelf(target);
return receiver;
}
const nodes = getNodes(target, $NODE);
const tracked = nodes[property];
let value = tracked ? tracked() : target[property];
if (property === $NODE || property === $HAS || property === "__proto__") return value;
if (!tracked) {
const desc = Object.getOwnPropertyDescriptor(target, property);
const isFunction = typeof value === "function";
if (solidJs.getListener() && (!isFunction || Object.prototype.hasOwnProperty.call(target, property)) && !(desc && desc.get)) value = getNode(nodes, property, value)();else if (value != null && isFunction && value === Array.prototype[property]) {
return (...args) => solidJs.batch(() => Array.prototype[property].apply(receiver, args));
}
}
return isWrappable(value) ? wrap(value) : value;
},
has(target, property) {
if (property === $RAW || property === solidJs.$PROXY || property === solidJs.$TRACK || property === $NODE || property === $HAS || property === "__proto__") return true;
solidJs.getListener() && getNode(getNodes(target, $HAS), property)();
return property in target;
},
set(target, property, value) {
solidJs.batch(() => setProperty(target, property, unwrap(value)));
return true;
},
deleteProperty(target, property) {
solidJs.batch(() => setProperty(target, property, undefined, true));
return true;
},
ownKeys: ownKeys,
getOwnPropertyDescriptor: proxyDescriptor
};
function wrap(value) {
let p = value[solidJs.$PROXY];
if (!p) {
Object.defineProperty(value, solidJs.$PROXY, {
value: p = new Proxy(value, proxyTraps)
});
const keys = Object.keys(value),
desc = Object.getOwnPropertyDescriptors(value);
const proto = Object.getPrototypeOf(value);
const isClass = proto !== null && value !== null && typeof value === "object" && !Array.isArray(value) && proto !== Object.prototype;
if (isClass) {
let curProto = proto;
while (curProto != null) {
const descriptors = Object.getOwnPropertyDescriptors(curProto);
keys.push(...Object.keys(descriptors));
Object.assign(desc, descriptors);
curProto = Object.getPrototypeOf(curProto);
}
}
for (let i = 0, l = keys.length; i < l; i++) {
const prop = keys[i];
if (isClass && prop === "constructor") continue;
if (desc[prop].get) {
const get = desc[prop].get.bind(p);
Object.defineProperty(value, prop, {
get,
configurable: true
});
}
if (desc[prop].set) {
const og = desc[prop].set,
set = v => solidJs.batch(() => og.call(p, v));
Object.defineProperty(value, prop, {
set,
configurable: true
});
}
}
}
return p;
}
function createMutable(state, options) {
const unwrappedStore = unwrap(state || {});
if (typeof unwrappedStore !== "object" && typeof unwrappedStore !== "function") throw new Error(`Unexpected type ${typeof unwrappedStore} received when initializing 'createMutable'. Expected an object.`);
const wrappedStore = wrap(unwrappedStore);
solidJs.DEV.registerGraph({
value: unwrappedStore,
name: options && options.name
});
return wrappedStore;
}
function modifyMutable(state, modifier) {
solidJs.batch(() => modifier(unwrap(state)));
}
const $ROOT = Symbol("store-root");
function isUnsafeKey(property) {
return property === "__proto__" || property === "constructor" || property === "prototype";
}
function applyState(target, parent, property, merge, key) {
if (isUnsafeKey(property)) return;
const previous = parent[property];
if (target === previous) return;
const isArray = Array.isArray(target);
if (property !== $ROOT && (!isWrappable(target) || !isWrappable(previous) || isArray !== Array.isArray(previous) || key && target[key] !== previous[key])) {
setProperty(parent, property, target);
return;
}
if (isArray) {
if (target.length && previous.length && (!merge || key && target[0] && target[0][key] != null)) {
let i, j, start, end, newEnd, item, newIndicesNext, keyVal;
for (start = 0, end = Math.min(previous.length, target.length); start < end && (previous[start] === target[start] || key && previous[start] && target[start] && previous[start][key] && previous[start][key] === target[start][key]); start++) {
applyState(target[start], previous, start, merge, key);
}
const temp = new Array(target.length),
newIndices = new Map();
for (end = previous.length - 1, newEnd = target.length - 1; end >= start && newEnd >= start && (previous[end] === target[newEnd] || key && previous[end] && target[newEnd] && previous[end][key] && previous[end][key] === target[newEnd][key]); end--, newEnd--) {
temp[newEnd] = previous[end];
}
if (start > newEnd || start > end) {
for (j = start; j <= newEnd; j++) setProperty(previous, j, target[j]);
for (; j < target.length; j++) {
setProperty(previous, j, temp[j]);
applyState(target[j], previous, j, merge, key);
}
if (previous.length > target.length) setProperty(previous, "length", target.length);
return;
}
newIndicesNext = new Array(newEnd + 1);
for (j = newEnd; j >= start; j--) {
item = target[j];
keyVal = key && item ? item[key] : item;
i = newIndices.get(keyVal);
newIndicesNext[j] = i === undefined ? -1 : i;
newIndices.set(keyVal, j);
}
for (i = start; i <= end; i++) {
item = previous[i];
keyVal = key && item ? item[key] : item;
j = newIndices.get(keyVal);
if (j !== undefined && j !== -1) {
temp[j] = previous[i];
j = newIndicesNext[j];
newIndices.set(keyVal, j);
}
}
for (j = start; j < target.length; j++) {
if (j in temp) {
setProperty(previous, j, temp[j]);
applyState(target[j], previous, j, merge, key);
} else setProperty(previous, j, target[j]);
}
} else {
for (let i = 0, len = target.length; i < len; i++) {
applyState(target[i], previous, i, merge, key);
}
}
if (previous.length > target.length) setProperty(previous, "length", target.length);
return;
}
const targetKeys = Object.keys(target);
for (let i = 0, len = targetKeys.length; i < len; i++) {
if (isUnsafeKey(targetKeys[i])) continue;
applyState(target[targetKeys[i]], previous, targetKeys[i], merge, key);
}
const previousKeys = Object.keys(previous);
for (let i = 0, len = previousKeys.length; i < len; i++) {
if (target[previousKeys[i]] === undefined) setProperty(previous, previousKeys[i], undefined);
}
}
function reconcile(value, options = {}) {
const {
merge,
key = "id"
} = options,
v = unwrap(value);
return state => {
if (!isWrappable(state) || !isWrappable(v)) return v;
const res = applyState(v, {
[$ROOT]: state
}, $ROOT, merge, key);
return res === undefined ? state : res;
};
}
const producers = new WeakMap();
const setterTraps = {
get(target, property) {
if (property === $RAW) return target;
const value = target[property];
if (property === solidJs.$PROXY || property === solidJs.$TRACK || property === $NODE || property === $HAS || property === "__proto__") return value;
let proxy;
return isWrappable(value) ? producers.get(value) || (producers.set(value, proxy = new Proxy(value, setterTraps)), proxy) : value;
},
set(target, property, value) {
setProperty(target, property, unwrap(value));
return true;
},
deleteProperty(target, property) {
setProperty(target, property, undefined, true);
return true;
}
};
function produce(fn) {
return state => {
if (isWrappable(state)) {
let proxy;
if (!(proxy = producers.get(state))) {
producers.set(state, proxy = new Proxy(state, setterTraps));
}
fn(proxy);
}
return state;
};
}
const DEV = {
$NODE,
isWrappable,
hooks: DevHooks
} ;
exports.$RAW = $RAW;
exports.DEV = DEV;
exports.createMutable = createMutable;
exports.createStore = createStore;
exports.modifyMutable = modifyMutable;
exports.produce = produce;
exports.reconcile = reconcile;
exports.unwrap = unwrap;

View File

@@ -0,0 +1,476 @@
import { $PROXY, DEV as DEV$1, batch, $TRACK, getListener, createSignal } from 'solid-js';
const $RAW = Symbol("store-raw"),
$NODE = Symbol("store-node"),
$HAS = Symbol("store-has"),
$SELF = Symbol("store-self");
const DevHooks = {
onStoreNodeUpdate: null
};
function wrap$1(value) {
let p = value[$PROXY];
if (!p) {
Object.defineProperty(value, $PROXY, {
value: p = new Proxy(value, proxyTraps$1)
});
if (!Array.isArray(value)) {
const keys = Object.keys(value),
desc = Object.getOwnPropertyDescriptors(value),
proto = Object.getPrototypeOf(value);
const isClass = proto !== null && value !== null && typeof value === "object" && !Array.isArray(value) && proto !== Object.prototype;
if (isClass) {
const descriptors = Object.getOwnPropertyDescriptors(proto);
keys.push(...Object.keys(descriptors));
Object.assign(desc, descriptors);
}
for (let i = 0, l = keys.length; i < l; i++) {
const prop = keys[i];
if (isClass && prop === "constructor") continue;
if (desc[prop].get) {
Object.defineProperty(value, prop, {
configurable: true,
enumerable: desc[prop].enumerable,
get: desc[prop].get.bind(p)
});
}
}
}
}
return p;
}
function isWrappable(obj) {
let proto;
return obj != null && typeof obj === "object" && (obj[$PROXY] || !(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype || Array.isArray(obj));
}
function unwrap(item, set = new Set()) {
let result, unwrapped, v, prop;
if (result = item != null && item[$RAW]) return result;
if (!isWrappable(item) || set.has(item)) return item;
if (Array.isArray(item)) {
if (Object.isFrozen(item)) item = item.slice(0);else set.add(item);
for (let i = 0, l = item.length; i < l; i++) {
v = item[i];
if ((unwrapped = unwrap(v, set)) !== v) item[i] = unwrapped;
}
} else {
if (Object.isFrozen(item)) item = Object.assign({}, item);else set.add(item);
const keys = Object.keys(item),
desc = Object.getOwnPropertyDescriptors(item);
for (let i = 0, l = keys.length; i < l; i++) {
prop = keys[i];
if (desc[prop].get) continue;
v = item[prop];
if ((unwrapped = unwrap(v, set)) !== v) item[prop] = unwrapped;
}
}
return item;
}
function getNodes(target, symbol) {
let nodes = target[symbol];
if (!nodes) Object.defineProperty(target, symbol, {
value: nodes = Object.create(null)
});
return nodes;
}
function getNode(nodes, property, value) {
if (nodes[property]) return nodes[property];
const [s, set] = createSignal(value, {
equals: false,
internal: true
});
s.$ = set;
return nodes[property] = s;
}
function proxyDescriptor$1(target, property) {
const desc = Reflect.getOwnPropertyDescriptor(target, property);
if (!desc || desc.get || !desc.configurable || property === $PROXY || property === $NODE) return desc;
delete desc.value;
delete desc.writable;
desc.get = () => target[$PROXY][property];
return desc;
}
function trackSelf(target) {
getListener() && getNode(getNodes(target, $NODE), $SELF)();
}
function ownKeys(target) {
trackSelf(target);
return Reflect.ownKeys(target);
}
const proxyTraps$1 = {
get(target, property, receiver) {
if (property === $RAW) return target;
if (property === $PROXY) return receiver;
if (property === $TRACK) {
trackSelf(target);
return receiver;
}
const nodes = getNodes(target, $NODE);
const tracked = nodes[property];
let value = tracked ? tracked() : target[property];
if (property === $NODE || property === $HAS || property === "__proto__") return value;
if (!tracked) {
const desc = Object.getOwnPropertyDescriptor(target, property);
if (getListener() && (typeof value !== "function" || Object.prototype.hasOwnProperty.call(target, property)) && !(desc && desc.get)) value = getNode(nodes, property, value)();
}
return isWrappable(value) ? wrap$1(value) : value;
},
has(target, property) {
if (property === $RAW || property === $PROXY || property === $TRACK || property === $NODE || property === $HAS || property === "__proto__") return true;
getListener() && getNode(getNodes(target, $HAS), property)();
return property in target;
},
set() {
console.warn("Cannot mutate a Store directly");
return true;
},
deleteProperty() {
console.warn("Cannot mutate a Store directly");
return true;
},
ownKeys: ownKeys,
getOwnPropertyDescriptor: proxyDescriptor$1
};
function setProperty(state, property, value, deleting = false) {
if (property === "__proto__") {
console.warn(`Refusing to set "__proto__" on a store.`);
return;
}
if (!deleting && state[property] === value) return;
const prev = state[property],
len = state.length;
DevHooks.onStoreNodeUpdate && DevHooks.onStoreNodeUpdate(state, property, value, prev);
if (value === undefined) {
delete state[property];
if (state[$HAS] && state[$HAS][property] && prev !== undefined) state[$HAS][property].$();
} else {
state[property] = value;
if (state[$HAS] && state[$HAS][property] && prev === undefined) state[$HAS][property].$();
}
let nodes = getNodes(state, $NODE),
node;
if (node = getNode(nodes, property, prev)) node.$(() => value);
if (Array.isArray(state) && state.length !== len) {
for (let i = state.length; i < len; i++) (node = nodes[i]) && node.$();
(node = getNode(nodes, "length", len)) && node.$(state.length);
}
(node = nodes[$SELF]) && node.$();
}
function mergeStoreNode(state, value) {
const keys = Object.keys(value);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
if (isUnsafeKey$1(key)) continue;
setProperty(state, key, value[key]);
}
}
function isUnsafeKey$1(property) {
return property === "__proto__" || property === "constructor" || property === "prototype";
}
function updateArray(current, next) {
if (typeof next === "function") next = next(current);
next = unwrap(next);
if (Array.isArray(next)) {
if (current === next) return;
let i = 0,
len = next.length;
for (; i < len; i++) {
const value = next[i];
if (current[i] !== value) setProperty(current, i, value);
}
setProperty(current, "length", len);
} else mergeStoreNode(current, next);
}
function updatePath(current, path, traversed = []) {
let part,
prev = current;
if (path.length > 1) {
part = path.shift();
const partType = typeof part,
isArray = Array.isArray(current);
if (partType === "string" && (part === "__proto__" || path.length > 1 && isUnsafeKey$1(part))) {
console.warn(`Refusing to traverse unsafe key "${part}" on a store.`);
return;
}
if (Array.isArray(part)) {
for (let i = 0; i < part.length; i++) {
updatePath(current, [part[i]].concat(path), traversed);
}
return;
} else if (isArray && partType === "function") {
for (let i = 0; i < current.length; i++) {
if (part(current[i], i)) updatePath(current, [i].concat(path), traversed);
}
return;
} else if (isArray && partType === "object") {
const {
from = 0,
to = current.length - 1,
by = 1
} = part;
for (let i = from; i <= to; i += by) {
updatePath(current, [i].concat(path), traversed);
}
return;
} else if (path.length > 1) {
updatePath(current[part], path, [part].concat(traversed));
return;
}
prev = current[part];
traversed = [part].concat(traversed);
}
let value = path[0];
if (typeof value === "function") {
value = value(prev, traversed);
if (value === prev) return;
}
if (part === undefined && value == undefined) return;
value = unwrap(value);
if (part === undefined || isWrappable(prev) && isWrappable(value) && !Array.isArray(value)) {
mergeStoreNode(prev, value);
} else setProperty(current, part, value);
}
function createStore(...[store, options]) {
const unwrappedStore = unwrap(store || {});
const isArray = Array.isArray(unwrappedStore);
if (typeof unwrappedStore !== "object" && typeof unwrappedStore !== "function") throw new Error(`Unexpected type ${typeof unwrappedStore} received when initializing 'createStore'. Expected an object.`);
const wrappedStore = wrap$1(unwrappedStore);
DEV$1.registerGraph({
value: unwrappedStore,
name: options && options.name
});
function setStore(...args) {
batch(() => {
isArray && args.length === 1 ? updateArray(unwrappedStore, args[0]) : updatePath(unwrappedStore, args);
});
}
return [wrappedStore, setStore];
}
function proxyDescriptor(target, property) {
const desc = Reflect.getOwnPropertyDescriptor(target, property);
if (!desc || desc.get || desc.set || !desc.configurable || property === $PROXY || property === $NODE) return desc;
delete desc.value;
delete desc.writable;
desc.get = () => target[$PROXY][property];
desc.set = v => target[$PROXY][property] = v;
return desc;
}
const proxyTraps = {
get(target, property, receiver) {
if (property === $RAW) return target;
if (property === $PROXY) return receiver;
if (property === $TRACK) {
trackSelf(target);
return receiver;
}
const nodes = getNodes(target, $NODE);
const tracked = nodes[property];
let value = tracked ? tracked() : target[property];
if (property === $NODE || property === $HAS || property === "__proto__") return value;
if (!tracked) {
const desc = Object.getOwnPropertyDescriptor(target, property);
const isFunction = typeof value === "function";
if (getListener() && (!isFunction || Object.prototype.hasOwnProperty.call(target, property)) && !(desc && desc.get)) value = getNode(nodes, property, value)();else if (value != null && isFunction && value === Array.prototype[property]) {
return (...args) => batch(() => Array.prototype[property].apply(receiver, args));
}
}
return isWrappable(value) ? wrap(value) : value;
},
has(target, property) {
if (property === $RAW || property === $PROXY || property === $TRACK || property === $NODE || property === $HAS || property === "__proto__") return true;
getListener() && getNode(getNodes(target, $HAS), property)();
return property in target;
},
set(target, property, value) {
batch(() => setProperty(target, property, unwrap(value)));
return true;
},
deleteProperty(target, property) {
batch(() => setProperty(target, property, undefined, true));
return true;
},
ownKeys: ownKeys,
getOwnPropertyDescriptor: proxyDescriptor
};
function wrap(value) {
let p = value[$PROXY];
if (!p) {
Object.defineProperty(value, $PROXY, {
value: p = new Proxy(value, proxyTraps)
});
const keys = Object.keys(value),
desc = Object.getOwnPropertyDescriptors(value);
const proto = Object.getPrototypeOf(value);
const isClass = proto !== null && value !== null && typeof value === "object" && !Array.isArray(value) && proto !== Object.prototype;
if (isClass) {
let curProto = proto;
while (curProto != null) {
const descriptors = Object.getOwnPropertyDescriptors(curProto);
keys.push(...Object.keys(descriptors));
Object.assign(desc, descriptors);
curProto = Object.getPrototypeOf(curProto);
}
}
for (let i = 0, l = keys.length; i < l; i++) {
const prop = keys[i];
if (isClass && prop === "constructor") continue;
if (desc[prop].get) {
const get = desc[prop].get.bind(p);
Object.defineProperty(value, prop, {
get,
configurable: true
});
}
if (desc[prop].set) {
const og = desc[prop].set,
set = v => batch(() => og.call(p, v));
Object.defineProperty(value, prop, {
set,
configurable: true
});
}
}
}
return p;
}
function createMutable(state, options) {
const unwrappedStore = unwrap(state || {});
if (typeof unwrappedStore !== "object" && typeof unwrappedStore !== "function") throw new Error(`Unexpected type ${typeof unwrappedStore} received when initializing 'createMutable'. Expected an object.`);
const wrappedStore = wrap(unwrappedStore);
DEV$1.registerGraph({
value: unwrappedStore,
name: options && options.name
});
return wrappedStore;
}
function modifyMutable(state, modifier) {
batch(() => modifier(unwrap(state)));
}
const $ROOT = Symbol("store-root");
function isUnsafeKey(property) {
return property === "__proto__" || property === "constructor" || property === "prototype";
}
function applyState(target, parent, property, merge, key) {
if (isUnsafeKey(property)) return;
const previous = parent[property];
if (target === previous) return;
const isArray = Array.isArray(target);
if (property !== $ROOT && (!isWrappable(target) || !isWrappable(previous) || isArray !== Array.isArray(previous) || key && target[key] !== previous[key])) {
setProperty(parent, property, target);
return;
}
if (isArray) {
if (target.length && previous.length && (!merge || key && target[0] && target[0][key] != null)) {
let i, j, start, end, newEnd, item, newIndicesNext, keyVal;
for (start = 0, end = Math.min(previous.length, target.length); start < end && (previous[start] === target[start] || key && previous[start] && target[start] && previous[start][key] && previous[start][key] === target[start][key]); start++) {
applyState(target[start], previous, start, merge, key);
}
const temp = new Array(target.length),
newIndices = new Map();
for (end = previous.length - 1, newEnd = target.length - 1; end >= start && newEnd >= start && (previous[end] === target[newEnd] || key && previous[end] && target[newEnd] && previous[end][key] && previous[end][key] === target[newEnd][key]); end--, newEnd--) {
temp[newEnd] = previous[end];
}
if (start > newEnd || start > end) {
for (j = start; j <= newEnd; j++) setProperty(previous, j, target[j]);
for (; j < target.length; j++) {
setProperty(previous, j, temp[j]);
applyState(target[j], previous, j, merge, key);
}
if (previous.length > target.length) setProperty(previous, "length", target.length);
return;
}
newIndicesNext = new Array(newEnd + 1);
for (j = newEnd; j >= start; j--) {
item = target[j];
keyVal = key && item ? item[key] : item;
i = newIndices.get(keyVal);
newIndicesNext[j] = i === undefined ? -1 : i;
newIndices.set(keyVal, j);
}
for (i = start; i <= end; i++) {
item = previous[i];
keyVal = key && item ? item[key] : item;
j = newIndices.get(keyVal);
if (j !== undefined && j !== -1) {
temp[j] = previous[i];
j = newIndicesNext[j];
newIndices.set(keyVal, j);
}
}
for (j = start; j < target.length; j++) {
if (j in temp) {
setProperty(previous, j, temp[j]);
applyState(target[j], previous, j, merge, key);
} else setProperty(previous, j, target[j]);
}
} else {
for (let i = 0, len = target.length; i < len; i++) {
applyState(target[i], previous, i, merge, key);
}
}
if (previous.length > target.length) setProperty(previous, "length", target.length);
return;
}
const targetKeys = Object.keys(target);
for (let i = 0, len = targetKeys.length; i < len; i++) {
if (isUnsafeKey(targetKeys[i])) continue;
applyState(target[targetKeys[i]], previous, targetKeys[i], merge, key);
}
const previousKeys = Object.keys(previous);
for (let i = 0, len = previousKeys.length; i < len; i++) {
if (target[previousKeys[i]] === undefined) setProperty(previous, previousKeys[i], undefined);
}
}
function reconcile(value, options = {}) {
const {
merge,
key = "id"
} = options,
v = unwrap(value);
return state => {
if (!isWrappable(state) || !isWrappable(v)) return v;
const res = applyState(v, {
[$ROOT]: state
}, $ROOT, merge, key);
return res === undefined ? state : res;
};
}
const producers = new WeakMap();
const setterTraps = {
get(target, property) {
if (property === $RAW) return target;
const value = target[property];
if (property === $PROXY || property === $TRACK || property === $NODE || property === $HAS || property === "__proto__") return value;
let proxy;
return isWrappable(value) ? producers.get(value) || (producers.set(value, proxy = new Proxy(value, setterTraps)), proxy) : value;
},
set(target, property, value) {
setProperty(target, property, unwrap(value));
return true;
},
deleteProperty(target, property) {
setProperty(target, property, undefined, true);
return true;
}
};
function produce(fn) {
return state => {
if (isWrappable(state)) {
let proxy;
if (!(proxy = producers.get(state))) {
producers.set(state, proxy = new Proxy(state, setterTraps));
}
fn(proxy);
}
return state;
};
}
const DEV = {
$NODE,
isWrappable,
hooks: DevHooks
} ;
export { $RAW, DEV, createMutable, createStore, modifyMutable, produce, reconcile, unwrap };

View File

@@ -0,0 +1,133 @@
'use strict';
const $RAW = Symbol("state-raw");
function isWrappable(obj) {
return obj != null && typeof obj === "object" && (Object.getPrototypeOf(obj) === Object.prototype || Array.isArray(obj));
}
function unwrap(item) {
return item;
}
function setProperty(state, property, value, force) {
if (property === "__proto__") return;
if (!force && state[property] === value) return;
if (value === undefined) {
delete state[property];
} else state[property] = value;
}
function mergeStoreNode(state, value, force) {
const keys = Object.keys(value);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
if (isUnsafeKey(key)) continue;
setProperty(state, key, value[key], force);
}
}
function isUnsafeKey(property) {
return property === "__proto__" || property === "constructor" || property === "prototype";
}
function updateArray(current, next) {
if (typeof next === "function") next = next(current);
if (Array.isArray(next)) {
if (current === next) return;
let i = 0,
len = next.length;
for (; i < len; i++) {
const value = next[i];
if (current[i] !== value) setProperty(current, i, value);
}
setProperty(current, "length", len);
} else mergeStoreNode(current, next);
}
function updatePath(current, path, traversed = []) {
let part,
next = current;
if (path.length > 1) {
part = path.shift();
const partType = typeof part,
isArray = Array.isArray(current);
if (partType === "string" && (part === "__proto__" || path.length > 1 && isUnsafeKey(part))) return;
if (Array.isArray(part)) {
for (let i = 0; i < part.length; i++) {
updatePath(current, [part[i]].concat(path), traversed);
}
return;
} else if (isArray && partType === "function") {
for (let i = 0; i < current.length; i++) {
if (part(current[i], i)) updatePath(current, [i].concat(path), traversed);
}
return;
} else if (isArray && partType === "object") {
const {
from = 0,
to = current.length - 1,
by = 1
} = part;
for (let i = from; i <= to; i += by) {
updatePath(current, [i].concat(path), traversed);
}
return;
} else if (path.length > 1) {
updatePath(current[part], path, [part].concat(traversed));
return;
}
next = current[part];
traversed = [part].concat(traversed);
}
let value = path[0];
if (typeof value === "function") {
value = value(next, traversed);
if (value === next) return;
}
if (part === undefined && value == undefined) return;
if (part === undefined || isWrappable(next) && isWrappable(value) && !Array.isArray(value)) {
mergeStoreNode(next, value);
} else setProperty(current, part, value);
}
function createStore(state) {
const isArray = Array.isArray(state);
function setStore(...args) {
isArray && args.length === 1 ? updateArray(state, args[0]) : updatePath(state, args);
}
return [state, setStore];
}
function createMutable(state) {
return state;
}
function modifyMutable(state, modifier) {
modifier(state);
}
function reconcile(value, options = {}) {
return state => {
if (!isWrappable(state) || !isWrappable(value)) return value;
const targetKeys = Object.keys(value);
for (let i = 0, len = targetKeys.length; i < len; i++) {
const key = targetKeys[i];
if (isUnsafeKey(key)) continue;
setProperty(state, key, value[key]);
}
const previousKeys = Object.keys(state);
for (let i = 0, len = previousKeys.length; i < len; i++) {
if (value[previousKeys[i]] === undefined) setProperty(state, previousKeys[i], undefined);
}
return state;
};
}
function produce(fn) {
return state => {
if (isWrappable(state)) fn(state);
return state;
};
}
const DEV = undefined;
exports.$RAW = $RAW;
exports.DEV = DEV;
exports.createMutable = createMutable;
exports.createStore = createStore;
exports.isWrappable = isWrappable;
exports.modifyMutable = modifyMutable;
exports.produce = produce;
exports.reconcile = reconcile;
exports.setProperty = setProperty;
exports.unwrap = unwrap;
exports.updatePath = updatePath;

View File

@@ -0,0 +1,121 @@
const $RAW = Symbol("state-raw");
function isWrappable(obj) {
return obj != null && typeof obj === "object" && (Object.getPrototypeOf(obj) === Object.prototype || Array.isArray(obj));
}
function unwrap(item) {
return item;
}
function setProperty(state, property, value, force) {
if (property === "__proto__") return;
if (!force && state[property] === value) return;
if (value === undefined) {
delete state[property];
} else state[property] = value;
}
function mergeStoreNode(state, value, force) {
const keys = Object.keys(value);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
if (isUnsafeKey(key)) continue;
setProperty(state, key, value[key], force);
}
}
function isUnsafeKey(property) {
return property === "__proto__" || property === "constructor" || property === "prototype";
}
function updateArray(current, next) {
if (typeof next === "function") next = next(current);
if (Array.isArray(next)) {
if (current === next) return;
let i = 0,
len = next.length;
for (; i < len; i++) {
const value = next[i];
if (current[i] !== value) setProperty(current, i, value);
}
setProperty(current, "length", len);
} else mergeStoreNode(current, next);
}
function updatePath(current, path, traversed = []) {
let part,
next = current;
if (path.length > 1) {
part = path.shift();
const partType = typeof part,
isArray = Array.isArray(current);
if (partType === "string" && (part === "__proto__" || path.length > 1 && isUnsafeKey(part))) return;
if (Array.isArray(part)) {
for (let i = 0; i < part.length; i++) {
updatePath(current, [part[i]].concat(path), traversed);
}
return;
} else if (isArray && partType === "function") {
for (let i = 0; i < current.length; i++) {
if (part(current[i], i)) updatePath(current, [i].concat(path), traversed);
}
return;
} else if (isArray && partType === "object") {
const {
from = 0,
to = current.length - 1,
by = 1
} = part;
for (let i = from; i <= to; i += by) {
updatePath(current, [i].concat(path), traversed);
}
return;
} else if (path.length > 1) {
updatePath(current[part], path, [part].concat(traversed));
return;
}
next = current[part];
traversed = [part].concat(traversed);
}
let value = path[0];
if (typeof value === "function") {
value = value(next, traversed);
if (value === next) return;
}
if (part === undefined && value == undefined) return;
if (part === undefined || isWrappable(next) && isWrappable(value) && !Array.isArray(value)) {
mergeStoreNode(next, value);
} else setProperty(current, part, value);
}
function createStore(state) {
const isArray = Array.isArray(state);
function setStore(...args) {
isArray && args.length === 1 ? updateArray(state, args[0]) : updatePath(state, args);
}
return [state, setStore];
}
function createMutable(state) {
return state;
}
function modifyMutable(state, modifier) {
modifier(state);
}
function reconcile(value, options = {}) {
return state => {
if (!isWrappable(state) || !isWrappable(value)) return value;
const targetKeys = Object.keys(value);
for (let i = 0, len = targetKeys.length; i < len; i++) {
const key = targetKeys[i];
if (isUnsafeKey(key)) continue;
setProperty(state, key, value[key]);
}
const previousKeys = Object.keys(state);
for (let i = 0, len = previousKeys.length; i < len; i++) {
if (value[previousKeys[i]] === undefined) setProperty(state, previousKeys[i], undefined);
}
return state;
};
}
function produce(fn) {
return state => {
if (isWrappable(state)) fn(state);
return state;
};
}
const DEV = undefined;
export { $RAW, DEV, createMutable, createStore, isWrappable, modifyMutable, produce, reconcile, setProperty, unwrap, updatePath };

View File

@@ -0,0 +1,463 @@
'use strict';
var solidJs = require('solid-js');
const $RAW = Symbol("store-raw"),
$NODE = Symbol("store-node"),
$HAS = Symbol("store-has"),
$SELF = Symbol("store-self");
function wrap$1(value) {
let p = value[solidJs.$PROXY];
if (!p) {
Object.defineProperty(value, solidJs.$PROXY, {
value: p = new Proxy(value, proxyTraps$1)
});
if (!Array.isArray(value)) {
const keys = Object.keys(value),
desc = Object.getOwnPropertyDescriptors(value),
proto = Object.getPrototypeOf(value);
const isClass = proto !== null && value !== null && typeof value === "object" && !Array.isArray(value) && proto !== Object.prototype;
if (isClass) {
const descriptors = Object.getOwnPropertyDescriptors(proto);
keys.push(...Object.keys(descriptors));
Object.assign(desc, descriptors);
}
for (let i = 0, l = keys.length; i < l; i++) {
const prop = keys[i];
if (isClass && prop === "constructor") continue;
if (desc[prop].get) {
Object.defineProperty(value, prop, {
configurable: true,
enumerable: desc[prop].enumerable,
get: desc[prop].get.bind(p)
});
}
}
}
}
return p;
}
function isWrappable(obj) {
let proto;
return obj != null && typeof obj === "object" && (obj[solidJs.$PROXY] || !(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype || Array.isArray(obj));
}
function unwrap(item, set = new Set()) {
let result, unwrapped, v, prop;
if (result = item != null && item[$RAW]) return result;
if (!isWrappable(item) || set.has(item)) return item;
if (Array.isArray(item)) {
if (Object.isFrozen(item)) item = item.slice(0);else set.add(item);
for (let i = 0, l = item.length; i < l; i++) {
v = item[i];
if ((unwrapped = unwrap(v, set)) !== v) item[i] = unwrapped;
}
} else {
if (Object.isFrozen(item)) item = Object.assign({}, item);else set.add(item);
const keys = Object.keys(item),
desc = Object.getOwnPropertyDescriptors(item);
for (let i = 0, l = keys.length; i < l; i++) {
prop = keys[i];
if (desc[prop].get) continue;
v = item[prop];
if ((unwrapped = unwrap(v, set)) !== v) item[prop] = unwrapped;
}
}
return item;
}
function getNodes(target, symbol) {
let nodes = target[symbol];
if (!nodes) Object.defineProperty(target, symbol, {
value: nodes = Object.create(null)
});
return nodes;
}
function getNode(nodes, property, value) {
if (nodes[property]) return nodes[property];
const [s, set] = solidJs.createSignal(value, {
equals: false,
internal: true
});
s.$ = set;
return nodes[property] = s;
}
function proxyDescriptor$1(target, property) {
const desc = Reflect.getOwnPropertyDescriptor(target, property);
if (!desc || desc.get || !desc.configurable || property === solidJs.$PROXY || property === $NODE) return desc;
delete desc.value;
delete desc.writable;
desc.get = () => target[solidJs.$PROXY][property];
return desc;
}
function trackSelf(target) {
solidJs.getListener() && getNode(getNodes(target, $NODE), $SELF)();
}
function ownKeys(target) {
trackSelf(target);
return Reflect.ownKeys(target);
}
const proxyTraps$1 = {
get(target, property, receiver) {
if (property === $RAW) return target;
if (property === solidJs.$PROXY) return receiver;
if (property === solidJs.$TRACK) {
trackSelf(target);
return receiver;
}
const nodes = getNodes(target, $NODE);
const tracked = nodes[property];
let value = tracked ? tracked() : target[property];
if (property === $NODE || property === $HAS || property === "__proto__") return value;
if (!tracked) {
const desc = Object.getOwnPropertyDescriptor(target, property);
if (solidJs.getListener() && (typeof value !== "function" || Object.prototype.hasOwnProperty.call(target, property)) && !(desc && desc.get)) value = getNode(nodes, property, value)();
}
return isWrappable(value) ? wrap$1(value) : value;
},
has(target, property) {
if (property === $RAW || property === solidJs.$PROXY || property === solidJs.$TRACK || property === $NODE || property === $HAS || property === "__proto__") return true;
solidJs.getListener() && getNode(getNodes(target, $HAS), property)();
return property in target;
},
set() {
return true;
},
deleteProperty() {
return true;
},
ownKeys: ownKeys,
getOwnPropertyDescriptor: proxyDescriptor$1
};
function setProperty(state, property, value, deleting = false) {
if (property === "__proto__") {
return;
}
if (!deleting && state[property] === value) return;
const prev = state[property],
len = state.length;
if (value === undefined) {
delete state[property];
if (state[$HAS] && state[$HAS][property] && prev !== undefined) state[$HAS][property].$();
} else {
state[property] = value;
if (state[$HAS] && state[$HAS][property] && prev === undefined) state[$HAS][property].$();
}
let nodes = getNodes(state, $NODE),
node;
if (node = getNode(nodes, property, prev)) node.$(() => value);
if (Array.isArray(state) && state.length !== len) {
for (let i = state.length; i < len; i++) (node = nodes[i]) && node.$();
(node = getNode(nodes, "length", len)) && node.$(state.length);
}
(node = nodes[$SELF]) && node.$();
}
function mergeStoreNode(state, value) {
const keys = Object.keys(value);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
if (isUnsafeKey$1(key)) continue;
setProperty(state, key, value[key]);
}
}
function isUnsafeKey$1(property) {
return property === "__proto__" || property === "constructor" || property === "prototype";
}
function updateArray(current, next) {
if (typeof next === "function") next = next(current);
next = unwrap(next);
if (Array.isArray(next)) {
if (current === next) return;
let i = 0,
len = next.length;
for (; i < len; i++) {
const value = next[i];
if (current[i] !== value) setProperty(current, i, value);
}
setProperty(current, "length", len);
} else mergeStoreNode(current, next);
}
function updatePath(current, path, traversed = []) {
let part,
prev = current;
if (path.length > 1) {
part = path.shift();
const partType = typeof part,
isArray = Array.isArray(current);
if (partType === "string" && (part === "__proto__" || path.length > 1 && isUnsafeKey$1(part))) {
return;
}
if (Array.isArray(part)) {
for (let i = 0; i < part.length; i++) {
updatePath(current, [part[i]].concat(path), traversed);
}
return;
} else if (isArray && partType === "function") {
for (let i = 0; i < current.length; i++) {
if (part(current[i], i)) updatePath(current, [i].concat(path), traversed);
}
return;
} else if (isArray && partType === "object") {
const {
from = 0,
to = current.length - 1,
by = 1
} = part;
for (let i = from; i <= to; i += by) {
updatePath(current, [i].concat(path), traversed);
}
return;
} else if (path.length > 1) {
updatePath(current[part], path, [part].concat(traversed));
return;
}
prev = current[part];
traversed = [part].concat(traversed);
}
let value = path[0];
if (typeof value === "function") {
value = value(prev, traversed);
if (value === prev) return;
}
if (part === undefined && value == undefined) return;
value = unwrap(value);
if (part === undefined || isWrappable(prev) && isWrappable(value) && !Array.isArray(value)) {
mergeStoreNode(prev, value);
} else setProperty(current, part, value);
}
function createStore(...[store, options]) {
const unwrappedStore = unwrap(store || {});
const isArray = Array.isArray(unwrappedStore);
const wrappedStore = wrap$1(unwrappedStore);
function setStore(...args) {
solidJs.batch(() => {
isArray && args.length === 1 ? updateArray(unwrappedStore, args[0]) : updatePath(unwrappedStore, args);
});
}
return [wrappedStore, setStore];
}
function proxyDescriptor(target, property) {
const desc = Reflect.getOwnPropertyDescriptor(target, property);
if (!desc || desc.get || desc.set || !desc.configurable || property === solidJs.$PROXY || property === $NODE) return desc;
delete desc.value;
delete desc.writable;
desc.get = () => target[solidJs.$PROXY][property];
desc.set = v => target[solidJs.$PROXY][property] = v;
return desc;
}
const proxyTraps = {
get(target, property, receiver) {
if (property === $RAW) return target;
if (property === solidJs.$PROXY) return receiver;
if (property === solidJs.$TRACK) {
trackSelf(target);
return receiver;
}
const nodes = getNodes(target, $NODE);
const tracked = nodes[property];
let value = tracked ? tracked() : target[property];
if (property === $NODE || property === $HAS || property === "__proto__") return value;
if (!tracked) {
const desc = Object.getOwnPropertyDescriptor(target, property);
const isFunction = typeof value === "function";
if (solidJs.getListener() && (!isFunction || Object.prototype.hasOwnProperty.call(target, property)) && !(desc && desc.get)) value = getNode(nodes, property, value)();else if (value != null && isFunction && value === Array.prototype[property]) {
return (...args) => solidJs.batch(() => Array.prototype[property].apply(receiver, args));
}
}
return isWrappable(value) ? wrap(value) : value;
},
has(target, property) {
if (property === $RAW || property === solidJs.$PROXY || property === solidJs.$TRACK || property === $NODE || property === $HAS || property === "__proto__") return true;
solidJs.getListener() && getNode(getNodes(target, $HAS), property)();
return property in target;
},
set(target, property, value) {
solidJs.batch(() => setProperty(target, property, unwrap(value)));
return true;
},
deleteProperty(target, property) {
solidJs.batch(() => setProperty(target, property, undefined, true));
return true;
},
ownKeys: ownKeys,
getOwnPropertyDescriptor: proxyDescriptor
};
function wrap(value) {
let p = value[solidJs.$PROXY];
if (!p) {
Object.defineProperty(value, solidJs.$PROXY, {
value: p = new Proxy(value, proxyTraps)
});
const keys = Object.keys(value),
desc = Object.getOwnPropertyDescriptors(value);
const proto = Object.getPrototypeOf(value);
const isClass = proto !== null && value !== null && typeof value === "object" && !Array.isArray(value) && proto !== Object.prototype;
if (isClass) {
let curProto = proto;
while (curProto != null) {
const descriptors = Object.getOwnPropertyDescriptors(curProto);
keys.push(...Object.keys(descriptors));
Object.assign(desc, descriptors);
curProto = Object.getPrototypeOf(curProto);
}
}
for (let i = 0, l = keys.length; i < l; i++) {
const prop = keys[i];
if (isClass && prop === "constructor") continue;
if (desc[prop].get) {
const get = desc[prop].get.bind(p);
Object.defineProperty(value, prop, {
get,
configurable: true
});
}
if (desc[prop].set) {
const og = desc[prop].set,
set = v => solidJs.batch(() => og.call(p, v));
Object.defineProperty(value, prop, {
set,
configurable: true
});
}
}
}
return p;
}
function createMutable(state, options) {
const unwrappedStore = unwrap(state || {});
const wrappedStore = wrap(unwrappedStore);
return wrappedStore;
}
function modifyMutable(state, modifier) {
solidJs.batch(() => modifier(unwrap(state)));
}
const $ROOT = Symbol("store-root");
function isUnsafeKey(property) {
return property === "__proto__" || property === "constructor" || property === "prototype";
}
function applyState(target, parent, property, merge, key) {
if (isUnsafeKey(property)) return;
const previous = parent[property];
if (target === previous) return;
const isArray = Array.isArray(target);
if (property !== $ROOT && (!isWrappable(target) || !isWrappable(previous) || isArray !== Array.isArray(previous) || key && target[key] !== previous[key])) {
setProperty(parent, property, target);
return;
}
if (isArray) {
if (target.length && previous.length && (!merge || key && target[0] && target[0][key] != null)) {
let i, j, start, end, newEnd, item, newIndicesNext, keyVal;
for (start = 0, end = Math.min(previous.length, target.length); start < end && (previous[start] === target[start] || key && previous[start] && target[start] && previous[start][key] && previous[start][key] === target[start][key]); start++) {
applyState(target[start], previous, start, merge, key);
}
const temp = new Array(target.length),
newIndices = new Map();
for (end = previous.length - 1, newEnd = target.length - 1; end >= start && newEnd >= start && (previous[end] === target[newEnd] || key && previous[end] && target[newEnd] && previous[end][key] && previous[end][key] === target[newEnd][key]); end--, newEnd--) {
temp[newEnd] = previous[end];
}
if (start > newEnd || start > end) {
for (j = start; j <= newEnd; j++) setProperty(previous, j, target[j]);
for (; j < target.length; j++) {
setProperty(previous, j, temp[j]);
applyState(target[j], previous, j, merge, key);
}
if (previous.length > target.length) setProperty(previous, "length", target.length);
return;
}
newIndicesNext = new Array(newEnd + 1);
for (j = newEnd; j >= start; j--) {
item = target[j];
keyVal = key && item ? item[key] : item;
i = newIndices.get(keyVal);
newIndicesNext[j] = i === undefined ? -1 : i;
newIndices.set(keyVal, j);
}
for (i = start; i <= end; i++) {
item = previous[i];
keyVal = key && item ? item[key] : item;
j = newIndices.get(keyVal);
if (j !== undefined && j !== -1) {
temp[j] = previous[i];
j = newIndicesNext[j];
newIndices.set(keyVal, j);
}
}
for (j = start; j < target.length; j++) {
if (j in temp) {
setProperty(previous, j, temp[j]);
applyState(target[j], previous, j, merge, key);
} else setProperty(previous, j, target[j]);
}
} else {
for (let i = 0, len = target.length; i < len; i++) {
applyState(target[i], previous, i, merge, key);
}
}
if (previous.length > target.length) setProperty(previous, "length", target.length);
return;
}
const targetKeys = Object.keys(target);
for (let i = 0, len = targetKeys.length; i < len; i++) {
if (isUnsafeKey(targetKeys[i])) continue;
applyState(target[targetKeys[i]], previous, targetKeys[i], merge, key);
}
const previousKeys = Object.keys(previous);
for (let i = 0, len = previousKeys.length; i < len; i++) {
if (target[previousKeys[i]] === undefined) setProperty(previous, previousKeys[i], undefined);
}
}
function reconcile(value, options = {}) {
const {
merge,
key = "id"
} = options,
v = unwrap(value);
return state => {
if (!isWrappable(state) || !isWrappable(v)) return v;
const res = applyState(v, {
[$ROOT]: state
}, $ROOT, merge, key);
return res === undefined ? state : res;
};
}
const producers = new WeakMap();
const setterTraps = {
get(target, property) {
if (property === $RAW) return target;
const value = target[property];
if (property === solidJs.$PROXY || property === solidJs.$TRACK || property === $NODE || property === $HAS || property === "__proto__") return value;
let proxy;
return isWrappable(value) ? producers.get(value) || (producers.set(value, proxy = new Proxy(value, setterTraps)), proxy) : value;
},
set(target, property, value) {
setProperty(target, property, unwrap(value));
return true;
},
deleteProperty(target, property) {
setProperty(target, property, undefined, true);
return true;
}
};
function produce(fn) {
return state => {
if (isWrappable(state)) {
let proxy;
if (!(proxy = producers.get(state))) {
producers.set(state, proxy = new Proxy(state, setterTraps));
}
fn(proxy);
}
return state;
};
}
const DEV = undefined;
exports.$RAW = $RAW;
exports.DEV = DEV;
exports.createMutable = createMutable;
exports.createStore = createStore;
exports.modifyMutable = modifyMutable;
exports.produce = produce;
exports.reconcile = reconcile;
exports.unwrap = unwrap;

View File

@@ -0,0 +1,454 @@
import { batch, $PROXY, $TRACK, getListener, createSignal } from 'solid-js';
const $RAW = Symbol("store-raw"),
$NODE = Symbol("store-node"),
$HAS = Symbol("store-has"),
$SELF = Symbol("store-self");
function wrap$1(value) {
let p = value[$PROXY];
if (!p) {
Object.defineProperty(value, $PROXY, {
value: p = new Proxy(value, proxyTraps$1)
});
if (!Array.isArray(value)) {
const keys = Object.keys(value),
desc = Object.getOwnPropertyDescriptors(value),
proto = Object.getPrototypeOf(value);
const isClass = proto !== null && value !== null && typeof value === "object" && !Array.isArray(value) && proto !== Object.prototype;
if (isClass) {
const descriptors = Object.getOwnPropertyDescriptors(proto);
keys.push(...Object.keys(descriptors));
Object.assign(desc, descriptors);
}
for (let i = 0, l = keys.length; i < l; i++) {
const prop = keys[i];
if (isClass && prop === "constructor") continue;
if (desc[prop].get) {
Object.defineProperty(value, prop, {
configurable: true,
enumerable: desc[prop].enumerable,
get: desc[prop].get.bind(p)
});
}
}
}
}
return p;
}
function isWrappable(obj) {
let proto;
return obj != null && typeof obj === "object" && (obj[$PROXY] || !(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype || Array.isArray(obj));
}
function unwrap(item, set = new Set()) {
let result, unwrapped, v, prop;
if (result = item != null && item[$RAW]) return result;
if (!isWrappable(item) || set.has(item)) return item;
if (Array.isArray(item)) {
if (Object.isFrozen(item)) item = item.slice(0);else set.add(item);
for (let i = 0, l = item.length; i < l; i++) {
v = item[i];
if ((unwrapped = unwrap(v, set)) !== v) item[i] = unwrapped;
}
} else {
if (Object.isFrozen(item)) item = Object.assign({}, item);else set.add(item);
const keys = Object.keys(item),
desc = Object.getOwnPropertyDescriptors(item);
for (let i = 0, l = keys.length; i < l; i++) {
prop = keys[i];
if (desc[prop].get) continue;
v = item[prop];
if ((unwrapped = unwrap(v, set)) !== v) item[prop] = unwrapped;
}
}
return item;
}
function getNodes(target, symbol) {
let nodes = target[symbol];
if (!nodes) Object.defineProperty(target, symbol, {
value: nodes = Object.create(null)
});
return nodes;
}
function getNode(nodes, property, value) {
if (nodes[property]) return nodes[property];
const [s, set] = createSignal(value, {
equals: false,
internal: true
});
s.$ = set;
return nodes[property] = s;
}
function proxyDescriptor$1(target, property) {
const desc = Reflect.getOwnPropertyDescriptor(target, property);
if (!desc || desc.get || !desc.configurable || property === $PROXY || property === $NODE) return desc;
delete desc.value;
delete desc.writable;
desc.get = () => target[$PROXY][property];
return desc;
}
function trackSelf(target) {
getListener() && getNode(getNodes(target, $NODE), $SELF)();
}
function ownKeys(target) {
trackSelf(target);
return Reflect.ownKeys(target);
}
const proxyTraps$1 = {
get(target, property, receiver) {
if (property === $RAW) return target;
if (property === $PROXY) return receiver;
if (property === $TRACK) {
trackSelf(target);
return receiver;
}
const nodes = getNodes(target, $NODE);
const tracked = nodes[property];
let value = tracked ? tracked() : target[property];
if (property === $NODE || property === $HAS || property === "__proto__") return value;
if (!tracked) {
const desc = Object.getOwnPropertyDescriptor(target, property);
if (getListener() && (typeof value !== "function" || Object.prototype.hasOwnProperty.call(target, property)) && !(desc && desc.get)) value = getNode(nodes, property, value)();
}
return isWrappable(value) ? wrap$1(value) : value;
},
has(target, property) {
if (property === $RAW || property === $PROXY || property === $TRACK || property === $NODE || property === $HAS || property === "__proto__") return true;
getListener() && getNode(getNodes(target, $HAS), property)();
return property in target;
},
set() {
return true;
},
deleteProperty() {
return true;
},
ownKeys: ownKeys,
getOwnPropertyDescriptor: proxyDescriptor$1
};
function setProperty(state, property, value, deleting = false) {
if (property === "__proto__") {
return;
}
if (!deleting && state[property] === value) return;
const prev = state[property],
len = state.length;
if (value === undefined) {
delete state[property];
if (state[$HAS] && state[$HAS][property] && prev !== undefined) state[$HAS][property].$();
} else {
state[property] = value;
if (state[$HAS] && state[$HAS][property] && prev === undefined) state[$HAS][property].$();
}
let nodes = getNodes(state, $NODE),
node;
if (node = getNode(nodes, property, prev)) node.$(() => value);
if (Array.isArray(state) && state.length !== len) {
for (let i = state.length; i < len; i++) (node = nodes[i]) && node.$();
(node = getNode(nodes, "length", len)) && node.$(state.length);
}
(node = nodes[$SELF]) && node.$();
}
function mergeStoreNode(state, value) {
const keys = Object.keys(value);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
if (isUnsafeKey$1(key)) continue;
setProperty(state, key, value[key]);
}
}
function isUnsafeKey$1(property) {
return property === "__proto__" || property === "constructor" || property === "prototype";
}
function updateArray(current, next) {
if (typeof next === "function") next = next(current);
next = unwrap(next);
if (Array.isArray(next)) {
if (current === next) return;
let i = 0,
len = next.length;
for (; i < len; i++) {
const value = next[i];
if (current[i] !== value) setProperty(current, i, value);
}
setProperty(current, "length", len);
} else mergeStoreNode(current, next);
}
function updatePath(current, path, traversed = []) {
let part,
prev = current;
if (path.length > 1) {
part = path.shift();
const partType = typeof part,
isArray = Array.isArray(current);
if (partType === "string" && (part === "__proto__" || path.length > 1 && isUnsafeKey$1(part))) {
return;
}
if (Array.isArray(part)) {
for (let i = 0; i < part.length; i++) {
updatePath(current, [part[i]].concat(path), traversed);
}
return;
} else if (isArray && partType === "function") {
for (let i = 0; i < current.length; i++) {
if (part(current[i], i)) updatePath(current, [i].concat(path), traversed);
}
return;
} else if (isArray && partType === "object") {
const {
from = 0,
to = current.length - 1,
by = 1
} = part;
for (let i = from; i <= to; i += by) {
updatePath(current, [i].concat(path), traversed);
}
return;
} else if (path.length > 1) {
updatePath(current[part], path, [part].concat(traversed));
return;
}
prev = current[part];
traversed = [part].concat(traversed);
}
let value = path[0];
if (typeof value === "function") {
value = value(prev, traversed);
if (value === prev) return;
}
if (part === undefined && value == undefined) return;
value = unwrap(value);
if (part === undefined || isWrappable(prev) && isWrappable(value) && !Array.isArray(value)) {
mergeStoreNode(prev, value);
} else setProperty(current, part, value);
}
function createStore(...[store, options]) {
const unwrappedStore = unwrap(store || {});
const isArray = Array.isArray(unwrappedStore);
const wrappedStore = wrap$1(unwrappedStore);
function setStore(...args) {
batch(() => {
isArray && args.length === 1 ? updateArray(unwrappedStore, args[0]) : updatePath(unwrappedStore, args);
});
}
return [wrappedStore, setStore];
}
function proxyDescriptor(target, property) {
const desc = Reflect.getOwnPropertyDescriptor(target, property);
if (!desc || desc.get || desc.set || !desc.configurable || property === $PROXY || property === $NODE) return desc;
delete desc.value;
delete desc.writable;
desc.get = () => target[$PROXY][property];
desc.set = v => target[$PROXY][property] = v;
return desc;
}
const proxyTraps = {
get(target, property, receiver) {
if (property === $RAW) return target;
if (property === $PROXY) return receiver;
if (property === $TRACK) {
trackSelf(target);
return receiver;
}
const nodes = getNodes(target, $NODE);
const tracked = nodes[property];
let value = tracked ? tracked() : target[property];
if (property === $NODE || property === $HAS || property === "__proto__") return value;
if (!tracked) {
const desc = Object.getOwnPropertyDescriptor(target, property);
const isFunction = typeof value === "function";
if (getListener() && (!isFunction || Object.prototype.hasOwnProperty.call(target, property)) && !(desc && desc.get)) value = getNode(nodes, property, value)();else if (value != null && isFunction && value === Array.prototype[property]) {
return (...args) => batch(() => Array.prototype[property].apply(receiver, args));
}
}
return isWrappable(value) ? wrap(value) : value;
},
has(target, property) {
if (property === $RAW || property === $PROXY || property === $TRACK || property === $NODE || property === $HAS || property === "__proto__") return true;
getListener() && getNode(getNodes(target, $HAS), property)();
return property in target;
},
set(target, property, value) {
batch(() => setProperty(target, property, unwrap(value)));
return true;
},
deleteProperty(target, property) {
batch(() => setProperty(target, property, undefined, true));
return true;
},
ownKeys: ownKeys,
getOwnPropertyDescriptor: proxyDescriptor
};
function wrap(value) {
let p = value[$PROXY];
if (!p) {
Object.defineProperty(value, $PROXY, {
value: p = new Proxy(value, proxyTraps)
});
const keys = Object.keys(value),
desc = Object.getOwnPropertyDescriptors(value);
const proto = Object.getPrototypeOf(value);
const isClass = proto !== null && value !== null && typeof value === "object" && !Array.isArray(value) && proto !== Object.prototype;
if (isClass) {
let curProto = proto;
while (curProto != null) {
const descriptors = Object.getOwnPropertyDescriptors(curProto);
keys.push(...Object.keys(descriptors));
Object.assign(desc, descriptors);
curProto = Object.getPrototypeOf(curProto);
}
}
for (let i = 0, l = keys.length; i < l; i++) {
const prop = keys[i];
if (isClass && prop === "constructor") continue;
if (desc[prop].get) {
const get = desc[prop].get.bind(p);
Object.defineProperty(value, prop, {
get,
configurable: true
});
}
if (desc[prop].set) {
const og = desc[prop].set,
set = v => batch(() => og.call(p, v));
Object.defineProperty(value, prop, {
set,
configurable: true
});
}
}
}
return p;
}
function createMutable(state, options) {
const unwrappedStore = unwrap(state || {});
const wrappedStore = wrap(unwrappedStore);
return wrappedStore;
}
function modifyMutable(state, modifier) {
batch(() => modifier(unwrap(state)));
}
const $ROOT = Symbol("store-root");
function isUnsafeKey(property) {
return property === "__proto__" || property === "constructor" || property === "prototype";
}
function applyState(target, parent, property, merge, key) {
if (isUnsafeKey(property)) return;
const previous = parent[property];
if (target === previous) return;
const isArray = Array.isArray(target);
if (property !== $ROOT && (!isWrappable(target) || !isWrappable(previous) || isArray !== Array.isArray(previous) || key && target[key] !== previous[key])) {
setProperty(parent, property, target);
return;
}
if (isArray) {
if (target.length && previous.length && (!merge || key && target[0] && target[0][key] != null)) {
let i, j, start, end, newEnd, item, newIndicesNext, keyVal;
for (start = 0, end = Math.min(previous.length, target.length); start < end && (previous[start] === target[start] || key && previous[start] && target[start] && previous[start][key] && previous[start][key] === target[start][key]); start++) {
applyState(target[start], previous, start, merge, key);
}
const temp = new Array(target.length),
newIndices = new Map();
for (end = previous.length - 1, newEnd = target.length - 1; end >= start && newEnd >= start && (previous[end] === target[newEnd] || key && previous[end] && target[newEnd] && previous[end][key] && previous[end][key] === target[newEnd][key]); end--, newEnd--) {
temp[newEnd] = previous[end];
}
if (start > newEnd || start > end) {
for (j = start; j <= newEnd; j++) setProperty(previous, j, target[j]);
for (; j < target.length; j++) {
setProperty(previous, j, temp[j]);
applyState(target[j], previous, j, merge, key);
}
if (previous.length > target.length) setProperty(previous, "length", target.length);
return;
}
newIndicesNext = new Array(newEnd + 1);
for (j = newEnd; j >= start; j--) {
item = target[j];
keyVal = key && item ? item[key] : item;
i = newIndices.get(keyVal);
newIndicesNext[j] = i === undefined ? -1 : i;
newIndices.set(keyVal, j);
}
for (i = start; i <= end; i++) {
item = previous[i];
keyVal = key && item ? item[key] : item;
j = newIndices.get(keyVal);
if (j !== undefined && j !== -1) {
temp[j] = previous[i];
j = newIndicesNext[j];
newIndices.set(keyVal, j);
}
}
for (j = start; j < target.length; j++) {
if (j in temp) {
setProperty(previous, j, temp[j]);
applyState(target[j], previous, j, merge, key);
} else setProperty(previous, j, target[j]);
}
} else {
for (let i = 0, len = target.length; i < len; i++) {
applyState(target[i], previous, i, merge, key);
}
}
if (previous.length > target.length) setProperty(previous, "length", target.length);
return;
}
const targetKeys = Object.keys(target);
for (let i = 0, len = targetKeys.length; i < len; i++) {
if (isUnsafeKey(targetKeys[i])) continue;
applyState(target[targetKeys[i]], previous, targetKeys[i], merge, key);
}
const previousKeys = Object.keys(previous);
for (let i = 0, len = previousKeys.length; i < len; i++) {
if (target[previousKeys[i]] === undefined) setProperty(previous, previousKeys[i], undefined);
}
}
function reconcile(value, options = {}) {
const {
merge,
key = "id"
} = options,
v = unwrap(value);
return state => {
if (!isWrappable(state) || !isWrappable(v)) return v;
const res = applyState(v, {
[$ROOT]: state
}, $ROOT, merge, key);
return res === undefined ? state : res;
};
}
const producers = new WeakMap();
const setterTraps = {
get(target, property) {
if (property === $RAW) return target;
const value = target[property];
if (property === $PROXY || property === $TRACK || property === $NODE || property === $HAS || property === "__proto__") return value;
let proxy;
return isWrappable(value) ? producers.get(value) || (producers.set(value, proxy = new Proxy(value, setterTraps)), proxy) : value;
},
set(target, property, value) {
setProperty(target, property, unwrap(value));
return true;
},
deleteProperty(target, property) {
setProperty(target, property, undefined, true);
return true;
}
};
function produce(fn) {
return state => {
if (isWrappable(state)) {
let proxy;
if (!(proxy = producers.get(state))) {
producers.set(state, proxy = new Proxy(state, setterTraps));
}
fn(proxy);
}
return state;
};
}
const DEV = undefined;
export { $RAW, DEV, createMutable, createStore, modifyMutable, produce, reconcile, unwrap };

View File

@@ -0,0 +1,46 @@
{
"name": "solid-js/store",
"main": "./dist/server.cjs",
"module": "./dist/server.js",
"unpkg": "./dist/store.cjs",
"types": "./types/index.d.ts",
"type": "module",
"sideEffects": false,
"exports": {
".": {
"worker": {
"types": "./types/index.d.ts",
"import": "./dist/server.js",
"require": "./dist/server.cjs"
},
"browser": {
"development": {
"types": "./types/index.d.ts",
"import": "./dist/dev.js",
"require": "./dist/dev.cjs"
},
"types": "./types/index.d.ts",
"import": "./dist/store.js",
"require": "./dist/store.cjs"
},
"deno": {
"types": "./types/index.d.ts",
"import": "./dist/server.js",
"require": "./dist/server.cjs"
},
"node": {
"types": "./types/index.d.ts",
"import": "./dist/server.js",
"require": "./dist/server.cjs"
},
"development": {
"types": "./types/index.d.ts",
"import": "./dist/dev.js",
"require": "./dist/dev.cjs"
},
"types": "./types/index.d.ts",
"import": "./dist/store.js",
"require": "./dist/store.cjs"
}
}
}

View File

@@ -0,0 +1,12 @@
export { $RAW, createStore, unwrap } from "./store.js";
export type { ArrayFilterFn, DeepMutable, DeepReadonly, NotWrappable, Part, SetStoreFunction, SolidStore, Store, StoreNode, StoreReturn, StorePathRange, StoreSetter } from "./store.js";
export * from "./mutable.js";
export * from "./modifiers.js";
import { $NODE, isWrappable } from "./store.js";
export declare const DEV: {
readonly $NODE: typeof $NODE;
readonly isWrappable: typeof isWrappable;
readonly hooks: {
onStoreNodeUpdate: import("./store.js").OnStoreNodeUpdate | null;
};
} | undefined;

View File

@@ -0,0 +1,6 @@
export type ReconcileOptions = {
key?: string | null;
merge?: boolean;
};
export declare function reconcile<T extends U, U>(value: T, options?: ReconcileOptions): (state: U) => T;
export declare function produce<T>(fn: (state: T) => void): (state: T) => T;

View File

@@ -0,0 +1,5 @@
import { StoreNode } from "./store.js";
export declare function createMutable<T extends StoreNode>(state: T, options?: {
name?: string;
}): T;
export declare function modifyMutable<T>(state: T, modifier: (state: T) => T): void;

View File

@@ -0,0 +1,17 @@
import type { Store, StoreReturn } from "./store.js";
export type { ArrayFilterFn, DeepMutable, DeepReadonly, NotWrappable, Part, SetStoreFunction, SolidStore, Store, StoreNode, StoreReturn, StorePathRange, StoreSetter } from "./store.js";
export declare const $RAW: unique symbol;
export declare function isWrappable(obj: any): boolean;
export declare function unwrap<T>(item: T): T;
export declare function setProperty(state: any, property: PropertyKey, value: any, force?: boolean): void;
export declare function updatePath(current: any, path: any[], traversed?: PropertyKey[]): void;
export declare function createStore<T>(state: T | Store<T>): StoreReturn<T>;
export declare function createMutable<T>(state: T | Store<T>): T;
export declare function modifyMutable<T>(state: T, modifier: (state: T) => T): void;
type ReconcileOptions = {
key?: string | null;
merge?: boolean;
};
export declare function reconcile<T extends U, U extends object>(value: T, options?: ReconcileOptions): (state: U) => T;
export declare function produce<T>(fn: (state: T) => void): (state: T) => T;
export declare const DEV: undefined;

View File

@@ -0,0 +1,108 @@
export declare const IS_DEV: string | boolean;
export declare const $RAW: unique symbol, $NODE: unique symbol, $HAS: unique symbol, $SELF: unique symbol;
export declare const DevHooks: {
onStoreNodeUpdate: OnStoreNodeUpdate | null;
};
type DataNode = {
(): any;
$(value?: any): void;
};
export type DataNodes = Record<PropertyKey, DataNode | undefined>;
export type OnStoreNodeUpdate = (state: StoreNode, property: PropertyKey, value: StoreNode | NotWrappable, prev: StoreNode | NotWrappable) => void;
export interface StoreNode {
[$NODE]?: DataNodes;
[key: PropertyKey]: any;
}
export declare namespace SolidStore {
interface Unwrappable {
}
}
export type NotWrappable = string | number | bigint | symbol | boolean | Function | null | undefined | SolidStore.Unwrappable[keyof SolidStore.Unwrappable];
export type Store<T> = T;
export declare function isWrappable<T>(obj: T | NotWrappable): obj is T;
/**
* Returns the underlying data in the store without a proxy.
* @param item store proxy object
* @example
* ```js
* const initial = {z...};
* const [state, setState] = createStore(initial);
* initial === state; // => false
* initial === unwrap(state); // => true
* ```
*/
export declare function unwrap<T>(item: T, set?: Set<unknown>): T;
export declare function getNodes(target: StoreNode, symbol: typeof $NODE | typeof $HAS): DataNodes;
export declare function getNode(nodes: DataNodes, property: PropertyKey, value?: any): DataNode;
export declare function proxyDescriptor(target: StoreNode, property: PropertyKey): TypedPropertyDescriptor<any> | undefined;
export declare function trackSelf(target: StoreNode): void;
export declare function ownKeys(target: StoreNode): (string | symbol)[];
export declare function setProperty(state: StoreNode, property: PropertyKey, value: any, deleting?: boolean): void;
export declare function updatePath(current: StoreNode, path: any[], traversed?: PropertyKey[]): void;
/** @deprecated */
export type DeepReadonly<T> = 0 extends 1 & T ? T : T extends NotWrappable ? T : {
readonly [K in keyof T]: DeepReadonly<T[K]>;
};
/** @deprecated */
export type DeepMutable<T> = 0 extends 1 & T ? T : T extends NotWrappable ? T : {
-readonly [K in keyof T]: DeepMutable<T[K]>;
};
export type CustomPartial<T> = T extends readonly unknown[] ? "0" extends keyof T ? {
[K in Extract<keyof T, `${number}`>]?: T[K];
} : {
[x: number]: T[number];
} : Partial<T>;
export type PickMutable<T> = {
[K in keyof T as (<U>() => U extends {
[V in K]: T[V];
} ? 1 : 2) extends <U>() => U extends {
-readonly [V in K]: T[V];
} ? 1 : 2 ? K : never]: T[K];
};
export type StorePathRange = {
from?: number;
to?: number;
by?: number;
};
export type ArrayFilterFn<T> = (item: T, index: number) => boolean;
export type StoreSetter<T, U extends PropertyKey[] = []> = T | CustomPartial<T> | ((prevState: T, traversed: U) => T | CustomPartial<T>);
export type Part<T, K extends KeyOf<T> = KeyOf<T>> = K | ([K] extends [never] ? never : readonly K[]) | ([T] extends [readonly unknown[]] ? ArrayFilterFn<T[number]> | StorePathRange : never);
type W<T> = Exclude<T, NotWrappable>;
type KeyOf<T> = number extends keyof T ? 0 extends 1 & T ? keyof T : [T] extends [never] ? never : [
T
] extends [readonly unknown[]] ? number : keyof T : keyof T;
type MutableKeyOf<T> = KeyOf<T> & keyof PickMutable<T>;
type Rest<T, U extends PropertyKey[], K extends KeyOf<T> = KeyOf<T>> = [T] extends [never] ? never : K extends MutableKeyOf<T> ? [Part<T, K>, ...RestSetterOrContinue<T[K], [K, ...U]>] : K extends KeyOf<T> ? [Part<T, K>, ...RestContinue<T[K], [K, ...U]>] : never;
type RestContinue<T, U extends PropertyKey[]> = 0 extends 1 & T ? [...Part<any>[], StoreSetter<any, PropertyKey[]>] : Rest<W<T>, U>;
type RestSetterOrContinue<T, U extends PropertyKey[]> = [StoreSetter<T, U>] | RestContinue<T, U>;
export interface SetStoreFunction<T> {
<K1 extends KeyOf<W<T>>, K2 extends KeyOf<W<W<T>[K1]>>, K3 extends KeyOf<W<W<W<T>[K1]>[K2]>>, K4 extends KeyOf<W<W<W<W<T>[K1]>[K2]>[K3]>>, K5 extends KeyOf<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>>, K6 extends KeyOf<W<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5]>>, K7 extends MutableKeyOf<W<W<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5]>[K6]>>>(k1: Part<W<T>, K1>, k2: Part<W<W<T>[K1]>, K2>, k3: Part<W<W<W<T>[K1]>[K2]>, K3>, k4: Part<W<W<W<W<T>[K1]>[K2]>[K3]>, K4>, k5: Part<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>, K5>, k6: Part<W<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5]>, K6>, k7: Part<W<W<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5]>[K6]>, K7>, setter: StoreSetter<W<W<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5]>[K6]>[K7], [
K7,
K6,
K5,
K4,
K3,
K2,
K1
]>): void;
<K1 extends KeyOf<W<T>>, K2 extends KeyOf<W<W<T>[K1]>>, K3 extends KeyOf<W<W<W<T>[K1]>[K2]>>, K4 extends KeyOf<W<W<W<W<T>[K1]>[K2]>[K3]>>, K5 extends KeyOf<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>>, K6 extends MutableKeyOf<W<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5]>>>(k1: Part<W<T>, K1>, k2: Part<W<W<T>[K1]>, K2>, k3: Part<W<W<W<T>[K1]>[K2]>, K3>, k4: Part<W<W<W<W<T>[K1]>[K2]>[K3]>, K4>, k5: Part<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>, K5>, k6: Part<W<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5]>, K6>, setter: StoreSetter<W<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5]>[K6], [K6, K5, K4, K3, K2, K1]>): void;
<K1 extends KeyOf<W<T>>, K2 extends KeyOf<W<W<T>[K1]>>, K3 extends KeyOf<W<W<W<T>[K1]>[K2]>>, K4 extends KeyOf<W<W<W<W<T>[K1]>[K2]>[K3]>>, K5 extends MutableKeyOf<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>>>(k1: Part<W<T>, K1>, k2: Part<W<W<T>[K1]>, K2>, k3: Part<W<W<W<T>[K1]>[K2]>, K3>, k4: Part<W<W<W<W<T>[K1]>[K2]>[K3]>, K4>, k5: Part<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>, K5>, setter: StoreSetter<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5], [K5, K4, K3, K2, K1]>): void;
<K1 extends KeyOf<W<T>>, K2 extends KeyOf<W<W<T>[K1]>>, K3 extends KeyOf<W<W<W<T>[K1]>[K2]>>, K4 extends MutableKeyOf<W<W<W<W<T>[K1]>[K2]>[K3]>>>(k1: Part<W<T>, K1>, k2: Part<W<W<T>[K1]>, K2>, k3: Part<W<W<W<T>[K1]>[K2]>, K3>, k4: Part<W<W<W<W<T>[K1]>[K2]>[K3]>, K4>, setter: StoreSetter<W<W<W<W<T>[K1]>[K2]>[K3]>[K4], [K4, K3, K2, K1]>): void;
<K1 extends KeyOf<W<T>>, K2 extends KeyOf<W<W<T>[K1]>>, K3 extends MutableKeyOf<W<W<W<T>[K1]>[K2]>>>(k1: Part<W<T>, K1>, k2: Part<W<W<T>[K1]>, K2>, k3: Part<W<W<W<T>[K1]>[K2]>, K3>, setter: StoreSetter<W<W<W<T>[K1]>[K2]>[K3], [K3, K2, K1]>): void;
<K1 extends KeyOf<W<T>>, K2 extends MutableKeyOf<W<W<T>[K1]>>>(k1: Part<W<T>, K1>, k2: Part<W<W<T>[K1]>, K2>, setter: StoreSetter<W<W<T>[K1]>[K2], [K2, K1]>): void;
<K1 extends MutableKeyOf<W<T>>>(k1: Part<W<T>, K1>, setter: StoreSetter<W<T>[K1], [K1]>): void;
(setter: StoreSetter<T, []>): void;
<K1 extends KeyOf<W<T>>, K2 extends KeyOf<W<W<T>[K1]>>, K3 extends KeyOf<W<W<W<T>[K1]>[K2]>>, K4 extends KeyOf<W<W<W<W<T>[K1]>[K2]>[K3]>>, K5 extends KeyOf<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>>, K6 extends KeyOf<W<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5]>>, K7 extends KeyOf<W<W<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5]>[K6]>>>(k1: Part<W<T>, K1>, k2: Part<W<W<T>[K1]>, K2>, k3: Part<W<W<W<T>[K1]>[K2]>, K3>, k4: Part<W<W<W<W<T>[K1]>[K2]>[K3]>, K4>, k5: Part<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>, K5>, k6: Part<W<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5]>, K6>, k7: Part<W<W<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5]>[K6]>, K7>, ...rest: Rest<W<W<W<W<W<W<W<T>[K1]>[K2]>[K3]>[K4]>[K5]>[K6]>[K7], [K7, K6, K5, K4, K3, K2, K1]>): void;
}
export type StoreReturn<T> = [get: Store<T>, set: SetStoreFunction<T>];
/**
* Creates a reactive store that can be read through a proxy object and written with a setter function
*
* @description https://docs.solidjs.com/reference/store-utilities/create-store
*/
export declare function createStore<T extends object = {}>(...[store, options]: {} extends T ? [store?: T | Store<T>, options?: {
name?: string;
}] : [store: T | Store<T>, options?: {
name?: string;
}]): StoreReturn<T>;
export {};

View File

@@ -0,0 +1,23 @@
export { $DEVCOMP, $PROXY, $TRACK, batch, catchError, children, createComputed, createContext, createDeferred, createEffect, createMemo, createReaction, createRenderEffect, createResource, createRoot, createSelector, createSignal, enableExternalSource, enableScheduling, equalFn, getListener, getOwner, on, onCleanup, onError, onMount, runWithOwner, startTransition, untrack, useContext, useTransition } from "./reactive/signal.js";
export type { Accessor, AccessorArray, ChildrenReturn, Context, ContextProviderComponent, EffectFunction, EffectOptions, InitializedResource, InitializedResourceOptions, InitializedResourceReturn, MemoOptions, NoInfer, OnEffectFunction, OnOptions, Owner, ResolvedChildren, ResolvedJSXElement, Resource, ResourceActions, ResourceFetcher, ResourceFetcherInfo, ResourceOptions, ResourceReturn, ResourceSource, ReturnTypes, Setter, Signal, SignalOptions, Transition } from "./reactive/signal.js";
export * from "./reactive/observable.js";
export * from "./reactive/scheduler.js";
export * from "./reactive/array.js";
export * from "./render/index.js";
import type { JSX } from "./jsx.js";
type JSXElement = JSX.Element;
export type { JSXElement, JSX };
import { registerGraph, writeSignal } from "./reactive/signal.js";
export declare const DEV: {
readonly hooks: {
afterUpdate: (() => void) | null;
afterCreateOwner: ((owner: import("./reactive/signal.js").Owner) => void) | null;
afterCreateSignal: ((signal: import("./reactive/signal.js").SignalState<any>) => void) | null;
afterRegisterGraph: ((sourceMapValue: import("./reactive/signal.js").SourceMapValue) => void) | null;
};
readonly writeSignal: typeof writeSignal;
readonly registerGraph: typeof registerGraph;
} | undefined;
declare global {
var Solid$$: boolean;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,44 @@
import { Accessor } from "./signal.js";
/**
The MIT License (MIT)
Copyright (c) 2017 Adam Haile
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* Reactively transforms an array with a callback function - underlying helper for the `<For>` control flow
*
* similar to `Array.prototype.map`, but gets the index as accessor, transforms only values that changed and returns an accessor and reactively tracks changes to the list.
*
* @description https://docs.solidjs.com/reference/reactive-utilities/map-array
*/
export declare function mapArray<T, U>(list: Accessor<readonly T[] | undefined | null | false>, mapFn: (v: T, i: Accessor<number>) => U, options?: {
fallback?: Accessor<any>;
}): () => U[];
/**
* Reactively maps arrays by index instead of value - underlying helper for the `<Index>` control flow
*
* similar to `Array.prototype.map`, but gets the value as an accessor, transforms only changed items of the original arrays anew and returns an accessor.
*
* @description https://docs.solidjs.com/reference/reactive-utilities/index-array
*/
export declare function indexArray<T, U>(list: Accessor<readonly T[] | undefined | null | false>, mapFn: (v: Accessor<T>, i: number) => U, options?: {
fallback?: Accessor<any>;
}): () => U[];

View File

@@ -0,0 +1,36 @@
import { Accessor, Setter } from "./signal.js";
declare global {
interface SymbolConstructor {
readonly observable: symbol;
}
}
interface Observable<T> {
subscribe(observer: ObservableObserver<T>): {
unsubscribe(): void;
};
[Symbol.observable](): Observable<T>;
}
export type ObservableObserver<T> = ((v: T) => void) | {
next?: (v: T) => void;
error?: (v: any) => void;
complete?: (v: boolean) => void;
};
/**
* Creates a simple observable from a signal's accessor to be used with the `from` operator of observable libraries like e.g. rxjs
* ```typescript
* import { from } from "rxjs";
* const [s, set] = createSignal(0);
* const obsv$ = from(observable(s));
* obsv$.subscribe((v) => console.log(v));
* ```
* description https://docs.solidjs.com/reference/reactive-utilities/observable
*/
export declare function observable<T>(input: Accessor<T>): Observable<T>;
type Producer<T> = ((setter: Setter<T>) => () => void) | {
subscribe: (fn: (v: T) => void) => (() => void) | {
unsubscribe: () => void;
};
};
export declare function from<T>(producer: Producer<T>, initalValue: T): Accessor<T>;
export declare function from<T>(producer: Producer<T | undefined>): Accessor<T | undefined>;
export {};

View File

@@ -0,0 +1,10 @@
export interface Task {
id: number;
fn: ((didTimeout: boolean) => void) | null;
startTime: number;
expirationTime: number;
}
export declare function requestCallback(fn: () => void, options?: {
timeout: number;
}): Task;
export declare function cancelCallback(task: Task): void;

View File

@@ -0,0 +1,581 @@
/**
The MIT License (MIT)
Copyright (c) 2017 Adam Haile
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import { requestCallback } from "./scheduler.js";
import type { JSX } from "../jsx.js";
import type { FlowComponent } from "../render/index.js";
export declare const IS_DEV: string | boolean;
export declare const equalFn: <T>(a: T, b: T) => boolean;
export declare const $PROXY: unique symbol;
export declare const SUPPORTS_PROXY: boolean;
export declare const $TRACK: unique symbol;
export declare const $DEVCOMP: unique symbol;
export declare var Owner: Owner | null;
export declare let Transition: TransitionState | null;
/** Object storing callbacks for debugging during development */
export declare const DevHooks: {
afterUpdate: (() => void) | null;
afterCreateOwner: ((owner: Owner) => void) | null;
/** @deprecated use `afterRegisterGraph` */
afterCreateSignal: ((signal: SignalState<any>) => void) | null;
afterRegisterGraph: ((sourceMapValue: SourceMapValue) => void) | null;
};
export type ComputationState = 0 | 1 | 2;
export interface SourceMapValue {
value: unknown;
name?: string;
graph?: Owner;
}
export interface SignalState<T> extends SourceMapValue {
value: T;
observers: Computation<any>[] | null;
observerSlots: number[] | null;
tValue?: T;
comparator?: (prev: T, next: T) => boolean;
internal?: true;
}
export interface Owner {
owned: Computation<any>[] | null;
cleanups: (() => void)[] | null;
owner: Owner | null;
context: any | null;
sourceMap?: SourceMapValue[];
name?: string;
}
export interface Computation<Init, Next extends Init = Init> extends Owner {
fn: EffectFunction<Init, Next>;
state: ComputationState;
tState?: ComputationState;
sources: SignalState<Next>[] | null;
sourceSlots: number[] | null;
value?: Init;
updatedAt: number | null;
pure: boolean;
user?: boolean;
suspense?: SuspenseContextType;
}
export interface TransitionState {
sources: Set<SignalState<any>>;
effects: Computation<any>[];
promises: Set<Promise<any>>;
disposed: Set<Computation<any>>;
queue: Set<Computation<any>>;
scheduler?: (fn: () => void) => unknown;
running: boolean;
done?: Promise<void>;
resolve?: () => void;
}
type ExternalSourceFactory = <Prev, Next extends Prev = Prev>(fn: EffectFunction<Prev, Next>, trigger: () => void) => ExternalSource;
export interface ExternalSource {
track: EffectFunction<any, any>;
dispose: () => void;
}
export type RootFunction<T> = (dispose: () => void) => T;
/**
* Creates a new non-tracked reactive context that doesn't auto-dispose
*
* @param fn a function in which the reactive state is scoped
* @param detachedOwner optional reactive context to bind the root to
* @returns the output of `fn`.
*
* @description https://docs.solidjs.com/reference/reactive-utilities/create-root
*/
export declare function createRoot<T>(fn: RootFunction<T>, detachedOwner?: typeof Owner): T;
export type Accessor<T> = () => T;
export type Setter<in out T> = {
<U extends T>(...args: undefined extends T ? [] : [value: Exclude<U, Function> | ((prev: T) => U)]): undefined extends T ? undefined : U;
<U extends T>(value: (prev: T) => U): U;
<U extends T>(value: Exclude<U, Function>): U;
<U extends T>(value: Exclude<U, Function> | ((prev: T) => U)): U;
};
export type Signal<T> = [get: Accessor<T>, set: Setter<T>];
export interface SignalOptions<T> extends MemoOptions<T> {
internal?: boolean;
}
/**
* Creates a simple reactive state with a getter and setter
* ```typescript
* const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>(
* value: T,
* options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) }
* )
* ```
* @param value initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error
* @param options optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity
*
* @returns ```typescript
* [state: Accessor<T>, setState: Setter<T>]
* ```
* * the Accessor is merely a function that returns the current value and registers each call to the reactive root
* * the Setter is a function that allows directly setting or mutating the value:
* ```typescript
* const [count, setCount] = createSignal(0);
* setCount(count => count + 1);
* ```
*
* @description https://docs.solidjs.com/reference/basic-reactivity/create-signal
*/
export declare function createSignal<T>(): Signal<T | undefined>;
export declare function createSignal<T>(value: T, options?: SignalOptions<T>): Signal<T>;
export interface BaseOptions {
name?: string;
}
export type NoInfer<T extends any> = [T][T extends any ? 0 : never];
export interface EffectOptions extends BaseOptions {
}
export type EffectFunction<Prev, Next extends Prev = Prev> = (v: Prev) => Next;
/**
* Creates a reactive computation that runs immediately before render, mainly used to write to other reactive primitives
* ```typescript
* export function createComputed<Next, Init = Next>(
* fn: (v: Init | Next) => Next,
* value?: Init,
* options?: { name?: string }
* ): void;
* ```
* @param fn a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
* @param options allows to set a name in dev mode for debugging purposes
*
* @description https://docs.solidjs.com/reference/secondary-primitives/create-computed
*/
export declare function createComputed<Next>(fn: EffectFunction<undefined | NoInfer<Next>, Next>): void;
export declare function createComputed<Next, Init = Next>(fn: EffectFunction<Init | Next, Next>, value: Init, options?: EffectOptions): void;
/**
* Creates a reactive computation that runs during the render phase as DOM elements are created and updated but not necessarily connected
* ```typescript
* export function createRenderEffect<T>(
* fn: (v: T) => T,
* value?: T,
* options?: { name?: string }
* ): void;
* ```
* @param fn a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
* @param options allows to set a name in dev mode for debugging purposes
*
* @description https://docs.solidjs.com/reference/secondary-primitives/create-render-effect
*/
export declare function createRenderEffect<Next>(fn: EffectFunction<undefined | NoInfer<Next>, Next>): void;
export declare function createRenderEffect<Next, Init = Next>(fn: EffectFunction<Init | Next, Next>, value: Init, options?: EffectOptions): void;
/**
* Creates a reactive computation that runs after the render phase
* ```typescript
* export function createEffect<T>(
* fn: (v: T) => T,
* value?: T,
* options?: { name?: string }
* ): void;
* ```
* @param fn a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
* @param options allows to set a name in dev mode for debugging purposes
*
* @description https://docs.solidjs.com/reference/basic-reactivity/create-effect
*/
export declare function createEffect<Next>(fn: EffectFunction<undefined | NoInfer<Next>, Next>): void;
export declare function createEffect<Next, Init = Next>(fn: EffectFunction<Init | Next, Next>, value: Init, options?: EffectOptions & {
render?: boolean;
}): void;
/**
* Creates a reactive computation that runs after the render phase with flexible tracking
* ```typescript
* export function createReaction(
* onInvalidate: () => void,
* options?: { name?: string }
* ): (fn: () => void) => void;
* ```
* @param invalidated a function that is called when tracked function is invalidated.
* @param options allows to set a name in dev mode for debugging purposes
*
* @description https://docs.solidjs.com/reference/secondary-primitives/create-reaction
*/
export declare function createReaction(onInvalidate: () => void, options?: EffectOptions): (tracking: () => void) => void;
export interface Memo<Prev, Next = Prev> extends SignalState<Next>, Computation<Next> {
value: Next;
tOwned?: Computation<Prev | Next, Next>[];
}
export interface MemoOptions<T> extends EffectOptions {
equals?: false | ((prev: T, next: T) => boolean);
}
/**
* Creates a readonly derived reactive memoized signal
* ```typescript
* export function createMemo<T>(
* fn: (v: T) => T,
* value?: T,
* options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) }
* ): () => T;
* ```
* @param fn a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
* @param options allows to set a name in dev mode for debugging purposes and use a custom comparison function in equals
*
* @description https://docs.solidjs.com/reference/basic-reactivity/create-memo
*/
export declare function createMemo<Next extends Prev, Prev = Next>(fn: EffectFunction<undefined | NoInfer<Prev>, Next>): Accessor<Next>;
export declare function createMemo<Next extends Prev, Init = Next, Prev = Next>(fn: EffectFunction<Init | Prev, Next>, value: Init, options?: MemoOptions<Next>): Accessor<Next>;
interface Unresolved {
state: "unresolved";
loading: false;
error: undefined;
latest: undefined;
(): undefined;
}
interface Pending {
state: "pending";
loading: true;
error: undefined;
latest: undefined;
(): undefined;
}
interface Ready<T> {
state: "ready";
loading: false;
error: undefined;
latest: T;
(): T;
}
interface Refreshing<T> {
state: "refreshing";
loading: true;
error: undefined;
latest: T;
(): T;
}
interface Errored {
state: "errored";
loading: false;
error: any;
latest: never;
(): never;
}
export type Resource<T> = Unresolved | Pending | Ready<T> | Refreshing<T> | Errored;
export type InitializedResource<T> = Ready<T> | Refreshing<T> | Errored;
export type ResourceActions<T, R = unknown> = {
mutate: Setter<T>;
refetch: (info?: R) => T | Promise<T> | undefined | null;
};
export type ResourceSource<S> = S | false | null | undefined | (() => S | false | null | undefined);
export type ResourceFetcher<S, T, R = unknown> = (k: S, info: ResourceFetcherInfo<T, R>) => T | Promise<T>;
export type ResourceFetcherInfo<T, R = unknown> = {
value: T | undefined;
refetching: R | boolean;
};
export type ResourceOptions<T, S = unknown> = {
initialValue?: T;
name?: string;
deferStream?: boolean;
ssrLoadFrom?: "initial" | "server";
storage?: (init: T | undefined) => [Accessor<T | undefined>, Setter<T | undefined>];
onHydrated?: (k: S | undefined, info: {
value: T | undefined;
}) => void;
};
export type InitializedResourceOptions<T, S = unknown> = ResourceOptions<T, S> & {
initialValue: T;
};
export type ResourceReturn<T, R = unknown> = [Resource<T>, ResourceActions<T | undefined, R>];
export type InitializedResourceReturn<T, R = unknown> = [
InitializedResource<T>,
ResourceActions<T, R>
];
/**
* Creates a resource that wraps a repeated promise in a reactive pattern:
* ```typescript
* // Without source
* const [resource, { mutate, refetch }] = createResource(fetcher, options);
* // With source
* const [resource, { mutate, refetch }] = createResource(source, fetcher, options);
* ```
* @param source - reactive data function which has its non-nullish and non-false values passed to the fetcher, optional
* @param fetcher - function that receives the source (true if source not provided), the last or initial value, and whether the resource is being refetched, and returns a value or a Promise:
* ```typescript
* const fetcher: ResourceFetcher<S, T, R> = (
* sourceOutput: S,
* info: { value: T | undefined, refetching: R | boolean }
* ) => T | Promise<T>;
* ```
* @param options - an optional object with the initialValue and the name (for debugging purposes); see {@link ResourceOptions}
*
* @returns ```typescript
* [Resource<T>, { mutate: Setter<T>, refetch: () => void }]
* ```
*
* * Setting an `initialValue` in the options will mean that both the prev() accessor and the resource should never return undefined (if that is wanted, you need to extend the type with undefined)
* * `mutate` allows to manually overwrite the resource without calling the fetcher
* * `refetch` will re-run the fetcher without changing the source, and if called with a value, that value will be passed to the fetcher via the `refetching` property on the fetcher's second parameter
*
* @description https://docs.solidjs.com/reference/basic-reactivity/create-resource
*/
export declare function createResource<T, R = unknown, I = T>(fetcher: (k: true, info: ResourceFetcherInfo<T | I, R>) => T | Promise<T>, options: ResourceOptions<T | I, true> & {
initialValue: I;
}): InitializedResourceReturn<T | I, R>;
export declare function createResource<T, R = unknown>(fetcher: ResourceFetcher<true, T, R>, options?: ResourceOptions<NoInfer<T>, true>): ResourceReturn<T, R>;
export declare function createResource<T, S, R = unknown, I = T>(source: ResourceSource<S>, fetcher: (k: S, info: ResourceFetcherInfo<T | I, R>) => T | Promise<T>, options: ResourceOptions<T | I, S> & {
initialValue: I;
}): InitializedResourceReturn<T | I, R>;
export declare function createResource<T, S, R = unknown>(source: ResourceSource<S>, fetcher: ResourceFetcher<S, T, R>, options?: ResourceOptions<NoInfer<T>, S>): ResourceReturn<T, R>;
export interface DeferredOptions<T> {
equals?: false | ((prev: T, next: T) => boolean);
name?: string;
timeoutMs?: number;
}
/**
* Creates a reactive computation that only runs and notifies the reactive context when the browser is idle
* ```typescript
* export function createDeferred<T>(
* fn: (v: T) => T,
* options?: { timeoutMs?: number, name?: string, equals?: false | ((prev: T, next: T) => boolean) }
* ): () => T);
* ```
* @param fn a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
* @param options allows to set the timeout in milliseconds, use a custom comparison function and set a name in dev mode for debugging purposes
*
* @description https://docs.solidjs.com/reference/secondary-primitives/create-deferred
*/
export declare function createDeferred<T>(source: Accessor<T>, options?: DeferredOptions<T>): Accessor<T>;
export type EqualityCheckerFunction<T, U> = (a: U, b: T) => boolean;
/**
* Creates a conditional signal that only notifies subscribers when entering or exiting their key matching the value
* ```typescript
* export function createSelector<T, U>(
* source: () => T
* fn: (a: U, b: T) => boolean,
* options?: { name?: string }
* ): (k: U) => boolean;
* ```
* @param source
* @param fn a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
* @param options allows to set a name in dev mode for debugging purposes, optional
*
* ```typescript
* const isSelected = createSelector(selectedId);
* <For each={list()}>
* {(item) => <li classList={{ active: isSelected(item.id) }}>{item.name}</li>}
* </For>
* ```
*
* This makes the operation O(2) instead of O(n).
*
* @description https://docs.solidjs.com/reference/secondary-primitives/create-selector
*/
export declare function createSelector<T, U = T>(source: Accessor<T>, fn?: EqualityCheckerFunction<T, U>, options?: BaseOptions): (key: U) => boolean;
/**
* Holds changes inside the block before the reactive context is updated
* @param fn wraps the reactive updates that should be batched
* @returns the return value from `fn`
*
* @description https://docs.solidjs.com/reference/reactive-utilities/batch
*/
export declare function batch<T>(fn: Accessor<T>): T;
/**
* Ignores tracking context inside its scope
* @param fn the scope that is out of the tracking context
* @returns the return value of `fn`
*
* @description https://docs.solidjs.com/reference/reactive-utilities/untrack
*/
export declare function untrack<T>(fn: Accessor<T>): T;
/** @deprecated */
export type ReturnTypes<T> = T extends readonly Accessor<unknown>[] ? {
[K in keyof T]: T[K] extends Accessor<infer I> ? I : never;
} : T extends Accessor<infer I> ? I : never;
export type AccessorArray<T> = [...Extract<{
[K in keyof T]: Accessor<T[K]>;
}, readonly unknown[]>];
export type OnEffectFunction<S, Prev, Next extends Prev = Prev> = (input: S, prevInput: S | undefined, prev: Prev) => Next;
export interface OnOptions {
defer?: boolean;
}
/**
* Makes dependencies of a computation explicit
* ```typescript
* export function on<S, U>(
* deps: Accessor<S> | AccessorArray<S>,
* fn: (input: S, prevInput: S | undefined, prevValue: U | undefined) => U,
* options?: { defer?: boolean } = {}
* ): (prevValue: U | undefined) => U;
* ```
* @param deps list of reactive dependencies or a single reactive dependency
* @param fn computation on input; the current previous content(s) of input and the previous value are given as arguments and it returns a new value
* @param options optional, allows deferred computation until at the end of the next change
* @returns an effect function that is passed into createEffect. For example:
*
* ```typescript
* createEffect(on(a, (v) => console.log(v, b())));
*
* // is equivalent to:
* createEffect(() => {
* const v = a();
* untrack(() => console.log(v, b()));
* });
* ```
*
* @description https://docs.solidjs.com/reference/reactive-utilities/on-util
*/
export declare function on<S, Next extends Prev, Prev = Next>(deps: AccessorArray<S> | Accessor<S>, fn: OnEffectFunction<S, undefined | NoInfer<Prev>, Next>, options?: OnOptions & {
defer?: false;
}): EffectFunction<undefined | NoInfer<Next>, NoInfer<Next>>;
export declare function on<S, Next extends Prev, Prev = Next>(deps: AccessorArray<S> | Accessor<S>, fn: OnEffectFunction<S, undefined | NoInfer<Prev>, Next>, options: OnOptions | {
defer: true;
}): EffectFunction<undefined | NoInfer<Next>>;
/**
* Runs an effect only after initial render on mount
* @param fn an effect that should run only once on mount
*
* @description https://docs.solidjs.com/reference/lifecycle/on-mount
*/
export declare function onMount(fn: () => void): void;
/**
* Runs an effect once before the reactive scope is disposed
* @param fn an effect that should run only once on cleanup
*
* @returns the same {@link fn} function that was passed in
*
* @description https://docs.solidjs.com/reference/lifecycle/on-cleanup
*/
export declare function onCleanup<T extends () => any>(fn: T): T;
/**
* Runs an effect whenever an error is thrown within the context of the child scopes
* @param fn boundary for the error
* @param handler an error handler that receives the error
*
* * If the error is thrown again inside the error handler, it will trigger the next available parent handler
*
* @description https://docs.solidjs.com/reference/reactive-utilities/catch-error
*/
export declare function catchError<T>(fn: () => T, handler: (err: Error) => void): T | undefined;
export declare function getListener(): Computation<any, any> | null;
export declare function getOwner(): Owner | null;
export declare function runWithOwner<T>(o: typeof Owner, fn: () => T): T | undefined;
export declare function enableScheduling(scheduler?: typeof requestCallback): void;
/**
* ```typescript
* export function startTransition(fn: () => void) => Promise<void>
* ```
*
* @description https://docs.solidjs.com/reference/reactive-utilities/start-transition
*/
export declare function startTransition(fn: () => unknown): Promise<void>;
export type Transition = [Accessor<boolean>, (fn: () => void) => Promise<void>];
/**
* ```typescript
* export function useTransition(): [
* () => boolean,
* (fn: () => void, cb?: () => void) => void
* ];
* ```
* @returns a tuple; first value is an accessor if the transition is pending and a callback to start the transition
*
* @description https://docs.solidjs.com/reference/reactive-utilities/use-transition
*/
export declare function useTransition(): Transition;
export declare function resumeEffects(e: Computation<any>[]): void;
export interface DevComponent<T> extends Memo<unknown> {
props: T;
name: string;
component: (props: T) => unknown;
}
export declare function devComponent<P, V>(Comp: (props: P) => V, props: P): V;
export declare function registerGraph(value: SourceMapValue): void;
export type ContextProviderComponent<T> = FlowComponent<{
value: T;
}>;
export interface Context<T> {
id: symbol;
Provider: ContextProviderComponent<T>;
defaultValue: T;
}
/**
* Creates a Context to handle a state scoped for the children of a component
* ```typescript
* interface Context<T> {
* id: symbol;
* Provider: FlowComponent<{ value: T }>;
* defaultValue: T;
* }
* export function createContext<T>(
* defaultValue?: T,
* options?: { name?: string }
* ): Context<T | undefined>;
* ```
* @param defaultValue optional default to inject into context
* @param options allows to set a name in dev mode for debugging purposes
* @returns The context that contains the Provider Component and that can be used with `useContext`
*
* @description https://docs.solidjs.com/reference/component-apis/create-context
*/
export declare function createContext<T>(defaultValue?: undefined, options?: EffectOptions): Context<T | undefined>;
export declare function createContext<T>(defaultValue: T, options?: EffectOptions): Context<T>;
/**
* Uses a context to receive a scoped state from a parent's Context.Provider
*
* @param context Context object made by `createContext`
* @returns the current or `defaultValue`, if present
*
* @description https://docs.solidjs.com/reference/component-apis/use-context
*/
export declare function useContext<T>(context: Context<T>): T;
export type ResolvedJSXElement = Exclude<JSX.Element, JSX.ArrayElement>;
export type ResolvedChildren = ResolvedJSXElement | ResolvedJSXElement[];
export type ChildrenReturn = Accessor<ResolvedChildren> & {
toArray: () => ResolvedJSXElement[];
};
/**
* Resolves child elements to help interact with children
*
* @param fn an accessor for the children
* @returns a accessor of the same children, but resolved
*
* @description https://docs.solidjs.com/reference/component-apis/children
*/
export declare function children(fn: Accessor<JSX.Element>): ChildrenReturn;
export type SuspenseContextType = {
increment?: () => void;
decrement?: () => void;
inFallback?: () => boolean;
effects?: Computation<any>[];
resolved?: boolean;
};
type SuspenseContext = Context<SuspenseContextType | undefined> & {
active?(): boolean;
increment?(): void;
decrement?(): void;
};
declare let SuspenseContext: SuspenseContext;
export declare function getSuspenseContext(): SuspenseContext;
export declare function enableExternalSource(factory: ExternalSourceFactory, untrack?: <V>(fn: () => V) => V): void;
export declare function readSignal(this: SignalState<any> | Memo<any>): any;
export declare function writeSignal(node: SignalState<any> | Memo<any>, value: any, isComp?: boolean): any;
/**
* @deprecated since version 1.7.0 and will be removed in next major - use catchError instead
* onError - run an effect whenever an error is thrown within the context of the child scopes
* @param fn an error handler that receives the error
*
* * If the error is thrown again inside the error handler, it will trigger the next available parent handler
*
* @description https://docs.solidjs.com/reference/reactive-utilities/catch-error
*/
export declare function onError(fn: (err: Error) => void): void;
export {};

View File

@@ -0,0 +1,26 @@
import type { JSX } from "../jsx.js";
/**
* **[experimental]** Controls the order in which suspended content is rendered
*
* @description https://docs.solidjs.com/reference/components/suspense-list
*/
export declare function SuspenseList(props: {
children: JSX.Element;
revealOrder: "forwards" | "backwards" | "together";
tail?: "collapsed" | "hidden";
}): JSX.Element;
/**
* Tracks all resources inside a component and renders a fallback until they are all resolved
* ```typescript
* const AsyncComponent = lazy(() => import('./component'));
*
* <Suspense fallback={<LoadingIndicator />}>
* <AsyncComponent />
* </Suspense>
* ```
* @description https://docs.solidjs.com/reference/components/suspense
*/
export declare function Suspense(props: {
fallback?: JSX.Element;
children: JSX.Element;
}): JSX.Element;

View File

@@ -0,0 +1,111 @@
import type { JSX } from "../jsx.js";
export declare function enableHydration(): void;
/**
* A general `Component` has no implicit `children` prop. If desired, you can
* specify one as in `Component<{name: String, children: JSX.Element}>`.
*/
export type Component<P extends Record<string, any> = {}> = (props: P) => JSX.Element;
/**
* Extend props to forbid the `children` prop.
* Use this to prevent accidentally passing `children` to components that
* would silently throw them away.
*/
export type VoidProps<P extends Record<string, any> = {}> = P & {
children?: never;
};
/**
* `VoidComponent` forbids the `children` prop.
* Use this to prevent accidentally passing `children` to components that
* would silently throw them away.
*/
export type VoidComponent<P extends Record<string, any> = {}> = Component<VoidProps<P>>;
/**
* Extend props to allow an optional `children` prop with the usual
* type in JSX, `JSX.Element` (which allows elements, arrays, strings, etc.).
* Use this for components that you want to accept children.
*/
export type ParentProps<P extends Record<string, any> = {}> = P & {
children?: JSX.Element;
};
/**
* `ParentComponent` allows an optional `children` prop with the usual
* type in JSX, `JSX.Element` (which allows elements, arrays, strings, etc.).
* Use this for components that you want to accept children.
*/
export type ParentComponent<P extends Record<string, any> = {}> = Component<ParentProps<P>>;
/**
* Extend props to require a `children` prop with the specified type.
* Use this for components where you need a specific child type,
* typically a function that receives specific argument types.
* Note that all JSX <Elements> are of the type `JSX.Element`.
*/
export type FlowProps<P extends Record<string, any> = {}, C = JSX.Element> = P & {
children: C;
};
/**
* `FlowComponent` requires a `children` prop with the specified type.
* Use this for components where you need a specific child type,
* typically a function that receives specific argument types.
* Note that all JSX <Elements> are of the type `JSX.Element`.
*/
export type FlowComponent<P extends Record<string, any> = {}, C = JSX.Element> = Component<FlowProps<P, C>>;
/** @deprecated: use `ParentProps` instead */
export type PropsWithChildren<P extends Record<string, any> = {}> = ParentProps<P>;
export type ValidComponent = keyof JSX.IntrinsicElements | Component<any> | (string & {});
/**
* Takes the props of the passed component and returns its type
*
* @example
* ComponentProps<typeof Portal> // { mount?: Node; useShadow?: boolean; children: JSX.Element }
* ComponentProps<'div'> // JSX.HTMLAttributes<HTMLDivElement>
*/
export type ComponentProps<T extends ValidComponent> = T extends Component<infer P> ? P : T extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[T] : Record<string, unknown>;
/**
* Type of `props.ref`, for use in `Component` or `props` typing.
*
* @example Component<{ref: Ref<Element>}>
*/
export type Ref<T> = T | ((val: T) => void);
export declare function createComponent<T extends Record<string, any>>(Comp: Component<T>, props: T): JSX.Element;
type DistributeOverride<T, F> = T extends undefined ? F : T;
type Override<T, U> = T extends any ? U extends any ? {
[K in keyof T]: K extends keyof U ? DistributeOverride<U[K], T[K]> : T[K];
} & {
[K in keyof U]: K extends keyof T ? DistributeOverride<U[K], T[K]> : U[K];
} : T & U : T & U;
type OverrideSpread<T, U> = T extends any ? {
[K in keyof ({
[K in keyof T]: any;
} & {
[K in keyof U]?: any;
} & {
[K in U extends any ? keyof U : keyof U]?: any;
})]: K extends keyof T ? Exclude<U extends any ? U[K & keyof U] : never, undefined> | T[K] : U extends any ? U[K & keyof U] : never;
} : T & U;
type Simplify<T> = T extends any ? {
[K in keyof T]: T[K];
} : T;
type _MergeProps<T extends unknown[], Curr = {}> = T extends [
infer Next | (() => infer Next),
...infer Rest
] ? _MergeProps<Rest, Override<Curr, Next>> : T extends [...infer Rest, infer Next | (() => infer Next)] ? Override<_MergeProps<Rest, Curr>, Next> : T extends [] ? Curr : T extends (infer I | (() => infer I))[] ? OverrideSpread<Curr, I> : Curr;
export type MergeProps<T extends unknown[]> = Simplify<_MergeProps<T>>;
export declare function mergeProps<T extends unknown[]>(...sources: T): MergeProps<T>;
export type SplitProps<T, K extends (readonly (keyof T)[])[]> = [
...{
[P in keyof K]: P extends `${number}` ? Pick<T, Extract<K[P], readonly (keyof T)[]>[number]> : never;
},
{
[P in keyof T as Exclude<P, K[number][number]>]: T[P];
}
];
export declare function splitProps<T extends Record<any, any>, K extends [readonly (keyof T)[], ...(readonly (keyof T)[])[]]>(props: T, ...keys: K): SplitProps<T, K>;
export declare function lazy<T extends Component<any>>(fn: () => Promise<{
default: T;
}>): T & {
preload: () => Promise<{
default: T;
}>;
};
export declare function createUniqueId(): string;
export {};

View File

@@ -0,0 +1,118 @@
import { Accessor } from "../reactive/signal.js";
import type { JSX } from "../jsx.js";
/**
* Creates a list elements from a list
*
* it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned:
* ```typescript
* <For each={items} fallback={<div>No items</div>}>
* {(item, index) => <div data-index={index()}>{item}</div>}
* </For>
* ```
* If you have a list with fixed indices and changing values, consider using `<Index>` instead.
*
* @description https://docs.solidjs.com/reference/components/for
*/
export declare function For<T extends readonly any[], U extends JSX.Element>(props: {
each: T | undefined | null | false;
fallback?: JSX.Element;
children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element;
/**
* Non-keyed iteration over a list creating elements from its items
*
* To be used if you have a list with fixed indices, but changing values.
* ```typescript
* <Index each={items} fallback={<div>No items</div>}>
* {(item, index) => <div data-index={index}>{item()}</div>}
* </Index>
* ```
* If you have a list with changing indices, better use `<For>`.
*
* @description https://docs.solidjs.com/reference/components/index-component
*/
export declare function Index<T extends readonly any[], U extends JSX.Element>(props: {
each: T | undefined | null | false;
fallback?: JSX.Element;
children: (item: Accessor<T[number]>, index: number) => U;
}): JSX.Element;
type RequiredParameter<T> = T extends () => unknown ? never : T;
/**
* Conditionally render its children or an optional fallback component
* @description https://docs.solidjs.com/reference/components/show
*/
export declare function Show<T, TRenderFunction extends (item: Accessor<NonNullable<T>>) => JSX.Element>(props: {
when: T | undefined | null | false;
keyed?: false;
fallback?: JSX.Element;
children: JSX.Element | RequiredParameter<TRenderFunction>;
}): JSX.Element;
export declare function Show<T, TRenderFunction extends (item: NonNullable<T>) => JSX.Element>(props: {
when: T | undefined | null | false;
keyed: true;
fallback?: JSX.Element;
children: JSX.Element | RequiredParameter<TRenderFunction>;
}): JSX.Element;
/**
* Switches between content based on mutually exclusive conditions
* ```typescript
* <Switch fallback={<FourOhFour />}>
* <Match when={state.route === 'home'}>
* <Home />
* </Match>
* <Match when={state.route === 'settings'}>
* <Settings />
* </Match>
* </Switch>
* ```
* @description https://docs.solidjs.com/reference/components/switch-and-match
*/
export declare function Switch(props: {
fallback?: JSX.Element;
children: JSX.Element;
}): JSX.Element;
export type MatchProps<T> = {
when: T | undefined | null | false;
keyed?: boolean;
children: JSX.Element | ((item: NonNullable<T> | Accessor<NonNullable<T>>) => JSX.Element);
};
/**
* Selects a content based on condition when inside a `<Switch>` control flow
* ```typescript
* <Match when={condition()}>
* <Content/>
* </Match>
* ```
* @description https://docs.solidjs.com/reference/components/switch-and-match
*/
export declare function Match<T, TRenderFunction extends (item: Accessor<NonNullable<T>>) => JSX.Element>(props: {
when: T | undefined | null | false;
keyed?: false;
children: JSX.Element | RequiredParameter<TRenderFunction>;
}): JSX.Element;
export declare function Match<T, TRenderFunction extends (item: NonNullable<T>) => JSX.Element>(props: {
when: T | undefined | null | false;
keyed: true;
children: JSX.Element | RequiredParameter<TRenderFunction>;
}): JSX.Element;
export declare function resetErrorBoundaries(): void;
/**
* Catches uncaught errors inside components and renders a fallback content
*
* Also supports a callback form that passes the error and a reset function:
* ```typescript
* <ErrorBoundary fallback={
* (err, reset) => <div onClick={reset}>Error: {err.toString()}</div>
* }>
* <MyComp />
* </ErrorBoundary>
* ```
* Errors thrown from the fallback can be caught by a parent ErrorBoundary
*
* @description https://docs.solidjs.com/reference/components/error-boundary
*/
export declare function ErrorBoundary(props: {
fallback: JSX.Element | ((err: any, reset: () => void) => JSX.Element);
children: JSX.Element;
}): JSX.Element;
export {};

View File

@@ -0,0 +1,24 @@
import { Computation } from "../reactive/signal.js";
export type HydrationContext = {
id: string;
count: number;
};
type SharedConfig = {
context?: HydrationContext;
resources?: {
[key: string]: any;
};
load?: (id: string) => Promise<any> | any;
has?: (id: string) => boolean;
gather?: (key: string) => void;
registry?: Map<string, Element>;
done?: boolean;
count?: number;
effects?: Computation<any, any>[];
getContextId(): string;
getNextContextId(): string;
};
export declare const sharedConfig: SharedConfig;
export declare function setHydrateContext(context?: HydrationContext): void;
export declare function nextHydrateContext(): HydrationContext | undefined;
export {};

View File

@@ -0,0 +1,4 @@
export * from "./component.js";
export * from "./flow.js";
export * from "./Suspense.js";
export { sharedConfig } from "./hydration.js";

View File

@@ -0,0 +1,3 @@
export { catchError, createRoot, createSignal, createComputed, createRenderEffect, createEffect, createReaction, createDeferred, createSelector, createMemo, getListener, onMount, onCleanup, onError, untrack, batch, on, children, createContext, useContext, getOwner, runWithOwner, equalFn, requestCallback, mapArray, indexArray, observable, from, $PROXY, $DEVCOMP, $TRACK, DEV, enableExternalSource } from "./reactive.js";
export { mergeProps, splitProps, createComponent, For, Index, Show, Switch, Match, ErrorBoundary, Suspense, SuspenseList, createResource, resetErrorBoundaries, enableScheduling, enableHydration, startTransition, useTransition, createUniqueId, lazy, sharedConfig } from "./rendering.js";
export type { Component, Resource } from "./rendering.js";

View File

@@ -0,0 +1,98 @@
export declare const equalFn: <T>(a: T, b: T) => boolean;
export declare const $PROXY: unique symbol;
export declare const $TRACK: unique symbol;
export declare const $DEVCOMP: unique symbol;
export declare const DEV: undefined;
export type Accessor<T> = () => T;
export type Setter<T> = undefined extends T ? <U extends T>(value?: (U extends Function ? never : U) | ((prev?: T) => U)) => U : <U extends T>(value: (U extends Function ? never : U) | ((prev: T) => U)) => U;
export type Signal<T> = [get: Accessor<T>, set: Setter<T>];
export declare function castError(err: unknown): Error;
export declare let Owner: Owner | null;
interface Owner {
owner: Owner | null;
context: any | null;
owned: Owner[] | null;
cleanups: (() => void)[] | null;
}
export declare function createOwner(): Owner;
export declare function createRoot<T>(fn: (dispose: () => void) => T, detachedOwner?: typeof Owner): T;
export declare function createSignal<T>(value: T, options?: {
equals?: false | ((prev: T, next: T) => boolean);
name?: string;
}): [get: () => T, set: (v: (T extends Function ? never : T) | ((prev: T) => T)) => T];
export declare function createComputed<T>(fn: (v?: T) => T, value?: T): void;
export declare const createRenderEffect: typeof createComputed;
export declare function createEffect<T>(fn: (v?: T) => T, value?: T): void;
export declare function createReaction(fn: () => void): (fn: () => void) => void;
export declare function createMemo<T>(fn: (v?: T) => T, value?: T): () => T;
export declare function createDeferred<T>(source: () => T): () => T;
export declare function createSelector<T>(source: () => T, fn?: (k: T, value: T) => boolean): (k: T) => boolean;
export declare function batch<T>(fn: () => T): T;
export declare const untrack: typeof batch;
export declare function on<T, U>(deps: Array<() => T> | (() => T), fn: (value: Array<T> | T, prev?: Array<T> | T, prevResults?: U) => U, options?: {
defer?: boolean;
}): (prev?: U) => U | undefined;
export declare function onMount(fn: () => void): void;
export declare function onCleanup(fn: () => void): () => void;
export declare function cleanNode(node: Owner): void;
export declare function catchError<T>(fn: () => T, handler: (err: Error) => void): T | undefined;
export declare function getListener(): null;
export interface Context<T> {
id: symbol;
Provider: (props: {
value: T;
children: any;
}) => any;
defaultValue?: T;
}
export declare function createContext<T>(defaultValue?: T): Context<T>;
export declare function useContext<T>(context: Context<T>): T;
export declare function getOwner(): Owner | null;
type ChildrenReturn = Accessor<any> & {
toArray: () => any[];
};
export declare function children(fn: () => any): ChildrenReturn;
export declare function runWithOwner<T>(o: typeof Owner, fn: () => T): T | undefined;
export interface Task {
id: number;
fn: ((didTimeout: boolean) => void) | null;
startTime: number;
expirationTime: number;
}
export declare function requestCallback(fn: () => void, options?: {
timeout: number;
}): Task;
export declare function cancelCallback(task: Task): void;
export declare function mapArray<T, U>(list: Accessor<readonly T[] | undefined | null | false>, mapFn: (v: T, i: Accessor<number>) => U, options?: {
fallback?: Accessor<any>;
}): () => U[];
export declare function indexArray<T, U>(list: Accessor<readonly T[] | undefined | null | false>, mapFn: (v: Accessor<T>, i: number) => U, options?: {
fallback?: Accessor<any>;
}): () => U[];
export type ObservableObserver<T> = ((v: T) => void) | {
next: (v: T) => void;
error?: (v: any) => void;
complete?: (v: boolean) => void;
};
export declare function observable<T>(input: Accessor<T>): {
subscribe(observer: ObservableObserver<T>): {
unsubscribe(): void;
};
[Symbol.observable](): {
subscribe(observer: ObservableObserver<T>): {
unsubscribe(): void;
};
[Symbol.observable](): /*elided*/ any;
};
};
export declare function from<T>(producer: ((setter: Setter<T>) => () => void) | {
subscribe: (fn: (v: T) => void) => (() => void) | {
unsubscribe: () => void;
};
}): Accessor<T>;
export declare function enableExternalSource(factory: any): void;
/**
* @deprecated since version 1.7.0 and will be removed in next major - use catchError instead
*/
export declare function onError(fn: (err: Error) => void): void;
export {};

View File

@@ -0,0 +1,160 @@
import { Accessor, Setter, Signal } from "./reactive.js";
import type { JSX } from "../jsx.js";
export type Component<P = {}> = (props: P) => JSX.Element;
export type VoidProps<P = {}> = P & {
children?: never;
};
export type VoidComponent<P = {}> = Component<VoidProps<P>>;
export type ParentProps<P = {}> = P & {
children?: JSX.Element;
};
export type ParentComponent<P = {}> = Component<ParentProps<P>>;
export type FlowProps<P = {}, C = JSX.Element> = P & {
children: C;
};
export type FlowComponent<P = {}, C = JSX.Element> = Component<FlowProps<P, C>>;
export type Ref<T> = T | ((val: T) => void);
export type ValidComponent = keyof JSX.IntrinsicElements | Component<any> | (string & {});
export type ComponentProps<T extends ValidComponent> = T extends Component<infer P> ? P : T extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[T] : Record<string, unknown>;
type SharedConfig = {
context?: HydrationContext;
getContextId(): string;
getNextContextId(): string;
};
export declare const sharedConfig: SharedConfig;
export declare function createUniqueId(): string;
export declare function createComponent<T>(Comp: (props: T) => JSX.Element, props: T): JSX.Element;
export declare function mergeProps<T>(source: T): T;
export declare function mergeProps<T, U>(source: T, source1: U): T & U;
export declare function mergeProps<T, U, V>(source: T, source1: U, source2: V): T & U & V;
export declare function mergeProps<T, U, V, W>(source: T, source1: U, source2: V, source3: W): T & U & V & W;
export declare function splitProps<T extends object, K1 extends keyof T>(props: T, ...keys: [K1[]]): [Pick<T, K1>, Omit<T, K1>];
export declare function splitProps<T extends object, K1 extends keyof T, K2 extends keyof T>(props: T, ...keys: [K1[], K2[]]): [Pick<T, K1>, Pick<T, K2>, Omit<T, K1 | K2>];
export declare function splitProps<T extends object, K1 extends keyof T, K2 extends keyof T, K3 extends keyof T>(props: T, ...keys: [K1[], K2[], K3[]]): [Pick<T, K1>, Pick<T, K2>, Pick<T, K3>, Omit<T, K1 | K2 | K3>];
export declare function splitProps<T extends object, K1 extends keyof T, K2 extends keyof T, K3 extends keyof T, K4 extends keyof T>(props: T, ...keys: [K1[], K2[], K3[], K4[]]): [Pick<T, K1>, Pick<T, K2>, Pick<T, K3>, Pick<T, K4>, Omit<T, K1 | K2 | K3 | K4>];
export declare function splitProps<T extends object, K1 extends keyof T, K2 extends keyof T, K3 extends keyof T, K4 extends keyof T, K5 extends keyof T>(props: T, ...keys: [K1[], K2[], K3[], K4[], K5[]]): [
Pick<T, K1>,
Pick<T, K2>,
Pick<T, K3>,
Pick<T, K4>,
Pick<T, K5>,
Omit<T, K1 | K2 | K3 | K4 | K5>
];
export declare function For<T>(props: {
each: T[];
fallback?: string;
children: (item: T, index: () => number) => string;
}): string | any[] | undefined;
export declare function Index<T>(props: {
each: T[];
fallback?: string;
children: (item: () => T, index: number) => string;
}): string | any[] | undefined;
/**
* Conditionally render its children or an optional fallback component
* @description https://docs.solidjs.com/reference/components/show
*/
export declare function Show<T>(props: {
when: T | undefined | null | false;
keyed?: boolean;
fallback?: string;
children: string | ((item: NonNullable<T> | Accessor<NonNullable<T>>) => string);
}): string;
export declare function Switch(props: {
fallback?: string;
children: MatchProps<unknown> | MatchProps<unknown>[];
}): string;
type MatchProps<T> = {
when: T | false;
keyed?: boolean;
children: string | ((item: NonNullable<T> | Accessor<NonNullable<T>>) => string);
};
export declare function Match<T>(props: MatchProps<T>): MatchProps<T>;
export declare function resetErrorBoundaries(): void;
export declare function ErrorBoundary(props: {
fallback: string | ((err: any, reset: () => void) => string);
children: string;
}): string | ((err: any, reset: () => void) => string) | {
t: string;
};
export interface Resource<T> {
(): T | undefined;
state: "unresolved" | "pending" | "ready" | "refreshing" | "errored";
loading: boolean;
error: any;
latest: T | undefined;
}
type SuspenseContextType = {
resources: Map<string, {
_loading: boolean;
error: any;
}>;
completed: () => void;
};
export type ResourceActions<T> = {
mutate: Setter<T>;
refetch: (info?: unknown) => void;
};
export type ResourceReturn<T> = [Resource<T>, ResourceActions<T>];
export type ResourceSource<S> = S | false | null | undefined | (() => S | false | null | undefined);
export type ResourceFetcher<S, T> = (k: S, info: ResourceFetcherInfo<T>) => T | Promise<T>;
export type ResourceFetcherInfo<T> = {
value: T | undefined;
refetching?: unknown;
};
export type ResourceOptions<T> = undefined extends T ? {
initialValue?: T;
name?: string;
deferStream?: boolean;
ssrLoadFrom?: "initial" | "server";
storage?: () => Signal<T | undefined>;
onHydrated?: <S, T>(k: S, info: ResourceFetcherInfo<T>) => void;
} : {
initialValue: T;
name?: string;
deferStream?: boolean;
ssrLoadFrom?: "initial" | "server";
storage?: (v?: T) => Signal<T | undefined>;
onHydrated?: <S, T>(k: S, info: ResourceFetcherInfo<T>) => void;
};
export declare function createResource<T, S = true>(fetcher: ResourceFetcher<S, T>, options?: ResourceOptions<undefined>): ResourceReturn<T | undefined>;
export declare function createResource<T, S = true>(fetcher: ResourceFetcher<S, T>, options: ResourceOptions<T>): ResourceReturn<T>;
export declare function createResource<T, S>(source: ResourceSource<S>, fetcher: ResourceFetcher<S, T>, options?: ResourceOptions<undefined>): ResourceReturn<T | undefined>;
export declare function createResource<T, S>(source: ResourceSource<S>, fetcher: ResourceFetcher<S, T>, options: ResourceOptions<T>): ResourceReturn<T>;
export declare function lazy<T extends Component<any>>(fn: () => Promise<{
default: T;
}>): T & {
preload: () => Promise<{
default: T;
}>;
};
export declare function enableScheduling(): void;
export declare function enableHydration(): void;
export declare function startTransition(fn: () => any): void;
export declare function useTransition(): [() => boolean, (fn: () => any) => void];
type HydrationContext = {
id: string;
count: number;
serialize: (id: string, v: Promise<any> | any, deferStream?: boolean) => void;
nextRoot: (v: any) => string;
replace: (id: string, replacement: () => any) => void;
block: (p: Promise<any>) => void;
resources: Record<string, any>;
suspense: Record<string, SuspenseContextType>;
registerFragment: (v: string) => (v?: string, err?: any) => boolean;
lazy: Record<string, Promise<any>>;
async?: boolean;
noHydrate: boolean;
};
export declare function SuspenseList(props: {
children: string;
revealOrder: "forwards" | "backwards" | "together";
tail?: "collapsed" | "hidden";
}): string;
export declare function Suspense(props: {
fallback?: string;
children: string;
}): string | number | boolean | Node | JSX.ArrayElement | {
t: string;
} | null | undefined;
export {};

View File

@@ -0,0 +1,245 @@
'use strict';
var solidJs = require('solid-js');
const memo = fn => solidJs.createMemo(() => fn());
function createRenderer$1({
createElement,
createTextNode,
isTextNode,
replaceText,
insertNode,
removeNode,
setProperty,
getParentNode,
getFirstChild,
getNextSibling
}) {
function insert(parent, accessor, marker, initial) {
if (marker !== undefined && !initial) initial = [];
if (typeof accessor !== "function") return insertExpression(parent, accessor, initial, marker);
solidJs.createRenderEffect(current => insertExpression(parent, accessor(), current, marker), initial);
}
function insertExpression(parent, value, current, marker, unwrapArray) {
while (typeof current === "function") current = current();
if (value === current) return current;
const t = typeof value,
multi = marker !== undefined;
if (t === "string" || t === "number") {
if (t === "number") value = value.toString();
if (multi) {
let node = current[0];
if (node && isTextNode(node)) {
replaceText(node, value);
} else node = createTextNode(value);
current = cleanChildren(parent, current, marker, node);
} else {
if (current !== "" && typeof current === "string") {
replaceText(getFirstChild(parent), current = value);
} else {
cleanChildren(parent, current, marker, createTextNode(value));
current = value;
}
}
} else if (value == null || t === "boolean") {
current = cleanChildren(parent, current, marker);
} else if (t === "function") {
solidJs.createRenderEffect(() => {
let v = value();
while (typeof v === "function") v = v();
current = insertExpression(parent, v, current, marker);
});
return () => current;
} else if (Array.isArray(value)) {
const array = [];
if (normalizeIncomingArray(array, value, unwrapArray)) {
solidJs.createRenderEffect(() => current = insertExpression(parent, array, current, marker, true));
return () => current;
}
if (array.length === 0) {
const replacement = cleanChildren(parent, current, marker);
if (multi) return current = replacement;
} else {
if (Array.isArray(current)) {
if (current.length === 0) {
appendNodes(parent, array, marker);
} else reconcileArrays(parent, current, array);
} else if (current == null || current === "") {
appendNodes(parent, array);
} else {
reconcileArrays(parent, multi && current || [getFirstChild(parent)], array);
}
}
current = array;
} else {
if (Array.isArray(current)) {
if (multi) return current = cleanChildren(parent, current, marker, value);
cleanChildren(parent, current, null, value);
} else if (current == null || current === "" || !getFirstChild(parent)) {
insertNode(parent, value);
} else replaceNode(parent, value, getFirstChild(parent));
current = value;
}
return current;
}
function normalizeIncomingArray(normalized, array, unwrap) {
let dynamic = false;
for (let i = 0, len = array.length; i < len; i++) {
let item = array[i],
t;
if (item == null || item === true || item === false) ; else if (Array.isArray(item)) {
dynamic = normalizeIncomingArray(normalized, item) || dynamic;
} else if ((t = typeof item) === "string" || t === "number") {
normalized.push(createTextNode(item));
} else if (t === "function") {
if (unwrap) {
while (typeof item === "function") item = item();
dynamic = normalizeIncomingArray(normalized, Array.isArray(item) ? item : [item]) || dynamic;
} else {
normalized.push(item);
dynamic = true;
}
} else normalized.push(item);
}
return dynamic;
}
function reconcileArrays(parentNode, a, b) {
let bLength = b.length,
aEnd = a.length,
bEnd = bLength,
aStart = 0,
bStart = 0,
after = getNextSibling(a[aEnd - 1]),
map = null;
while (aStart < aEnd || bStart < bEnd) {
if (a[aStart] === b[bStart]) {
aStart++;
bStart++;
continue;
}
while (a[aEnd - 1] === b[bEnd - 1]) {
aEnd--;
bEnd--;
}
if (aEnd === aStart) {
const node = bEnd < bLength ? bStart ? getNextSibling(b[bStart - 1]) : b[bEnd - bStart] : after;
while (bStart < bEnd) insertNode(parentNode, b[bStart++], node);
} else if (bEnd === bStart) {
while (aStart < aEnd) {
if (!map || !map.has(a[aStart])) removeNode(parentNode, a[aStart]);
aStart++;
}
} else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) {
const node = getNextSibling(a[--aEnd]);
insertNode(parentNode, b[bStart++], getNextSibling(a[aStart++]));
insertNode(parentNode, b[--bEnd], node);
a[aEnd] = b[bEnd];
} else {
if (!map) {
map = new Map();
let i = bStart;
while (i < bEnd) map.set(b[i], i++);
}
const index = map.get(a[aStart]);
if (index != null) {
if (bStart < index && index < bEnd) {
let i = aStart,
sequence = 1,
t;
while (++i < aEnd && i < bEnd) {
if ((t = map.get(a[i])) == null || t !== index + sequence) break;
sequence++;
}
if (sequence > index - bStart) {
const node = a[aStart];
while (bStart < index) insertNode(parentNode, b[bStart++], node);
} else replaceNode(parentNode, b[bStart++], a[aStart++]);
} else aStart++;
} else removeNode(parentNode, a[aStart++]);
}
}
}
function cleanChildren(parent, current, marker, replacement) {
if (marker === undefined) {
let removed;
while (removed = getFirstChild(parent)) removeNode(parent, removed);
replacement && insertNode(parent, replacement);
return "";
}
const node = replacement || createTextNode("");
if (current.length) {
let inserted = false;
for (let i = current.length - 1; i >= 0; i--) {
const el = current[i];
if (node !== el) {
const isParent = getParentNode(el) === parent;
if (!inserted && !i) isParent ? replaceNode(parent, node, el) : insertNode(parent, node, marker);else isParent && removeNode(parent, el);
} else inserted = true;
}
} else insertNode(parent, node, marker);
return [node];
}
function appendNodes(parent, array, marker) {
for (let i = 0, len = array.length; i < len; i++) insertNode(parent, array[i], marker);
}
function replaceNode(parent, newNode, oldNode) {
insertNode(parent, newNode, oldNode);
removeNode(parent, oldNode);
}
function spreadExpression(node, props, prevProps = {}, skipChildren) {
props || (props = {});
if (!skipChildren) {
solidJs.createRenderEffect(() => prevProps.children = insertExpression(node, props.children, prevProps.children));
}
solidJs.createRenderEffect(() => props.ref && props.ref(node));
solidJs.createRenderEffect(() => {
for (const prop in props) {
if (prop === "children" || prop === "ref") continue;
const value = props[prop];
if (value === prevProps[prop]) continue;
setProperty(node, prop, value, prevProps[prop]);
prevProps[prop] = value;
}
});
return prevProps;
}
return {
render(code, element) {
let disposer;
solidJs.createRoot(dispose => {
disposer = dispose;
insert(element, code());
});
return disposer;
},
insert,
spread(node, accessor, skipChildren) {
if (typeof accessor === "function") {
solidJs.createRenderEffect(current => spreadExpression(node, accessor(), current, skipChildren));
} else spreadExpression(node, accessor, undefined, skipChildren);
},
createElement,
createTextNode,
insertNode,
setProp(node, name, value, prev) {
setProperty(node, name, value, prev);
return value;
},
mergeProps: solidJs.mergeProps,
effect: solidJs.createRenderEffect,
memo,
createComponent: solidJs.createComponent,
use(fn, element, arg) {
return solidJs.untrack(() => fn(element, arg));
}
};
}
function createRenderer(options) {
const renderer = createRenderer$1(options);
renderer.mergeProps = solidJs.mergeProps;
return renderer;
}
exports.createRenderer = createRenderer;

Some files were not shown because too many files have changed in this diff Show More