seroval
Version:
Stringify JS values
2,075 lines (2,046 loc) • 107 kB
JavaScript
// src/core/compat.ts
var Feature = /* @__PURE__ */ ((Feature2) => {
Feature2[Feature2["AggregateError"] = 1] = "AggregateError";
Feature2[Feature2["ArrowFunction"] = 2] = "ArrowFunction";
Feature2[Feature2["ErrorPrototypeStack"] = 4] = "ErrorPrototypeStack";
Feature2[Feature2["ObjectAssign"] = 8] = "ObjectAssign";
Feature2[Feature2["BigIntTypedArray"] = 16] = "BigIntTypedArray";
Feature2[Feature2["AbortSignal"] = 32] = "AbortSignal";
return Feature2;
})(Feature || {});
var ALL_ENABLED = 47;
// src/core/string.ts
function serializeChar(str) {
switch (str) {
case '"':
return '\\"';
case "\\":
return "\\\\";
case "\n":
return "\\n";
case "\r":
return "\\r";
case "\b":
return "\\b";
case " ":
return "\\t";
case "\f":
return "\\f";
case "<":
return "\\x3C";
case "\u2028":
return "\\u2028";
case "\u2029":
return "\\u2029";
default:
return void 0;
}
}
function serializeString(str) {
let result = "";
let lastPos = 0;
let replacement;
for (let i = 0, len = str.length; i < len; i++) {
replacement = serializeChar(str[i]);
if (replacement) {
result += str.slice(lastPos, i) + replacement;
lastPos = i + 1;
}
}
if (lastPos === 0) {
result = str;
} else {
result += str.slice(lastPos);
}
return result;
}
function deserializeReplacer(str) {
switch (str) {
case "\\\\":
return "\\";
case '\\"':
return '"';
case "\\n":
return "\n";
case "\\r":
return "\r";
case "\\b":
return "\b";
case "\\t":
return " ";
case "\\f":
return "\f";
case "\\x3C":
return "<";
case "\\u2028":
return "\u2028";
case "\\u2029":
return "\u2029";
default:
return str;
}
}
function deserializeString(str) {
return str.replace(
/(\\\\|\\"|\\n|\\r|\\b|\\t|\\f|\\u2028|\\u2029|\\x3C)/g,
deserializeReplacer
);
}
// src/core/keys.ts
var REFERENCES_KEY = "__SEROVAL_REFS__";
var GLOBAL_CONTEXT_REFERENCES = "$R";
var GLOBAL_CONTEXT_R = `self.${GLOBAL_CONTEXT_REFERENCES}`;
function getCrossReferenceHeader(id) {
if (id == null) {
return `${GLOBAL_CONTEXT_R}=${GLOBAL_CONTEXT_R}||[]`;
}
return `(${GLOBAL_CONTEXT_R}=${GLOBAL_CONTEXT_R}||{})["${serializeString(
id
)}"]=[]`;
}
// src/core/utils/assert.ts
function assert(cond, error) {
if (!cond) {
throw error;
}
}
// src/core/reference.ts
var REFERENCE = /* @__PURE__ */ new Map();
var INV_REFERENCE = /* @__PURE__ */ new Map();
function createReference(id, value) {
REFERENCE.set(value, id);
INV_REFERENCE.set(id, value);
return value;
}
function hasReferenceID(value) {
return REFERENCE.has(value);
}
function hasReference(id) {
return INV_REFERENCE.has(id);
}
function getReferenceID(value) {
assert(hasReferenceID(value), new SerovalMissingReferenceError(value));
return REFERENCE.get(value);
}
function getReference(id) {
assert(hasReference(id), new SerovalMissingReferenceForIdError(id));
return INV_REFERENCE.get(id);
}
if (typeof globalThis !== "undefined") {
Object.defineProperty(globalThis, REFERENCES_KEY, {
value: INV_REFERENCE,
configurable: true,
writable: false,
enumerable: false
});
} else if (typeof window !== "undefined") {
Object.defineProperty(window, REFERENCES_KEY, {
value: INV_REFERENCE,
configurable: true,
writable: false,
enumerable: false
});
} else if (typeof self !== "undefined") {
Object.defineProperty(self, REFERENCES_KEY, {
value: INV_REFERENCE,
configurable: true,
writable: false,
enumerable: false
});
} else if (typeof global !== "undefined") {
Object.defineProperty(global, REFERENCES_KEY, {
value: INV_REFERENCE,
configurable: true,
writable: false,
enumerable: false
});
}
// src/core/plugin.ts
function createPlugin(plugin) {
return plugin;
}
function dedupePlugins(deduped, plugins) {
for (let i = 0, len = plugins.length; i < len; i++) {
const current = plugins[i];
if (!deduped.has(current)) {
deduped.add(current);
if (current.extends) {
dedupePlugins(deduped, current.extends);
}
}
}
}
function resolvePlugins(plugins) {
if (plugins) {
const deduped = /* @__PURE__ */ new Set();
dedupePlugins(deduped, plugins);
return [...deduped];
}
return void 0;
}
// src/core/abort-signal.ts
function resolveAbortSignalResult(resolve) {
resolve(this.reason);
}
function resolveAbortSignal(resolve) {
this.addEventListener("abort", resolveAbortSignalResult.bind(this, resolve), {
once: true
});
}
function abortSignalToPromise(signal) {
return new Promise(resolveAbortSignal.bind(signal));
}
// src/core/constants.ts
var SYMBOL_STRING = {
[0 /* AsyncIterator */]: "Symbol.asyncIterator",
[1 /* HasInstance */]: "Symbol.hasInstance",
[2 /* IsConcatSpreadable */]: "Symbol.isConcatSpreadable",
[3 /* Iterator */]: "Symbol.iterator",
[4 /* Match */]: "Symbol.match",
[5 /* MatchAll */]: "Symbol.matchAll",
[6 /* Replace */]: "Symbol.replace",
[7 /* Search */]: "Symbol.search",
[8 /* Species */]: "Symbol.species",
[9 /* Split */]: "Symbol.split",
[10 /* ToPrimitive */]: "Symbol.toPrimitive",
[11 /* ToStringTag */]: "Symbol.toStringTag",
[12 /* Unscopables */]: "Symbol.unscopables"
};
var INV_SYMBOL_REF = {
[Symbol.asyncIterator]: 0 /* AsyncIterator */,
[Symbol.hasInstance]: 1 /* HasInstance */,
[Symbol.isConcatSpreadable]: 2 /* IsConcatSpreadable */,
[Symbol.iterator]: 3 /* Iterator */,
[Symbol.match]: 4 /* Match */,
[Symbol.matchAll]: 5 /* MatchAll */,
[Symbol.replace]: 6 /* Replace */,
[Symbol.search]: 7 /* Search */,
[Symbol.species]: 8 /* Species */,
[Symbol.split]: 9 /* Split */,
[Symbol.toPrimitive]: 10 /* ToPrimitive */,
[Symbol.toStringTag]: 11 /* ToStringTag */,
[Symbol.unscopables]: 12 /* Unscopables */
};
var SYMBOL_REF = {
[0 /* AsyncIterator */]: Symbol.asyncIterator,
[1 /* HasInstance */]: Symbol.hasInstance,
[2 /* IsConcatSpreadable */]: Symbol.isConcatSpreadable,
[3 /* Iterator */]: Symbol.iterator,
[4 /* Match */]: Symbol.match,
[5 /* MatchAll */]: Symbol.matchAll,
[6 /* Replace */]: Symbol.replace,
[7 /* Search */]: Symbol.search,
[8 /* Species */]: Symbol.species,
[9 /* Split */]: Symbol.split,
[10 /* ToPrimitive */]: Symbol.toPrimitive,
[11 /* ToStringTag */]: Symbol.toStringTag,
[12 /* Unscopables */]: Symbol.unscopables
};
var CONSTANT_STRING = {
[2 /* True */]: "!0",
[3 /* False */]: "!1",
[1 /* Undefined */]: "void 0",
[0 /* Null */]: "null",
[4 /* NegZero */]: "-0",
[5 /* Inf */]: "1/0",
[6 /* NegInf */]: "-1/0",
[7 /* Nan */]: "0/0"
};
var CONSTANT_VAL = {
[2 /* True */]: true,
[3 /* False */]: false,
[1 /* Undefined */]: void 0,
[0 /* Null */]: null,
[4 /* NegZero */]: -0,
[5 /* Inf */]: Number.POSITIVE_INFINITY,
[6 /* NegInf */]: Number.NEGATIVE_INFINITY,
[7 /* Nan */]: Number.NaN
};
var ERROR_CONSTRUCTOR_STRING = {
[0 /* Error */]: "Error",
[1 /* EvalError */]: "EvalError",
[2 /* RangeError */]: "RangeError",
[3 /* ReferenceError */]: "ReferenceError",
[4 /* SyntaxError */]: "SyntaxError",
[5 /* TypeError */]: "TypeError",
[6 /* URIError */]: "URIError"
};
var ERROR_CONSTRUCTOR = {
[0 /* Error */]: Error,
[1 /* EvalError */]: EvalError,
[2 /* RangeError */]: RangeError,
[3 /* ReferenceError */]: ReferenceError,
[4 /* SyntaxError */]: SyntaxError,
[5 /* TypeError */]: TypeError,
[6 /* URIError */]: URIError
};
var NIL = void 0;
// src/core/node.ts
function createSerovalNode(t, i, s, l, c, m, p, e, a, f, b, o) {
return {
t,
i,
s,
l,
c,
m,
p,
e,
a,
f,
b,
o
};
}
// src/core/literals.ts
function createConstantNode(value) {
return createSerovalNode(
2 /* Constant */,
NIL,
value,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
var TRUE_NODE = /* @__PURE__ */ createConstantNode(
2 /* True */
);
var FALSE_NODE = /* @__PURE__ */ createConstantNode(
3 /* False */
);
var UNDEFINED_NODE = /* @__PURE__ */ createConstantNode(
1 /* Undefined */
);
var NULL_NODE = /* @__PURE__ */ createConstantNode(
0 /* Null */
);
var NEG_ZERO_NODE = /* @__PURE__ */ createConstantNode(
4 /* NegZero */
);
var INFINITY_NODE = /* @__PURE__ */ createConstantNode(
5 /* Inf */
);
var NEG_INFINITY_NODE = /* @__PURE__ */ createConstantNode(
6 /* NegInf */
);
var NAN_NODE = /* @__PURE__ */ createConstantNode(7 /* Nan */);
// src/core/utils/error.ts
function getErrorConstructor(error) {
if (error instanceof EvalError) {
return 1 /* EvalError */;
}
if (error instanceof RangeError) {
return 2 /* RangeError */;
}
if (error instanceof ReferenceError) {
return 3 /* ReferenceError */;
}
if (error instanceof SyntaxError) {
return 4 /* SyntaxError */;
}
if (error instanceof TypeError) {
return 5 /* TypeError */;
}
if (error instanceof URIError) {
return 6 /* URIError */;
}
return 0 /* Error */;
}
function getInitialErrorOptions(error) {
const construct = ERROR_CONSTRUCTOR_STRING[getErrorConstructor(error)];
if (error.name !== construct) {
return { name: error.name };
}
if (error.constructor.name !== construct) {
return { name: error.constructor.name };
}
return {};
}
function getErrorOptions(error, features) {
let options = getInitialErrorOptions(error);
const names = Object.getOwnPropertyNames(error);
for (let i = 0, len = names.length, name; i < len; i++) {
name = names[i];
if (name !== "name" && name !== "message") {
if (name === "stack") {
if (features & 4 /* ErrorPrototypeStack */) {
options = options || {};
options[name] = error[name];
}
} else {
options = options || {};
options[name] = error[name];
}
}
}
return options;
}
// src/core/utils/get-object-flag.ts
function getObjectFlag(obj) {
if (Object.isFrozen(obj)) {
return 3 /* Frozen */;
}
if (Object.isSealed(obj)) {
return 2 /* Sealed */;
}
if (Object.isExtensible(obj)) {
return 0 /* None */;
}
return 1 /* NonExtensible */;
}
// src/core/base-primitives.ts
function createNumberNode(value) {
switch (value) {
case Number.POSITIVE_INFINITY:
return INFINITY_NODE;
case Number.NEGATIVE_INFINITY:
return NEG_INFINITY_NODE;
}
if (value !== value) {
return NAN_NODE;
}
if (Object.is(value, -0)) {
return NEG_ZERO_NODE;
}
return createSerovalNode(
0 /* Number */,
NIL,
value,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
function createStringNode(value) {
return createSerovalNode(
1 /* String */,
NIL,
serializeString(value),
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
function createBigIntNode(current) {
return createSerovalNode(
3 /* BigInt */,
NIL,
"" + current,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
function createIndexedValueNode(id) {
return createSerovalNode(
4 /* IndexedValue */,
id,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
function createDateNode(id, current) {
return createSerovalNode(
5 /* Date */,
id,
current.toISOString(),
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
function createRegExpNode(id, current) {
return createSerovalNode(
6 /* RegExp */,
id,
NIL,
NIL,
serializeString(current.source),
current.flags,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
function createArrayBufferNode(id, current) {
const bytes = new Uint8Array(current);
const len = bytes.length;
const values = new Array(len);
for (let i = 0; i < len; i++) {
values[i] = bytes[i];
}
return createSerovalNode(
19 /* ArrayBuffer */,
id,
values,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
function createWKSymbolNode(id, current) {
return createSerovalNode(
17 /* WKSymbol */,
id,
INV_SYMBOL_REF[current],
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
function createReferenceNode(id, ref) {
return createSerovalNode(
18 /* Reference */,
id,
serializeString(getReferenceID(ref)),
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
function createPluginNode(id, tag, value) {
return createSerovalNode(
25 /* Plugin */,
id,
value,
NIL,
serializeString(tag),
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
function createArrayNode(id, current, parsedItems) {
return createSerovalNode(
9 /* Array */,
id,
NIL,
current.length,
NIL,
NIL,
NIL,
NIL,
parsedItems,
NIL,
NIL,
getObjectFlag(current)
);
}
function createBoxedNode(id, boxed) {
return createSerovalNode(
21 /* Boxed */,
id,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
boxed,
NIL,
NIL
);
}
function createTypedArrayNode(id, current, buffer) {
return createSerovalNode(
15 /* TypedArray */,
id,
NIL,
current.length,
current.constructor.name,
NIL,
NIL,
NIL,
NIL,
buffer,
current.byteOffset,
NIL
);
}
function createBigIntTypedArrayNode(id, current, buffer) {
return createSerovalNode(
16 /* BigIntTypedArray */,
id,
NIL,
current.length,
current.constructor.name,
NIL,
NIL,
NIL,
NIL,
buffer,
current.byteOffset,
NIL
);
}
function createDataViewNode(id, current, buffer) {
return createSerovalNode(
20 /* DataView */,
id,
NIL,
current.byteLength,
NIL,
NIL,
NIL,
NIL,
NIL,
buffer,
current.byteOffset,
NIL
);
}
function createErrorNode(id, current, options) {
return createSerovalNode(
13 /* Error */,
id,
getErrorConstructor(current),
NIL,
NIL,
serializeString(current.message),
options,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
function createAggregateErrorNode(id, current, options) {
return createSerovalNode(
14 /* AggregateError */,
id,
getErrorConstructor(current),
NIL,
NIL,
serializeString(current.message),
options,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
function createSetNode(id, size, items) {
return createSerovalNode(
7 /* Set */,
id,
NIL,
size,
NIL,
NIL,
NIL,
NIL,
items,
NIL,
NIL,
NIL
);
}
function createIteratorFactoryInstanceNode(factory, items) {
return createSerovalNode(
28 /* IteratorFactoryInstance */,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
[factory, items],
NIL,
NIL,
NIL
);
}
function createAsyncIteratorFactoryInstanceNode(factory, items) {
return createSerovalNode(
30 /* AsyncIteratorFactoryInstance */,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
[factory, items],
NIL,
NIL,
NIL
);
}
function createStreamConstructorNode(id, factory, sequence) {
return createSerovalNode(
31 /* StreamConstructor */,
id,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
sequence,
factory,
NIL,
NIL
);
}
function createStreamNextNode(id, parsed) {
return createSerovalNode(
32 /* StreamNext */,
id,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
parsed,
NIL,
NIL
);
}
function createStreamThrowNode(id, parsed) {
return createSerovalNode(
33 /* StreamThrow */,
id,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
parsed,
NIL,
NIL
);
}
function createStreamReturnNode(id, parsed) {
return createSerovalNode(
34 /* StreamReturn */,
id,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
parsed,
NIL,
NIL
);
}
// src/core/errors.ts
var { toString: objectToString } = Object.prototype;
function getErrorMessage(type, cause) {
if (cause instanceof Error) {
return `Seroval caught an error during the ${type} process.
${cause.name}
${cause.message}
- For more information, please check the "cause" property of this error.
- If you believe this is an error in Seroval, please submit an issue at https://github.com/lxsmnsyc/seroval/issues/new`;
}
return `Seroval caught an error during the ${type} process.
"${objectToString.call(cause)}"
For more information, please check the "cause" property of this error.`;
}
var SerovalError = class extends Error {
constructor(type, cause) {
super(getErrorMessage(type, cause));
this.cause = cause;
}
};
var SerovalParserError = class extends SerovalError {
constructor(cause) {
super("parsing", cause);
}
};
var SerovalSerializationError = class extends SerovalError {
constructor(cause) {
super("serialization", cause);
}
};
var SerovalDeserializationError = class extends SerovalError {
constructor(cause) {
super("deserialization", cause);
}
};
var SerovalUnsupportedTypeError = class extends Error {
constructor(value) {
super(
`The value ${objectToString.call(value)} of type "${typeof value}" cannot be parsed/serialized.
There are few workarounds for this problem:
- Transform the value in a way that it can be serialized.
- If the reference is present on multiple runtimes (isomorphic), you can use the Reference API to map the references.`
);
this.value = value;
}
};
var SerovalUnsupportedNodeError = class extends Error {
constructor(node) {
super('Unsupported node type "' + node.t + '".');
}
};
var SerovalMissingPluginError = class extends Error {
constructor(tag) {
super('Missing plugin for tag "' + tag + '".');
}
};
var SerovalMissingInstanceError = class extends Error {
constructor(tag) {
super('Missing "' + tag + '" instance.');
}
};
var SerovalMissingReferenceError = class extends Error {
constructor(value) {
super(
'Missing reference for the value "' + objectToString.call(value) + '" of type "' + typeof value + '"'
);
this.value = value;
}
};
var SerovalMissingReferenceForIdError = class extends Error {
constructor(id) {
super('Missing reference for id "' + serializeString(id) + '"');
}
};
var SerovalUnknownTypedArrayError = class extends Error {
constructor(name) {
super('Unknown TypedArray "' + name + '"');
}
};
// src/core/opaque-reference.ts
var OpaqueReference = class {
constructor(value, replacement) {
this.value = value;
this.replacement = replacement;
}
};
// src/core/special-reference.ts
var ITERATOR = {};
var ASYNC_ITERATOR = {};
var SPECIAL_REFS = {
[0 /* MapSentinel */]: {},
[1 /* PromiseConstructor */]: {},
[2 /* PromiseResolve */]: {},
[3 /* PromiseReject */]: {},
[4 /* StreamConstructor */]: {},
[5 /* AbortSignalConstructor */]: {},
[6 /* AbortSignalAbort */]: {}
};
// src/core/utils/deferred.ts
function createDeferred() {
let resolve;
let reject;
return {
promise: new Promise((res, rej) => {
resolve = res;
reject = rej;
}),
resolve(value) {
resolve(value);
},
reject(value) {
reject(value);
}
};
}
// src/core/stream.ts
function isStream(value) {
return "__SEROVAL_STREAM__" in value;
}
function createStream() {
const listeners = /* @__PURE__ */ new Set();
const buffer = [];
let alive = true;
let success = true;
function flushNext(value) {
for (const listener of listeners.keys()) {
listener.next(value);
}
}
function flushThrow(value) {
for (const listener of listeners.keys()) {
listener.throw(value);
}
}
function flushReturn(value) {
for (const listener of listeners.keys()) {
listener.return(value);
}
}
return {
__SEROVAL_STREAM__: true,
on(listener) {
if (alive) {
listeners.add(listener);
}
for (let i = 0, len = buffer.length; i < len; i++) {
const value = buffer[i];
if (i === len - 1 && !alive) {
if (success) {
listener.return(value);
} else {
listener.throw(value);
}
} else {
listener.next(value);
}
}
return () => {
if (alive) {
listeners.delete(listener);
}
};
},
next(value) {
if (alive) {
buffer.push(value);
flushNext(value);
}
},
throw(value) {
if (alive) {
buffer.push(value);
flushThrow(value);
alive = false;
success = false;
listeners.clear();
}
},
return(value) {
if (alive) {
buffer.push(value);
flushReturn(value);
alive = false;
success = true;
listeners.clear();
}
}
};
}
function createStreamFromAsyncIterable(iterable) {
const stream = createStream();
const iterator = iterable[Symbol.asyncIterator]();
async function push() {
try {
const value = await iterator.next();
if (value.done) {
stream.return(value.value);
} else {
stream.next(value.value);
await push();
}
} catch (error) {
stream.throw(error);
}
}
push().catch(() => {
});
return stream;
}
function streamToAsyncIterable(stream) {
return () => {
const buffer = [];
const pending = [];
let count = 0;
let doneAt = -1;
let isThrow = false;
function resolveAll() {
for (let i = 0, len = pending.length; i < len; i++) {
pending[i].resolve({ done: true, value: void 0 });
}
}
stream.on({
next(value) {
const current = pending.shift();
if (current) {
current.resolve({ done: false, value });
}
buffer.push(value);
},
throw(value) {
const current = pending.shift();
if (current) {
current.reject(value);
}
resolveAll();
doneAt = buffer.length;
buffer.push(value);
isThrow = true;
},
return(value) {
const current = pending.shift();
if (current) {
current.resolve({ done: true, value });
}
resolveAll();
doneAt = buffer.length;
buffer.push(value);
}
});
function finalize() {
const current = count++;
const value = buffer[current];
if (current !== doneAt) {
return { done: false, value };
}
if (isThrow) {
throw value;
}
return { done: true, value };
}
return {
[Symbol.asyncIterator]() {
return this;
},
async next() {
if (doneAt === -1) {
const current = count++;
if (current >= buffer.length) {
const deferred = createDeferred();
pending.push(deferred);
return await deferred.promise;
}
return { done: false, value: buffer[current] };
}
if (count > doneAt) {
return { done: true, value: void 0 };
}
return finalize();
}
};
};
}
// src/core/utils/iterator-to-sequence.ts
function iteratorToSequence(source) {
const values = [];
let throwsAt = -1;
let doneAt = -1;
const iterator = source[Symbol.iterator]();
while (true) {
try {
const value = iterator.next();
values.push(value.value);
if (value.done) {
doneAt = values.length - 1;
break;
}
} catch (error) {
throwsAt = values.length;
values.push(error);
}
}
return {
v: values,
t: throwsAt,
d: doneAt
};
}
function sequenceToIterator(sequence) {
return () => {
let index = 0;
return {
[Symbol.iterator]() {
return this;
},
next() {
if (index > sequence.d) {
return {
done: true,
value: NIL
};
}
const currentIndex = index++;
const currentItem = sequence.v[currentIndex];
if (currentIndex === sequence.t) {
throw currentItem;
}
return {
done: currentIndex === sequence.d,
value: currentItem
};
}
};
};
}
// src/core/utils/promise-to-result.ts
async function promiseToResult(current) {
try {
return [1, await current];
} catch (e) {
return [0, e];
}
}
// src/core/context/parser.ts
var BaseParserContext = class {
constructor(options) {
this.marked = /* @__PURE__ */ new Set();
this.plugins = options.plugins;
this.features = ALL_ENABLED ^ (options.disabledFeatures || 0);
this.refs = options.refs || /* @__PURE__ */ new Map();
}
markRef(id) {
this.marked.add(id);
}
isMarked(id) {
return this.marked.has(id);
}
getIndexedValue(current) {
const registeredId = this.refs.get(current);
if (registeredId != null) {
this.markRef(registeredId);
return {
type: 1 /* Indexed */,
value: createIndexedValueNode(registeredId)
};
}
const id = this.refs.size;
this.refs.set(current, id);
return {
type: 0 /* Fresh */,
value: id
};
}
getReference(current) {
const indexed = this.getIndexedValue(current);
if (indexed.type === 1 /* Indexed */) {
return indexed;
}
if (hasReferenceID(current)) {
return {
type: 2 /* Referenced */,
value: createReferenceNode(indexed.value, current)
};
}
return indexed;
}
parseWellKnownSymbol(current) {
const ref = this.getReference(current);
if (ref.type !== 0 /* Fresh */) {
return ref.value;
}
assert(current in INV_SYMBOL_REF, new SerovalUnsupportedTypeError(current));
return createWKSymbolNode(ref.value, current);
}
parseSpecialReference(ref) {
const result = this.getIndexedValue(SPECIAL_REFS[ref]);
if (result.type === 1 /* Indexed */) {
return result.value;
}
return createSerovalNode(
26 /* SpecialReference */,
result.value,
ref,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL
);
}
parseIteratorFactory() {
const result = this.getIndexedValue(ITERATOR);
if (result.type === 1 /* Indexed */) {
return result.value;
}
return createSerovalNode(
27 /* IteratorFactory */,
result.value,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
this.parseWellKnownSymbol(Symbol.iterator),
NIL,
NIL
);
}
parseAsyncIteratorFactory() {
const result = this.getIndexedValue(ASYNC_ITERATOR);
if (result.type === 1 /* Indexed */) {
return result.value;
}
return createSerovalNode(
29 /* AsyncIteratorFactory */,
result.value,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
[
this.parseSpecialReference(1 /* PromiseConstructor */),
this.parseWellKnownSymbol(Symbol.asyncIterator)
],
NIL,
NIL,
NIL
);
}
createObjectNode(id, current, empty, record) {
return createSerovalNode(
empty ? 11 /* NullConstructor */ : 10 /* Object */,
id,
NIL,
NIL,
NIL,
NIL,
record,
NIL,
NIL,
NIL,
NIL,
getObjectFlag(current)
);
}
createMapNode(id, k, v, s) {
return createSerovalNode(
8 /* Map */,
id,
NIL,
NIL,
NIL,
NIL,
NIL,
{ k, v, s },
NIL,
this.parseSpecialReference(0 /* MapSentinel */),
NIL,
NIL
);
}
createPromiseConstructorNode(id) {
return createSerovalNode(
22 /* PromiseConstructor */,
id,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
this.parseSpecialReference(1 /* PromiseConstructor */),
NIL,
NIL
);
}
createAbortSignalConstructorNode(id) {
return createSerovalNode(
35 /* AbortSignalConstructor */,
id,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
this.parseSpecialReference(5 /* AbortSignalConstructor */),
NIL,
NIL
);
}
};
// src/core/context/parser/async.ts
var BaseAsyncParserContext = class extends BaseParserContext {
async parseItems(current) {
const nodes = [];
for (let i = 0, len = current.length; i < len; i++) {
if (i in current) {
nodes[i] = await this.parse(current[i]);
}
}
return nodes;
}
async parseArray(id, current) {
return createArrayNode(id, current, await this.parseItems(current));
}
async parseProperties(properties) {
const entries = Object.entries(properties);
const keyNodes = [];
const valueNodes = [];
for (let i = 0, len = entries.length; i < len; i++) {
keyNodes.push(serializeString(entries[i][0]));
valueNodes.push(await this.parse(entries[i][1]));
}
let symbol = Symbol.iterator;
if (symbol in properties) {
keyNodes.push(this.parseWellKnownSymbol(symbol));
valueNodes.push(
createIteratorFactoryInstanceNode(
this.parseIteratorFactory(),
await this.parse(
iteratorToSequence(properties)
)
)
);
}
symbol = Symbol.asyncIterator;
if (symbol in properties) {
keyNodes.push(this.parseWellKnownSymbol(symbol));
valueNodes.push(
createAsyncIteratorFactoryInstanceNode(
this.parseAsyncIteratorFactory(),
await this.parse(
createStreamFromAsyncIterable(
properties
)
)
)
);
}
symbol = Symbol.toStringTag;
if (symbol in properties) {
keyNodes.push(this.parseWellKnownSymbol(symbol));
valueNodes.push(createStringNode(properties[symbol]));
}
symbol = Symbol.isConcatSpreadable;
if (symbol in properties) {
keyNodes.push(this.parseWellKnownSymbol(symbol));
valueNodes.push(properties[symbol] ? TRUE_NODE : FALSE_NODE);
}
return {
k: keyNodes,
v: valueNodes,
s: keyNodes.length
};
}
async parsePlainObject(id, current, empty) {
return this.createObjectNode(
id,
current,
empty,
await this.parseProperties(current)
);
}
async parseBoxed(id, current) {
return createBoxedNode(id, await this.parse(current.valueOf()));
}
async parseTypedArray(id, current) {
return createTypedArrayNode(id, current, await this.parse(current.buffer));
}
async parseBigIntTypedArray(id, current) {
return createBigIntTypedArrayNode(
id,
current,
await this.parse(current.buffer)
);
}
async parseDataView(id, current) {
return createDataViewNode(id, current, await this.parse(current.buffer));
}
async parseError(id, current) {
const options = getErrorOptions(current, this.features);
return createErrorNode(
id,
current,
options ? await this.parseProperties(options) : NIL
);
}
async parseAggregateError(id, current) {
const options = getErrorOptions(current, this.features);
return createAggregateErrorNode(
id,
current,
options ? await this.parseProperties(options) : NIL
);
}
async parseMap(id, current) {
const keyNodes = [];
const valueNodes = [];
for (const [key, value] of current.entries()) {
keyNodes.push(await this.parse(key));
valueNodes.push(await this.parse(value));
}
return this.createMapNode(id, keyNodes, valueNodes, current.size);
}
async parseSet(id, current) {
const items = [];
for (const item of current.keys()) {
items.push(await this.parse(item));
}
return createSetNode(id, current.size, items);
}
async parsePromise(id, current) {
const [status, result] = await promiseToResult(current);
return createSerovalNode(
12 /* Promise */,
id,
status,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
await this.parse(result),
NIL,
NIL
);
}
async parsePlugin(id, current) {
const currentPlugins = this.plugins;
if (currentPlugins) {
for (let i = 0, len = currentPlugins.length; i < len; i++) {
const plugin = currentPlugins[i];
if (plugin.parse.async && plugin.test(current)) {
return createPluginNode(
id,
plugin.tag,
await plugin.parse.async(current, this, {
id
})
);
}
}
}
return NIL;
}
async parseStream(id, current) {
return createStreamConstructorNode(
id,
this.parseSpecialReference(4 /* StreamConstructor */),
await new Promise((resolve, reject) => {
const sequence = [];
const cleanup = current.on({
next: (value) => {
this.markRef(id);
this.parse(value).then(
(data) => {
sequence.push(createStreamNextNode(id, data));
},
(data) => {
reject(data);
cleanup();
}
);
},
throw: (value) => {
this.markRef(id);
this.parse(value).then(
(data) => {
sequence.push(createStreamThrowNode(id, data));
resolve(sequence);
cleanup();
},
(data) => {
reject(data);
cleanup();
}
);
},
return: (value) => {
this.markRef(id);
this.parse(value).then(
(data) => {
sequence.push(createStreamReturnNode(id, data));
resolve(sequence);
cleanup();
},
(data) => {
reject(data);
cleanup();
}
);
}
});
})
);
}
async parseAbortSignalSync(id, current) {
return createSerovalNode(
37 /* AbortSignalSync */,
id,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
NIL,
await this.parse(current.reason),
NIL,
NIL
);
}
async parseAbortSignal(id, current) {
if (!current.aborted) {
await abortSignalToPromise(current);
}
return this.parseAbortSignalSync(id, current);
}
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: ehh
async parseObject(id, current) {
if (Array.isArray(current)) {
return this.parseArray(id, current);
}
if (isStream(current)) {
return this.parseStream(id, current);
}
const currentClass = current.constructor;
if (currentClass === OpaqueReference) {
return this.parse(
current.replacement
);
}
const parsed = await this.parsePlugin(id, current);
if (parsed) {
return parsed;
}
switch (currentClass) {
case Object:
return this.parsePlainObject(
id,
current,
false
);
case NIL:
return this.parsePlainObject(
id,
current,
true
);
case Date:
return createDateNode(id, current);
case RegExp:
return createRegExpNode(id, current);
case Error:
case EvalError:
case RangeError:
case ReferenceError:
case SyntaxError:
case TypeError:
case URIError:
return this.parseError(id, current);
case Number:
case Boolean:
case String:
case BigInt:
return this.parseBoxed(id, current);
case ArrayBuffer:
return createArrayBufferNode(id, current);
case Int8Array:
case Int16Array:
case Int32Array:
case Uint8Array:
case Uint16Array:
case Uint32Array:
case Uint8ClampedArray:
case Float32Array:
case Float64Array:
return this.parseTypedArray(id, current);
case DataView:
return this.parseDataView(id, current);
case Map:
return this.parseMap(id, current);
case Set:
return this.parseSet(id, current);
default:
break;
}
if (currentClass === Promise || current instanceof Promise) {
return this.parsePromise(id, current);
}
const currentFeatures = this.features;
if (currentFeatures & 32 /* AbortSignal */ && typeof AbortSignal !== "undefined" && currentClass === AbortSignal) {
return this.parseAbortSignal(id, current);
}
if (currentFeatures & 16 /* BigIntTypedArray */) {
switch (currentClass) {
case BigInt64Array:
case BigUint64Array:
return this.parseBigIntTypedArray(
id,
current
);
default:
break;
}
}
if (currentFeatures & 1 /* AggregateError */ && typeof AggregateError !== "undefined" && (currentClass === AggregateError || current instanceof AggregateError)) {
return this.parseAggregateError(id, current);
}
if (current instanceof Error) {
return this.parseError(id, current);
}
if (Symbol.iterator in current || Symbol.asyncIterator in current) {
return this.parsePlainObject(id, current, !!currentClass);
}
throw new SerovalUnsupportedTypeError(current);
}
async parseFunction(current) {
const ref = this.getReference(current);
if (ref.type !== 0 /* Fresh */) {
return ref.value;
}
const plugin = await this.parsePlugin(ref.value, current);
if (plugin) {
return plugin;
}
throw new SerovalUnsupportedTypeError(current);
}
async parse(current) {
try {
switch (typeof current) {
case "boolean":
return current ? TRUE_NODE : FALSE_NODE;
case "undefined":
return UNDEFINED_NODE;
case "string":
return createStringNode(current);
case "number":
return createNumberNode(current);
case "bigint":
return createBigIntNode(current);
case "object": {
if (current) {
const ref = this.getReference(current);
return ref.type === 0 ? await this.parseObject(ref.value, current) : ref.value;
}
return NULL_NODE;
}
case "symbol":
return this.parseWellKnownSymbol(current);
case "function":
return this.parseFunction(current);
default:
throw new SerovalUnsupportedTypeError(current);
}
} catch (error) {
throw new SerovalParserError(error);
}
}
};
// src/core/cross/async.ts
var CrossAsyncParserContext = class extends BaseAsyncParserContext {
constructor() {
super(...arguments);
this.mode = "cross";
}
};
// src/core/utils/typed-array.ts
function getTypedArrayConstructor(name) {
switch (name) {
case "Int8Array":
return Int8Array;
case "Int16Array":
return Int16Array;
case "Int32Array":
return Int32Array;
case "Uint8Array":
return Uint8Array;
case "Uint16Array":
return Uint16Array;
case "Uint32Array":
return Uint32Array;
case "Uint8ClampedArray":
return Uint8ClampedArray;
case "Float32Array":
return Float32Array;
case "Float64Array":
return Float64Array;
case "BigInt64Array":
return BigInt64Array;
case "BigUint64Array":
return BigUint64Array;
default:
throw new SerovalUnknownTypedArrayError(name);
}
}
// src/core/context/deserializer.ts
function applyObjectFlag(obj, flag) {
switch (flag) {
case 3 /* Frozen */:
return Object.freeze(obj);
case 1 /* NonExtensible */:
return Object.preventExtensions(obj);
case 2 /* Sealed */:
return Object.seal(obj);
default:
return obj;
}
}
var BaseDeserializerContext = class {
constructor(options) {
this.plugins = options.plugins;
this.refs = options.refs || /* @__PURE__ */ new Map();
}
deserializeReference(node) {
return this.assignIndexedValue(
node.i,
getReference(deserializeString(node.s))
);
}
deserializeArray(node) {
const len = node.l;
const result = this.assignIndexedValue(
node.i,
new Array(len)
);
let item;
for (let i = 0; i < len; i++) {
item = node.a[i];
if (item) {
result[i] = this.deserialize(item);
}
}
applyObjectFlag(result, node.o);
return result;
}
deserializeProperties(node, result) {
const len = node.s;
if (len) {
const keys = node.k;
const vals = node.v;
for (let i = 0, key; i < len; i++) {
key = keys[i];
if (typeof key === "string") {
result[deserializeString(key)] = this.deserialize(vals[i]);
} else {
result[this.deserialize(key)] = this.deserialize(vals[i]);
}
}
}
return result;
}
deserializeObject(node) {
const result = this.assignIndexedValue(
node.i,
node.t === 10 /* Object */ ? {} : /* @__PURE__ */ Object.create(null)
);
this.deserializeProperties(node.p, result);
applyObjectFlag(result, node.o);
return result;
}
deserializeDate(node) {
return this.assignIndexedValue(node.i, new Date(node.s));
}
deserializeRegExp(node) {
return this.assignIndexedValue(
node.i,
new RegExp(deserializeString(node.c), node.m)
);
}
deserializeSet(node) {
const result = this.assignIndexedValue(node.i, /* @__PURE__ */ new Set());
const items = node.a;
for (let i = 0, len = node.l; i < len; i++) {
result.add(this.deserialize(items[i]));
}
return result;
}
deserializeMap(node) {
const result = this.assignIndexedValue(node.i, /* @__PURE__ */ new Map());
const keys = node.e.k;
const vals = node.e.v;
for (let i = 0, len = node.e.s; i < len; i++) {
result.set(this.deserialize(keys[i]), this.deserialize(vals[i]));
}
return result;
}
deserializeArrayBuffer(node) {
const bytes = new Uint8Array(node.s);
const result = this.assignIndexedValue(node.i, bytes.buffer);
return result;
}
deserializeTypedArray(node) {
const construct = getTypedArrayConstructor(node.c);
const source = this.deserialize(node.f);
const result = this.assignIndexedValue(
node.i,
new construct(source, node.b, node.l)
);
return result;
}
deserializeDataView(node) {
const source = this.deserialize(node.f);
const result = this.assignIndexedValue(
node.i,
new DataView(source, node.b, node.l)
);
return result;
}
deserializeDictionary(node, result) {
if (node.p) {
const fields = this.deserializeProperties(node.p, {});
Object.assign(result, fields);
}
return result;
}
deserializeAggregateError(node) {
const result = this.assignIndexedValue(
node.i,
new AggregateError([], deserializeString(node.m))
);
return this.deserializeDictionary(node, result);
}
deserializeError(node) {
const construct = ERROR_CONSTRUCTOR[node.s];
const result = this.assignIndexedValue(
node.i,
new construct(deserializeString(node.m))
);
return this.deserializeDictionary(node, result);
}
deserializePromise(node) {
const deferred = createDeferred();
const result = this.assignIndexedValue(node.i, deferred);
const deserialized = this.deserialize(node.f);
if (node.s) {
deferred.resolve(deserialized);
} else {
deferred.reject(deserialized);
}
return result.promise;
}
deserializeBoxed(node) {
return this.assignIndexedValue(node.i, Object(this.deserialize(node.f)));
}
deserializePlugin(node) {
const currentPlugins = this.plugins;
if (currentPlugins) {
const tag = deserializeString(node.c);
for (let i = 0, len = currentPlugins.length; i < len; i++) {
const plugin = currentPlugins[i];
if (plugin.tag === tag) {
return this.assignIndexedValue(
node.i,
plugin.deserialize(node.s, this, {
id: node.i
})
);
}
}
}
throw new SerovalMissingPluginError(node.c);
}
deserializePromiseConstructor(node) {
return this.assignIndexedValue(node.i, createDeferred()).promise;
}
deserializePromiseResolve(node) {
const deferred = this.refs.get(node.i);
assert(deferred, new SerovalMissingInstanceError("Promise"));
deferred.resolve(this.deserialize(node.a[1]));
return void 0;
}
deserializePromiseReject(node) {
const deferred = this.refs.get(node.i);
assert(deferred, new SerovalMissingInstanceError("Promise"));
deferred.reject(this.deserialize(node.a[1]));
return void 0;
}
deserializeIteratorFactoryInstance(node) {
this.deserialize(node.a[0]);
const source = this.deserialize(node.a[1]);
return sequenceToIterator(source);
}
deserializeAsyncIteratorFactoryInstance(node) {
this.deserialize(node.a[0]);
const source = this.deserialize(node.a[1]);
return streamToAsyncIterable(source);
}
deserializeStreamConstructor(node) {
const result = this.assignIndexedValue(node.i, createStream());
const len = node.a.length;
if (len) {
for (let i = 0; i < len; i++) {
this.deserialize(node.a[i]);
}
}
return result;
}
deserializeStreamNext(node) {
const deferred = this.refs.get(node.i);
assert(deferred, new SerovalMissingInstanceError("Stream"));
deferred.next(this.deserialize(node.f));
return void 0;
}
deserializeStreamThrow(node) {
const deferred = this.refs.get(node.i);
assert(deferred, new SerovalMissingInstanceError("Stream"));
deferred.throw(this.deserialize(node.f));
return void 0;
}
deserializeStreamReturn(node) {
const deferred = this.refs.get(node.i);
assert(deferred, new SerovalMissingInstanceError("Stream"));
deferred.return(this.deserialize(node.f));
return void 0;
}
deserializeIteratorFactory(node) {
this.deserialize(node.f);
return void 0;
}
deserializeAsyncIteratorFactory(node) {
this.deserialize(node.a[1]);
return void 0;
}
deserializeAbortSignalConstructor(node) {
return this.assignIndexedValue(node.i, new AbortController()).signal;
}
deserializeAbortSignalAbort(node) {
const controller = this.refs.get(node.i);
assert(controller, new SerovalMissingInstanceError("AbortSignal"));
controller.abort(this.deserialize(node.a[1]));
return void 0;
}
deserializeAbortSignalSync(node) {
return this.assignIndexedValue(
node.i,
AbortSignal.abort(this.deserialize(node.f))
);
}
deserialize(node) {
try {
switch (node.t) {
case 2 /* Constant */:
return CONSTANT_VAL[node.s];
case 0 /* Number */:
return node.s;
case 1 /* String */:
return deserializeString(node.s);
case 3 /* BigInt */:
return BigInt(node.s);
case 4 /* IndexedValue */:
return this.refs.get(node.i);
case 18 /* Reference */:
return this.deserializeReference(node);
case 9 /* Array */:
return this.deserializeArray(node);
case 10 /* Object */:
case 11 /* NullConstructor */:
return this.deserializeObject(node);
case 5 /* Date */:
return this.deserializeDate(node);
case 6 /* RegExp */:
return this.deserializeRegExp(node);
case 7 /* Set */:
return this.deserializeSet(node);
case 8 /* Map */:
return this.deserializeMap(node);
case 19 /* ArrayBuffer */:
return this.deserializeArrayBuffer(node);
case 16 /* BigIntTypedArray */:
case 15 /* TypedArray */:
return this.deserializeTypedArray(node);
case 20 /* DataView */:
return this.deserializeDataView(node);
case 14 /* AggregateError */:
return this.deserializeAggregateError(node);
case 13 /* Error */:
return this.deserializeError(node);
case 12 /* Promise */:
return this.deserializePromise(node);
case 17 /* WKSymbol */:
return SYMBOL_REF[node.s];
case 21 /* Boxed */:
return this.deserializeBoxed(node);
case 25 /* Plugin */:
return this.deserializePlugin(node);
case 22 /* PromiseConstructor */:
return this.deserializePromiseConstructor(node);
case 23 /* PromiseResolve */:
return this.deserializePromiseResolve(node);
case 24 /* PromiseReject */:
return this.deserializePromiseReject(node);
case 28 /* IteratorFactoryInstance */:
return this.deserializeIteratorFactoryInstance(node);
case 30 /* AsyncIteratorFactoryInstance */:
return this.deserializeAsyncIteratorFactoryInstance(node);
case 31 /* StreamConstructor */:
return this.deserializeStreamConstructor(node);
case 32 /* StreamNext */:
return this.deserializeStreamNext(node);
case 33 /* StreamThrow */:
return this.deserializeStreamThrow(node);
case 34 /* StreamReturn */:
return this.deserializeStreamReturn(node);
case 27 /* IteratorFactory */:
return this.deserializeIteratorFactory(node);
case 29 /* AsyncIteratorFactory */:
return this.deserializeAsyncIteratorFactory(node);
case 36 /* AbortSignalAbort */:
return this.deserializeAbortSignalAbort(node);
case 35 /* AbortSignalConstructor */:
return this.deserializeAbortSignalConstructor(node);
case 37 /* AbortSignalSync */:
return this.deserializeAbortSignalSync(node);
/