1733 lines
48 KiB
JavaScript
1733 lines
48 KiB
JavaScript
import { clsx as clsx$1 } from 'clsx';
|
||
|
||
/** @type {Record<string, string>} */
|
||
const escaped = {
|
||
'<': '\\u003C',
|
||
'\\': '\\\\',
|
||
'\b': '\\b',
|
||
'\f': '\\f',
|
||
'\n': '\\n',
|
||
'\r': '\\r',
|
||
'\t': '\\t',
|
||
'\u2028': '\\u2028',
|
||
'\u2029': '\\u2029'
|
||
};
|
||
|
||
class DevalueError extends Error {
|
||
/**
|
||
* @param {string} message
|
||
* @param {string[]} keys
|
||
* @param {any} [value] - The value that failed to be serialized
|
||
* @param {any} [root] - The root value being serialized
|
||
*/
|
||
constructor(message, keys, value, root) {
|
||
super(message);
|
||
this.name = 'DevalueError';
|
||
this.path = keys.join('');
|
||
this.value = value;
|
||
this.root = root;
|
||
}
|
||
}
|
||
|
||
/** @param {any} thing */
|
||
function is_primitive(thing) {
|
||
return Object(thing) !== thing;
|
||
}
|
||
|
||
const object_proto_names = /* @__PURE__ */ Object.getOwnPropertyNames(
|
||
Object.prototype
|
||
)
|
||
.sort()
|
||
.join('\0');
|
||
|
||
/** @param {any} thing */
|
||
function is_plain_object(thing) {
|
||
const proto = Object.getPrototypeOf(thing);
|
||
|
||
return (
|
||
proto === Object.prototype ||
|
||
proto === null ||
|
||
Object.getPrototypeOf(proto) === null ||
|
||
Object.getOwnPropertyNames(proto).sort().join('\0') === object_proto_names
|
||
);
|
||
}
|
||
|
||
/** @param {any} thing */
|
||
function get_type(thing) {
|
||
return Object.prototype.toString.call(thing).slice(8, -1);
|
||
}
|
||
|
||
/** @param {string} char */
|
||
function get_escaped_char(char) {
|
||
switch (char) {
|
||
case '"':
|
||
return '\\"';
|
||
case '<':
|
||
return '\\u003C';
|
||
case '\\':
|
||
return '\\\\';
|
||
case '\n':
|
||
return '\\n';
|
||
case '\r':
|
||
return '\\r';
|
||
case '\t':
|
||
return '\\t';
|
||
case '\b':
|
||
return '\\b';
|
||
case '\f':
|
||
return '\\f';
|
||
case '\u2028':
|
||
return '\\u2028';
|
||
case '\u2029':
|
||
return '\\u2029';
|
||
default:
|
||
return char < ' '
|
||
? `\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}`
|
||
: '';
|
||
}
|
||
}
|
||
|
||
/** @param {string} str */
|
||
function stringify_string(str) {
|
||
let result = '';
|
||
let last_pos = 0;
|
||
const len = str.length;
|
||
|
||
for (let i = 0; i < len; i += 1) {
|
||
const char = str[i];
|
||
const replacement = get_escaped_char(char);
|
||
if (replacement) {
|
||
result += str.slice(last_pos, i) + replacement;
|
||
last_pos = i + 1;
|
||
}
|
||
}
|
||
|
||
return `"${last_pos === 0 ? str : result + str.slice(last_pos)}"`;
|
||
}
|
||
|
||
/** @param {Record<string | symbol, any>} object */
|
||
function enumerable_symbols(object) {
|
||
return Object.getOwnPropertySymbols(object).filter(
|
||
(symbol) => Object.getOwnPropertyDescriptor(object, symbol).enumerable
|
||
);
|
||
}
|
||
|
||
const is_identifier = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/;
|
||
|
||
/** @param {string} key */
|
||
function stringify_key(key) {
|
||
return is_identifier.test(key) ? '.' + key : '[' + JSON.stringify(key) + ']';
|
||
}
|
||
|
||
/** @param {string} s */
|
||
function is_valid_array_index(s) {
|
||
if (s.length === 0) return false;
|
||
if (s.length > 1 && s.charCodeAt(0) === 48) return false; // leading zero
|
||
for (let i = 0; i < s.length; i++) {
|
||
const c = s.charCodeAt(i);
|
||
if (c < 48 || c > 57) return false;
|
||
}
|
||
// by this point we know it's a string of digits, but it has to be within the range of valid array indices
|
||
const n = +s;
|
||
if (n >= 2 ** 32 - 1) return false;
|
||
if (n < 0) return false;
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Finds the populated indices of an array.
|
||
* @param {unknown[]} array
|
||
*/
|
||
function valid_array_indices(array) {
|
||
const keys = Object.keys(array);
|
||
for (var i = keys.length - 1; i >= 0; i--) {
|
||
if (is_valid_array_index(keys[i])) {
|
||
break;
|
||
}
|
||
}
|
||
keys.length = i + 1;
|
||
return keys;
|
||
}
|
||
|
||
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$';
|
||
const unsafe_chars = /[<\b\f\n\r\t\0\u2028\u2029]/g;
|
||
const reserved =
|
||
/^(?:do|if|in|for|int|let|new|try|var|byte|case|char|else|enum|goto|long|this|void|with|await|break|catch|class|const|final|float|short|super|throw|while|yield|delete|double|export|import|native|return|switch|throws|typeof|boolean|default|extends|finally|package|private|abstract|continue|debugger|function|volatile|interface|protected|transient|implements|instanceof|synchronized)$/;
|
||
|
||
/**
|
||
* Turn a value into the JavaScript that creates an equivalent value
|
||
* @param {any} value
|
||
* @param {(value: any, uneval: (value: any) => string) => string | void} [replacer]
|
||
*/
|
||
function uneval(value, replacer) {
|
||
const counts = new Map();
|
||
|
||
/** @type {string[]} */
|
||
const keys = [];
|
||
|
||
const custom = new Map();
|
||
|
||
/** @param {any} thing */
|
||
function walk(thing) {
|
||
if (!is_primitive(thing)) {
|
||
if (counts.has(thing)) {
|
||
counts.set(thing, counts.get(thing) + 1);
|
||
return;
|
||
}
|
||
|
||
counts.set(thing, 1);
|
||
|
||
if (replacer) {
|
||
const str = replacer(thing, (value) => uneval(value, replacer));
|
||
|
||
if (typeof str === 'string') {
|
||
custom.set(thing, str);
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (typeof thing === 'function') {
|
||
throw new DevalueError(`Cannot stringify a function`, keys, thing, value);
|
||
}
|
||
|
||
const type = get_type(thing);
|
||
|
||
switch (type) {
|
||
case 'Number':
|
||
case 'BigInt':
|
||
case 'String':
|
||
case 'Boolean':
|
||
case 'Date':
|
||
case 'RegExp':
|
||
case 'URL':
|
||
case 'URLSearchParams':
|
||
return;
|
||
|
||
case 'Array':
|
||
/** @type {any[]} */ (thing).forEach((value, i) => {
|
||
keys.push(`[${i}]`);
|
||
walk(value);
|
||
keys.pop();
|
||
});
|
||
break;
|
||
|
||
case 'Set':
|
||
Array.from(thing).forEach(walk);
|
||
break;
|
||
|
||
case 'Map':
|
||
for (const [key, value] of thing) {
|
||
keys.push(
|
||
`.get(${is_primitive(key) ? stringify_primitive(key) : '...'})`
|
||
);
|
||
walk(value);
|
||
keys.pop();
|
||
}
|
||
break;
|
||
|
||
case 'Int8Array':
|
||
case 'Uint8Array':
|
||
case 'Uint8ClampedArray':
|
||
case 'Int16Array':
|
||
case 'Uint16Array':
|
||
case 'Int32Array':
|
||
case 'Uint32Array':
|
||
case 'Float32Array':
|
||
case 'Float64Array':
|
||
case 'BigInt64Array':
|
||
case 'BigUint64Array':
|
||
walk(thing.buffer);
|
||
return;
|
||
|
||
case 'ArrayBuffer':
|
||
return;
|
||
|
||
case 'Temporal.Duration':
|
||
case 'Temporal.Instant':
|
||
case 'Temporal.PlainDate':
|
||
case 'Temporal.PlainTime':
|
||
case 'Temporal.PlainDateTime':
|
||
case 'Temporal.PlainMonthDay':
|
||
case 'Temporal.PlainYearMonth':
|
||
case 'Temporal.ZonedDateTime':
|
||
return;
|
||
|
||
default:
|
||
if (!is_plain_object(thing)) {
|
||
throw new DevalueError(
|
||
`Cannot stringify arbitrary non-POJOs`,
|
||
keys,
|
||
thing,
|
||
value
|
||
);
|
||
}
|
||
|
||
if (enumerable_symbols(thing).length > 0) {
|
||
throw new DevalueError(
|
||
`Cannot stringify POJOs with symbolic keys`,
|
||
keys,
|
||
thing,
|
||
value
|
||
);
|
||
}
|
||
|
||
for (const key of Object.keys(thing)) {
|
||
if (key === '__proto__') {
|
||
throw new DevalueError(
|
||
`Cannot stringify objects with __proto__ keys`,
|
||
keys,
|
||
thing,
|
||
value
|
||
);
|
||
}
|
||
|
||
keys.push(stringify_key(key));
|
||
walk(thing[key]);
|
||
keys.pop();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
walk(value);
|
||
|
||
const names = new Map();
|
||
|
||
Array.from(counts)
|
||
.filter((entry) => entry[1] > 1)
|
||
.sort((a, b) => b[1] - a[1])
|
||
.forEach((entry, i) => {
|
||
names.set(entry[0], get_name(i));
|
||
});
|
||
|
||
/**
|
||
* @param {any} thing
|
||
* @returns {string}
|
||
*/
|
||
function stringify(thing) {
|
||
if (names.has(thing)) {
|
||
return names.get(thing);
|
||
}
|
||
|
||
if (is_primitive(thing)) {
|
||
return stringify_primitive(thing);
|
||
}
|
||
|
||
if (custom.has(thing)) {
|
||
return custom.get(thing);
|
||
}
|
||
|
||
const type = get_type(thing);
|
||
|
||
switch (type) {
|
||
case 'Number':
|
||
case 'String':
|
||
case 'Boolean':
|
||
return `Object(${stringify(thing.valueOf())})`;
|
||
|
||
case 'RegExp':
|
||
return `new RegExp(${stringify_string(thing.source)}, "${
|
||
thing.flags
|
||
}")`;
|
||
|
||
case 'Date':
|
||
return `new Date(${thing.getTime()})`;
|
||
|
||
case 'URL':
|
||
return `new URL(${stringify_string(thing.toString())})`;
|
||
|
||
case 'URLSearchParams':
|
||
return `new URLSearchParams(${stringify_string(thing.toString())})`;
|
||
|
||
case 'Array': {
|
||
// For dense arrays (no holes), we iterate normally.
|
||
// When we encounter the first hole, we call Object.keys
|
||
// to determine the sparseness, then decide between:
|
||
// - Array literal with holes: [,"a",,] (default)
|
||
// - Object.assign: Object.assign(Array(n),{...}) (for very sparse arrays)
|
||
// Only the Object.assign path avoids iterating every slot, which
|
||
// is what protects against the DoS of e.g. `arr[1000000] = 1`.
|
||
let has_holes = false;
|
||
|
||
let result = '[';
|
||
|
||
for (let i = 0; i < thing.length; i += 1) {
|
||
if (i > 0) result += ',';
|
||
|
||
if (Object.hasOwn(thing, i)) {
|
||
result += stringify(thing[i]);
|
||
} else if (!has_holes) {
|
||
// Decide between array literal and Object.assign.
|
||
//
|
||
// Array literal: holes are consecutive commas.
|
||
// For example, [, "a", ,] is written as [,"a",,].
|
||
// Each hole costs 1 char (a comma).
|
||
//
|
||
// Object.assign: populated indices are listed explicitly.
|
||
// For example, [, "a", ,] would be written as
|
||
// Object.assign(Array(3),{1:"a"}). This avoids paying
|
||
// per-hole, but has a large fixed overhead for the
|
||
// "Object.assign(Array(n),{...})" wrapper, and each
|
||
// element costs extra chars for its index and colon.
|
||
//
|
||
// The serialized values are the same size either way, so
|
||
// the choice comes down to the structural overhead:
|
||
//
|
||
// Array literal overhead:
|
||
// 1 char per element or hole (comma separators)
|
||
// + 2 chars for "[" and "]"
|
||
// = L + 2
|
||
//
|
||
// Object.assign overhead:
|
||
// "Object.assign(Array(" — 20 chars
|
||
// + length — d chars
|
||
// + "),{" — 3 chars
|
||
// + for each populated element:
|
||
// index + ":" + "," — (d + 2) chars
|
||
// + "})" — 2 chars
|
||
// = (25 + d) + P * (d + 2)
|
||
//
|
||
// where L is the array length, P is the number of
|
||
// populated elements, and d is the number of digits
|
||
// in L (an upper bound on the digits in any index).
|
||
//
|
||
// Object.assign is cheaper when:
|
||
// (25 + d) + P * (d + 2) < L + 2
|
||
const populated_keys = valid_array_indices(/** @type {any[]} */ (thing));
|
||
const population = populated_keys.length;
|
||
const d = String(thing.length).length;
|
||
|
||
const hole_cost = thing.length + 2;
|
||
const sparse_cost = (25 + d) + population * (d + 2);
|
||
|
||
if (hole_cost > sparse_cost) {
|
||
const entries = populated_keys
|
||
.map((k) => `${k}:${stringify(thing[k])}`)
|
||
.join(',');
|
||
return `Object.assign(Array(${thing.length}),{${entries}})`;
|
||
}
|
||
|
||
// Re-process this index as a hole in the array literal
|
||
has_holes = true;
|
||
i -= 1;
|
||
}
|
||
// else: already decided on array literal, hole is just an empty slot
|
||
// (the comma separator is all we need — no content for this position)
|
||
}
|
||
|
||
const tail = thing.length === 0 || thing.length - 1 in thing ? '' : ',';
|
||
return result + tail + ']';
|
||
}
|
||
|
||
case 'Set':
|
||
case 'Map':
|
||
return `new ${type}([${Array.from(thing).map(stringify).join(',')}])`;
|
||
|
||
case 'Int8Array':
|
||
case 'Uint8Array':
|
||
case 'Uint8ClampedArray':
|
||
case 'Int16Array':
|
||
case 'Uint16Array':
|
||
case 'Int32Array':
|
||
case 'Uint32Array':
|
||
case 'Float32Array':
|
||
case 'Float64Array':
|
||
case 'BigInt64Array':
|
||
case 'BigUint64Array': {
|
||
let str = `new ${type}`;
|
||
|
||
if (counts.get(thing.buffer) === 1) {
|
||
const array = new thing.constructor(thing.buffer);
|
||
str += `([${array}])`;
|
||
} else {
|
||
str += `([${stringify(thing.buffer)}])`;
|
||
}
|
||
|
||
const a = thing.byteOffset;
|
||
const b = a + thing.byteLength;
|
||
|
||
// handle subarrays
|
||
if (a > 0 || b !== thing.buffer.byteLength) {
|
||
const m = +/(\d+)/.exec(type)[1] / 8;
|
||
str += `.subarray(${a / m},${b / m})`;
|
||
}
|
||
|
||
return str;
|
||
}
|
||
|
||
case 'ArrayBuffer': {
|
||
const ui8 = new Uint8Array(thing);
|
||
return `new Uint8Array([${ui8.toString()}]).buffer`;
|
||
}
|
||
|
||
case 'Temporal.Duration':
|
||
case 'Temporal.Instant':
|
||
case 'Temporal.PlainDate':
|
||
case 'Temporal.PlainTime':
|
||
case 'Temporal.PlainDateTime':
|
||
case 'Temporal.PlainMonthDay':
|
||
case 'Temporal.PlainYearMonth':
|
||
case 'Temporal.ZonedDateTime':
|
||
return `${type}.from(${stringify_string(thing.toString())})`;
|
||
|
||
default:
|
||
const keys = Object.keys(thing);
|
||
const obj = keys
|
||
.map((key) => `${safe_key(key)}:${stringify(thing[key])}`)
|
||
.join(',');
|
||
const proto = Object.getPrototypeOf(thing);
|
||
if (proto === null) {
|
||
return keys.length > 0
|
||
? `{${obj},__proto__:null}`
|
||
: `{__proto__:null}`;
|
||
}
|
||
|
||
return `{${obj}}`;
|
||
}
|
||
}
|
||
|
||
const str = stringify(value);
|
||
|
||
if (names.size) {
|
||
/** @type {string[]} */
|
||
const params = [];
|
||
|
||
/** @type {string[]} */
|
||
const statements = [];
|
||
|
||
/** @type {string[]} */
|
||
const values = [];
|
||
|
||
names.forEach((name, thing) => {
|
||
params.push(name);
|
||
|
||
if (custom.has(thing)) {
|
||
values.push(/** @type {string} */ (custom.get(thing)));
|
||
return;
|
||
}
|
||
|
||
if (is_primitive(thing)) {
|
||
values.push(stringify_primitive(thing));
|
||
return;
|
||
}
|
||
|
||
const type = get_type(thing);
|
||
|
||
switch (type) {
|
||
case 'Number':
|
||
case 'String':
|
||
case 'Boolean':
|
||
values.push(`Object(${stringify(thing.valueOf())})`);
|
||
break;
|
||
|
||
case 'RegExp':
|
||
values.push(thing.toString());
|
||
break;
|
||
|
||
case 'Date':
|
||
values.push(`new Date(${thing.getTime()})`);
|
||
break;
|
||
|
||
case 'Array':
|
||
values.push(`Array(${thing.length})`);
|
||
/** @type {any[]} */ (thing).forEach((v, i) => {
|
||
statements.push(`${name}[${i}]=${stringify(v)}`);
|
||
});
|
||
break;
|
||
|
||
case 'Set':
|
||
values.push(`new Set`);
|
||
statements.push(
|
||
`${name}.${Array.from(thing)
|
||
.map((v) => `add(${stringify(v)})`)
|
||
.join('.')}`
|
||
);
|
||
break;
|
||
|
||
case 'Map':
|
||
values.push(`new Map`);
|
||
statements.push(
|
||
`${name}.${Array.from(thing)
|
||
.map(([k, v]) => `set(${stringify(k)}, ${stringify(v)})`)
|
||
.join('.')}`
|
||
);
|
||
break;
|
||
|
||
case 'ArrayBuffer':
|
||
values.push(
|
||
`new Uint8Array([${new Uint8Array(thing).join(',')}]).buffer`
|
||
);
|
||
break;
|
||
|
||
default:
|
||
values.push(
|
||
Object.getPrototypeOf(thing) === null ? 'Object.create(null)' : '{}'
|
||
);
|
||
Object.keys(thing).forEach((key) => {
|
||
statements.push(
|
||
`${name}${safe_prop(key)}=${stringify(thing[key])}`
|
||
);
|
||
});
|
||
}
|
||
});
|
||
|
||
statements.push(`return ${str}`);
|
||
|
||
return `(function(${params.join(',')}){${statements.join(
|
||
';'
|
||
)}}(${values.join(',')}))`;
|
||
} else {
|
||
return str;
|
||
}
|
||
}
|
||
|
||
/** @param {number} num */
|
||
function get_name(num) {
|
||
let name = '';
|
||
|
||
do {
|
||
name = chars[num % chars.length] + name;
|
||
num = ~~(num / chars.length) - 1;
|
||
} while (num >= 0);
|
||
|
||
return reserved.test(name) ? `${name}0` : name;
|
||
}
|
||
|
||
/** @param {string} c */
|
||
function escape_unsafe_char(c) {
|
||
return escaped[c] || c;
|
||
}
|
||
|
||
/** @param {string} str */
|
||
function escape_unsafe_chars(str) {
|
||
return str.replace(unsafe_chars, escape_unsafe_char);
|
||
}
|
||
|
||
/** @param {string} key */
|
||
function safe_key(key) {
|
||
return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key)
|
||
? key
|
||
: escape_unsafe_chars(JSON.stringify(key));
|
||
}
|
||
|
||
/** @param {string} key */
|
||
function safe_prop(key) {
|
||
return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key)
|
||
? `.${key}`
|
||
: `[${escape_unsafe_chars(JSON.stringify(key))}]`;
|
||
}
|
||
|
||
/** @param {any} thing */
|
||
function stringify_primitive(thing) {
|
||
if (typeof thing === 'string') return stringify_string(thing);
|
||
if (thing === void 0) return 'void 0';
|
||
if (thing === 0 && 1 / thing < 0) return '-0';
|
||
const str = String(thing);
|
||
if (typeof thing === 'number') return str.replace(/^(-)?0\./, '$1.');
|
||
if (typeof thing === 'bigint') return thing + 'n';
|
||
return str;
|
||
}
|
||
|
||
var is_array = Array.isArray;
|
||
var index_of = Array.prototype.indexOf;
|
||
var includes = Array.prototype.includes;
|
||
var array_from = Array.from;
|
||
var define_property = Object.defineProperty;
|
||
var get_descriptor = Object.getOwnPropertyDescriptor;
|
||
var object_prototype = Object.prototype;
|
||
var array_prototype = Array.prototype;
|
||
var get_prototype_of = Object.getPrototypeOf;
|
||
var is_extensible = Object.isExtensible;
|
||
var has_own_property = Object.prototype.hasOwnProperty;
|
||
const noop = () => {
|
||
};
|
||
function run(fn) {
|
||
return fn();
|
||
}
|
||
function run_all(arr) {
|
||
for (var i = 0; i < arr.length; i++) {
|
||
arr[i]();
|
||
}
|
||
}
|
||
function deferred() {
|
||
var resolve;
|
||
var reject;
|
||
var promise = new Promise((res, rej) => {
|
||
resolve = res;
|
||
reject = rej;
|
||
});
|
||
return { promise, resolve, reject };
|
||
}
|
||
const DERIVED = 1 << 1;
|
||
const EFFECT = 1 << 2;
|
||
const RENDER_EFFECT = 1 << 3;
|
||
const MANAGED_EFFECT = 1 << 24;
|
||
const BLOCK_EFFECT = 1 << 4;
|
||
const BRANCH_EFFECT = 1 << 5;
|
||
const ROOT_EFFECT = 1 << 6;
|
||
const BOUNDARY_EFFECT = 1 << 7;
|
||
const CONNECTED = 1 << 9;
|
||
const CLEAN = 1 << 10;
|
||
const DIRTY = 1 << 11;
|
||
const MAYBE_DIRTY = 1 << 12;
|
||
const INERT = 1 << 13;
|
||
const DESTROYED = 1 << 14;
|
||
const REACTION_RAN = 1 << 15;
|
||
const EFFECT_TRANSPARENT = 1 << 16;
|
||
const EAGER_EFFECT = 1 << 17;
|
||
const HEAD_EFFECT = 1 << 18;
|
||
const EFFECT_PRESERVED = 1 << 19;
|
||
const USER_EFFECT = 1 << 20;
|
||
const WAS_MARKED = 1 << 16;
|
||
const REACTION_IS_UPDATING = 1 << 21;
|
||
const ASYNC = 1 << 22;
|
||
const ERROR_VALUE = 1 << 23;
|
||
const STATE_SYMBOL = Symbol("$state");
|
||
const LEGACY_PROPS = Symbol("legacy props");
|
||
const STALE_REACTION = new class StaleReactionError extends Error {
|
||
name = "StaleReactionError";
|
||
message = "The reaction that called `getAbortSignal()` was re-run or destroyed";
|
||
}();
|
||
const COMMENT_NODE = 8;
|
||
function lifecycle_outside_component(name) {
|
||
{
|
||
throw new Error(`https://svelte.dev/e/lifecycle_outside_component`);
|
||
}
|
||
}
|
||
const HYDRATION_START = "[";
|
||
const HYDRATION_START_ELSE = "[!";
|
||
const HYDRATION_END = "]";
|
||
const HYDRATION_ERROR = {};
|
||
const ELEMENT_IS_NAMESPACED = 1;
|
||
const ELEMENT_PRESERVE_ATTRIBUTE_CASE = 1 << 1;
|
||
const ELEMENT_IS_INPUT = 1 << 2;
|
||
const UNINITIALIZED = Symbol();
|
||
const ATTACHMENT_KEY = "@attach";
|
||
const DOM_BOOLEAN_ATTRIBUTES = [
|
||
"allowfullscreen",
|
||
"async",
|
||
"autofocus",
|
||
"autoplay",
|
||
"checked",
|
||
"controls",
|
||
"default",
|
||
"disabled",
|
||
"formnovalidate",
|
||
"indeterminate",
|
||
"inert",
|
||
"ismap",
|
||
"loop",
|
||
"multiple",
|
||
"muted",
|
||
"nomodule",
|
||
"novalidate",
|
||
"open",
|
||
"playsinline",
|
||
"readonly",
|
||
"required",
|
||
"reversed",
|
||
"seamless",
|
||
"selected",
|
||
"webkitdirectory",
|
||
"defer",
|
||
"disablepictureinpicture",
|
||
"disableremoteplayback"
|
||
];
|
||
function is_boolean_attribute(name) {
|
||
return DOM_BOOLEAN_ATTRIBUTES.includes(name);
|
||
}
|
||
const PASSIVE_EVENTS = ["touchstart", "touchmove"];
|
||
function is_passive_event(name) {
|
||
return PASSIVE_EVENTS.includes(name);
|
||
}
|
||
const ATTR_REGEX = /[&"<]/g;
|
||
const CONTENT_REGEX = /[&<]/g;
|
||
function escape_html(value, is_attr) {
|
||
const str = String(value ?? "");
|
||
const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX;
|
||
pattern.lastIndex = 0;
|
||
let escaped = "";
|
||
let last = 0;
|
||
while (pattern.test(str)) {
|
||
const i = pattern.lastIndex - 1;
|
||
const ch = str[i];
|
||
escaped += str.substring(last, i) + (ch === "&" ? "&" : ch === '"' ? """ : "<");
|
||
last = i + 1;
|
||
}
|
||
return escaped + str.substring(last);
|
||
}
|
||
const replacements = {
|
||
translate: /* @__PURE__ */ new Map([
|
||
[true, "yes"],
|
||
[false, "no"]
|
||
])
|
||
};
|
||
function attr(name, value, is_boolean = false) {
|
||
if (name === "hidden" && value !== "until-found") {
|
||
is_boolean = true;
|
||
}
|
||
if (value == null || !value && is_boolean) return "";
|
||
const normalized = has_own_property.call(replacements, name) && replacements[name].get(value) || value;
|
||
const assignment = is_boolean ? `=""` : `="${escape_html(normalized, true)}"`;
|
||
return ` ${name}${assignment}`;
|
||
}
|
||
function clsx(value) {
|
||
if (typeof value === "object") {
|
||
return clsx$1(value);
|
||
} else {
|
||
return value ?? "";
|
||
}
|
||
}
|
||
const whitespace = [..." \n\r\f \v\uFEFF"];
|
||
function to_class(value, hash, directives) {
|
||
var classname = value == null ? "" : "" + value;
|
||
if (hash) {
|
||
classname = classname ? classname + " " + hash : hash;
|
||
}
|
||
if (directives) {
|
||
for (var key of Object.keys(directives)) {
|
||
if (directives[key]) {
|
||
classname = classname ? classname + " " + key : key;
|
||
} else if (classname.length) {
|
||
var len = key.length;
|
||
var a = 0;
|
||
while ((a = classname.indexOf(key, a)) >= 0) {
|
||
var b = a + len;
|
||
if ((a === 0 || whitespace.includes(classname[a - 1])) && (b === classname.length || whitespace.includes(classname[b]))) {
|
||
classname = (a === 0 ? "" : classname.substring(0, a)) + classname.substring(b + 1);
|
||
} else {
|
||
a = b;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return classname === "" ? null : classname;
|
||
}
|
||
function append_styles(styles, important = false) {
|
||
var separator = important ? " !important;" : ";";
|
||
var css = "";
|
||
for (var key of Object.keys(styles)) {
|
||
var value = styles[key];
|
||
if (value != null && value !== "") {
|
||
css += " " + key + ": " + value + separator;
|
||
}
|
||
}
|
||
return css;
|
||
}
|
||
function to_css_name(name) {
|
||
if (name[0] !== "-" || name[1] !== "-") {
|
||
return name.toLowerCase();
|
||
}
|
||
return name;
|
||
}
|
||
function to_style(value, styles) {
|
||
if (styles) {
|
||
var new_style = "";
|
||
var normal_styles;
|
||
var important_styles;
|
||
if (Array.isArray(styles)) {
|
||
normal_styles = styles[0];
|
||
important_styles = styles[1];
|
||
} else {
|
||
normal_styles = styles;
|
||
}
|
||
if (value) {
|
||
value = String(value).replaceAll(/\s*\/\*.*?\*\/\s*/g, "").trim();
|
||
var in_str = false;
|
||
var in_apo = 0;
|
||
var in_comment = false;
|
||
var reserved_names = [];
|
||
if (normal_styles) {
|
||
reserved_names.push(...Object.keys(normal_styles).map(to_css_name));
|
||
}
|
||
if (important_styles) {
|
||
reserved_names.push(...Object.keys(important_styles).map(to_css_name));
|
||
}
|
||
var start_index = 0;
|
||
var name_index = -1;
|
||
const len = value.length;
|
||
for (var i = 0; i < len; i++) {
|
||
var c = value[i];
|
||
if (in_comment) {
|
||
if (c === "/" && value[i - 1] === "*") {
|
||
in_comment = false;
|
||
}
|
||
} else if (in_str) {
|
||
if (in_str === c) {
|
||
in_str = false;
|
||
}
|
||
} else if (c === "/" && value[i + 1] === "*") {
|
||
in_comment = true;
|
||
} else if (c === '"' || c === "'") {
|
||
in_str = c;
|
||
} else if (c === "(") {
|
||
in_apo++;
|
||
} else if (c === ")") {
|
||
in_apo--;
|
||
}
|
||
if (!in_comment && in_str === false && in_apo === 0) {
|
||
if (c === ":" && name_index === -1) {
|
||
name_index = i;
|
||
} else if (c === ";" || i === len - 1) {
|
||
if (name_index !== -1) {
|
||
var name = to_css_name(value.substring(start_index, name_index).trim());
|
||
if (!reserved_names.includes(name)) {
|
||
if (c !== ";") {
|
||
i++;
|
||
}
|
||
var property = value.substring(start_index, i).trim();
|
||
new_style += " " + property + ";";
|
||
}
|
||
}
|
||
start_index = i + 1;
|
||
name_index = -1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (normal_styles) {
|
||
new_style += append_styles(normal_styles);
|
||
}
|
||
if (important_styles) {
|
||
new_style += append_styles(important_styles, true);
|
||
}
|
||
new_style = new_style.trim();
|
||
return new_style === "" ? null : new_style;
|
||
}
|
||
return value == null ? null : String(value);
|
||
}
|
||
const BLOCK_OPEN = `<!--${HYDRATION_START}-->`;
|
||
const BLOCK_CLOSE = `<!--${HYDRATION_END}-->`;
|
||
let controller = null;
|
||
function abort() {
|
||
controller?.abort(STALE_REACTION);
|
||
controller = null;
|
||
}
|
||
function await_invalid() {
|
||
const error = new Error(`await_invalid
|
||
Encountered asynchronous work while rendering synchronously.
|
||
https://svelte.dev/e/await_invalid`);
|
||
error.name = "Svelte error";
|
||
throw error;
|
||
}
|
||
function invalid_csp() {
|
||
const error = new Error(`invalid_csp
|
||
\`csp.nonce\` was set while \`csp.hash\` was \`true\`. These options cannot be used simultaneously.
|
||
https://svelte.dev/e/invalid_csp`);
|
||
error.name = "Svelte error";
|
||
throw error;
|
||
}
|
||
function lifecycle_function_unavailable(name) {
|
||
const error = new Error(`lifecycle_function_unavailable
|
||
\`${name}(...)\` is not available on the server
|
||
https://svelte.dev/e/lifecycle_function_unavailable`);
|
||
error.name = "Svelte error";
|
||
throw error;
|
||
}
|
||
function server_context_required() {
|
||
const error = new Error(`server_context_required
|
||
Could not resolve \`render\` context.
|
||
https://svelte.dev/e/server_context_required`);
|
||
error.name = "Svelte error";
|
||
throw error;
|
||
}
|
||
var ssr_context = null;
|
||
function set_ssr_context(v) {
|
||
ssr_context = v;
|
||
}
|
||
function getContext(key) {
|
||
const context_map = get_or_init_context_map();
|
||
const result = (
|
||
/** @type {T} */
|
||
context_map.get(key)
|
||
);
|
||
return result;
|
||
}
|
||
function setContext(key, context) {
|
||
get_or_init_context_map().set(key, context);
|
||
return context;
|
||
}
|
||
function hasContext(key) {
|
||
return get_or_init_context_map().has(key);
|
||
}
|
||
function getAllContexts() {
|
||
return get_or_init_context_map();
|
||
}
|
||
function get_or_init_context_map(name) {
|
||
if (ssr_context === null) {
|
||
lifecycle_outside_component();
|
||
}
|
||
return ssr_context.c ??= new Map(get_parent_context(ssr_context) || void 0);
|
||
}
|
||
function push(fn) {
|
||
ssr_context = { p: ssr_context, c: null, r: null };
|
||
}
|
||
function pop() {
|
||
ssr_context = /** @type {SSRContext} */
|
||
ssr_context.p;
|
||
}
|
||
function get_parent_context(ssr_context2) {
|
||
let parent = ssr_context2.p;
|
||
while (parent !== null) {
|
||
const context_map = parent.c;
|
||
if (context_map !== null) {
|
||
return context_map;
|
||
}
|
||
parent = parent.p;
|
||
}
|
||
return null;
|
||
}
|
||
function unresolved_hydratable(key, stack) {
|
||
{
|
||
console.warn(`https://svelte.dev/e/unresolved_hydratable`);
|
||
}
|
||
}
|
||
function get_render_context() {
|
||
const store = als?.getStore();
|
||
{
|
||
server_context_required();
|
||
}
|
||
return store;
|
||
}
|
||
let als = null;
|
||
let text_encoder;
|
||
let crypto;
|
||
async function sha256(data) {
|
||
text_encoder ??= new TextEncoder();
|
||
crypto ??= globalThis.crypto?.subtle?.digest ? globalThis.crypto : (
|
||
// @ts-ignore - we don't install node types in the prod build
|
||
// don't use 'node:crypto' because static analysers will think we rely on node when we don't
|
||
(await import(
|
||
/* @vite-ignore */
|
||
'node:crypto'
|
||
)).webcrypto
|
||
);
|
||
const hash_buffer = await crypto.subtle.digest("SHA-256", text_encoder.encode(data));
|
||
return base64_encode(hash_buffer);
|
||
}
|
||
function base64_encode(bytes) {
|
||
if (globalThis.Buffer) {
|
||
return globalThis.Buffer.from(bytes).toString("base64");
|
||
}
|
||
let binary = "";
|
||
for (let i = 0; i < bytes.length; i++) {
|
||
binary += String.fromCharCode(bytes[i]);
|
||
}
|
||
return btoa(binary);
|
||
}
|
||
class Renderer {
|
||
/**
|
||
* The contents of the renderer.
|
||
* @type {RendererItem[]}
|
||
*/
|
||
#out = [];
|
||
/**
|
||
* Any `onDestroy` callbacks registered during execution of this renderer.
|
||
* @type {(() => void)[] | undefined}
|
||
*/
|
||
#on_destroy = void 0;
|
||
/**
|
||
* Whether this renderer is a component body.
|
||
* @type {boolean}
|
||
*/
|
||
#is_component_body = false;
|
||
/**
|
||
* The type of string content that this renderer is accumulating.
|
||
* @type {RendererType}
|
||
*/
|
||
type;
|
||
/** @type {Renderer | undefined} */
|
||
#parent;
|
||
/**
|
||
* Asynchronous work associated with this renderer
|
||
* @type {Promise<void> | undefined}
|
||
*/
|
||
promise = void 0;
|
||
/**
|
||
* State which is associated with the content tree as a whole.
|
||
* It will be re-exposed, uncopied, on all children.
|
||
* @type {SSRState}
|
||
* @readonly
|
||
*/
|
||
global;
|
||
/**
|
||
* State that is local to the branch it is declared in.
|
||
* It will be shallow-copied to all children.
|
||
*
|
||
* @type {{ select_value: string | undefined }}
|
||
*/
|
||
local;
|
||
/**
|
||
* @param {SSRState} global
|
||
* @param {Renderer | undefined} [parent]
|
||
*/
|
||
constructor(global, parent) {
|
||
this.#parent = parent;
|
||
this.global = global;
|
||
this.local = parent ? { ...parent.local } : { select_value: void 0 };
|
||
this.type = parent ? parent.type : "body";
|
||
}
|
||
/**
|
||
* @param {(renderer: Renderer) => void} fn
|
||
*/
|
||
head(fn) {
|
||
const head = new Renderer(this.global, this);
|
||
head.type = "head";
|
||
this.#out.push(head);
|
||
head.child(fn);
|
||
}
|
||
/**
|
||
* @param {Array<Promise<void>>} blockers
|
||
* @param {(renderer: Renderer) => void} fn
|
||
*/
|
||
async_block(blockers, fn) {
|
||
this.#out.push(BLOCK_OPEN);
|
||
this.async(blockers, fn);
|
||
this.#out.push(BLOCK_CLOSE);
|
||
}
|
||
/**
|
||
* @param {Array<Promise<void>>} blockers
|
||
* @param {(renderer: Renderer) => void} fn
|
||
*/
|
||
async(blockers, fn) {
|
||
let callback = fn;
|
||
if (blockers.length > 0) {
|
||
const context = ssr_context;
|
||
callback = (renderer) => {
|
||
return Promise.all(blockers).then(() => {
|
||
const previous_context = ssr_context;
|
||
try {
|
||
set_ssr_context(context);
|
||
return fn(renderer);
|
||
} finally {
|
||
set_ssr_context(previous_context);
|
||
}
|
||
});
|
||
};
|
||
}
|
||
this.child(callback);
|
||
}
|
||
/**
|
||
* @param {Array<() => void>} thunks
|
||
*/
|
||
run(thunks) {
|
||
const context = ssr_context;
|
||
let promise = Promise.resolve(thunks[0]());
|
||
const promises = [promise];
|
||
for (const fn of thunks.slice(1)) {
|
||
promise = promise.then(() => {
|
||
const previous_context = ssr_context;
|
||
set_ssr_context(context);
|
||
try {
|
||
return fn();
|
||
} finally {
|
||
set_ssr_context(previous_context);
|
||
}
|
||
});
|
||
promises.push(promise);
|
||
}
|
||
promise.catch(noop);
|
||
this.promise = promise;
|
||
return promises;
|
||
}
|
||
/**
|
||
* @param {(renderer: Renderer) => MaybePromise<void>} fn
|
||
*/
|
||
child_block(fn) {
|
||
this.#out.push(BLOCK_OPEN);
|
||
this.child(fn);
|
||
this.#out.push(BLOCK_CLOSE);
|
||
}
|
||
/**
|
||
* Create a child renderer. The child renderer inherits the state from the parent,
|
||
* but has its own content.
|
||
* @param {(renderer: Renderer) => MaybePromise<void>} fn
|
||
*/
|
||
child(fn) {
|
||
const child = new Renderer(this.global, this);
|
||
this.#out.push(child);
|
||
const parent = ssr_context;
|
||
set_ssr_context({
|
||
...ssr_context,
|
||
p: parent,
|
||
c: null,
|
||
r: child
|
||
});
|
||
const result = fn(child);
|
||
set_ssr_context(parent);
|
||
if (result instanceof Promise) {
|
||
if (child.global.mode === "sync") {
|
||
await_invalid();
|
||
}
|
||
result.catch(() => {
|
||
});
|
||
child.promise = result;
|
||
}
|
||
return child;
|
||
}
|
||
/**
|
||
* Create a component renderer. The component renderer inherits the state from the parent,
|
||
* but has its own content. It is treated as an ordering boundary for ondestroy callbacks.
|
||
* @param {(renderer: Renderer) => MaybePromise<void>} fn
|
||
* @param {Function} [component_fn]
|
||
* @returns {void}
|
||
*/
|
||
component(fn, component_fn) {
|
||
push();
|
||
const child = this.child(fn);
|
||
child.#is_component_body = true;
|
||
pop();
|
||
}
|
||
/**
|
||
* @param {Record<string, any>} attrs
|
||
* @param {(renderer: Renderer) => void} fn
|
||
* @param {string | undefined} [css_hash]
|
||
* @param {Record<string, boolean> | undefined} [classes]
|
||
* @param {Record<string, string> | undefined} [styles]
|
||
* @param {number | undefined} [flags]
|
||
* @param {boolean | undefined} [is_rich]
|
||
* @returns {void}
|
||
*/
|
||
select(attrs, fn, css_hash, classes, styles, flags, is_rich) {
|
||
const { value, ...select_attrs } = attrs;
|
||
this.push(`<select${attributes(select_attrs, css_hash, classes, styles, flags)}>`);
|
||
this.child((renderer) => {
|
||
renderer.local.select_value = value;
|
||
fn(renderer);
|
||
});
|
||
this.push(`${is_rich ? "<!>" : ""}</select>`);
|
||
}
|
||
/**
|
||
* @param {Record<string, any>} attrs
|
||
* @param {string | number | boolean | ((renderer: Renderer) => void)} body
|
||
* @param {string | undefined} [css_hash]
|
||
* @param {Record<string, boolean> | undefined} [classes]
|
||
* @param {Record<string, string> | undefined} [styles]
|
||
* @param {number | undefined} [flags]
|
||
* @param {boolean | undefined} [is_rich]
|
||
*/
|
||
option(attrs, body, css_hash, classes, styles, flags, is_rich) {
|
||
this.#out.push(`<option${attributes(attrs, css_hash, classes, styles, flags)}`);
|
||
const close = (renderer, value, { head, body: body2 }) => {
|
||
if (has_own_property.call(attrs, "value")) {
|
||
value = attrs.value;
|
||
}
|
||
if (value === this.local.select_value) {
|
||
renderer.#out.push(' selected=""');
|
||
}
|
||
renderer.#out.push(`>${body2}${is_rich ? "<!>" : ""}</option>`);
|
||
if (head) {
|
||
renderer.head((child) => child.push(head));
|
||
}
|
||
};
|
||
if (typeof body === "function") {
|
||
this.child((renderer) => {
|
||
const r = new Renderer(this.global, this);
|
||
body(r);
|
||
if (this.global.mode === "async") {
|
||
return r.#collect_content_async().then((content) => {
|
||
close(renderer, content.body.replaceAll("<!---->", ""), content);
|
||
});
|
||
} else {
|
||
const content = r.#collect_content();
|
||
close(renderer, content.body.replaceAll("<!---->", ""), content);
|
||
}
|
||
});
|
||
} else {
|
||
close(this, body, { body: escape_html(body) });
|
||
}
|
||
}
|
||
/**
|
||
* @param {(renderer: Renderer) => void} fn
|
||
*/
|
||
title(fn) {
|
||
const path = this.get_path();
|
||
const close = (head) => {
|
||
this.global.set_title(head, path);
|
||
};
|
||
this.child((renderer) => {
|
||
const r = new Renderer(renderer.global, renderer);
|
||
fn(r);
|
||
if (renderer.global.mode === "async") {
|
||
return r.#collect_content_async().then((content) => {
|
||
close(content.head);
|
||
});
|
||
} else {
|
||
const content = r.#collect_content();
|
||
close(content.head);
|
||
}
|
||
});
|
||
}
|
||
/**
|
||
* @param {string | (() => Promise<string>)} content
|
||
*/
|
||
push(content) {
|
||
if (typeof content === "function") {
|
||
this.child(async (renderer) => renderer.push(await content()));
|
||
} else {
|
||
this.#out.push(content);
|
||
}
|
||
}
|
||
/**
|
||
* @param {() => void} fn
|
||
*/
|
||
on_destroy(fn) {
|
||
(this.#on_destroy ??= []).push(fn);
|
||
}
|
||
/**
|
||
* @returns {number[]}
|
||
*/
|
||
get_path() {
|
||
return this.#parent ? [...this.#parent.get_path(), this.#parent.#out.indexOf(this)] : [];
|
||
}
|
||
/**
|
||
* @deprecated this is needed for legacy component bindings
|
||
*/
|
||
copy() {
|
||
const copy = new Renderer(this.global, this.#parent);
|
||
copy.#out = this.#out.map((item) => item instanceof Renderer ? item.copy() : item);
|
||
copy.promise = this.promise;
|
||
return copy;
|
||
}
|
||
/**
|
||
* @param {Renderer} other
|
||
* @deprecated this is needed for legacy component bindings
|
||
*/
|
||
subsume(other) {
|
||
if (this.global.mode !== other.global.mode) {
|
||
throw new Error(
|
||
"invariant: A renderer cannot switch modes. If you're seeing this, there's a compiler bug. File an issue!"
|
||
);
|
||
}
|
||
this.local = other.local;
|
||
this.#out = other.#out.map((item) => {
|
||
if (item instanceof Renderer) {
|
||
item.subsume(item);
|
||
}
|
||
return item;
|
||
});
|
||
this.promise = other.promise;
|
||
this.type = other.type;
|
||
}
|
||
get length() {
|
||
return this.#out.length;
|
||
}
|
||
/**
|
||
* Only available on the server and when compiling with the `server` option.
|
||
* Takes a component and returns an object with `body` and `head` properties on it, which you can use to populate the HTML when server-rendering your app.
|
||
* @template {Record<string, any>} Props
|
||
* @param {Component<Props>} component
|
||
* @param {{ props?: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any>; idPrefix?: string; csp?: Csp }} [options]
|
||
* @returns {RenderOutput}
|
||
*/
|
||
static render(component, options = {}) {
|
||
let sync;
|
||
const result = (
|
||
/** @type {RenderOutput} */
|
||
{}
|
||
);
|
||
Object.defineProperties(result, {
|
||
html: {
|
||
get: () => {
|
||
return (sync ??= Renderer.#render(component, options)).body;
|
||
}
|
||
},
|
||
head: {
|
||
get: () => {
|
||
return (sync ??= Renderer.#render(component, options)).head;
|
||
}
|
||
},
|
||
body: {
|
||
get: () => {
|
||
return (sync ??= Renderer.#render(component, options)).body;
|
||
}
|
||
},
|
||
hashes: {
|
||
value: {
|
||
script: ""
|
||
}
|
||
},
|
||
then: {
|
||
value: (
|
||
/**
|
||
* this is not type-safe, but honestly it's the best I can do right now, and it's a straightforward function.
|
||
*
|
||
* @template TResult1
|
||
* @template [TResult2=never]
|
||
* @param { (value: SyncRenderOutput) => TResult1 } onfulfilled
|
||
* @param { (reason: unknown) => TResult2 } onrejected
|
||
*/
|
||
(onfulfilled, onrejected) => {
|
||
{
|
||
const result2 = sync ??= Renderer.#render(component, options);
|
||
const user_result = onfulfilled({
|
||
head: result2.head,
|
||
body: result2.body,
|
||
html: result2.body,
|
||
hashes: { script: [] }
|
||
});
|
||
return Promise.resolve(user_result);
|
||
}
|
||
}
|
||
)
|
||
}
|
||
});
|
||
return result;
|
||
}
|
||
/**
|
||
* Collect all of the `onDestroy` callbacks registered during rendering. In an async context, this is only safe to call
|
||
* after awaiting `collect_async`.
|
||
*
|
||
* Child renderers are "porous" and don't affect execution order, but component body renderers
|
||
* create ordering boundaries. Within a renderer, callbacks run in order until hitting a component boundary.
|
||
* @returns {Iterable<() => void>}
|
||
*/
|
||
*#collect_on_destroy() {
|
||
for (const component of this.#traverse_components()) {
|
||
yield* component.#collect_ondestroy();
|
||
}
|
||
}
|
||
/**
|
||
* Performs a depth-first search of renderers, yielding the deepest components first, then additional components as we backtrack up the tree.
|
||
* @returns {Iterable<Renderer>}
|
||
*/
|
||
*#traverse_components() {
|
||
for (const child of this.#out) {
|
||
if (typeof child !== "string") {
|
||
yield* child.#traverse_components();
|
||
}
|
||
}
|
||
if (this.#is_component_body) {
|
||
yield this;
|
||
}
|
||
}
|
||
/**
|
||
* @returns {Iterable<() => void>}
|
||
*/
|
||
*#collect_ondestroy() {
|
||
if (this.#on_destroy) {
|
||
for (const fn of this.#on_destroy) {
|
||
yield fn;
|
||
}
|
||
}
|
||
for (const child of this.#out) {
|
||
if (child instanceof Renderer && !child.#is_component_body) {
|
||
yield* child.#collect_ondestroy();
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* Render a component. Throws if any of the children are performing asynchronous work.
|
||
*
|
||
* @template {Record<string, any>} Props
|
||
* @param {Component<Props>} component
|
||
* @param {{ props?: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any>; idPrefix?: string }} options
|
||
* @returns {AccumulatedContent}
|
||
*/
|
||
static #render(component, options) {
|
||
var previous_context = ssr_context;
|
||
try {
|
||
const renderer = Renderer.#open_render("sync", component, options);
|
||
const content = renderer.#collect_content();
|
||
return Renderer.#close_render(content, renderer);
|
||
} finally {
|
||
abort();
|
||
set_ssr_context(previous_context);
|
||
}
|
||
}
|
||
/**
|
||
* Render a component.
|
||
*
|
||
* @template {Record<string, any>} Props
|
||
* @param {Component<Props>} component
|
||
* @param {{ props?: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any>; idPrefix?: string; csp?: Csp }} options
|
||
* @returns {Promise<AccumulatedContent & { hashes: { script: Sha256Source[] } }>}
|
||
*/
|
||
static async #render_async(component, options) {
|
||
const previous_context = ssr_context;
|
||
try {
|
||
const renderer = Renderer.#open_render("async", component, options);
|
||
const content = await renderer.#collect_content_async();
|
||
const hydratables = await renderer.#collect_hydratables();
|
||
if (hydratables !== null) {
|
||
content.head = hydratables + content.head;
|
||
}
|
||
return Renderer.#close_render(content, renderer);
|
||
} finally {
|
||
set_ssr_context(previous_context);
|
||
abort();
|
||
}
|
||
}
|
||
/**
|
||
* Collect all of the code from the `out` array and return it as a string, or a promise resolving to a string.
|
||
* @param {AccumulatedContent} content
|
||
* @returns {AccumulatedContent}
|
||
*/
|
||
#collect_content(content = { head: "", body: "" }) {
|
||
for (const item of this.#out) {
|
||
if (typeof item === "string") {
|
||
content[this.type] += item;
|
||
} else if (item instanceof Renderer) {
|
||
item.#collect_content(content);
|
||
}
|
||
}
|
||
return content;
|
||
}
|
||
/**
|
||
* Collect all of the code from the `out` array and return it as a string.
|
||
* @param {AccumulatedContent} content
|
||
* @returns {Promise<AccumulatedContent>}
|
||
*/
|
||
async #collect_content_async(content = { head: "", body: "" }) {
|
||
await this.promise;
|
||
for (const item of this.#out) {
|
||
if (typeof item === "string") {
|
||
content[this.type] += item;
|
||
} else if (item instanceof Renderer) {
|
||
await item.#collect_content_async(content);
|
||
}
|
||
}
|
||
return content;
|
||
}
|
||
async #collect_hydratables() {
|
||
const ctx = get_render_context().hydratable;
|
||
for (const [_, key] of ctx.unresolved_promises) {
|
||
unresolved_hydratable(key, ctx.lookup.get(key)?.stack ?? "<missing stack trace>");
|
||
}
|
||
for (const comparison of ctx.comparisons) {
|
||
await comparison;
|
||
}
|
||
return await this.#hydratable_block(ctx);
|
||
}
|
||
/**
|
||
* @template {Record<string, any>} Props
|
||
* @param {'sync' | 'async'} mode
|
||
* @param {import('svelte').Component<Props>} component
|
||
* @param {{ props?: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any>; idPrefix?: string; csp?: Csp }} options
|
||
* @returns {Renderer}
|
||
*/
|
||
static #open_render(mode, component, options) {
|
||
const renderer = new Renderer(
|
||
new SSRState(mode, options.idPrefix ? options.idPrefix + "-" : "", options.csp)
|
||
);
|
||
renderer.push(BLOCK_OPEN);
|
||
push();
|
||
if (options.context) ssr_context.c = options.context;
|
||
ssr_context.r = renderer;
|
||
component(renderer, options.props ?? {});
|
||
pop();
|
||
renderer.push(BLOCK_CLOSE);
|
||
return renderer;
|
||
}
|
||
/**
|
||
* @param {AccumulatedContent} content
|
||
* @param {Renderer} renderer
|
||
* @returns {AccumulatedContent & { hashes: { script: Sha256Source[] } }}
|
||
*/
|
||
static #close_render(content, renderer) {
|
||
for (const cleanup of renderer.#collect_on_destroy()) {
|
||
cleanup();
|
||
}
|
||
let head = content.head + renderer.global.get_title();
|
||
let body = content.body;
|
||
for (const { hash, code } of renderer.global.css) {
|
||
head += `<style id="${hash}">${code}</style>`;
|
||
}
|
||
return {
|
||
head,
|
||
body,
|
||
hashes: {
|
||
script: renderer.global.csp.script_hashes
|
||
}
|
||
};
|
||
}
|
||
/**
|
||
* @param {HydratableContext} ctx
|
||
*/
|
||
async #hydratable_block(ctx) {
|
||
if (ctx.lookup.size === 0) {
|
||
return null;
|
||
}
|
||
let entries = [];
|
||
let has_promises = false;
|
||
for (const [k, v] of ctx.lookup) {
|
||
if (v.promises) {
|
||
has_promises = true;
|
||
for (const p of v.promises) await p;
|
||
}
|
||
entries.push(`[${uneval(k)},${v.serialized}]`);
|
||
}
|
||
let prelude = `const h = (window.__svelte ??= {}).h ??= new Map();`;
|
||
if (has_promises) {
|
||
prelude = `const r = (v) => Promise.resolve(v);
|
||
${prelude}`;
|
||
}
|
||
const body = `
|
||
{
|
||
${prelude}
|
||
|
||
for (const [k, v] of [
|
||
${entries.join(",\n ")}
|
||
]) {
|
||
h.set(k, v);
|
||
}
|
||
}
|
||
`;
|
||
let csp_attr = "";
|
||
if (this.global.csp.nonce) {
|
||
csp_attr = ` nonce="${this.global.csp.nonce}"`;
|
||
} else if (this.global.csp.hash) {
|
||
const hash = await sha256(body);
|
||
this.global.csp.script_hashes.push(`sha256-${hash}`);
|
||
}
|
||
return `
|
||
<script${csp_attr}>${body}<\/script>`;
|
||
}
|
||
}
|
||
class SSRState {
|
||
/** @readonly @type {Csp & { script_hashes: Sha256Source[] }} */
|
||
csp;
|
||
/** @readonly @type {'sync' | 'async'} */
|
||
mode;
|
||
/** @readonly @type {() => string} */
|
||
uid;
|
||
/** @readonly @type {Set<{ hash: string; code: string }>} */
|
||
css = /* @__PURE__ */ new Set();
|
||
/** @type {{ path: number[], value: string }} */
|
||
#title = { path: [], value: "" };
|
||
/**
|
||
* @param {'sync' | 'async'} mode
|
||
* @param {string} id_prefix
|
||
* @param {Csp} csp
|
||
*/
|
||
constructor(mode, id_prefix = "", csp = { hash: false }) {
|
||
this.mode = mode;
|
||
this.csp = { ...csp, script_hashes: [] };
|
||
let uid = 1;
|
||
this.uid = () => `${id_prefix}s${uid++}`;
|
||
}
|
||
get_title() {
|
||
return this.#title.value;
|
||
}
|
||
/**
|
||
* Performs a depth-first (lexicographic) comparison using the path. Rejects sets
|
||
* from earlier than or equal to the current value.
|
||
* @param {string} value
|
||
* @param {number[]} path
|
||
*/
|
||
set_title(value, path) {
|
||
const current = this.#title.path;
|
||
let i = 0;
|
||
let l = Math.min(path.length, current.length);
|
||
while (i < l && path[i] === current[i]) i += 1;
|
||
if (path[i] === void 0) return;
|
||
if (current[i] === void 0 || path[i] > current[i]) {
|
||
this.#title.path = path;
|
||
this.#title.value = value;
|
||
}
|
||
}
|
||
}
|
||
const INVALID_ATTR_NAME_CHAR_REGEX = /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u;
|
||
function render(component, options = {}) {
|
||
if (options.csp?.hash && options.csp.nonce) {
|
||
invalid_csp();
|
||
}
|
||
return Renderer.render(
|
||
/** @type {Component<Props>} */
|
||
component,
|
||
options
|
||
);
|
||
}
|
||
function attributes(attrs, css_hash, classes, styles, flags = 0) {
|
||
if (styles) {
|
||
attrs.style = to_style(attrs.style, styles);
|
||
}
|
||
if (attrs.class) {
|
||
attrs.class = clsx(attrs.class);
|
||
}
|
||
if (css_hash || classes) {
|
||
attrs.class = to_class(attrs.class, css_hash, classes);
|
||
}
|
||
let attr_str = "";
|
||
let name;
|
||
const is_html = (flags & ELEMENT_IS_NAMESPACED) === 0;
|
||
const lowercase = (flags & ELEMENT_PRESERVE_ATTRIBUTE_CASE) === 0;
|
||
const is_input = (flags & ELEMENT_IS_INPUT) !== 0;
|
||
for (name of Object.keys(attrs)) {
|
||
if (typeof attrs[name] === "function") continue;
|
||
if (name[0] === "$" && name[1] === "$") continue;
|
||
if (INVALID_ATTR_NAME_CHAR_REGEX.test(name)) continue;
|
||
var value = attrs[name];
|
||
if (lowercase) {
|
||
name = name.toLowerCase();
|
||
}
|
||
if (name.length > 2 && name.startsWith("on")) continue;
|
||
if (is_input) {
|
||
if (name === "defaultvalue" || name === "defaultchecked") {
|
||
name = name === "defaultvalue" ? "value" : "checked";
|
||
if (attrs[name]) continue;
|
||
}
|
||
}
|
||
attr_str += attr(name, value, is_html && is_boolean_attribute(name));
|
||
}
|
||
return attr_str;
|
||
}
|
||
function spread_props(props) {
|
||
const merged_props = {};
|
||
let key;
|
||
for (let i = 0; i < props.length; i++) {
|
||
const obj = props[i];
|
||
if (obj == null) continue;
|
||
for (key of Object.keys(obj)) {
|
||
const desc = Object.getOwnPropertyDescriptor(obj, key);
|
||
if (desc) {
|
||
Object.defineProperty(merged_props, key, desc);
|
||
} else {
|
||
merged_props[key] = obj[key];
|
||
}
|
||
}
|
||
}
|
||
return merged_props;
|
||
}
|
||
function bind_props(props_parent, props_now) {
|
||
for (const key of Object.keys(props_now)) {
|
||
const initial_value = props_parent[key];
|
||
const value = props_now[key];
|
||
if (initial_value === void 0 && value !== void 0 && Object.getOwnPropertyDescriptor(props_parent, key)?.set) {
|
||
props_parent[key] = value;
|
||
}
|
||
}
|
||
}
|
||
function once(get_value) {
|
||
let value = (
|
||
/** @type {V} */
|
||
UNINITIALIZED
|
||
);
|
||
return () => {
|
||
if (value === UNINITIALIZED) {
|
||
value = get_value();
|
||
}
|
||
return value;
|
||
};
|
||
}
|
||
function props_id(renderer) {
|
||
const uid = renderer.global.uid();
|
||
renderer.push("<!--$" + uid + "-->");
|
||
return uid;
|
||
}
|
||
function derived(fn) {
|
||
const get_value = once(fn);
|
||
let updated_value;
|
||
return function(new_value) {
|
||
if (arguments.length === 0) {
|
||
return updated_value ?? get_value();
|
||
}
|
||
updated_value = new_value;
|
||
return updated_value;
|
||
};
|
||
}
|
||
|
||
export { run_all as $, ATTACHMENT_KEY as A, HYDRATION_ERROR as B, CONNECTED as C, DevalueError as D, ERROR_VALUE as E, object_prototype as F, array_prototype as G, HYDRATION_START as H, get_descriptor as I, DERIVED as J, DIRTY as K, LEGACY_PROPS as L, MAYBE_DIRTY as M, is_extensible as N, get_prototype_of as O, is_array as P, CLEAN as Q, REACTION_RAN as R, STATE_SYMBOL as S, INERT as T, UNINITIALIZED as U, EFFECT as V, BLOCK_EFFECT as W, deferred as X, WAS_MARKED as Y, DESTROYED as Z, MANAGED_EFFECT as _, is_plain_object as a, BRANCH_EFFECT as a0, ROOT_EFFECT as a1, RENDER_EFFECT as a2, HEAD_EFFECT as a3, ASYNC as a4, REACTION_IS_UPDATING as a5, EFFECT_PRESERVED as a6, EFFECT_TRANSPARENT as a7, BOUNDARY_EFFECT as a8, includes as a9, index_of as aa, STALE_REACTION as ab, EAGER_EFFECT as ac, array_from as ad, is_passive_event as ae, HYDRATION_END as af, HYDRATION_START_ELSE as ag, USER_EFFECT as ah, stringify_string as b, bind_props as c, spread_props as d, enumerable_symbols as e, getContext as f, get_type as g, hasContext as h, is_primitive as i, setContext as j, derived as k, getAllContexts as l, attributes as m, lifecycle_function_unavailable as n, escape_html as o, props_id as p, noop as q, attr as r, stringify_key as s, clsx as t, uneval as u, valid_array_indices as v, run as w, render as x, define_property as y, COMMENT_NODE as z };
|
||
//# sourceMappingURL=index2-DHYCG7Ly.js.map
|