New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

seroval

Package Overview
Dependencies
Maintainers
1
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

seroval - npm Package Compare versions

Comparing version 0.7.0 to 0.8.0

dist/types/tree/constants.d.ts

2

dist/types/assert.d.ts

@@ -1,1 +0,1 @@

export default function assert(cond: unknown, error: string): asserts cond;
export default function assert(cond: unknown, error: Error): asserts cond;

@@ -33,6 +33,6 @@ interface IndexAssignment {

stack: number[];
validRefs: number[];
validRefs: (number | undefined)[];
refSize: number;
markedRefs: Set<number>;
vars: string[];
vars: (string | undefined)[];
assignments: Assignment[];

@@ -39,0 +39,0 @@ features: number;

@@ -1,4 +0,4 @@

import { Options } from './context';
import { SerovalNode } from './tree/types';
export { AsyncServerValue, ServerValue, PrimitiveValue, CommonServerValue, SemiPrimitiveValue, ErrorValue, } from './types';
import type { Options } from './context';
import type { SerovalNode } from './tree/types';
export type { AsyncServerValue, ServerValue, PrimitiveValue, CommonServerValue, SemiPrimitiveValue, ErrorValue, } from './types';
export { Feature } from './compat';

@@ -11,3 +11,2 @@ export declare function serialize<T>(source: T, options?: Partial<Options>): string;

r: number;
i: boolean;
f: number;

@@ -14,0 +13,0 @@ m: number[];

@@ -1,3 +0,3 @@

export declare function serializeChar(str: string): "\\\"" | "\\\\" | "\\n" | "\\r" | "\\b" | "\\t" | "\\f" | "\\x3C" | "\\u2028" | "\\u2029" | undefined;
export declare function serializeChar(str: string): string | undefined;
export declare function serializeString(str: string): string;
export declare function deserializeString(str: string): string;

@@ -1,3 +0,3 @@

import { ParserContext } from '../context';
import { SerovalNode } from './types';
export default function parseAsync<T>(ctx: ParserContext, current: T): Promise<readonly [SerovalNode, number, boolean]>;
import type { ParserContext } from '../context';
import type { SerovalNode } from './types';
export default function parseAsync<T>(ctx: ParserContext, current: T): Promise<SerovalNode>;

@@ -1,3 +0,3 @@

import { SerializationContext } from '../context';
import { SerovalNode } from './types';
import type { SerializationContext } from '../context';
import type { SerovalNode } from './types';
export default function deserializeTree(ctx: SerializationContext, node: SerovalNode): unknown;

@@ -1,14 +0,6 @@

import { ParserContext } from '../context';
import { BigIntTypedArrayValue, TypedArrayValue } from '../types';
import { WellKnownSymbols } from './symbols';
import { SerovalBigIntNode, SerovalBigIntTypedArrayNode, SerovalBooleanNode, SerovalDateNode, SerovalInfinityNode, SerovalNaNNode, SerovalNegativeInfinityNode, SerovalNegativeZeroNode, SerovalNullNode, SerovalNumberNode, SerovalIndexedValueNode, SerovalRegExpNode, SerovalStringNode, SerovalTypedArrayNode, SerovalUndefinedNode, SerovalWKSymbolNode, SerovalReferenceNode, SerovalArrayBufferNode, SerovalDataViewNode } from './types';
export declare const TRUE_NODE: SerovalBooleanNode;
export declare const FALSE_NODE: SerovalBooleanNode;
export declare const UNDEFINED_NODE: SerovalUndefinedNode;
export declare const NULL_NODE: SerovalNullNode;
export declare const NEG_ZERO_NODE: SerovalNegativeZeroNode;
export declare const INFINITY_NODE: SerovalInfinityNode;
export declare const NEG_INFINITY_NODE: SerovalNegativeInfinityNode;
export declare const NAN_NODE: SerovalNaNNode;
export declare function createNumberNode(value: number): SerovalNumberNode;
import type { ParserContext } from '../context';
import type { BigIntTypedArrayValue, TypedArrayValue } from '../types';
import type { WellKnownSymbols } from './symbols';
import type { SerovalBigIntNode, SerovalBigIntTypedArrayNode, SerovalDateNode, SerovalIndexedValueNode, SerovalRegExpNode, SerovalStringNode, SerovalTypedArrayNode, SerovalWKSymbolNode, SerovalReferenceNode, SerovalArrayBufferNode, SerovalDataViewNode, SerovalNode } from './types';
export declare function createNumberNode(value: number): SerovalNode;
export declare function createStringNode(value: string): SerovalStringNode;

@@ -20,7 +12,9 @@ export declare function createBigIntNode(ctx: ParserContext, current: bigint): SerovalBigIntNode;

export declare function createArrayBufferNode(id: number, current: ArrayBuffer): SerovalArrayBufferNode;
export declare function serializeArrayBuffer(ctx: ParserContext, current: ArrayBuffer): SerovalIndexedValueNode | SerovalArrayBufferNode;
export declare function serializeArrayBuffer(ctx: ParserContext, current: ArrayBuffer): SerovalNode;
export declare function createTypedArrayNode(ctx: ParserContext, id: number, current: TypedArrayValue): SerovalTypedArrayNode;
export declare function createBigIntTypedArrayNode(ctx: ParserContext, id: number, current: BigIntTypedArrayValue): SerovalBigIntTypedArrayNode;
export declare function createWKSymbolNode(ctx: ParserContext, current: WellKnownSymbols): SerovalWKSymbolNode;
export declare function createWKSymbolNode(ctx: ParserContext, id: number, current: WellKnownSymbols): SerovalWKSymbolNode;
export declare function createReferenceNode<T>(id: number, ref: T): SerovalReferenceNode;
export declare function createDataViewNode(ctx: ParserContext, id: number, current: DataView): SerovalDataViewNode;
export declare function createSymbolNode(ctx: ParserContext, current: symbol): SerovalNode;
export declare function createFunctionNode(ctx: ParserContext, current: Function): SerovalNode;

@@ -1,4 +0,4 @@

import { SerializationContext } from '../context';
import { SerovalNode } from './types';
import type { SerializationContext } from '../context';
import type { SerovalNode } from './types';
export declare function resolvePatches(ctx: SerializationContext): string | undefined;
export default function serializeTree(ctx: SerializationContext, node: SerovalNode): string;

@@ -1,9 +0,11 @@

import { ParserContext } from '../context';
import { AsyncServerValue, ErrorValue } from '../types';
export declare function getErrorConstructorName(error: ErrorValue): "EvalError" | "RangeError" | "ReferenceError" | "SyntaxError" | "TypeError" | "URIError" | "Error";
export declare function getErrorConstructor(errorName: string): ErrorConstructor;
export declare function getErrorOptions(ctx: ParserContext, error: Error): Record<string, any> | undefined;
export declare function getIterableOptions(obj: Iterable<any>): Record<string, unknown> | undefined;
export declare function isIterable(value: unknown): value is Iterable<AsyncServerValue>;
export declare function getTypedArrayConstructor(name: string): Int8ArrayConstructor | Uint8ArrayConstructor | Uint8ClampedArrayConstructor | Int16ArrayConstructor | Uint16ArrayConstructor | Int32ArrayConstructor | Uint32ArrayConstructor | Float32ArrayConstructor | Float64ArrayConstructor | BigInt64ArrayConstructor | BigUint64ArrayConstructor;
import type { ParserContext } from '../context';
import type { ErrorValue } from '../types';
export declare function getErrorConstructorName(error: ErrorValue): string;
type ErrorConstructors = ErrorConstructor | EvalErrorConstructor | RangeErrorConstructor | ReferenceErrorConstructor | SyntaxErrorConstructor | TypeErrorConstructor | URIErrorConstructor;
export declare function getErrorConstructor(errorName: string): ErrorConstructors;
export declare function getErrorOptions(ctx: ParserContext, error: Error): Record<string, unknown> | undefined;
export declare function isIterable(value: unknown): value is Iterable<unknown>;
type TypedArrayConstructor = Int8ArrayConstructor | Int16ArrayConstructor | Int32ArrayConstructor | Uint8ArrayConstructor | Uint16ArrayConstructor | Uint32ArrayConstructor | Uint8ClampedArrayConstructor | Float32ArrayConstructor | Float64ArrayConstructor | BigInt64ArrayConstructor | BigUint64ArrayConstructor;
export declare function getTypedArrayConstructor(name: string): TypedArrayConstructor;
export declare function isValidIdentifier(name: string): boolean;
export {};

@@ -1,3 +0,3 @@

import { ParserContext } from '../context';
import { SerovalNode } from './types';
export default function parseSync<T>(ctx: ParserContext, current: T): readonly [SerovalNode, number, boolean];
import type { ParserContext } from '../context';
import type { SerovalNode } from './types';
export default function parseSync<T>(ctx: ParserContext, current: T): SerovalNode;

@@ -1,37 +0,41 @@

import { Symbols } from './symbols';
import type { Symbols } from './symbols';
export declare const enum SerovalConstant {
Null = 0,
Undefined = 1,
True = 2,
False = 3,
NegativeZero = 4,
Infinity = 5,
NegativeInfinity = 6,
NaN = 7
}
export declare const enum SerovalNodeType {
Number = 0,
String = 1,
Boolean = 2,
Null = 3,
Undefined = 4,
NegativeZero = 5,
Infinity = 6,
NegativeInfinity = 7,
NaN = 8,
BigInt = 9,
IndexedValue = 10,
Date = 11,
RegExp = 12,
Set = 13,
Map = 14,
Array = 15,
Object = 16,
NullConstructor = 17,
Promise = 18,
Error = 19,
AggregateError = 20,
Iterable = 21,
TypedArray = 22,
BigIntTypedArray = 23,
WKSymbol = 24,
URL = 25,
URLSearchParams = 26,
Reference = 27,
ArrayBuffer = 28,
DataView = 29,
Blob = 30,
File = 31,
Headers = 32,
FormData = 33
Constant = 2,
BigInt = 3,
IndexedValue = 4,
Date = 5,
RegExp = 6,
Set = 7,
Map = 8,
Array = 9,
Object = 10,
NullConstructor = 11,
Promise = 12,
Error = 13,
AggregateError = 14,
TypedArray = 15,
BigIntTypedArray = 16,
WKSymbol = 17,
URL = 18,
URLSearchParams = 19,
Reference = 20,
ArrayBuffer = 21,
DataView = 22,
Blob = 23,
File = 24,
Headers = 25,
FormData = 26,
Boxed = 27
}

@@ -41,12 +45,16 @@ export interface SerovalBaseNode {

i: number | undefined;
s: any;
s: unknown;
l: number | undefined;
c: string | undefined;
m: string | undefined;
d: SerovalDictionaryNode | undefined;
a: SerovalNode[] | undefined;
d: SerovalObjectRecordNode | SerovalMapRecordNode | undefined;
a: (SerovalNode | undefined)[] | undefined;
f: SerovalNode | undefined;
b: number | undefined;
}
export interface SerovalObjectRecordNode {
export declare const enum SerovalObjectRecordSpecialKey {
SymbolIterator = 0
}
export type SerovalObjectRecordKey = string | SerovalObjectRecordSpecialKey;
export interface SerovalPlainRecordNode {
k: string[];

@@ -56,2 +64,7 @@ v: SerovalNode[];

}
export interface SerovalObjectRecordNode {
k: SerovalObjectRecordKey[];
v: SerovalNode[];
s: number;
}
export interface SerovalMapRecordNode {

@@ -62,3 +75,2 @@ k: SerovalNode[];

}
export type SerovalDictionaryNode = SerovalObjectRecordNode | SerovalMapRecordNode;
export interface SerovalNumberNode extends SerovalBaseNode {

@@ -72,25 +84,7 @@ t: SerovalNodeType.Number;

}
export interface SerovalBooleanNode extends SerovalBaseNode {
t: SerovalNodeType.Boolean;
s: boolean;
export interface SerovalConstantNode extends SerovalBaseNode {
t: SerovalNodeType.Constant;
s: SerovalConstant;
}
export interface SerovalNullNode extends SerovalBaseNode {
t: SerovalNodeType.Null;
}
export interface SerovalUndefinedNode extends SerovalBaseNode {
t: SerovalNodeType.Undefined;
}
export interface SerovalNegativeZeroNode extends SerovalBaseNode {
t: SerovalNodeType.NegativeZero;
}
export interface SerovalInfinityNode extends SerovalBaseNode {
t: SerovalNodeType.Infinity;
}
export interface SerovalNegativeInfinityNode extends SerovalBaseNode {
t: SerovalNodeType.NegativeInfinity;
}
export interface SerovalNaNNode extends SerovalBaseNode {
t: SerovalNodeType.NaN;
}
export type SerovalPrimitiveNode = SerovalNumberNode | SerovalStringNode | SerovalBooleanNode | SerovalNullNode | SerovalUndefinedNode | SerovalNegativeZeroNode | SerovalNegativeInfinityNode | SerovalInfinityNode | SerovalNaNNode;
export type SerovalPrimitiveNode = SerovalNumberNode | SerovalStringNode | SerovalConstantNode;
export interface SerovalIndexedValueNode extends SerovalBaseNode {

@@ -151,3 +145,3 @@ t: SerovalNodeType.IndexedValue;

l: number;
a: SerovalNode[];
a: (SerovalNode | undefined)[];
i: number;

@@ -183,11 +177,5 @@ }

}
export interface SerovalIterableNode extends SerovalBaseNode {
t: SerovalNodeType.Iterable;
d: SerovalObjectRecordNode | undefined;
l: number;
a: SerovalNode[];
i: number;
}
export interface SerovalWKSymbolNode extends SerovalBaseNode {
t: SerovalNodeType.WKSymbol;
i: number;
s: Symbols;

@@ -234,3 +222,3 @@ }

i: number;
d: SerovalObjectRecordNode;
d: SerovalPlainRecordNode;
}

@@ -240,4 +228,9 @@ export interface SerovalFormDataNode extends SerovalBaseNode {

i: number;
d: SerovalObjectRecordNode;
d: SerovalPlainRecordNode;
}
export type SerovalNode = SerovalPrimitiveNode | SerovalIndexedValueNode | SerovalSemiPrimitiveNode | SerovalSetNode | SerovalMapNode | SerovalArrayNode | SerovalObjectNode | SerovalNullConstructorNode | SerovalPromiseNode | SerovalErrorNode | SerovalAggregateErrorNode | SerovalIterableNode | SerovalWKSymbolNode | SerovalURLNode | SerovalURLSearchParamsNode | SerovalReferenceNode | SerovalArrayBufferNode | SerovalDataViewNode | SerovalBlobNode | SerovalFileNode | SerovalHeadersNode | SerovalFormDataNode;
export interface SerovalBoxedNode extends SerovalBaseNode {
t: SerovalNodeType.Boxed;
i: number;
f: SerovalNode;
}
export type SerovalNode = SerovalPrimitiveNode | SerovalIndexedValueNode | SerovalSemiPrimitiveNode | SerovalSetNode | SerovalMapNode | SerovalArrayNode | SerovalObjectNode | SerovalNullConstructorNode | SerovalPromiseNode | SerovalErrorNode | SerovalAggregateErrorNode | SerovalWKSymbolNode | SerovalURLNode | SerovalURLSearchParamsNode | SerovalReferenceNode | SerovalArrayBufferNode | SerovalDataViewNode | SerovalBlobNode | SerovalFileNode | SerovalHeadersNode | SerovalFormDataNode | SerovalBoxedNode;

@@ -1,3 +0,3 @@

import { ParserContext } from '../context';
import { SerovalBlobNode, SerovalFileNode, SerovalURLNode, SerovalURLSearchParamsNode } from './types';
import type { ParserContext } from '../context';
import type { SerovalBlobNode, SerovalFileNode, SerovalURLNode, SerovalURLSearchParamsNode } from './types';
export declare function createURLNode(ctx: ParserContext, id: number, current: URL): SerovalURLNode;

@@ -4,0 +4,0 @@ export declare function createURLSearchParamsNode(ctx: ParserContext, id: number, current: URLSearchParams): SerovalURLSearchParamsNode;

@@ -1,2 +0,2 @@

import { WellKnownSymbols } from './tree/symbols';
import type { WellKnownSymbols } from './tree/symbols';
export type PrimitiveValue = boolean | string | number | undefined | null | WellKnownSymbols;

@@ -6,4 +6,4 @@ export type ErrorValue = Error | AggregateError | EvalError | RangeError | ReferenceError | TypeError | SyntaxError | URIError;

export type BigIntTypedArrayValue = BigInt64Array | BigUint64Array;
export type WebAPIValue = URL | URLSearchParams;
export type SemiPrimitiveValue = RegExp | Date | TypedArrayValue | BigIntTypedArrayValue | bigint | WebAPIValue;
export type WebAPIValue = URL | URLSearchParams | Blob | File;
export type SemiPrimitiveValue = RegExp | Date | ArrayBuffer | DataView | TypedArrayValue | BigIntTypedArrayValue | bigint | WebAPIValue;
export type CommonServerValue = PrimitiveValue | SemiPrimitiveValue | ErrorValue;

@@ -19,4 +19,4 @@ export type ServerValue = CommonServerValue | Array<ServerValue> | readonly ServerValue[] | Iterable<ServerValue> | {

readonly [key: string | number]: AsyncServerValue;
} | Set<AsyncServerValue> | Map<AsyncServerValue, AsyncServerValue> | PromiseLike<AsyncServerValue>;
} | Set<AsyncServerValue> | Map<AsyncServerValue, AsyncServerValue> | Promise<AsyncServerValue>;
export type NonPrimitiveServerValue<T> = T extends PrimitiveValue ? never : T;
export type MaybePromise<T> = T | Promise<T>;
{
"name": "seroval",
"type": "module",
"version": "0.7.0",
"version": "0.8.0",
"files": [

@@ -18,9 +18,10 @@ "dist",

"@types/node": "^18.15.3",
"eslint": "^8.32.0",
"eslint-config-lxsmnsyc": "^0.5.1",
"@vitest/ui": "^0.30.1",
"eslint": "^8.39.0",
"eslint-config-lxsmnsyc": "^0.6.4",
"node-fetch-native": "^1.1.0",
"pridepack": "2.4.1",
"tslib": "^2.4.1",
"pridepack": "2.4.4",
"tslib": "^2.5.0",
"typescript": "^4.9.4",
"vitest": "^0.28.1"
"vitest": "^0.30.1"
},

@@ -36,3 +37,4 @@ "scripts": {

"dev": "pridepack dev",
"test": "vitest"
"test": "vitest",
"test:ui": "vitest --ui"
},

@@ -70,3 +72,3 @@ "private": false,

},
"gitHead": "187cbd91a44f5e88c6a87288d9ea440ddbaf5be0"
"gitHead": "f7fe3305e0295499989d9f675ff54f9305db23b0"
}

