solid-js
Version:
A declarative JavaScript library for building user interfaces.
800 lines (794 loc) • 24.9 kB
JavaScript
import { sharedConfig, splitProps } from 'solid-js';
export { ErrorBoundary, For, Index, Match, Show, Suspense, SuspenseList, Switch, createComponent, mergeProps } from 'solid-js';
const booleans = ["allowfullscreen", "async", "autofocus", "autoplay", "checked", "controls", "default", "disabled", "formnovalidate", "hidden", "indeterminate", "ismap", "loop", "multiple", "muted", "nomodule", "novalidate", "open", "playsinline", "readonly", "required", "reversed", "seamless", "selected"];
const BooleanAttributes = /*#__PURE__*/new Set(booleans);
/*#__PURE__*/new Set(["className", "value", "readOnly", "formNoValidate", "isMap", "noModule", "playsInline", ...booleans]);
const ChildProperties = /*#__PURE__*/new Set(["innerHTML", "textContent", "innerText", "children"]);
const Aliases = /*#__PURE__*/Object.assign(Object.create(null), {
className: "class",
htmlFor: "for"
});
const {
hasOwnProperty
} = Object.prototype;
const REF_START_CHARS = "hjkmoquxzABCDEFGHIJKLNPQRTUVWXYZ$_";
const REF_START_CHARS_LEN = REF_START_CHARS.length;
const REF_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$_";
const REF_CHARS_LEN = REF_CHARS.length;
const STACK = [];
const BUFFER = [""];
let ASSIGNMENTS = new Map();
let INDEX_OR_REF = new WeakMap();
let REF_COUNT = 0;
BUFFER.pop();
function stringify(root) {
if (writeProp(root, "")) {
let result = BUFFER[0];
for (let i = 1, len = BUFFER.length; i < len; i++) {
result += BUFFER[i];
}
if (REF_COUNT) {
if (ASSIGNMENTS.size) {
let ref = INDEX_OR_REF.get(root);
if (typeof ref === "number") {
ref = toRefParam(REF_COUNT++);
result = ref + "=" + result;
}
for (const [assignmentRef, assignments] of ASSIGNMENTS) {
result += ";" + assignments + assignmentRef;
}
result += ";return " + ref;
ASSIGNMENTS = new Map();
} else {
result = "return " + result;
}
result = "(function(" + refParamsString() + "){" + result + "}())";
} else if (root && root.constructor === Object) {
result = "(" + result + ")";
}
BUFFER.length = 0;
INDEX_OR_REF = new WeakMap();
return result;
}
return "void 0";
}
function writeProp(cur, accessor) {
switch (typeof cur) {
case "string":
BUFFER.push(quote(cur, 0));
break;
case "number":
BUFFER.push(cur + "");
break;
case "boolean":
BUFFER.push(cur ? "!0" : "!1");
break;
case "object":
if (cur === null) {
BUFFER.push("null");
} else {
const ref = getRef(cur, accessor);
switch (ref) {
case true:
return false;
case false:
switch (cur.constructor) {
case Object:
writeObject(cur);
break;
case Array:
writeArray(cur);
break;
case Date:
BUFFER.push('new Date("' + cur.toISOString() + '")');
break;
case RegExp:
BUFFER.push(cur + "");
break;
case Map:
BUFFER.push("new Map(");
writeArray(Array.from(cur));
BUFFER.push(")");
break;
case Set:
BUFFER.push("new Set(");
writeArray(Array.from(cur));
BUFFER.push(")");
break;
case undefined:
BUFFER.push("Object.assign(Object.create(null),");
writeObject(cur);
BUFFER.push(")");
break;
default:
return false;
}
break;
default:
BUFFER.push(ref);
break;
}
}
break;
default:
return false;
}
return true;
}
function writeObject(obj) {
let sep = "{";
STACK.push(obj);
for (const key in obj) {
if (hasOwnProperty.call(obj, key)) {
const val = obj[key];
const escapedKey = toObjectKey(key);
BUFFER.push(sep + escapedKey + ":");
if (writeProp(val, escapedKey)) {
sep = ",";
} else {
BUFFER.pop();
}
}
}
if (sep === "{") {
BUFFER.push("{}");
} else {
BUFFER.push("}");
}
STACK.pop();
}
function writeArray(arr) {
BUFFER.push("[");
STACK.push(arr);
writeProp(arr[0], 0);
for (let i = 1, len = arr.length; i < len; i++) {
BUFFER.push(",");
writeProp(arr[i], i);
}
STACK.pop();
BUFFER.push("]");
}
function getRef(cur, accessor) {
let ref = INDEX_OR_REF.get(cur);
if (ref === undefined) {
INDEX_OR_REF.set(cur, BUFFER.length);
return false;
}
if (typeof ref === "number") {
ref = insertAndGetRef(cur, ref);
}
if (STACK.includes(cur)) {
const parent = STACK[STACK.length - 1];
let parentRef = INDEX_OR_REF.get(parent);
if (typeof parentRef === "number") {
parentRef = insertAndGetRef(parent, parentRef);
}
ASSIGNMENTS.set(ref, (ASSIGNMENTS.get(ref) || "") + toAssignment(parentRef, accessor) + "=");
return true;
}
return ref;
}
function toObjectKey(name) {
const invalidIdentifierPos = getInvalidIdentifierPos(name);
return invalidIdentifierPos === -1 ? name : quote(name, invalidIdentifierPos);
}
function toAssignment(parent, key) {
return parent + (typeof key === "number" || key[0] === '"' ? "[" + key + "]" : "." + key);
}
function getInvalidIdentifierPos(name) {
let char = name[0];
if (!(char >= "a" && char <= "z" || char >= "A" && char <= "Z" || char === "$" || char === "_")) {
return 0;
}
for (let i = 1, len = name.length; i < len; i++) {
char = name[i];
if (!(char >= "a" && char <= "z" || char >= "A" && char <= "Z" || char >= "0" && char <= "9" || char === "$" || char === "_")) {
return i;
}
}
return -1;
}
function quote(str, startPos) {
let result = "";
let lastPos = 0;
for (let i = startPos, len = str.length; i < len; i++) {
let replacement;
switch (str[i]) {
case '"':
replacement = '\\"';
break;
case "\\":
replacement = "\\\\";
break;
case "<":
replacement = "\\x3C";
break;
case "\n":
replacement = "\\n";
break;
case "\r":
replacement = "\\r";
break;
case "\u2028":
replacement = "\\u2028";
break;
case "\u2029":
replacement = "\\u2029";
break;
default:
continue;
}
result += str.slice(lastPos, i) + replacement;
lastPos = i + 1;
}
if (lastPos === startPos) {
result = str;
} else {
result += str.slice(lastPos);
}
return '"' + result + '"';
}
function insertAndGetRef(obj, pos) {
const ref = toRefParam(REF_COUNT++);
INDEX_OR_REF.set(obj, ref);
if (pos) {
BUFFER[pos - 1] += ref + "=";
} else {
BUFFER[pos] = ref + "=" + BUFFER[pos];
}
return ref;
}
function refParamsString() {
let result = REF_START_CHARS[0];
for (let i = 1; i < REF_COUNT; i++) {
result += "," + toRefParam(i);
}
REF_COUNT = 0;
return result;
}
function toRefParam(index) {
let mod = index % REF_START_CHARS_LEN;
let ref = REF_START_CHARS[mod];
index = (index - mod) / REF_START_CHARS_LEN;
while (index > 0) {
mod = index % REF_CHARS_LEN;
ref += REF_CHARS[mod];
index = (index - mod) / REF_CHARS_LEN;
}
return ref;
}
const REPLACE_SCRIPT = `function $df(e,t,n,o,d){if(n=document.getElementById(e),o=document.getElementById("pl-"+e)){for(;o&&8!==o.nodeType&&o.nodeValue!=="pl-"+e;)d=o.nextSibling,o.remove(),o=d;o.replaceWith(n.content)}n.remove(),_$HY.set(e,t),_$HY.fe(e)}`;
function renderToString(code, options = {}) {
let scripts = "";
sharedConfig.context = {
id: options.renderId || "",
count: 0,
suspense: {},
lazy: {},
assets: [],
nonce: options.nonce,
writeResource(id, p, error) {
if (sharedConfig.context.noHydrate) return;
if (error) return scripts += `_$HY.set("${id}", ${serializeError(p)});`;
scripts += `_$HY.set("${id}", ${stringify(p)});`;
}
};
let html = resolveSSRNode(escape(code()));
sharedConfig.context.noHydrate = true;
html = injectAssets(sharedConfig.context.assets, html);
if (scripts.length) html = injectScripts(html, scripts, options.nonce);
return html;
}
function renderToStringAsync(code, options = {}) {
const {
timeoutMs = 30000
} = options;
let timeoutHandle;
const timeout = new Promise((_, reject) => {
timeoutHandle = setTimeout(() => reject("renderToString timed out"), timeoutMs);
});
return Promise.race([renderToStream(code, options), timeout]).then(html => {
clearTimeout(timeoutHandle);
return html;
});
}
function renderToStream(code, options = {}) {
let {
nonce,
onCompleteShell,
onCompleteAll,
renderId
} = options;
const blockingResources = [];
const registry = new Map();
const dedupe = new WeakMap();
const checkEnd = () => {
if (!registry.size && !completed) {
writeTasks();
onCompleteAll && onCompleteAll({
write(v) {
!completed && buffer.write(v);
}
});
writable && writable.end();
completed = true;
}
};
const pushTask = task => {
tasks += task + ";";
if (!scheduled && firstFlushed) {
Promise.resolve().then(writeTasks);
scheduled = true;
}
};
const writeTasks = () => {
if (tasks.length && !completed && firstFlushed) {
buffer.write(`<script${nonce ? ` nonce="${nonce}"` : ""}>${tasks}</script>`);
tasks = "";
}
scheduled = false;
};
let context;
let writable;
let tmp = "";
let tasks = "";
let firstFlushed = false;
let completed = false;
let scriptFlushed = false;
let scheduled = true;
let buffer = {
write(payload) {
tmp += payload;
}
};
sharedConfig.context = context = {
id: renderId || "",
count: 0,
async: true,
resources: {},
lazy: {},
suspense: {},
assets: [],
nonce,
block(p) {
if (!firstFlushed) blockingResources.push(p);
},
replace(id, payloadFn) {
if (firstFlushed) return;
const placeholder = `<!${id}>`;
const first = html.indexOf(placeholder);
if (first === -1) return;
const last = html.indexOf(`<!/${id}>`, first + placeholder.length);
html = html.replace(html.slice(first, last + placeholder.length + 1), resolveSSRNode(payloadFn()));
},
writeResource(id, p, error, wait) {
const serverOnly = sharedConfig.context.noHydrate;
if (error) return !serverOnly && pushTask(serializeSet(dedupe, id, p, serializeError));
if (!p || typeof p !== "object" || !("then" in p)) return !serverOnly && pushTask(serializeSet(dedupe, id, p));
if (!firstFlushed) wait && blockingResources.push(p);else !serverOnly && pushTask(`_$HY.init("${id}")`);
if (serverOnly) return;
p.then(d => {
!completed && pushTask(serializeSet(dedupe, id, d));
}).catch(() => {
!completed && pushTask(`_$HY.set("${id}", {})`);
});
},
registerFragment(key) {
if (!registry.has(key)) {
registry.set(key, []);
firstFlushed && pushTask(`_$HY.init("${key}")`);
}
return (value, error) => {
if (registry.has(key)) {
const keys = registry.get(key);
registry.delete(key);
if (waitForFragments(registry, key)) return;
if ((value !== undefined || error) && !completed) {
if (!firstFlushed) {
Promise.resolve().then(() => html = replacePlaceholder(html, key, value !== undefined ? value : ""));
error && pushTask(serializeSet(dedupe, key, error, serializeError));
} else {
buffer.write(`<template id="${key}">${value !== undefined ? value : " "}</template>`);
pushTask(`${keys.length ? keys.map(k => `_$HY.unset("${k}")`).join(";") + ";" : ""}$df("${key}"${error ? "," + serializeError(error) : ""})${!scriptFlushed ? ";" + REPLACE_SCRIPT : ""}`);
scriptFlushed = true;
}
}
}
if (!registry.size) Promise.resolve().then(checkEnd);
return firstFlushed;
};
}
};
let html = resolveSSRNode(escape(code()));
function doShell() {
sharedConfig.context = context;
context.noHydrate = true;
html = injectAssets(context.assets, html);
for (const key in context.resources) {
if (!("data" in context.resources[key] || context.resources[key].ref[0].error)) pushTask(`_$HY.init("${key}")`);
}
for (const key of registry.keys()) pushTask(`_$HY.init("${key}")`);
if (tasks.length) html = injectScripts(html, tasks, nonce);
buffer.write(html);
tasks = "";
scheduled = false;
onCompleteShell && onCompleteShell({
write(v) {
!completed && buffer.write(v);
}
});
}
return {
then(fn) {
function complete() {
doShell();
fn(tmp);
}
if (onCompleteAll) {
ogComplete = onCompleteAll;
onCompleteAll = options => {
ogComplete(options);
complete();
};
} else onCompleteAll = complete;
if (!registry.size) Promise.resolve().then(checkEnd);
},
pipe(w) {
Promise.allSettled(blockingResources).then(() => {
doShell();
buffer = writable = w;
buffer.write(tmp);
firstFlushed = true;
if (completed) writable.end();else setTimeout(checkEnd);
});
},
pipeTo(w) {
Promise.allSettled(blockingResources).then(() => {
doShell();
const encoder = new TextEncoder();
const writer = w.getWriter();
writable = {
end() {
writer.releaseLock();
w.close();
}
};
buffer = {
write(payload) {
writer.write(encoder.encode(payload));
}
};
buffer.write(tmp);
firstFlushed = true;
if (completed) writable.end();else setTimeout(checkEnd);
});
}
};
}
function HydrationScript(props) {
const {
nonce
} = sharedConfig.context;
return ssr(generateHydrationScript({
nonce,
...props
}));
}
function ssr(t, ...nodes) {
if (nodes.length) {
let result = "";
for (let i = 0; i < nodes.length; i++) {
result += t[i];
const node = nodes[i];
if (node !== undefined) result += resolveSSRNode(node);
}
t = result + t[nodes.length];
}
return {
t
};
}
function ssrClassList(value) {
if (!value) return "";
let classKeys = Object.keys(value),
result = "";
for (let i = 0, len = classKeys.length; i < len; i++) {
const key = classKeys[i],
classValue = !!value[key];
if (!key || key === "undefined" || !classValue) continue;
i && (result += " ");
result += key;
}
return result;
}
function ssrStyle(value) {
if (!value) return "";
if (typeof value === "string") return value;
let result = "";
const k = Object.keys(value);
for (let i = 0; i < k.length; i++) {
const s = k[i];
const v = value[s];
if (v != undefined) {
if (i) result += ";";
result += `${s}:${escape(v, true)}`;
}
}
return result;
}
function ssrElement(tag, props, children, needsId) {
let result = `<${tag}${needsId ? ssrHydrationKey() : ""} `;
if (props == null) props = {};else if (typeof props === "function") props = props();
const keys = Object.keys(props);
let classResolved;
for (let i = 0; i < keys.length; i++) {
const prop = keys[i];
if (ChildProperties.has(prop)) {
if (children === undefined) children = prop === "innerHTML" ? props[prop] : escape(props[prop]);
continue;
}
const value = props[prop];
if (prop === "style") {
result += `style="${ssrStyle(value)}"`;
} else if (prop === "class" || prop === "className" || prop === "classList") {
if (classResolved) continue;
let n;
result += `class="${(n = props.class) ? n + " " : ""}${(n = props.className) ? n + " " : ""}${ssrClassList(props.classList)}"`;
classResolved = true;
} else if (BooleanAttributes.has(prop)) {
if (value) result += prop;else continue;
} else if (value == undefined || prop === "ref" || prop.slice(0, 2) === "on") {
continue;
} else {
result += `${Aliases[prop] || prop}="${escape(value, true)}"`;
}
if (i !== keys.length - 1) result += " ";
}
return {
t: result + `>${resolveSSRNode(children)}</${tag}>`
};
}
function ssrAttribute(key, value, isBoolean) {
return isBoolean ? value ? " " + key : "" : value != null ? ` ${key}="${value}"` : "";
}
function ssrHydrationKey() {
const hk = getHydrationKey();
return hk ? ` data-hk="${hk}"` : "";
}
function escape(s, attr) {
const t = typeof s;
if (t !== "string") {
if (!attr && t === "function") return escape(s(), attr);
if (!attr && Array.isArray(s)) {
let r = "";
for (let i = 0; i < s.length; i++) r += resolveSSRNode(escape(s[i], attr));
return {
t: r
};
}
if (attr && t === "boolean") return String(s);
return s;
}
const delim = attr ? '"' : "<";
const escDelim = attr ? """ : "<";
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 += "&";
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 += "&";
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 mapped = "";
for (let i = 0, len = node.length; i < len; i++) mapped += resolveSSRNode(node[i]);
return mapped;
}
if (t === "object") return node.t;
if (t === "function") return resolveSSRNode(node());
return String(node);
}
function getHydrationKey() {
const hydrate = sharedConfig.context;
return hydrate && !hydrate.noHydrate && `${hydrate.id}${hydrate.count++}`;
}
function useAssets(fn) {
sharedConfig.context.assets.push(() => resolveSSRNode(fn()));
}
function getAssets() {
const assets = sharedConfig.context.assets;
let out = "";
for (let i = 0, len = assets.length; i < len; i++) out += assets[i]();
return out;
}
function generateHydrationScript({
eventNames = ["click", "input"],
nonce
} = {}) {
return `<script${nonce ? ` nonce="${nonce}"` : ""}>(e=>{let t=e=>e&&e.hasAttribute&&(e.hasAttribute("data-hk")?e:t(e.host&&e.host instanceof Node?e.host:e.parentNode));["${eventNames.join('", "')}"].forEach((o=>document.addEventListener(o,(o=>{let s=o.composedPath&&o.composedPath()[0]||o.target,a=t(s);a&&!e.completed.has(a)&&e.events.push([a,o])}))))})(window._$HY||(_$HY={events:[],completed:new WeakSet,r:{},fe(){},init(e,t){_$HY.r[e]=[new Promise((e=>t=e)),t]},set(e,t,o){(o=_$HY.r[e])&&o[1](t),_$HY.r[e]=[t]},unset(e){delete _$HY.r[e]},load:e=>_$HY.r[e]}));</script><!--xs-->`;
}
function Hydration(props) {
if (!sharedConfig.context.noHydrate) return props.children;
const context = sharedConfig.context;
sharedConfig.context = {
...context,
count: 0,
id: `${context.id}${context.count++}-`,
noHydrate: false
};
const res = props.children;
sharedConfig.context = context;
return res;
}
function NoHydration(props) {
sharedConfig.context.noHydrate = true;
return props.children;
}
function injectAssets(assets, html) {
if (!assets || !assets.length) return html;
let out = "";
for (let i = 0, len = assets.length; i < len; i++) out += assets[i]();
return html.replace(`</head>`, out + `</head>`);
}
function injectScripts(html, scripts, nonce) {
const tag = `<script${nonce ? ` nonce="${nonce}"` : ""}>${scripts}</script>`;
const index = html.indexOf("<!--xs-->");
if (index > -1) {
return html.slice(0, index) + tag + html.slice(index);
}
return html + tag;
}
function serializeError(error) {
if (error.message) {
const fields = {};
const keys = Object.getOwnPropertyNames(error);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = error[key];
if (!value || key !== "message" && typeof value !== "function") {
fields[key] = value;
}
}
return `Object.assign(new Error(${stringify(error.message)}), ${stringify(fields)})`;
}
return stringify(error);
}
function waitForFragments(registry, key) {
for (const k of [...registry.keys()].reverse()) {
if (key.startsWith(k)) {
registry.get(k).push(key);
return true;
}
}
return false;
}
function serializeSet(registry, key, value, serializer = stringify) {
const exist = registry.get(value);
if (exist) return `_$HY.set("${key}", _$HY.r["${exist}"][0])`;
value !== null && typeof value === "object" && registry.set(value, key);
return `_$HY.set("${key}", ${serializer(value)})`;
}
function replacePlaceholder(html, key, value) {
const marker = `<template id="pl-${key}">`;
const close = `<!pl-${key}>`;
const first = html.indexOf(marker);
if (first === -1) return html;
const last = html.indexOf(close, first + marker.length);
return html.slice(0, first) + value + html.slice(last + close.length);
}
function Assets(props) {
useAssets(() => props.children);
}
function pipeToNodeWritable(code, writable, options = {}) {
if (options.onReady) {
options.onCompleteShell = ({
write
}) => {
options.onReady({
write,
startWriting() {
stream.pipe(writable);
}
});
};
}
const stream = renderToStream(code, options);
if (!options.onReady) stream.pipe(writable);
}
function pipeToWritable(code, writable, options = {}) {
if (options.onReady) {
options.onCompleteShell = ({
write
}) => {
options.onReady({
write,
startWriting() {
stream.pipeTo(writable);
}
});
};
}
const stream = renderToStream(code, options);
if (!options.onReady) stream.pipeTo(writable);
}
function ssrSpread(props, isSVG, skipChildren) {
let result = "";
if (props == null) return result;
if (typeof props === "function") props = props();
const keys = Object.keys(props);
let classResolved;
for (let i = 0; i < keys.length; i++) {
const prop = keys[i];
if (prop === "children") {
!skipChildren && console.warn(`SSR currently does not support spread children.`);
continue;
}
const value = props[prop];
if (prop === "style") {
result += `style="${ssrStyle(value)}"`;
} else if (prop === "class" || prop === "className" || prop === "classList") {
if (classResolved) continue;
let n;
result += `class="${(n = props.class) ? n + " " : ""}${(n = props.className) ? n + " " : ""}${ssrClassList(props.classList)}"`;
classResolved = true;
} else if (BooleanAttributes.has(prop)) {
if (value) result += prop;else continue;
} else if (value == undefined || prop === "ref" || prop.slice(0, 2) === "on") {
continue;
} else {
result += `${Aliases[prop] || prop}="${escape(value, true)}"`;
}
if (i !== keys.length - 1) result += " ";
}
return result;
}
const isServer = true;
function render() {}
function hydrate() {}
function insert() {}
function spread() {}
function addEventListener() {}
function delegateEvents() {}
function Dynamic(props) {
const [p, others] = splitProps(props, ["component"]);
const comp = p.component,
t = typeof comp;
if (comp) {
if (t === "function") return comp(others);else if (t === "string") {
return ssrElement(comp, others, undefined, true);
}
}
}
function Portal(props) {
return "";
}
export { Assets, Dynamic, Hydration, HydrationScript, NoHydration, Portal, addEventListener, delegateEvents, escape, generateHydrationScript, getAssets, getHydrationKey, hydrate, insert, isServer, pipeToNodeWritable, pipeToWritable, render, renderToStream, renderToString, renderToStringAsync, resolveSSRNode, spread, ssr, ssrAttribute, ssrClassList, ssrElement, ssrHydrationKey, ssrSpread, ssrStyle, stringify, useAssets };