UNPKG

solid-js

Version:

A declarative JavaScript library for building user interfaces.

872 lines (865 loc) 26.8 kB
'use strict'; var solidJs = require('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 = ""; solidJs.sharedConfig.context = { id: options.renderId || "", count: 0, suspense: {}, lazy: {}, assets: [], nonce: options.nonce, writeResource(id, p, error) { if (solidJs.sharedConfig.context.noHydrate) return; if (error) return scripts += `_$HY.set("${id}", ${serializeError(p)});`; scripts += `_$HY.set("${id}", ${stringify(p)});`; } }; let html = resolveSSRNode(escape(code())); solidJs.sharedConfig.context.noHydrate = true; html = injectAssets(solidJs.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; } }; solidJs.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 = solidJs.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() { solidJs.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 } = solidJs.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 ? "&quot;" : "&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 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 = solidJs.sharedConfig.context; return hydrate && !hydrate.noHydrate && `${hydrate.id}${hydrate.count++}`; } function useAssets(fn) { solidJs.sharedConfig.context.assets.push(() => resolveSSRNode(fn())); } function getAssets() { const assets = solidJs.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 (!solidJs.sharedConfig.context.noHydrate) return props.children; const context = solidJs.sharedConfig.context; solidJs.sharedConfig.context = { ...context, count: 0, id: `${context.id}${context.count++}-`, noHydrate: false }; const res = props.children; solidJs.sharedConfig.context = context; return res; } function NoHydration(props) { solidJs.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] = solidJs.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 ""; } Object.defineProperty(exports, 'ErrorBoundary', { enumerable: true, get: function () { return solidJs.ErrorBoundary; } }); Object.defineProperty(exports, 'For', { enumerable: true, get: function () { return solidJs.For; } }); Object.defineProperty(exports, 'Index', { enumerable: true, get: function () { return solidJs.Index; } }); Object.defineProperty(exports, 'Match', { enumerable: true, get: function () { return solidJs.Match; } }); Object.defineProperty(exports, 'Show', { enumerable: true, get: function () { return solidJs.Show; } }); Object.defineProperty(exports, 'Suspense', { enumerable: true, get: function () { return solidJs.Suspense; } }); Object.defineProperty(exports, 'SuspenseList', { enumerable: true, get: function () { return solidJs.SuspenseList; } }); Object.defineProperty(exports, 'Switch', { enumerable: true, get: function () { return solidJs.Switch; } }); Object.defineProperty(exports, 'createComponent', { enumerable: true, get: function () { return solidJs.createComponent; } }); Object.defineProperty(exports, 'mergeProps', { enumerable: true, get: function () { return solidJs.mergeProps; } }); exports.Assets = Assets; exports.Dynamic = Dynamic; exports.Hydration = Hydration; exports.HydrationScript = HydrationScript; exports.NoHydration = NoHydration; exports.Portal = Portal; exports.addEventListener = addEventListener; exports.delegateEvents = delegateEvents; exports.escape = escape; exports.generateHydrationScript = generateHydrationScript; exports.getAssets = getAssets; exports.getHydrationKey = getHydrationKey; exports.hydrate = hydrate; exports.insert = insert; exports.isServer = isServer; exports.pipeToNodeWritable = pipeToNodeWritable; exports.pipeToWritable = pipeToWritable; exports.render = render; exports.renderToStream = renderToStream; exports.renderToString = renderToString; exports.renderToStringAsync = renderToStringAsync; exports.resolveSSRNode = resolveSSRNode; exports.spread = spread; exports.ssr = ssr; exports.ssrAttribute = ssrAttribute; exports.ssrClassList = ssrClassList; exports.ssrElement = ssrElement; exports.ssrHydrationKey = ssrHydrationKey; exports.ssrSpread = ssrSpread; exports.ssrStyle = ssrStyle; exports.stringify = stringify; exports.useAssets = useAssets;