@@ -1,5 +0,5 @@

export default function assert(cond: unknown, error: string): asserts cond {
export default function assert(cond: unknown, error: Error): asserts cond {
if (!cond) {
throw new Error(error);
throw error;
}
}

@@ -1,2 +0,1 @@

/* eslint-disable guard-for-in */
/**

@@ -3,0 +2,0 @@ * References

@@ -48,3 +48,3 @@ import { ALL_ENABLED } from './compat';

// Map tree refs to actual refs
validRefs: number[];
validRefs: (number | undefined)[];
refSize: number;

@@ -54,3 +54,3 @@ // Refs that are...referenced

// Variables
vars: string[];
vars: (string | undefined)[];
// Array of assignments to be done (used for recursion)

@@ -74,3 +74,3 @@ assignments: Assignment[];

// eslint-disable-next-line prefer-object-spread
const result = Object.assign({}, DEFAULT_OPTIONS, options || {});
const result = Object.assign({}, DEFAULT_OPTIONS, options);
return {

@@ -104,3 +104,6 @@ markedRefs: new Set(),

*/
export function markRef(ctx: ParserContext | SerializationContext, current: number) {
export function markRef(
ctx: ParserContext | SerializationContext,
current: number,
): void {
ctx.markedRefs.add(current);

@@ -112,3 +115,3 @@ }

*/
export function getRefParam(ctx: SerializationContext, index: number) {
export function getRefParam(ctx: SerializationContext, index: number): string {
/**

@@ -136,3 +139,3 @@ * Creates a new reference ID from a given reference ID

current: T,
) {
): number {
const ref = ctx.refs.get(current);

@@ -148,3 +151,3 @@ if (ref == null) {

current: T,
) {
): number {
const ref = ctx.refs.get(current);

@@ -151,0 +154,0 @@ if (ref == null) {

@@ -7,3 +7,3 @@ // Written by https://github.com/DylanPiercey and is distributed under the MIT license.

export default function getIdentifier(index: number) {
export default function getIdentifier(index: number): string {
let mod = index % REF_START_CHARS_LEN;

@@ -10,0 +10,0 @@ let ref = REF_START_CHARS[mod];

/* eslint-disable no-await-in-loop */
import { Feature } from './compat';
import type {
SerializationContext,
Options,
} from './context';
import {
SerializationContext,
getRefParam,
Options,
createParserContext,
createSerializationContext,
getRootID,
} from './context';
import parseSync from './tree/sync';
import parseAsync from './tree/async';
import deserializeTree from './tree/deserialize';
import serializeTree, { resolvePatches } from './tree/serialize';
import parseSync from './tree/sync';
import { SerovalNode } from './tree/types';
import type { SerovalNode } from './tree/types';
import { SerovalNodeType } from './tree/types';
export {
export type {
AsyncServerValue,

@@ -31,3 +35,3 @@ ServerValue,

result: string,
) {
): string {
// Shared references detected

@@ -66,8 +70,13 @@ if (ctx.vars.length) {

options?: Partial<Options>,
) {
): string {
const ctx = createParserContext(options);
const [tree, rootID, isObject] = parseSync(ctx, source);
const tree = parseSync(ctx, source);
const serial = createSerializationContext(ctx);
const result = serializeTree(serial, tree);
return finalize(serial, rootID, isObject, result);
return finalize(
serial,
getRootID(ctx, source),
tree.t === SerovalNodeType.Object,
result,
);
}

@@ -78,8 +87,13 @@

options?: Partial<Options>,
) {
): Promise<string> {
const ctx = createParserContext(options);
const [tree, rootID, isObject] = await parseAsync(ctx, source);
const tree = await parseAsync(ctx, source);
const serial = createSerializationContext(ctx);
const result = serializeTree(serial, tree);
return finalize(serial, rootID, isObject, result);
return finalize(
serial,
getRootID(ctx, source),
tree.t === SerovalNodeType.Object,
result,
);
}

@@ -93,7 +107,6 @@

export interface SerovalJSON {
t: SerovalNode,
r: number,
i: boolean,
f: number,
m: number[],
t: SerovalNode;
r: number;
f: number;
m: number[];
}

@@ -106,7 +119,5 @@

const ctx = createParserContext(options);
const [tree, root, isObject] = parseSync(ctx, source);
return {
t: tree,
r: root,
i: isObject,
t: parseSync(ctx, source),
r: getRootID(ctx, source),
f: ctx.features,

@@ -122,7 +133,5 @@ m: Array.from(ctx.markedRefs),

const ctx = createParserContext(options);
const [tree, root, isObject] = await parseAsync(ctx, source);
return {
t: tree,
r: root,
i: isObject,
t: await parseAsync(ctx, source),
r: getRootID(ctx, source),
f: ctx.features,

@@ -139,3 +148,3 @@ m: Array.from(ctx.markedRefs),

const result = serializeTree(serial, source.t);
return finalize(serial, source.r, source.i, result);
return finalize(serial, source.r, source.t.i === SerovalNodeType.Object, result);
}

@@ -142,0 +151,0 @@

@@ -1,2 +0,2 @@

export function serializeChar(str: string) {
export function serializeChar(str: string): string | undefined {
switch (str) {

@@ -22,3 +22,3 @@ case '"': return '\\"';

// http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
export function serializeString(str: string) {
export function serializeString(str: string): string {
let result = '';

@@ -25,0 +25,0 @@ let lastPos = 0;

@@ -5,9 +5,19 @@ /* eslint-disable no-await-in-loop */

import { Feature } from '../compat';
import { createIndexedValue, getRootID, ParserContext } from '../context';
import type { ParserContext } from '../context';
import {
createIndexedValue,
} from '../context';
import { serializeString } from '../string';
import {
import type {
BigIntTypedArrayValue,
TypedArrayValue,
} from '../types';
import UnsupportedTypeError from './UnsupportedTypeError';
import {
TRUE_NODE,
FALSE_NODE,
UNDEFINED_NODE,
NULL_NODE,
} from './constants';
import {
createBigIntNode,

@@ -21,14 +31,7 @@ createBigIntTypedArrayNode,

createTypedArrayNode,
createWKSymbolNode,
FALSE_NODE,
INFINITY_NODE,
NAN_NODE,
NEG_INFINITY_NODE,
NEG_ZERO_NODE,
NULL_NODE,
TRUE_NODE,
UNDEFINED_NODE,
createReferenceNode,
createArrayBufferNode,
createDataViewNode,
createSymbolNode,
createFunctionNode,
} from './primitives';

@@ -39,19 +42,18 @@ import { hasReferenceID } from './reference';

getErrorOptions,
getIterableOptions,
isIterable,
} from './shared';
import { WellKnownSymbols } from './symbols';
import {
import type {
SerovalAggregateErrorNode,
SerovalArrayNode,
SerovalBoxedNode,
SerovalErrorNode,
SerovalFormDataNode,
SerovalHeadersNode,
SerovalIterableNode,
SerovalMapNode,
SerovalNode,
SerovalNodeType,
SerovalNullConstructorNode,
SerovalObjectNode,
SerovalObjectRecordKey,
SerovalObjectRecordNode,
SerovalPlainRecordNode,
SerovalPromiseNode,

@@ -61,2 +63,6 @@ SerovalSetNode,

import {
SerovalNodeType,
SerovalObjectRecordSpecialKey,
} from './types';
import {
createBlobNode,

@@ -71,14 +77,8 @@ createFileNode,

| SerovalNullConstructorNode
| SerovalIterableNode
| SerovalPromiseNode;
type ObjectLikeValue =
| Record<string, unknown>
| Iterable<unknown>
| PromiseLike<unknown>;
async function generateNodeList(
ctx: ParserContext,
current: unknown[],
) {
): Promise<SerovalNode[]> {
const size = current.length;

@@ -94,3 +94,3 @@ const nodes = new Array<SerovalNode>(size);

} else {
nodes[i] = await parse(ctx, item);
nodes[i] = await parseAsync(ctx, item);
}

@@ -101,3 +101,3 @@ }

if (i in deferred) {
nodes[i] = await parse(ctx, deferred[i]);
nodes[i] = await parseAsync(ctx, deferred[i]);
}

@@ -132,3 +132,3 @@ }

): Promise<SerovalMapNode> {
assert(ctx.features & Feature.Map, 'Unsupported type "Map"');
assert(ctx.features & Feature.Map, new UnsupportedTypeError(current));
const len = current.size;

@@ -148,4 +148,4 @@ const keyNodes = new Array<SerovalNode>(len);

} else {
keyNodes[nodeSize] = await parse(ctx, key);
valueNodes[nodeSize] = await parse(ctx, value);
keyNodes[nodeSize] = await parseAsync(ctx, key);
valueNodes[nodeSize] = await parseAsync(ctx, value);
nodeSize++;

@@ -155,4 +155,4 @@ }

for (let i = 0; i < deferredSize; i++) {
keyNodes[nodeSize + i] = await parse(ctx, deferredKey[i]);
valueNodes[nodeSize + i] = await parse(ctx, deferredValue[i]);
keyNodes[nodeSize + i] = await parseAsync(ctx, deferredKey[i]);
valueNodes[nodeSize + i] = await parseAsync(ctx, deferredValue[i]);
}

@@ -178,3 +178,3 @@ return {

): Promise<SerovalSetNode> {
assert(ctx.features & Feature.Set, 'Unsupported type "Set"');
assert(ctx.features & Feature.Set, new UnsupportedTypeError(current));
const len = current.size;

@@ -190,3 +190,3 @@ const nodes = new Array<SerovalNode>(len);

} else {
nodes[nodeSize++] = await parse(ctx, item);
nodes[nodeSize++] = await parseAsync(ctx, item);
}

@@ -196,3 +196,3 @@ }

for (let i = 0; i < deferredSize; i++) {
nodes[nodeSize + i] = await parse(ctx, deferred[i]);
nodes[nodeSize + i] = await parseAsync(ctx, deferred[i]);
}

@@ -218,6 +218,6 @@ return {

const keys = Object.keys(properties);
const size = keys.length;
const keyNodes = new Array<string>(size);
let size = keys.length;
const keyNodes = new Array<SerovalObjectRecordKey>(size);
const valueNodes = new Array<SerovalNode>(size);
const deferredKeys = new Array<string>(size);
const deferredKeys = new Array<SerovalObjectRecordKey>(size);
const deferredValues = new Array<unknown>(size);

@@ -227,3 +227,3 @@ let deferredSize = 0;

let item: unknown;
let escaped: string;
let escaped: SerovalObjectRecordKey;
for (const key of keys) {

@@ -238,3 +238,3 @@ item = properties[key];

keyNodes[nodesSize] = escaped;
valueNodes[nodesSize] = await parse(ctx, item);
valueNodes[nodesSize] = await parseAsync(ctx, item);
nodesSize++;

@@ -245,4 +245,16 @@ }

keyNodes[nodesSize + i] = deferredKeys[i];
valueNodes[nodesSize + i] = await parse(ctx, deferredValues[i]);
valueNodes[nodesSize + i] = await parseAsync(ctx, deferredValues[i]);
}
if (ctx.features & Feature.Symbol) {
if (Symbol.iterator in properties) {
keyNodes[size] = SerovalObjectRecordSpecialKey.SymbolIterator;
const items = Array.from(properties as Iterable<unknown>);
valueNodes[size] = await generateArrayNode(
ctx,
createIndexedValue(ctx, items),
items,
);
size++;
}
}
return {

@@ -255,24 +267,37 @@ k: keyNodes,

async function generateIterableNode(
async function generatePlainProperties(
ctx: ParserContext,
id: number,
current: Iterable<unknown>,
): Promise<SerovalIterableNode> {
assert(ctx.features & Feature.Symbol, 'Unsupported type "Iterable"');
const options = getIterableOptions(current);
const array = Array.from(current);
properties: Record<string, unknown>,
): Promise<SerovalPlainRecordNode> {
const keys = Object.keys(properties);
const size = keys.length;
const keyNodes = new Array<string>(size);
const valueNodes = new Array<SerovalNode>(size);
const deferredKeys = new Array<string>(size);
const deferredValues = new Array<unknown>(size);
let deferredSize = 0;
let nodesSize = 0;
let item: unknown;
let escaped: string;
for (const key of keys) {
item = properties[key];
escaped = serializeString(key);
if (isIterable(item)) {
deferredKeys[deferredSize] = escaped;
deferredValues[deferredSize] = item;
deferredSize++;
} else {
keyNodes[nodesSize] = escaped;
valueNodes[nodesSize] = await parseAsync(ctx, item);
nodesSize++;
}
}
for (let i = 0; i < deferredSize; i++) {
keyNodes[nodesSize + i] = deferredKeys[i];
valueNodes[nodesSize + i] = await parseAsync(ctx, deferredValues[i]);
}
return {
t: SerovalNodeType.Iterable,
i: id,
s: undefined,
l: array.length,
c: undefined,
m: undefined,
// Parse options first before the items
d: options
? await generateProperties(ctx, options)
: undefined,
a: await generateNodeList(ctx, array),
f: undefined,
b: undefined,
k: keyNodes,
v: valueNodes,
s: size,
};

@@ -284,6 +309,6 @@ }

id: number,
current: PromiseLike<unknown>,
current: Promise<unknown>,
): Promise<SerovalPromiseNode> {
assert(ctx.features & Feature.Promise, 'Unsupported type "Promise"');
return current.then(async (value) => ({
assert(ctx.features & Feature.Promise, new UnsupportedTypeError(current));
return {
t: SerovalNodeType.Promise,

@@ -298,5 +323,5 @@ i: id,

a: undefined,
f: await parse(ctx, value),
f: await parseAsync(ctx, await current),
b: undefined,
}));
};
}

@@ -307,11 +332,5 @@

id: number,
current: ObjectLikeValue,
current: Record<string, unknown>,
empty: boolean,
): Promise<ObjectLikeNode> {
if (Symbol.iterator in current) {
return generateIterableNode(ctx, id, current);
}
if ('then' in current && typeof current.then === 'function') {
return generatePromiseNode(ctx, id, current as PromiseLike<unknown>);
}
return {

@@ -324,3 +343,3 @@ t: empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,

m: undefined,
d: await generateProperties(ctx, current as Record<string, unknown>),
d: await generateProperties(ctx, current),
a: undefined,

@@ -383,3 +402,3 @@ f: undefined,

): Promise<SerovalHeadersNode> {
assert(ctx.features & Feature.WebAPI, 'Unsupported type "Headers"');
assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
const items: Record<string, string> = {};

@@ -396,3 +415,3 @@ current.forEach((value, key) => {

m: undefined,
d: await generateProperties(ctx, items),
d: await generatePlainProperties(ctx, items),
a: undefined,

@@ -409,3 +428,3 @@ f: undefined,

): Promise<SerovalFormDataNode> {
assert(ctx.features & Feature.WebAPI, 'Unsupported type "FormData"');
assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
const items: Record<string, FormDataEntryValue> = {};

@@ -422,3 +441,3 @@ current.forEach((value, key) => {

m: undefined,
d: await generateProperties(ctx, items),
d: await generatePlainProperties(ctx, items),
a: undefined,

@@ -430,4 +449,146 @@ f: undefined,

async function parse<T>(
async function generateBoxedNode(
ctx: ParserContext,
id: number,
current: object,
): Promise<SerovalBoxedNode> {
return {
t: SerovalNodeType.Boxed,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
f: await parseAsync(ctx, current.valueOf()),
b: undefined,
};
}
async function parseObject(
ctx: ParserContext,
current: object | null,
): Promise<SerovalNode> {
if (!current) {
return NULL_NODE;
}
// Non-primitive values needs a reference ID
// mostly because the values themselves are stateful
const id = createIndexedValue(ctx, current);
if (ctx.markedRefs.has(id)) {
return createIndexedValueNode(id);
}
if (hasReferenceID(current)) {
return createReferenceNode(id, current);
}
if (Array.isArray(current)) {
return generateArrayNode(ctx, id, current);
}
switch (current.constructor) {
case Number:
case Boolean:
case String:
case BigInt:
case Function:
case Symbol:
return generateBoxedNode(ctx, id, current);
case Date:
return createDateNode(id, current as unknown as Date);
case RegExp:
return createRegExpNode(id, current as unknown as RegExp);
case Promise:
return generatePromiseNode(ctx, id, current as unknown as Promise<unknown>);
case ArrayBuffer:
return createArrayBufferNode(id, current as unknown as ArrayBuffer);
case Int8Array:
case Int16Array:
case Int32Array:
case Uint8Array:
case Uint16Array:
case Uint32Array:
case Uint8ClampedArray:
case Float32Array:
case Float64Array:
return createTypedArrayNode(ctx, id, current as unknown as TypedArrayValue);
case BigInt64Array:
case BigUint64Array:
return createBigIntTypedArrayNode(ctx, id, current as unknown as BigIntTypedArrayValue);
case DataView:
return createDataViewNode(ctx, id, current as unknown as DataView);
case Map:
return generateMapNode(
ctx,
id,
current as unknown as Map<unknown, unknown>,
);
case Set:
return generateSetNode(
ctx,
id,
current as unknown as Set<unknown>,
);
case Object:
return generateObjectNode(
ctx,
id,
current as Record<string, unknown>,
false,
);
case undefined:
return generateObjectNode(
ctx,
id,
current as Record<string, unknown>,
true,
);
case AggregateError:
if (ctx.features & Feature.AggregateError) {
return generateAggregateErrorNode(ctx, id, current as unknown as AggregateError);
}
return generateErrorNode(ctx, id, current as unknown as AggregateError);
case Error:
case EvalError:
case RangeError:
case ReferenceError:
case SyntaxError:
case TypeError:
case URIError:
return generateErrorNode(ctx, id, current as unknown as Error);
case URL:
return createURLNode(ctx, id, current as unknown as URL);
case URLSearchParams:
return createURLSearchParamsNode(ctx, id, current as unknown as URLSearchParams);
case Blob:
return createBlobNode(ctx, id, current as unknown as Blob);
case File:
return createFileNode(ctx, id, current as unknown as File);
case Headers:
return generateHeadersNode(ctx, id, current as unknown as Headers);
case FormData:
return generateFormDataNode(ctx, id, current as unknown as FormData);
default:
break;
}
if (current instanceof AggregateError) {
if (ctx.features & Feature.AggregateError) {
return generateAggregateErrorNode(ctx, id, current);
}
return generateErrorNode(ctx, id, current);
}
if (current instanceof Error) {
return generateErrorNode(ctx, id, current);
}
if (current instanceof Promise) {
return generatePromiseNode(ctx, id, current);
}
// Generator functions don't have a global constructor
if (Symbol.iterator in current) {
return generateObjectNode(ctx, id, current, !!current.constructor);
}
throw new UnsupportedTypeError(current);
}
export default async function parseAsync<T>(
ctx: ParserContext,
current: T,

@@ -443,163 +604,14 @@ ): Promise<SerovalNode> {

case 'number':
switch (current) {
case Infinity: return INFINITY_NODE;
case -Infinity: return NEG_INFINITY_NODE;
default:
// eslint-disable-next-line no-self-compare
if (current !== current) {
return NAN_NODE;
}
if (Object.is(current, -0)) {
return NEG_ZERO_NODE;
}
return createNumberNode(current);
}
return createNumberNode(current);
case 'bigint':
return createBigIntNode(ctx, current);
case 'object': {
if (!current) {
return NULL_NODE;
}
// Non-primitive values needs a reference ID
// mostly because the values themselves are stateful
const id = createIndexedValue(ctx, current);
if (ctx.markedRefs.has(id)) {
return createIndexedValueNode(id);
}
if (hasReferenceID(current)) {
return createReferenceNode(id, current);
}
if (Array.isArray(current)) {
return generateArrayNode(ctx, id, current);
}
switch (current.constructor) {
case Date:
return createDateNode(id, current as unknown as Date);
case RegExp:
return createRegExpNode(id, current as unknown as RegExp);
case Promise:
return generatePromiseNode(ctx, id, current as unknown as Promise<unknown>);
case ArrayBuffer:
return createArrayBufferNode(id, current as unknown as ArrayBuffer);
case Int8Array:
case Int16Array:
case Int32Array:
case Uint8Array:
case Uint16Array:
case Uint32Array:
case Uint8ClampedArray:
case Float32Array:
case Float64Array:
return createTypedArrayNode(ctx, id, current as unknown as TypedArrayValue);
case BigInt64Array:
case BigUint64Array:
return createBigIntTypedArrayNode(ctx, id, current as unknown as BigIntTypedArrayValue);
case DataView:
return createDataViewNode(ctx, id, current as unknown as DataView);
case Map:
return generateMapNode(
ctx,
id,
current as unknown as Map<unknown, unknown>,
);
case Set:
return generateSetNode(
ctx,
id,
current as unknown as Set<unknown>,
);
case Object:
return generateObjectNode(
ctx,
id,
current as Record<string, unknown>,
false,
);
case undefined:
return generateObjectNode(
ctx,
id,
current as Record<string, unknown>,
true,
);
case AggregateError:
if (ctx.features & Feature.AggregateError) {
return generateAggregateErrorNode(ctx, id, current as unknown as AggregateError);
}
return generateErrorNode(ctx, id, current as unknown as AggregateError);
case Error:
case EvalError:
case RangeError:
case ReferenceError:
case SyntaxError:
case TypeError:
case URIError:
return generateErrorNode(ctx, id, current as unknown as Error);
case URL:
return createURLNode(ctx, id, current as unknown as URL);
case URLSearchParams:
return createURLSearchParamsNode(ctx, id, current as unknown as URLSearchParams);
case Blob:
return createBlobNode(ctx, id, current as unknown as Blob);
case File:
return createFileNode(ctx, id, current as unknown as File);
case Headers:
return generateHeadersNode(ctx, id, current as unknown as Headers);
case FormData:
return generateFormDataNode(ctx, id, current as unknown as FormData);
default:
break;
}
if (current instanceof AggregateError) {
if (ctx.features & Feature.AggregateError) {
return generateAggregateErrorNode(ctx, id, current);
}
return generateErrorNode(ctx, id, current);
}
if (current instanceof Error) {
return generateErrorNode(ctx, id, current);
}
if (current instanceof Promise) {
return generatePromiseNode(ctx, id, current);
}
// Generator functions don't have a global constructor
if (Symbol.iterator in current) {
return generateIterableNode(ctx, id, current as Iterable<unknown>);
}
// For Promise-like objects
if ('then' in current && typeof current.then === 'function') {
return generatePromiseNode(ctx, id, current as PromiseLike<unknown>);
}
throw new Error('Unsupported type');
}
case 'object':
return parseObject(ctx, current);
case 'symbol':
if (hasReferenceID(current)) {
const id = createIndexedValue(ctx, current);
if (ctx.markedRefs.has(id)) {
return createIndexedValueNode(id);
}
return createReferenceNode(id, current);
}
return createWKSymbolNode(ctx, current as WellKnownSymbols);
case 'function': {
assert(hasReferenceID(current), 'Cannot serialize function without reference ID.');
const id = createIndexedValue(ctx, current);
if (ctx.markedRefs.has(id)) {
return createIndexedValueNode(id);
}
return createReferenceNode(id, current);
}
return createSymbolNode(ctx, current);
case 'function':
return createFunctionNode(ctx, current);
default:
throw new Error('Unsupported type');
throw new UnsupportedTypeError(current);
}
}
export default async function parseAsync<T>(
ctx: ParserContext,
current: T,
) {
const result = await parse(ctx, current);
const isObject = result.t === SerovalNodeType.Object
|| result.t === SerovalNodeType.Iterable;
return [result, getRootID(ctx, current), isObject] as const;
}
/* eslint-disable prefer-spread */
/* eslint-disable @typescript-eslint/no-use-before-define */
import {
import type {
SerializationContext,
} from '../context';
import { deserializeString } from '../string';
import type { BigIntTypedArrayValue, TypedArrayValue } from '../types';
import { deserializeConstant } from './constants';
import { getReference } from './reference';
import { getErrorConstructor, getTypedArrayConstructor } from './shared';
import { SYMBOL_REF } from './symbols';
import {
import type {
SerovalAggregateErrorNode,

@@ -16,2 +18,3 @@ SerovalArrayBufferNode,

SerovalBlobNode,
SerovalBoxedNode,
SerovalDataViewNode,

@@ -23,8 +26,7 @@ SerovalDateNode,

SerovalHeadersNode,
SerovalIterableNode,
SerovalMapNode,
SerovalNode,
SerovalNodeType,
SerovalNullConstructorNode,
SerovalObjectNode,
SerovalObjectRecordKey,
SerovalObjectRecordNode,

@@ -39,2 +41,6 @@ SerovalPromiseNode,

} from './types';
import {
SerovalNodeType,
SerovalObjectRecordSpecialKey,
} from './types';

@@ -45,3 +51,3 @@ function assignIndexedValue<T>(

value: T,
) {
): T {
if (ctx.markedRefs.has(index)) {

@@ -56,10 +62,11 @@ ctx.valueMap.set(index, value);

node: SerovalArrayNode,
) {
): unknown[] {
const len = node.l;
const result: unknown[] = assignIndexedValue(
ctx,
node.i,
new Array<unknown>(node.l),
new Array<unknown>(len),
);
let item: SerovalNode;
for (let i = 0, len = node.l; i < len; i++) {
let item: SerovalNode | undefined;
for (let i = 0; i < len; i++) {
item = node.a[i];

@@ -76,21 +83,38 @@ if (item) {

node: SerovalObjectRecordNode,
result: Record<string, unknown>,
) {
if (node.s === 0) {
return {};
result: Record<string | symbol, unknown>,
): Record<string | symbol, unknown> {
const len = node.s;
if (len) {
let key: SerovalObjectRecordKey;
let value: unknown;
const keys = node.k;
const vals = node.v;
for (let i = 0; i < len; i++) {
key = keys[i];
value = deserializeTree(ctx, vals[i]);
switch (key) {
case SerovalObjectRecordSpecialKey.SymbolIterator: {
const current = value as unknown[];
result[Symbol.iterator] = (): IterableIterator<unknown> => current.values();
}
break;
default:
result[deserializeString(key)] = value;
break;
}
}
}
for (let i = 0; i < node.s; i++) {
result[deserializeString(node.k[i])] = deserializeTree(ctx, node.v[i]);
}
return result;
}
function deserializeNullConstructor(
function deserializeObject(
ctx: SerializationContext,
node: SerovalNullConstructorNode,
) {
node: SerovalObjectNode | SerovalNullConstructorNode,
): Record<string, unknown> {
const result = assignIndexedValue(
ctx,
node.i,
Object.create(null) as Record<string, unknown>,
(node.t === SerovalNodeType.Object
? {}
: Object.create(null)) as Record<string, unknown>,
);

@@ -101,18 +125,10 @@ deserializeProperties(ctx, node.d, result);

function deserializeObject(
ctx: SerializationContext,
node: SerovalObjectNode,
) {
const result = assignIndexedValue(ctx, node.i, {} as Record<string, unknown>);
deserializeProperties(ctx, node.d, result);
return result;
}
function deserializeSet(
ctx: SerializationContext,
node: SerovalSetNode,
) {
): Set<unknown> {
const result = assignIndexedValue(ctx, node.i, new Set<unknown>());
const items = node.a;
for (let i = 0, len = node.l; i < len; i++) {
result.add(deserializeTree(ctx, node.a[i]));
result.add(deserializeTree(ctx, items[i]));
}

@@ -125,3 +141,3 @@ return result;

node: SerovalMapNode,
) {
): Map<unknown, unknown> {
const result = assignIndexedValue(

@@ -132,6 +148,8 @@ ctx,

);
const keys = node.d.k;
const vals = node.d.v;
for (let i = 0, len = node.d.s; i < len; i++) {
result.set(
deserializeTree(ctx, node.d.k[i]),
deserializeTree(ctx, node.d.v[i]),
deserializeTree(ctx, keys[i]),
deserializeTree(ctx, vals[i]),
);

@@ -143,3 +161,3 @@ }

type AssignableValue = AggregateError | Error | Iterable<unknown>
type AssignableNode = SerovalAggregateErrorNode | SerovalErrorNode | SerovalIterableNode;
type AssignableNode = SerovalAggregateErrorNode | SerovalErrorNode;

@@ -150,3 +168,3 @@ function deserializeDictionary<T extends AssignableValue>(

result: T,
) {
): T {
if (node.d) {

@@ -162,3 +180,3 @@ const fields = deserializeProperties(ctx, node.d, {});

node: SerovalAggregateErrorNode,
) {
): AggregateError {
// Serialize the required arguments

@@ -179,3 +197,3 @@ const result = assignIndexedValue(

node: SerovalErrorNode,
) {
): Error {
const ErrorConstructor = getErrorConstructor(node.c);

@@ -194,3 +212,3 @@ const result = assignIndexedValue(ctx, node.i, new ErrorConstructor(deserializeString(node.m)));

return {
resolve(v) {
resolve(v): void {
resolver(v);

@@ -204,6 +222,6 @@ },

function deserializePromise(
async function deserializePromise(
ctx: SerializationContext,
node: SerovalPromiseNode,
) {
): Promise<unknown> {
const deferred = createDeferred();

@@ -218,3 +236,3 @@ const result = assignIndexedValue(ctx, node.i, deferred.promise);

node: SerovalArrayBufferNode,
) {
): ArrayBuffer {
const bytes = new Uint8Array(node.s);

@@ -228,3 +246,3 @@ const result = assignIndexedValue(ctx, node.i, bytes.buffer);

node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
) {
): TypedArrayValue | BigIntTypedArrayValue {
const TypedArray = getTypedArrayConstructor(node.c);

@@ -240,24 +258,6 @@ const source = deserializeTree(ctx, node.f) as ArrayBuffer;

function deserializeIterable(
ctx: SerializationContext,
node: SerovalIterableNode,
) {
const values: unknown[] = [];
let item: SerovalNode;
for (let i = 0, len = node.l; i < len; i++) {
item = node.a[i];
if (item) {
values[i] = deserializeTree(ctx, item);
}
}
const result: Iterable<unknown> = assignIndexedValue(ctx, node.i, {
[Symbol.iterator]: () => values.values(),
});
return deserializeDictionary(ctx, node, result);
}
function deserializeDate(
ctx: SerializationContext,
node: SerovalDateNode,
) {
): Date {
return assignIndexedValue(ctx, node.i, new Date(node.s));

@@ -269,3 +269,3 @@ }

node: SerovalRegExpNode,
) {
): RegExp {
return assignIndexedValue(ctx, node.i, new RegExp(node.c, node.m));

@@ -277,3 +277,3 @@ }

node: SerovalURLNode,
) {
): URL {
return assignIndexedValue(ctx, node.i, new URL(deserializeString(node.s)));

@@ -285,3 +285,3 @@ }

node: SerovalURLSearchParamsNode,
) {
): URLSearchParams {
return assignIndexedValue(ctx, node.i, new URLSearchParams(deserializeString(node.s)));

@@ -293,3 +293,3 @@ }

node: SerovalReferenceNode,
) {
): unknown {
return assignIndexedValue(ctx, node.i, getReference(deserializeString(node.s)));

@@ -301,3 +301,3 @@ }

node: SerovalDataViewNode,
) {
): DataView {
const source = deserializeTree(ctx, node.f) as ArrayBuffer;

@@ -315,3 +315,3 @@ const result = assignIndexedValue(ctx, node.i, new DataView(

node: SerovalBlobNode,
) {
): Blob {
const source = deserializeTree(ctx, node.f) as ArrayBuffer;

@@ -328,3 +328,3 @@ const result = assignIndexedValue(ctx, node.i, new Blob(

node: SerovalFileNode,
) {
): File {
const source = deserializeTree(ctx, node.f) as ArrayBuffer;

@@ -342,8 +342,10 @@ const result = assignIndexedValue(ctx, node.i, new File(

node: SerovalHeadersNode,
) {
): Headers {
const result = assignIndexedValue(ctx, node.i, new Headers());
const keys = node.d.k;
const vals = node.d.v;
for (let i = 0, len = node.d.s; i < len; i++) {
result.set(
deserializeString(node.d.k[i]),
deserializeTree(ctx, node.d.v[i]) as string,
deserializeString(keys[i]),
deserializeTree(ctx, vals[i]) as string,
);

@@ -357,8 +359,10 @@ }

node: SerovalFormDataNode,
) {
): FormData {
const result = assignIndexedValue(ctx, node.i, new FormData());
const keys = node.d.k;
const vals = node.d.v;
for (let i = 0, len = node.d.s; i < len; i++) {
result.set(
deserializeString(node.d.k[i]),
deserializeTree(ctx, node.d.v[i]) as FormDataEntryValue,
deserializeString(keys[i]),
deserializeTree(ctx, vals[i]) as FormDataEntryValue,
);

@@ -369,2 +373,13 @@ }

function deserializeBoxed(
ctx: SerializationContext,
node: SerovalBoxedNode,
): unknown {
return assignIndexedValue(
ctx,
node.i,
Object(deserializeTree(ctx, node.f)),
);
}
export default function deserializeTree(

@@ -375,19 +390,8 @@ ctx: SerializationContext,

switch (node.t) {
case SerovalNodeType.Constant:
return deserializeConstant(node);
case SerovalNodeType.Number:
case SerovalNodeType.Boolean:
return node.s;
case SerovalNodeType.String:
return deserializeString(node.s);
case SerovalNodeType.Undefined:
return undefined;
case SerovalNodeType.Null:
return null;
case SerovalNodeType.NegativeZero:
return -0;
case SerovalNodeType.Infinity:
return Infinity;
case SerovalNodeType.NegativeInfinity:
return -Infinity;
case SerovalNodeType.NaN:
return NaN;
case SerovalNodeType.BigInt:

@@ -400,5 +404,4 @@ return BigInt(node.s);

case SerovalNodeType.Object:
case SerovalNodeType.NullConstructor:
return deserializeObject(ctx, node);
case SerovalNodeType.NullConstructor:
return deserializeNullConstructor(ctx, node);
case SerovalNodeType.Date:

@@ -423,4 +426,2 @@ return deserializeDate(ctx, node);

return deserializeError(ctx, node);
case SerovalNodeType.Iterable:
return deserializeIterable(ctx, node);
case SerovalNodeType.Promise:

@@ -444,5 +445,7 @@ return deserializePromise(ctx, node);

return deserializeFormData(ctx, node);
case SerovalNodeType.Boxed:
return deserializeBoxed(ctx, node);
default:
throw new Error('Unsupported type');
throw new Error('invariant');
}
}
import assert from '../assert';
import { Feature } from '../compat';
import { ParserContext, createIndexedValue } from '../context';
import type { ParserContext } from '../context';
import { createIndexedValue } from '../context';
import { serializeString } from '../string';
import { BigIntTypedArrayValue, TypedArrayValue } from '../types';
import { getReferenceID } from './reference';
import { INV_SYMBOL_REF, WellKnownSymbols } from './symbols';
import type { BigIntTypedArrayValue, TypedArrayValue } from '../types';
import UnsupportedTypeError from './UnsupportedTypeError';
import {
INFINITY_NODE,
NEG_INFINITY_NODE,
NAN_NODE,
NEG_ZERO_NODE,
} from './constants';
import { getReferenceID, hasReferenceID } from './reference';
import type { WellKnownSymbols } from './symbols';
import { INV_SYMBOL_REF } from './symbols';
import type {
SerovalBigIntNode,
SerovalBigIntTypedArrayNode,
SerovalBooleanNode,
SerovalDateNode,
SerovalInfinityNode,
SerovalNaNNode,
SerovalNegativeInfinityNode,
SerovalNegativeZeroNode,
SerovalNodeType,
SerovalNullNode,
SerovalNumberNode,
SerovalIndexedValueNode,

@@ -24,3 +25,2 @@ SerovalRegExpNode,

SerovalTypedArrayNode,
SerovalUndefinedNode,
SerovalWKSymbolNode,

@@ -30,114 +30,35 @@ SerovalReferenceNode,

SerovalDataViewNode,
SerovalNode,
} from './types';
import {
SerovalNodeType,
} from './types';
export const TRUE_NODE: SerovalBooleanNode = {
t: SerovalNodeType.Boolean,
i: undefined,
s: true,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
f: undefined,
b: undefined,
};
export const FALSE_NODE: SerovalBooleanNode = {
t: SerovalNodeType.Boolean,
i: undefined,
s: false,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
f: undefined,
b: undefined,
};
export const UNDEFINED_NODE: SerovalUndefinedNode = {
t: SerovalNodeType.Undefined,
i: undefined,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
f: undefined,
b: undefined,
};
export const NULL_NODE: SerovalNullNode = {
t: SerovalNodeType.Null,
i: undefined,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
f: undefined,
b: undefined,
};
export const NEG_ZERO_NODE: SerovalNegativeZeroNode = {
t: SerovalNodeType.NegativeZero,
i: undefined,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
f: undefined,
b: undefined,
};
export const INFINITY_NODE: SerovalInfinityNode = {
t: SerovalNodeType.Infinity,
i: undefined,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
f: undefined,
b: undefined,
};
export const NEG_INFINITY_NODE: SerovalNegativeInfinityNode = {
t: SerovalNodeType.NegativeInfinity,
i: undefined,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
f: undefined,
b: undefined,
};
export const NAN_NODE: SerovalNaNNode = {
t: SerovalNodeType.NaN,
i: undefined,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
f: undefined,
b: undefined,
};
export function createNumberNode(value: number): SerovalNumberNode {
return {
t: SerovalNodeType.Number,
i: undefined,
s: value,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
f: undefined,
b: undefined,
};
export function createNumberNode(value: number): SerovalNode {
switch (value) {
case Infinity:
return INFINITY_NODE;
case -Infinity:
return NEG_INFINITY_NODE;
default:
// eslint-disable-next-line no-self-compare
if (value !== value) {
return NAN_NODE;
}
if (Object.is(value, -0)) {
return NEG_ZERO_NODE;
}
return {
t: SerovalNodeType.Number,
i: undefined,
s: value,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
f: undefined,
b: undefined,
};
}
}

@@ -164,3 +85,3 @@

): SerovalBigIntNode {
assert(ctx.features & Feature.BigInt, 'Unsupported type "BigInt"');
assert(ctx.features & Feature.BigInt, new UnsupportedTypeError(current));
return {

@@ -252,3 +173,3 @@ t: SerovalNodeType.BigInt,

current: ArrayBuffer,
) {
): SerovalNode {
const id = createIndexedValue(ctx, current);

@@ -266,4 +187,3 @@ if (ctx.markedRefs.has(id)) {

): SerovalTypedArrayNode {
const constructor = current.constructor.name;
assert(ctx.features & Feature.TypedArray, `Unsupported value type "${constructor}"`);
assert(ctx.features & Feature.TypedArray, new UnsupportedTypeError(current));
return {

@@ -274,3 +194,3 @@ t: SerovalNodeType.TypedArray,

l: current.length,
c: constructor,
c: current.constructor.name,
m: undefined,

@@ -291,6 +211,5 @@ d: undefined,

): SerovalBigIntTypedArrayNode {
const constructor = current.constructor.name;
assert(
(ctx.features & BIGINT_FLAG) === BIGINT_FLAG,
`Unsupported value type "${constructor}"`,
new UnsupportedTypeError(current),
);

@@ -302,3 +221,3 @@ return {

l: current.length,
c: constructor,
c: current.constructor.name,
m: undefined,

@@ -314,9 +233,10 @@ d: undefined,

ctx: ParserContext,
id: number,
current: WellKnownSymbols,
): SerovalWKSymbolNode {
assert(ctx.features & Feature.Symbol, 'Unsupported type "symbol"');
assert(current in INV_SYMBOL_REF, 'seroval only supports well-known symbols');
assert(ctx.features & Feature.Symbol, new UnsupportedTypeError(current));
assert(current in INV_SYMBOL_REF, new Error('Only well-known symbols are supported.'));
return {
t: SerovalNodeType.WKSymbol,
i: undefined,
i: id,
s: INV_SYMBOL_REF[current],

@@ -369,1 +289,28 @@ l: undefined,

}
export function createSymbolNode(
ctx: ParserContext,
current: symbol,
): SerovalNode {
const id = createIndexedValue(ctx, current);
if (ctx.markedRefs.has(id)) {
return createIndexedValueNode(id);
}
if (hasReferenceID(current)) {
return createReferenceNode(id, current);
}
return createWKSymbolNode(ctx, id, current as WellKnownSymbols);
}
export function createFunctionNode(
ctx: ParserContext,
// eslint-disable-next-line @typescript-eslint/ban-types
current: Function,
): SerovalNode {
assert(hasReferenceID(current), new Error('Cannot serialize function without reference ID.'));
const id = createIndexedValue(ctx, current);
if (ctx.markedRefs.has(id)) {
return createIndexedValueNode(id);
}
return createReferenceNode(id, current);
}

@@ -0,1 +1,2 @@

/* eslint-disable @typescript-eslint/no-unnecessary-condition */
/* eslint-disable no-restricted-globals */

@@ -22,8 +23,8 @@ import assert from '../assert';

export function getReferenceID<T>(value: T): string {
assert(hasReferenceID(value), 'Missing reference id');
return REFERENCE.get(value) as string;
assert(hasReferenceID(value), new Error('Missing reference id'));
return REFERENCE.get(value)!;
}
export function getReference<T>(id: string): T {
assert(hasReference(id), 'Missing reference for id:' + id);
assert(hasReference(id), new Error('Missing reference for id:' + id));
return INV_REFERENCE.get(id) as T;

@@ -30,0 +31,0 @@ }

/* eslint-disable @typescript-eslint/no-use-before-define */
import { Feature } from '../compat';
import {
import type {
SerializationContext,
Assignment,
} from '../context';
import {
getRefParam,
markRef,
} from '../context';
import { serializeConstant } from './constants';
import { GLOBAL_KEY } from './reference';
import { isValidIdentifier } from './shared';
import { SYMBOL_STRING } from './symbols';
import {
import type {
SerovalAggregateErrorNode,

@@ -17,9 +20,6 @@ SerovalArrayNode,

SerovalErrorNode,
SerovalIterableNode,
SerovalMapNode,
SerovalNode,
SerovalNodeType,
SerovalNullConstructorNode,
SerovalObjectNode,
SerovalObjectRecordNode,
SerovalPromiseNode,

@@ -40,3 +40,11 @@ SerovalIndexedValueNode,

SerovalFormDataNode,
SerovalObjectRecordNode,
SerovalObjectRecordKey,
SerovalBoxedNode,
SerovalWKSymbolNode,
} from './types';
import {
SerovalNodeType,
SerovalObjectRecordSpecialKey,
} from './types';

@@ -58,4 +66,4 @@ function getAssignmentExpression(assignment: Assignment): string {

function mergeAssignments(assignments: Assignment[]) {
const newAssignments = [];
function mergeAssignments(assignments: Assignment[]): Assignment[] {
const newAssignments: Assignment[] = [];
let current = assignments[0];

@@ -134,3 +142,3 @@ let prev = current;

function resolveAssignments(assignments: Assignment[]) {
function resolveAssignments(assignments: Assignment[]): string | undefined {
if (assignments.length) {

@@ -147,3 +155,3 @@ let result = '';

export function resolvePatches(ctx: SerializationContext) {
export function resolvePatches(ctx: SerializationContext): string | undefined {
return resolveAssignments(ctx.assignments);

@@ -162,3 +170,3 @@ }

value: string,
) {
): void {
ctx.assignments.push({

@@ -176,3 +184,3 @@ t: 'index',

value: string,
) {
): void {
ctx.assignments.push({

@@ -191,3 +199,3 @@ t: 'add',

value: string,
) {
): void {
ctx.assignments.push({

@@ -206,3 +214,3 @@ t: 'set',

value: string,
) {
): void {
ctx.assignments.push({

@@ -221,3 +229,3 @@ t: 'append',

value: string,
) {
): void {
createAssignment(ctx, getRefParam(ctx, ref) + '[' + index + ']', value);

@@ -231,3 +239,3 @@ }

value: string,
) {
): void {
markRef(ctx, ref);

@@ -241,3 +249,3 @@ createAssignment(ctx, getRefParam(ctx, ref) + '.' + key, value);

value: string,
) {
): string {
if (ctx.markedRefs.has(index)) {

@@ -256,18 +264,16 @@ return getRefParam(ctx, index) + '=' + value;

type SerovalNodeListNode =
| SerovalArrayNode
| SerovalIterableNode;
function serializeNodeList(
function serializeArray(
ctx: SerializationContext,
node: SerovalNodeListNode,
) {
node: SerovalArrayNode,
): string {
const id = node.i;
ctx.stack.push(id);
// This is different than Map and Set
// because we also need to serialize
// the holes of the Array
const size = node.l;
let values = '';
let item: SerovalNode;
let item: SerovalNode | undefined;
let isHoley = false;
for (let i = 0; i < size; i++) {
const list = node.a;
for (let i = 0, len = node.l; i < len; i++) {
if (i !== 0) {

@@ -277,3 +283,3 @@ // Add an empty item

}
item = node.a[i];
item = list[i];
// Check if index is a hole

@@ -283,4 +289,4 @@ if (item) {

if (isIndexedValueInStack(ctx, item)) {
markRef(ctx, node.i);
createArrayAssign(ctx, node.i, i, getRefParam(ctx, item.i));
markRef(ctx, id);
createArrayAssign(ctx, id, i, getRefParam(ctx, item.i));
isHoley = true;

@@ -295,13 +301,28 @@ } else {

}
return '[' + values + (isHoley ? ',]' : ']');
ctx.stack.pop();
return assignIndexedValue(ctx, id, '[' + values + (isHoley ? ',]' : ']'));
}
function serializeArray(
function getIterableAccess(ctx: SerializationContext): string {
return ctx.features & Feature.ArrayPrototypeValues
? '.values()'
: '[Symbol.iterator]()';
}
function serializeIterable(
ctx: SerializationContext,
node: SerovalArrayNode,
) {
ctx.stack.push(node.i);
const result = serializeNodeList(ctx, node);
ctx.stack.pop();
return assignIndexedValue(ctx, node.i, result);
node: SerovalNode,
): string {
const parent = ctx.stack;
ctx.stack = [];
let serialized = serializeTree(ctx, node) + getIterableAccess(ctx);
ctx.stack = parent;
if (ctx.features & Feature.ArrowFunction) {
serialized = '[Symbol.iterator]:()=>' + serialized;
} else if (ctx.features & Feature.MethodShorthand) {
serialized = '[Symbol.iterator](){return ' + serialized + '}';
} else {
serialized = '[Symbol.iterator]:function(){return ' + serialized + '}';
}
return serialized;
}

@@ -313,4 +334,5 @@

node: SerovalObjectRecordNode,
) {
if (node.s === 0) {
): string {
const len = node.s;
if (len === 0) {
return '{}';

@@ -320,3 +342,3 @@ }

ctx.stack.push(sourceID);
let key: string;
let key: SerovalObjectRecordKey;
let val: SerovalNode;

@@ -329,23 +351,30 @@ let check: number;

const values = node.v;
for (let i = 0, len = node.s; i < len; i++) {
for (let i = 0; i < len; i++) {
key = keys[i];
val = values[i];
check = Number(key);
// Test if key is a valid number or JS identifier
// so that we don't have to serialize the key and wrap with brackets
isIdentifier = check >= 0 || isValidIdentifier(key);
if (isIndexedValueInStack(ctx, val)) {
refParam = getRefParam(ctx, val.i);
if (isIdentifier && Number.isNaN(check)) {
markRef(ctx, sourceID);
createObjectAssign(ctx, sourceID, key, refParam);
} else {
markRef(ctx, sourceID);
createArrayAssign(ctx, sourceID, isIdentifier ? key : ('"' + key + '"'), refParam);
}
} else {
result += (hasPrev ? ',' : '')
+ (isIdentifier ? key : ('"' + key + '"'))
+ ':' + serializeTree(ctx, val);
hasPrev = true;
switch (key) {
case SerovalObjectRecordSpecialKey.SymbolIterator:
result += (hasPrev ? ',' : '') + serializeIterable(ctx, val);
hasPrev = true;
break;
default:
check = Number(key);
// Test if key is a valid number or JS identifier
// so that we don't have to serialize the key and wrap with brackets
isIdentifier = check >= 0 || isValidIdentifier(key);
if (isIndexedValueInStack(ctx, val)) {
refParam = getRefParam(ctx, val.i);
markRef(ctx, sourceID);
if (isIdentifier && Number.isNaN(check)) {
createObjectAssign(ctx, sourceID, key, refParam);
} else {
createArrayAssign(ctx, sourceID, isIdentifier ? key : ('"' + key + '"'), refParam);
}
} else {
result += (hasPrev ? ',' : '')
+ (isIdentifier ? key : ('"' + key + '"'))
+ ':' + serializeTree(ctx, val);
hasPrev = true;
}
break;
}

@@ -362,3 +391,3 @@ }

serialized: string,
) {
): string {
const fields = serializeProperties(ctx, id, value);

@@ -375,29 +404,43 @@ if (fields !== '{}') {

node: SerovalObjectRecordNode,
) {
): string | undefined {
ctx.stack.push(sourceID);
const mainAssignments: Assignment[] = [];
let parentStack: number[];
let refParam: string;
let key: string;
let check: number;
let key: SerovalObjectRecordKey;
let value: SerovalNode;
let parentAssignment: Assignment[];
let isIdentifier: boolean;
const keys = node.k;
const values = node.v;
for (let i = 0, len = node.s; i < len; i++) {
parentStack = ctx.stack;
ctx.stack = [];
refParam = serializeTree(ctx, values[i]);
ctx.stack = parentStack;
key = keys[i];
check = Number(key);
value = values[i];
parentAssignment = ctx.assignments;
ctx.assignments = mainAssignments;
// Test if key is a valid number or JS identifier
// so that we don't have to serialize the key and wrap with brackets
isIdentifier = check >= 0 || isValidIdentifier(key);
if (isIdentifier && Number.isNaN(check)) {
createObjectAssign(ctx, sourceID, key, refParam);
} else {
createArrayAssign(ctx, sourceID, isIdentifier ? key : ('"' + key + '"'), refParam);
switch (key) {
case SerovalObjectRecordSpecialKey.SymbolIterator: {
const parent = ctx.stack;
ctx.stack = [];
const serialized = serializeTree(ctx, value) + getIterableAccess(ctx);
ctx.stack = parent;
createArrayAssign(
ctx,
sourceID,
'Symbol.iterator',
ctx.features & Feature.ArrowFunction
? '()=>' + serialized
: 'function(){return ' + serialized + '}',
);
}
break;
default: {
const serialized = serializeTree(ctx, value);
const check = Number(key);
// Test if key is a valid number or JS identifier
// so that we don't have to serialize the key and wrap with brackets
const isIdentifier = check >= 0 || isValidIdentifier(key);
if (isIdentifier && Number.isNaN(check)) {
createObjectAssign(ctx, sourceID, key, serialized);
} else {
createArrayAssign(ctx, sourceID, isIdentifier ? key : ('"' + key + '"'), serialized);
}
}
}

@@ -415,3 +458,3 @@ ctx.assignments = parentAssignment;

init: string,
) {
): string {
if (d) {

@@ -431,7 +474,9 @@ if (ctx.features & Feature.ObjectAssign) {

const NULL_CONSTRUCTOR = 'Object.create(null)';
function serializeNullConstructor(
ctx: SerializationContext,
node: SerovalNullConstructorNode,
) {
return serializeDictionary(ctx, node.i, node.d, 'Object.create(null)');
): string {
return serializeDictionary(ctx, node.i, node.d, NULL_CONSTRUCTOR);
}

@@ -442,3 +487,3 @@

node: SerovalObjectNode,
) {
): string {
return assignIndexedValue(ctx, node.i, serializeProperties(ctx, node.i, node.d));

@@ -450,15 +495,17 @@ }

node: SerovalSetNode,
) {
): string {
let serialized = 'new Set';
const size = node.l;
const id = node.i;
if (size) {
let result = '';
ctx.stack.push(node.i);
let item: SerovalNode;
let hasPrev = false;
const items = node.a;
ctx.stack.push(id);
for (let i = 0; i < size; i++) {
item = node.a[i];
item = items[i];
if (isIndexedValueInStack(ctx, item)) {
markRef(ctx, node.i);
createAddAssignment(ctx, node.i, getRefParam(ctx, item.i));
markRef(ctx, id);
createAddAssignment(ctx, id, getRefParam(ctx, item.i));
} else {

@@ -475,3 +522,3 @@ // Push directly

}
return assignIndexedValue(ctx, node.i, serialized);
return assignIndexedValue(ctx, id, serialized);
}

@@ -482,7 +529,8 @@

node: SerovalMapNode,
) {
): string {
let serialized = 'new Map';
if (node.d.s) {
const size = node.d.s;
const id = node.i;
if (size) {
let result = '';
ctx.stack.push(node.i);
let key: SerovalNode;

@@ -494,10 +542,13 @@ let val: SerovalNode;

let hasPrev = false;
for (let i = 0; i < node.d.s; i++) {
const keys = node.d.k;
const vals = node.d.v;
ctx.stack.push(id);
for (let i = 0; i < size; i++) {
// Check if key is a parent
key = node.d.k[i];
val = node.d.v[i];
key = keys[i];
val = vals[i];
if (isIndexedValueInStack(ctx, key)) {
// Create reference for the map instance
keyRef = getRefParam(ctx, key.i);
markRef(ctx, node.i);
keyRef = getRefParam(ctx, id);
markRef(ctx, id);
// Check if value is a parent

@@ -509,3 +560,3 @@ if (isIndexedValueInStack(ctx, val)) {

// Map instance
createSetAssignment(ctx, node.i, keyRef, valueRef);
createSetAssignment(ctx, id, keyRef, valueRef);
} else {

@@ -519,3 +570,3 @@ // Reset the stack

ctx.stack = [];
createSetAssignment(ctx, node.i, keyRef, serializeTree(ctx, val));
createSetAssignment(ctx, id, keyRef, serializeTree(ctx, val));
ctx.stack = parent;

@@ -526,7 +577,7 @@ }

valueRef = getRefParam(ctx, val.i);
markRef(ctx, node.i);
markRef(ctx, id);
// Reset stack for the key serialization
parent = ctx.stack;
ctx.stack = [];
createSetAssignment(ctx, node.i, serializeTree(ctx, key), valueRef);
createSetAssignment(ctx, id, serializeTree(ctx, key), valueRef);
ctx.stack = parent;

@@ -546,3 +597,3 @@ } else {

}
return assignIndexedValue(ctx, node.i, serialized);
return assignIndexedValue(ctx, id, serialized);
}

@@ -553,5 +604,6 @@

node: SerovalAggregateErrorNode,
) {
): string {
// Serialize the required arguments
ctx.stack.push(node.i);
const id = node.i;
ctx.stack.push(id);
const serialized = 'new AggregateError([],"' + node.m + '")';

@@ -562,3 +614,3 @@ ctx.stack.pop();

// Make sure to assign extra properties
return serializeDictionary(ctx, node.i, node.d, serialized);
return serializeDictionary(ctx, id, node.d, serialized);
}

@@ -569,5 +621,4 @@

node: SerovalErrorNode,
) {
const serialized = 'new ' + node.c + '("' + node.m + '")';
return serializeDictionary(ctx, node.i, node.d, serialized);
): string {
return serializeDictionary(ctx, node.i, node.d, 'new ' + node.c + '("' + node.m + '")');
}

@@ -578,6 +629,8 @@

node: SerovalPromiseNode,
) {
): string {
let serialized: string;
// Check if resolved value is a parent expression
if (isIndexedValueInStack(ctx, node.f)) {
const fulfilled = node.f;
const id = node.i;
if (isIndexedValueInStack(ctx, fulfilled)) {
// A Promise trick, reference the value

@@ -587,3 +640,3 @@ // inside the `then` expression so that

// has initialized
const ref = getRefParam(ctx, node.f.i);
const ref = getRefParam(ctx, fulfilled.i);
if (ctx.features & Feature.ArrowFunction) {

@@ -595,4 +648,4 @@ serialized = 'Promise.resolve().then(()=>' + ref + ')';

} else {
ctx.stack.push(node.i);
const result = serializeTree(ctx, node.f);
ctx.stack.push(id);
const result = serializeTree(ctx, fulfilled);
ctx.stack.pop();

@@ -602,3 +655,3 @@ // just inline the value/reference here

}
return assignIndexedValue(ctx, node.i, serialized);
return assignIndexedValue(ctx, id, serialized);
}

@@ -609,8 +662,10 @@

node: SerovalArrayBufferNode,
) {
): string {
let result = 'new Uint8Array(';
if (node.s.length) {
const buffer = node.s;
const len = buffer.length;
if (len) {
result += '[';
for (let i = 0, len = node.s.length; i < len; i++) {
result += ((i > 0) ? ',' : '') + node.s[i];
for (let i = 0; i < len; i++) {
result += ((i > 0) ? ',' : '') + buffer[i];
}

@@ -625,35 +680,14 @@ result += ']';

node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
) {
const args = serializeTree(ctx, node.f) + ',' + node.b + ',' + node.l;
return assignIndexedValue(ctx, node.i, 'new ' + node.c + '(' + args + ')');
): string {
return assignIndexedValue(
ctx,
node.i,
'new ' + node.c + '(' + serializeTree(ctx, node.f) + ',' + node.b + ',' + node.l + ')',
);
}
function serializeIterable(
ctx: SerializationContext,
node: SerovalIterableNode,
) {
const parent = ctx.stack;
ctx.stack = [];
const values = serializeNodeList(ctx, node);
ctx.stack = parent;
let serialized = values;
if (ctx.features & Feature.ArrayPrototypeValues) {
serialized += '.values()';
} else {
serialized += '[Symbol.iterator]()';
}
if (ctx.features & Feature.ArrowFunction) {
serialized = '{[Symbol.iterator]:()=>' + serialized + '}';
} else if (ctx.features & Feature.MethodShorthand) {
serialized = '{[Symbol.iterator](){return ' + serialized + '}}';
} else {
serialized = '{[Symbol.iterator]:function(){return ' + serialized + '}}';
}
return serializeDictionary(ctx, node.i, node.d, serialized);
}
function serializeDate(
ctx: SerializationContext,
node: SerovalDateNode,
) {
): string {
return assignIndexedValue(ctx, node.i, 'new Date("' + node.s + '")');

@@ -665,3 +699,3 @@ }

node: SerovalRegExpNode,
) {
): string {
return assignIndexedValue(ctx, node.i, '/' + node.c + '/' + node.m);

@@ -673,3 +707,3 @@ }

node: SerovalURLNode,
) {
): string {
return assignIndexedValue(ctx, node.i, 'new URL("' + node.s + '")');

@@ -681,4 +715,8 @@ }

node: SerovalURLSearchParamsNode,
) {
return assignIndexedValue(ctx, node.i, node.s ? 'new URLSearchParams("' + node.s + '")' : 'new URLSearchParams');
): string {
return assignIndexedValue(
ctx,
node.i,
node.s ? 'new URLSearchParams("' + node.s + '")' : 'new URLSearchParams',
);
}

@@ -689,3 +727,3 @@

node: SerovalReferenceNode,
) {
): string {
return assignIndexedValue(ctx, node.i, GLOBAL_KEY + '.get("' + node.s + '")');

@@ -697,5 +735,8 @@ }

node: SerovalDataViewNode,
) {
const args = serializeTree(ctx, node.f) + ',' + node.b + ',' + node.l;
return assignIndexedValue(ctx, node.i, 'new DataView(' + args + ')');
): string {
return assignIndexedValue(
ctx,
node.i,
'new DataView(' + serializeTree(ctx, node.f) + ',' + node.b + ',' + node.l + ')',
);
}

@@ -706,5 +747,8 @@

node: SerovalBlobNode,
) {
const args = '[' + serializeTree(ctx, node.f) + '],{type:"' + node.c + '"}';
return assignIndexedValue(ctx, node.i, 'new Blob(' + args + ')');
): string {
return assignIndexedValue(
ctx,
node.i,
'new Blob([' + serializeTree(ctx, node.f) + '],{type:"' + node.c + '"})',
);
}

@@ -715,6 +759,8 @@

node: SerovalFileNode,
) {
const options = '{type:"' + node.c + '",lastModified:' + node.b + '}';
const args = '[' + serializeTree(ctx, node.f) + '],"' + node.m + '",' + options;
return assignIndexedValue(ctx, node.i, 'new File(' + args + ')');
): string {
return assignIndexedValue(
ctx,
node.i,
'new File([' + serializeTree(ctx, node.f) + '],"' + node.m + '",{type:"' + node.c + '",lastModified:' + node.b + '})',
);
}

@@ -725,4 +771,8 @@

node: SerovalHeadersNode,
) {
return assignIndexedValue(ctx, node.i, 'new Headers(' + serializeProperties(ctx, node.i, node.d) + ')');
): string {
return assignIndexedValue(
ctx,
node.i,
'new Headers(' + serializeProperties(ctx, node.i, node.d) + ')',
);
}

@@ -733,18 +783,17 @@

node: SerovalFormDataNode,
) {
ctx.stack.push(node.i);
const mainAssignments: Assignment[] = [];
let parentStack: number[];
): string | undefined {
let value: string;
let key: string;
const keys = node.d.k;
const vals = node.d.v;
const id = node.i;
const mainAssignments: Assignment[] = [];
let parentAssignment: Assignment[];
for (let i = 0; i < node.d.s; i++) {
parentStack = ctx.stack;
ctx.stack = [];
value = serializeTree(ctx, node.d.v[i]);
key = node.d.k[i];
ctx.stack = parentStack;
ctx.stack.push(id);
for (let i = 0, len = node.d.s; i < len; i++) {
key = keys[i];
value = serializeTree(ctx, vals[i]);
parentAssignment = ctx.assignments;
ctx.assignments = mainAssignments;
createAppendAssignment(ctx, node.i, '"' + key + '"', value);
createAppendAssignment(ctx, id, '"' + key + '"', value);
ctx.assignments = parentAssignment;

@@ -759,9 +808,12 @@ }

node: SerovalFormDataNode,
) {
if (node.d.s) {
markRef(ctx, node.i);
): string {
const size = node.d.s;
const id = node.i;
if (size) {
markRef(ctx, id);
}
const result = assignIndexedValue(ctx, node.i, 'new FormData()');
if (node.d.s) {
return '(' + result + ',' + serializeFormDataEntries(ctx, node) + getRefParam(ctx, node.i) + ')';
const result = assignIndexedValue(ctx, id, 'new FormData()');
if (size) {
const entries = serializeFormDataEntries(ctx, node);
return '(' + result + ',' + (entries == null ? '' : entries) + getRefParam(ctx, id) + ')';
}

@@ -771,2 +823,16 @@ return result;

function serializeBoxed(
ctx: SerializationContext,
node: SerovalBoxedNode,
): string {
return assignIndexedValue(ctx, node.i, 'Object(' + serializeTree(ctx, node.f) + ')');
}
function serializeWKSymbol(
ctx: SerializationContext,
node: SerovalWKSymbolNode,
): string {
return assignIndexedValue(ctx, node.i, SYMBOL_STRING[node.s]);
}
export default function serializeTree(

@@ -781,16 +847,4 @@ ctx: SerializationContext,

return '"' + node.s + '"';
case SerovalNodeType.Boolean:
return node.s ? '!0' : '!1';
case SerovalNodeType.Undefined:
return 'void 0';
case SerovalNodeType.Null:
return 'null';
case SerovalNodeType.NegativeZero:
return '-0';
case SerovalNodeType.Infinity:
return '1/0';
case SerovalNodeType.NegativeInfinity:
return '-1/0';
case SerovalNodeType.NaN:
return 'NaN';
case SerovalNodeType.Constant:
return serializeConstant(node);
case SerovalNodeType.BigInt:

@@ -825,8 +879,6 @@ return node.s + 'n';

return serializeError(ctx, node);
case SerovalNodeType.Iterable:
return serializeIterable(ctx, node);
case SerovalNodeType.Promise:
return serializePromise(ctx, node);
case SerovalNodeType.WKSymbol:
return SYMBOL_STRING[node.s];
return serializeWKSymbol(ctx, node);
case SerovalNodeType.URL:

@@ -846,5 +898,7 @@ return serializeURL(ctx, node);

return serializeFormData(ctx, node);
case SerovalNodeType.Boxed:
return serializeBoxed(ctx, node);
default:
throw new Error('Unsupported type');
throw new Error('invariant');
}
}
import { Feature } from '../compat';
import { ParserContext } from '../context';
import {
AsyncServerValue,
import type { ParserContext } from '../context';
import type {
ErrorValue,
} from '../types';
export function getErrorConstructorName(error: ErrorValue) {
export function getErrorConstructorName(error: ErrorValue): string {
if (error instanceof EvalError) {

@@ -30,3 +29,12 @@ return 'EvalError';

export function getErrorConstructor(errorName: string) {
type ErrorConstructors =
| ErrorConstructor
| EvalErrorConstructor
| RangeErrorConstructor
| ReferenceErrorConstructor
| SyntaxErrorConstructor
| TypeErrorConstructor
| URIErrorConstructor;
export function getErrorConstructor(errorName: string): ErrorConstructors {
switch (errorName) {

@@ -48,4 +56,4 @@ case 'Error': return Error;

error: Error,
) {
let options: Record<string, any> | undefined;
): Record<string, unknown> | undefined {
let options: Record<string, unknown> | undefined;
const constructor = getErrorConstructorName(error);

@@ -77,17 +85,5 @@ // Name has been modified

export function getIterableOptions(obj: Iterable<any>) {
const names = Object.getOwnPropertyNames(obj);
if (names.length) {
const options: Record<string, unknown> = {};
for (const name of names) {
options[name] = obj[name as unknown as keyof typeof obj];
}
return options;
}
return undefined;
}
export function isIterable(
value: unknown,
): value is Iterable<AsyncServerValue> {
): value is Iterable<unknown> {
if (!value || typeof value !== 'object') {

@@ -120,3 +116,16 @@ return false;

export function getTypedArrayConstructor(name: string) {
type TypedArrayConstructor =
| Int8ArrayConstructor
| Int16ArrayConstructor
| Int32ArrayConstructor
| Uint8ArrayConstructor
| Uint16ArrayConstructor
| Uint32ArrayConstructor
| Uint8ClampedArrayConstructor
| Float32ArrayConstructor
| Float64ArrayConstructor
| BigInt64ArrayConstructor
| BigUint64ArrayConstructor;
export function getTypedArrayConstructor(name: string): TypedArrayConstructor {
switch (name) {

@@ -141,3 +150,3 @@ case 'Int8Array': return Int8Array;

export function isValidIdentifier(name: string) {
export function isValidIdentifier(name: string): boolean {
const char = name[0];

@@ -144,0 +153,0 @@ return (

export const enum Symbols {
AsyncIterator,
HasInstance,
IsConcatSpreadable,
Iterator,
Match,
MatchAll,
Replace,
Search,
Species,
Split,
ToPrimitive,
ToStringTag,
Unscopables
AsyncIterator = 0,
HasInstance = 1,
IsConcatSpreadable = 2,
Iterator = 3,
Match = 4,
MatchAll = 5,
Replace = 6,
Search = 7,
Species = 8,
Split = 9,
ToPrimitive = 10,
ToStringTag = 11,
Unscopables = 12,
}

@@ -16,0 +16,0 @@

/* eslint-disable @typescript-eslint/no-use-before-define */
import assert from '../assert';
import { Feature } from '../compat';
import { createIndexedValue, getRootID, ParserContext } from '../context';
import type { ParserContext } from '../context';
import { createIndexedValue } from '../context';
import { serializeString } from '../string';
import { BigIntTypedArrayValue, TypedArrayValue } from '../types';
import type { BigIntTypedArrayValue, TypedArrayValue } from '../types';
import UnsupportedTypeError from './UnsupportedTypeError';
import {
TRUE_NODE,
FALSE_NODE,
UNDEFINED_NODE,
NULL_NODE,
} from './constants';
import {
createBigIntNode,

@@ -16,14 +24,7 @@ createBigIntTypedArrayNode,

createTypedArrayNode,
createWKSymbolNode,
FALSE_NODE,
INFINITY_NODE,
NAN_NODE,
NEG_INFINITY_NODE,
NEG_ZERO_NODE,
NULL_NODE,
TRUE_NODE,
UNDEFINED_NODE,
createReferenceNode,
createArrayBufferNode,
createDataViewNode,
createSymbolNode,
createFunctionNode,
} from './primitives';

@@ -36,26 +37,29 @@ import {

getErrorOptions,
getIterableOptions,
isIterable,
} from './shared';
import { WellKnownSymbols } from './symbols';
import {
import type {
SerovalAggregateErrorNode,
SerovalArrayNode,
SerovalBoxedNode,
SerovalErrorNode,
SerovalFormDataNode,
SerovalHeadersNode,
SerovalIterableNode,
SerovalMapNode,
SerovalNode,
SerovalNodeType,
SerovalNullConstructorNode,
SerovalObjectNode,
SerovalObjectRecordKey,
SerovalObjectRecordNode,
SerovalPlainRecordNode,
SerovalSetNode,
} from './types';
import {
SerovalNodeType,
SerovalObjectRecordSpecialKey,
} from './types';
import { createURLNode, createURLSearchParamsNode } from './web-api';
type ObjectLikeNode = SerovalObjectNode | SerovalNullConstructorNode | SerovalIterableNode;
type ObjectLikeNode = SerovalObjectNode | SerovalNullConstructorNode;
function generateNodeList(ctx: ParserContext, current: unknown[]) {
function generateNodeList(ctx: ParserContext, current: unknown[]): SerovalNode[] {
const size = current.length;

@@ -71,3 +75,3 @@ const nodes = new Array<SerovalNode>(size);

} else {
nodes[i] = parse(ctx, item);
nodes[i] = parseSync(ctx, item);
}

@@ -78,3 +82,3 @@ }

if (i in deferred) {
nodes[i] = parse(ctx, deferred[i]);
nodes[i] = parseSync(ctx, deferred[i]);
}

@@ -109,3 +113,3 @@ }

): SerovalMapNode {
assert(ctx.features & Feature.Map, 'Unsupported type "Map"');
assert(ctx.features & Feature.Map, new UnsupportedTypeError(current));
const len = current.size;

@@ -125,4 +129,4 @@ const keyNodes = new Array<SerovalNode>(len);

} else {
keyNodes[nodeSize] = parse(ctx, key);
valueNodes[nodeSize] = parse(ctx, value);
keyNodes[nodeSize] = parseSync(ctx, key);
valueNodes[nodeSize] = parseSync(ctx, value);
nodeSize++;

@@ -132,4 +136,4 @@ }

for (let i = 0; i < deferredSize; i++) {
keyNodes[nodeSize + i] = parse(ctx, deferredKey[i]);
valueNodes[nodeSize + i] = parse(ctx, deferredValue[i]);
keyNodes[nodeSize + i] = parseSync(ctx, deferredKey[i]);
valueNodes[nodeSize + i] = parseSync(ctx, deferredValue[i]);
}

@@ -155,3 +159,3 @@ return {

): SerovalSetNode {
assert(ctx.features & Feature.Set, 'Unsupported type "Set"');
assert(ctx.features & Feature.Set, new UnsupportedTypeError(current));
const len = current.size;

@@ -167,3 +171,3 @@ const nodes = new Array<SerovalNode>(len);

} else {
nodes[nodeSize++] = parse(ctx, item);
nodes[nodeSize++] = parseSync(ctx, item);
}

@@ -173,3 +177,3 @@ }

for (let i = 0; i < deferredSize; i++) {
nodes[nodeSize + i] = parse(ctx, deferred[i]);
nodes[nodeSize + i] = parseSync(ctx, deferred[i]);
}

@@ -195,6 +199,6 @@ return {

const keys = Object.keys(properties);
const size = keys.length;
const keyNodes = new Array<string>(size);
let size = keys.length;
const keyNodes = new Array<SerovalObjectRecordKey>(size);
const valueNodes = new Array<SerovalNode>(size);
const deferredKeys = new Array<string>(size);
const deferredKeys = new Array<SerovalObjectRecordKey>(size);
const deferredValues = new Array<unknown>(size);

@@ -204,3 +208,3 @@ let deferredSize = 0;

let item: unknown;
let escaped: string;
let escaped: SerovalObjectRecordKey;
for (const key of keys) {

@@ -215,3 +219,3 @@ item = properties[key];

keyNodes[nodesSize] = escaped;
valueNodes[nodesSize] = parse(ctx, item);
valueNodes[nodesSize] = parseSync(ctx, item);
nodesSize++;

@@ -222,4 +226,13 @@ }

keyNodes[nodesSize + i] = deferredKeys[i];
valueNodes[nodesSize + i] = parse(ctx, deferredValues[i]);
valueNodes[nodesSize + i] = parseSync(ctx, deferredValues[i]);
}
if (ctx.features & Feature.Symbol) {
if (Symbol.iterator in properties) {
keyNodes[size] = SerovalObjectRecordSpecialKey.SymbolIterator;
const items = Array.from(properties as Iterable<unknown>);
const id = createIndexedValue(ctx, items);
valueNodes[size] = generateArrayNode(ctx, id, items);
size++;
}
}
return {

@@ -232,24 +245,37 @@ k: keyNodes,

function generateIterableNode(
function generatePlainProperties(
ctx: ParserContext,
id: number,
current: Iterable<unknown>,
): SerovalIterableNode {
assert(ctx.features & Feature.Symbol, 'Unsupported type "Iterable"');
const options = getIterableOptions(current);
const array = Array.from(current);
properties: Record<string, unknown>,
): SerovalPlainRecordNode {
const keys = Object.keys(properties);
const size = keys.length;
const keyNodes = new Array<string>(size);
const valueNodes = new Array<SerovalNode>(size);
const deferredKeys = new Array<string>(size);
const deferredValues = new Array<unknown>(size);
let deferredSize = 0;
let nodesSize = 0;
let item: unknown;
let escaped: string;
for (const key of keys) {
item = properties[key];
escaped = serializeString(key);
if (isIterable(item)) {
deferredKeys[deferredSize] = escaped;
deferredValues[deferredSize] = item;
deferredSize++;
} else {
keyNodes[nodesSize] = escaped;
valueNodes[nodesSize] = parseSync(ctx, item);
nodesSize++;
}
}
for (let i = 0; i < deferredSize; i++) {
keyNodes[nodesSize + i] = deferredKeys[i];
valueNodes[nodesSize + i] = parseSync(ctx, deferredValues[i]);
}
return {
t: SerovalNodeType.Iterable,
i: id,
s: undefined,
l: array.length,
c: undefined,
m: undefined,
// Parse options first before the items
d: options
? generateProperties(ctx, options)
: undefined,
a: generateNodeList(ctx, array),
f: undefined,
b: undefined,
k: keyNodes,
v: valueNodes,
s: size,
};

@@ -261,8 +287,5 @@ }

id: number,
current: Record<string, unknown> | Iterable<unknown>,
current: Record<string, unknown>,
empty: boolean,
): ObjectLikeNode {
if (Symbol.iterator in current) {
return generateIterableNode(ctx, id, current);
}
return {

@@ -333,4 +356,5 @@ t: empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,

): SerovalHeadersNode {
assert(ctx.features & Feature.WebAPI, 'Unsupported type "Headers"');
assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
const items: Record<string, string> = {};
// TS Headers not an Iterable
current.forEach((value, key) => {

@@ -346,3 +370,3 @@ items[key] = value;

m: undefined,
d: generateProperties(ctx, items),
d: generatePlainProperties(ctx, items),
a: undefined,

@@ -359,4 +383,5 @@ f: undefined,

): SerovalFormDataNode {
assert(ctx.features & Feature.WebAPI, 'Unsupported type "FormData"');
assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
const items: Record<string, FormDataEntryValue> = {};
// TS FormData isn't an Iterable sadly
current.forEach((value, key) => {

@@ -372,3 +397,3 @@ items[key] = value;

m: undefined,
d: generateProperties(ctx, items),
d: generatePlainProperties(ctx, items),
a: undefined,

@@ -380,4 +405,135 @@ f: undefined,

function parse<T>(
function generateBoxedNode(
ctx: ParserContext,
id: number,
current: object,
): SerovalBoxedNode {
return {
t: SerovalNodeType.Boxed,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
f: parseSync(ctx, current.valueOf()),
b: undefined,
};
}
function parseObject(
ctx: ParserContext,
current: object | null,
): SerovalNode {
if (!current) {
return NULL_NODE;
}
// Non-primitive values needs a reference ID
// mostly because the values themselves are stateful
const id = createIndexedValue(ctx, current);
if (ctx.markedRefs.has(id)) {
return createIndexedValueNode(id);
}
if (hasReferenceID(current)) {
return createReferenceNode(id, current);
}
// Well well well
if (Array.isArray(current)) {
return generateArrayNode(ctx, id, current);
}
// Fast path
switch (current.constructor) {
case Number:
case Boolean:
case String:
case BigInt:
case Function:
case Symbol:
return generateBoxedNode(ctx, id, current);
case Date:
return createDateNode(id, current as unknown as Date);
case RegExp:
return createRegExpNode(id, current as unknown as RegExp);
case ArrayBuffer:
return createArrayBufferNode(id, current as unknown as ArrayBuffer);
case Int8Array:
case Int16Array:
case Int32Array:
case Uint8Array:
case Uint16Array:
case Uint32Array:
case Uint8ClampedArray:
case Float32Array:
case Float64Array:
return createTypedArrayNode(ctx, id, current as unknown as TypedArrayValue);
case BigInt64Array:
case BigUint64Array:
return createBigIntTypedArrayNode(ctx, id, current as unknown as BigIntTypedArrayValue);
case DataView:
return createDataViewNode(ctx, id, current as unknown as DataView);
case Map:
return generateMapNode(ctx, id, current as unknown as Map<unknown, unknown>);
case Set:
return generateSetNode(ctx, id, current as unknown as Set<unknown>);
case Object:
return generateObjectNode(
ctx,
id,
current as unknown as Record<string, unknown>,
false,
);
case undefined:
return generateObjectNode(
ctx,
id,
current as unknown as Record<string, unknown>,
true,
);
case AggregateError:
// Compile-down AggregateError to Error if disabled
if (ctx.features & Feature.AggregateError) {
return generateAggregateErrorNode(ctx, id, current as unknown as AggregateError);
}
return generateErrorNode(ctx, id, current as unknown as AggregateError);
case Error:
case EvalError:
case RangeError:
case ReferenceError:
case SyntaxError:
case TypeError:
case URIError:
return generateErrorNode(ctx, id, current as unknown as Error);
case URL:
return createURLNode(ctx, id, current as unknown as URL);
case URLSearchParams:
return createURLSearchParamsNode(ctx, id, current as unknown as URLSearchParams);
case Headers:
return generateHeadersNode(ctx, id, current as unknown as Headers);
case FormData:
return generateFormDataNode(ctx, id, current as unknown as FormData);
default:
break;
}
// Slow path. We only need to handle Errors and Iterators
// since they have very broad implementations.
if (current instanceof AggregateError) {
if (ctx.features & Feature.AggregateError) {
return generateAggregateErrorNode(ctx, id, current);
}
return generateErrorNode(ctx, id, current);
}
if (current instanceof Error) {
return generateErrorNode(ctx, id, current);
}
// Generator functions don't have a global constructor
// despite existing
if (Symbol.iterator in current) {
return generateObjectNode(ctx, id, current, !!current.constructor);
}
throw new UnsupportedTypeError(current);
}
export default function parseSync<T>(
ctx: ParserContext,
current: T,

@@ -393,142 +549,14 @@ ): SerovalNode {

case 'number':
switch (current) {
case Infinity: return INFINITY_NODE;
case -Infinity: return NEG_INFINITY_NODE;
default:
// eslint-disable-next-line no-self-compare
if (current !== current) {
return NAN_NODE;
}
if (Object.is(current, -0)) {
return NEG_ZERO_NODE;
}
return createNumberNode(current);
}
return createNumberNode(current);
case 'bigint':
return createBigIntNode(ctx, current);
case 'object': {
if (!current) {
return NULL_NODE;
}
// Non-primitive values needs a reference ID
// mostly because the values themselves are stateful
const id = createIndexedValue(ctx, current);
if (ctx.markedRefs.has(id)) {
return createIndexedValueNode(id);
}
if (hasReferenceID(current)) {
return createReferenceNode(id, current);
}
if (Array.isArray(current)) {
return generateArrayNode(ctx, id, current);
}
switch (current.constructor) {
case Date:
return createDateNode(id, current as unknown as Date);
case RegExp:
return createRegExpNode(id, current as unknown as RegExp);
case ArrayBuffer:
return createArrayBufferNode(id, current as unknown as ArrayBuffer);
case Int8Array:
case Int16Array:
case Int32Array:
case Uint8Array:
case Uint16Array:
case Uint32Array:
case Uint8ClampedArray:
case Float32Array:
case Float64Array:
return createTypedArrayNode(ctx, id, current as unknown as TypedArrayValue);
case BigInt64Array:
case BigUint64Array:
return createBigIntTypedArrayNode(ctx, id, current as unknown as BigIntTypedArrayValue);
case DataView:
return createDataViewNode(ctx, id, current as unknown as DataView);
case Map:
return generateMapNode(ctx, id, current as unknown as Map<unknown, unknown>);
case Set:
return generateSetNode(ctx, id, current as unknown as Set<unknown>);
case Object:
return generateObjectNode(
ctx,
id,
current as unknown as Record<string, unknown>,
false,
);
case undefined:
return generateObjectNode(
ctx,
id,
current as unknown as Record<string, unknown>,
true,
);
case AggregateError:
if (ctx.features & Feature.AggregateError) {
return generateAggregateErrorNode(ctx, id, current as unknown as AggregateError);
}
return generateErrorNode(ctx, id, current as unknown as AggregateError);
case Error:
case EvalError:
case RangeError:
case ReferenceError:
case SyntaxError:
case TypeError:
case URIError:
return generateErrorNode(ctx, id, current as unknown as Error);
case URL:
return createURLNode(ctx, id, current as unknown as URL);
case URLSearchParams:
return createURLSearchParamsNode(ctx, id, current as unknown as URLSearchParams);
case Headers:
return generateHeadersNode(ctx, id, current as unknown as Headers);
case FormData:
return generateFormDataNode(ctx, id, current as unknown as FormData);
default:
break;
}
if (current instanceof AggregateError) {
if (ctx.features & Feature.AggregateError) {
return generateAggregateErrorNode(ctx, id, current);
}
return generateErrorNode(ctx, id, current);
}
if (current instanceof Error) {
return generateErrorNode(ctx, id, current);
}
// Generator functions don't have a global constructor
if (Symbol.iterator in current) {
return generateIterableNode(ctx, id, current as Iterable<unknown>);
}
throw new Error('Unsupported type');
}
case 'object':
return parseObject(ctx, current);
case 'symbol':
if (hasReferenceID(current)) {
const id = createIndexedValue(ctx, current);
if (ctx.markedRefs.has(id)) {
return createIndexedValueNode(id);
}
return createReferenceNode(id, current);
}
return createWKSymbolNode(ctx, current as WellKnownSymbols);
case 'function': {
assert(hasReferenceID(current), 'Cannot serialize function without reference ID.');
const id = createIndexedValue(ctx, current);
if (ctx.markedRefs.has(id)) {
return createIndexedValueNode(id);
}
return createReferenceNode(id, current);
}
return createSymbolNode(ctx, current);
case 'function':
return createFunctionNode(ctx, current);
default:
throw new Error('Unsupported type');
throw new UnsupportedTypeError(current);
}
}
export default function parseSync<T>(
ctx: ParserContext,
current: T,
) {
const result = parse(ctx, current);
const isObject = result.t === SerovalNodeType.Object
|| result.t === SerovalNodeType.Iterable;
return [result, getRootID(ctx, current), isObject] as const;
}

@@ -1,38 +0,43 @@

import { Symbols } from './symbols';
import type { Symbols } from './symbols';
export const enum SerovalConstant {
Null = 0,
Undefined = 1,
True = 2,
False = 3,
NegativeZero = 4,
Infinity = 5,
NegativeInfinity = 6,
NaN = 7,
}
export const enum SerovalNodeType {
Number,
String,
Boolean,
Null,
Undefined,
NegativeZero,
Infinity,
NegativeInfinity,
NaN,
BigInt,
IndexedValue,
Date,
RegExp,
Set,
Map,
Array,
Object,
NullConstructor,
Promise,
Error,
AggregateError,
Iterable,
TypedArray,
BigIntTypedArray,
WKSymbol,
URL,
URLSearchParams,
Reference,
ArrayBuffer,
DataView,
Blob,
File,
Headers,
FormData,
Number = 0,
String = 1,
Constant = 2,
BigInt = 3,
IndexedValue = 4,
Date = 5,
RegExp = 6,
Set = 7,
Map = 8,
Array = 9,
Object = 10,
NullConstructor = 11,
Promise = 12,
Error = 13,
AggregateError = 14,
TypedArray = 15,
BigIntTypedArray = 16,
WKSymbol = 17,
URL = 18,
URLSearchParams = 19,
Reference = 20,
ArrayBuffer = 21,
DataView = 22,
Blob = 23,
File = 24,
Headers = 25,
FormData = 26,
Boxed = 27,
}

@@ -46,3 +51,3 @@

// Serialized value
s: any;
s: unknown;
// size/length

@@ -55,5 +60,5 @@ l: number | undefined;

// dictionary
d: SerovalDictionaryNode | undefined;
d: SerovalObjectRecordNode | SerovalMapRecordNode | undefined;
// array of nodes
a: SerovalNode[] | undefined;
a: (SerovalNode | undefined)[] | undefined;
// fulfilled node

@@ -65,3 +70,11 @@ f: SerovalNode | undefined;

export interface SerovalObjectRecordNode {
export const enum SerovalObjectRecordSpecialKey {
SymbolIterator = 0,
}
export type SerovalObjectRecordKey =
| string
| SerovalObjectRecordSpecialKey;
export interface SerovalPlainRecordNode {
k: string[];

@@ -72,2 +85,8 @@ v: SerovalNode[];

export interface SerovalObjectRecordNode {
k: SerovalObjectRecordKey[];
v: SerovalNode[];
s: number;
}
export interface SerovalMapRecordNode {

@@ -79,6 +98,2 @@ k: SerovalNode[];

export type SerovalDictionaryNode =
| SerovalObjectRecordNode
| SerovalMapRecordNode;
export interface SerovalNumberNode extends SerovalBaseNode {

@@ -94,41 +109,11 @@ t: SerovalNodeType.Number;

export interface SerovalBooleanNode extends SerovalBaseNode {
t: SerovalNodeType.Boolean;
s: boolean;
export interface SerovalConstantNode extends SerovalBaseNode {
t: SerovalNodeType.Constant;
s: SerovalConstant;
}
export interface SerovalNullNode extends SerovalBaseNode {
t: SerovalNodeType.Null;
}
export interface SerovalUndefinedNode extends SerovalBaseNode {
t: SerovalNodeType.Undefined;
}
export interface SerovalNegativeZeroNode extends SerovalBaseNode {
t: SerovalNodeType.NegativeZero;
}
export interface SerovalInfinityNode extends SerovalBaseNode {
t: SerovalNodeType.Infinity;
}
export interface SerovalNegativeInfinityNode extends SerovalBaseNode {
t: SerovalNodeType.NegativeInfinity;
}
export interface SerovalNaNNode extends SerovalBaseNode {
t: SerovalNodeType.NaN;
}
export type SerovalPrimitiveNode =
| SerovalNumberNode
| SerovalStringNode
| SerovalBooleanNode
| SerovalNullNode
| SerovalUndefinedNode
| SerovalNegativeZeroNode
| SerovalNegativeInfinityNode
| SerovalInfinityNode
| SerovalNaNNode;
| SerovalConstantNode;

@@ -229,3 +214,3 @@ export interface SerovalIndexedValueNode extends SerovalBaseNode {

// items
a: SerovalNode[];
a: (SerovalNode | undefined)[];
i: number;

@@ -275,15 +260,5 @@ }

export interface SerovalIterableNode extends SerovalBaseNode {
t: SerovalNodeType.Iterable;
// other properties
d: SerovalObjectRecordNode | undefined;
// number of emitted items
l: number;
// array of items
a: SerovalNode[];
i: number;
}
export interface SerovalWKSymbolNode extends SerovalBaseNode {
t: SerovalNodeType.WKSymbol;
i: number;
s: Symbols;

@@ -349,3 +324,3 @@ }

i: number;
d: SerovalObjectRecordNode;
d: SerovalPlainRecordNode;
}

@@ -356,5 +331,11 @@

i: number;
d: SerovalObjectRecordNode;
d: SerovalPlainRecordNode;
}
export interface SerovalBoxedNode extends SerovalBaseNode {
t: SerovalNodeType.Boxed;
i: number;
f: SerovalNode;
}
export type SerovalNode =

@@ -372,3 +353,2 @@ | SerovalPrimitiveNode

| SerovalAggregateErrorNode
| SerovalIterableNode
| SerovalWKSymbolNode

@@ -383,2 +363,3 @@ | SerovalURLNode

| SerovalHeadersNode
| SerovalFormDataNode;
| SerovalFormDataNode
| SerovalBoxedNode;
import assert from '../assert';
import { Feature } from '../compat';
import { ParserContext } from '../context';
import type { ParserContext } from '../context';
import { serializeString } from '../string';
import UnsupportedTypeError from './UnsupportedTypeError';
import { serializeArrayBuffer } from './primitives';
import {
import type {
SerovalBlobNode,
SerovalFileNode,
SerovalNodeType,
SerovalURLNode,
SerovalURLSearchParamsNode,
} from './types';
import {
SerovalNodeType,
} from './types';

@@ -19,3 +22,3 @@ export function createURLNode(

): SerovalURLNode {
assert(ctx.features & Feature.WebAPI, 'Unsupported type "URL"');
assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
return {

@@ -40,3 +43,3 @@ t: SerovalNodeType.URL,

): SerovalURLSearchParamsNode {
assert(ctx.features & Feature.WebAPI, 'Unsupported type "URLSearchParams"');
assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
return {

@@ -61,3 +64,3 @@ t: SerovalNodeType.URLSearchParams,

): Promise<SerovalBlobNode> {
assert(ctx.features & Feature.WebAPI, 'Unsupported type "Blob"');
assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
return {

@@ -82,3 +85,3 @@ t: SerovalNodeType.Blob,

): Promise<SerovalFileNode> {
assert(ctx.features & Feature.WebAPI, 'Unsupported type "File"');
assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
return {

@@ -85,0 +88,0 @@ t: SerovalNodeType.File,

@@ -1,2 +0,2 @@

import { WellKnownSymbols } from './tree/symbols';
import type { WellKnownSymbols } from './tree/symbols';

@@ -39,3 +39,5 @@ // Values that are non-recursive

| URL
| URLSearchParams;
| URLSearchParams
| Blob
| File;

@@ -45,2 +47,4 @@ export type SemiPrimitiveValue =

| Date
| ArrayBuffer
| DataView
| TypedArrayValue

@@ -75,3 +79,3 @@ | BigIntTypedArrayValue

| Map<AsyncServerValue, AsyncServerValue>
| PromiseLike<AsyncServerValue>;
| Promise<AsyncServerValue>;

@@ -78,0 +82,0 @@ export type NonPrimitiveServerValue<T> =

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc