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.4.0-alpha.13 to 0.4.0-alpha.14

48

dist/types/context.d.ts
interface IndexAssignment {
type: 'index';
source: string;
value: string;
t: 'index';
s: string;
k: undefined;
v: string;
}
interface MapAssignment {
type: 'map';
source: string;
key: string;
value: string;
t: 'map';
s: string;
k: string;
v: string;
}
interface SetAssignment {
type: 'set';
source: string;
value: string;
t: 'set';
s: string;
k: undefined;
v: string;
}
export type Assignment = IndexAssignment | MapAssignment | SetAssignment;
export interface Options {
target: string | string[];
}
export declare class ParserContext {
export interface ParserContext {
refs: Map<unknown, number>;
markedRefs: Record<number, number>;
markedRefs: Set<number>;
features: number;
constructor(options?: Partial<Options>);
}
export interface SerializationOptions {
markedRefs: Record<number, number>;
features: number;
}
export declare class SerializationContext {
export interface SerializationContext {
stack: number[];
validRefs: number[];
refSize: number;
markedRefs: Set<number>;
vars: string[];
assignments: Assignment[];
features: number;
markedRefs: Record<number, number>;
constructor(options: SerializationOptions);
}
export interface Options {
target: string | string[];
}
export declare function createParserContext(options?: Partial<Options>): ParserContext;
export interface SerializationOptions {
markedRefs: number[] | Set<number>;
features: number;
}
export declare function createSerializationContext(options: SerializationOptions): SerializationContext;
/**

@@ -42,0 +44,0 @@ * Increments the number of references the referenced value has

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

import { SerovalPrimitiveNode } from './types';
import { ParserContext } from '../context';
import { BigIntTypedArrayValue, TypedArrayValue } from '../types';
import { SerovalBigIntNode, SerovalBigIntTypedArrayNode, SerovalDateNode, SerovalPrimitiveNode, SerovalReferenceNode, SerovalRegExpNode, SerovalTypedArrayNode } from './types';
export declare function createPrimitiveNode(value: string | number | null): SerovalPrimitiveNode;
export declare const TRUE_NODE: SerovalPrimitiveNode;

@@ -9,1 +12,7 @@ export declare const FALSE_NODE: SerovalPrimitiveNode;

export declare const NEG_INFINITY_NODE: SerovalPrimitiveNode;
export declare function createBigIntNode(ctx: ParserContext, current: bigint): SerovalBigIntNode;
export declare function createReferenceNode(id: number): SerovalReferenceNode;
export declare function createDateNode(id: number, current: Date): SerovalDateNode;
export declare function createRegExpNode(id: number, current: RegExp): SerovalRegExpNode;
export declare function createTypedArrayNode(ctx: ParserContext, id: number, current: TypedArrayValue): SerovalTypedArrayNode;
export declare function createBigIntTypedArrayNode(ctx: ParserContext, id: number, current: BigIntTypedArrayValue): SerovalBigIntTypedArrayNode;
import { SerializationContext } from '../context';
import { SerovalNode } from './types';
import { SerovalAggregateErrorNode, SerovalArrayNode, SerovalBigIntTypedArrayNode, SerovalErrorNode, SerovalIterableNode, SerovalMapNode, SerovalNode, SerovalNullConstructorNode, SerovalObjectRecordNode, SerovalPromiseNode, SerovalReferenceNode, SerovalSetNode, SerovalTypedArrayNode } from './types';
export declare function resolvePatches(ctx: SerializationContext): string | undefined;
export default function serializeTree(ctx: SerializationContext, node: SerovalNode): string;
export default class SerovalSerializer {
ctx: SerializationContext;
constructor(ctx: SerializationContext);
assignRef(index: number, value: string): string;
isReferenceInStack(node: SerovalNode): node is SerovalReferenceNode;
serializeNodeList(node: SerovalArrayNode | SerovalIterableNode): string;
serializeArray(node: SerovalArrayNode): string;
serializeObject(sourceID: number, node: SerovalObjectRecordNode): string;
serializeWithObjectAssign(value: SerovalObjectRecordNode, id: number, serialized: string): string;
serializeAssignments(sourceID: number, node: SerovalObjectRecordNode): string | undefined;
serializeNullConstructor(node: SerovalNullConstructorNode): string;
serializeSet(node: SerovalSetNode): string;
serializeMap(node: SerovalMapNode): string;
serializeAggregateError(node: SerovalAggregateErrorNode): string;
serializeError(node: SerovalErrorNode): string;
serializePromise(node: SerovalPromiseNode): string;
serializeTypedArray(node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode): string;
serializeIterable(node: SerovalIterableNode): string;
serialize(node: SerovalNode): string;
}

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

import { SerializationContext } from '../context';
import { AsyncServerValue, ErrorValue } from '../types';
import { SerovalNode, SerovalReferenceNode } from './types';
export declare function getErrorConstructor(error: ErrorValue): "EvalError" | "RangeError" | "ReferenceError" | "SyntaxError" | "TypeError" | "URIError" | "Error";
export declare function getErrorOptions(error: Error): Record<string, any> | undefined;
export declare function getIterableOptions(obj: Iterable<any>): Record<string, unknown> | undefined;
export declare function isReferenceInStack(ctx: SerializationContext, node: SerovalNode): node is SerovalReferenceNode;
export declare function isIterable(value: unknown): value is Iterable<AsyncServerValue>;

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

import { BigIntTypedArrayValue, PrimitiveValue, TypedArrayValue } from '../types';
import { PrimitiveValue } from '../types';
export declare const enum SerovalNodeType {

@@ -21,53 +21,45 @@ Primitive = 0,

export interface SerovalBaseNode {
t?: SerovalNodeType;
s?: PrimitiveValue;
i?: number;
l?: number;
c?: string;
d?: SerovalDictionaryNode;
m?: string;
n?: SerovalNode;
a?: SerovalNode[];
t: SerovalNodeType;
s: PrimitiveValue | undefined;
i: number | undefined;
l: number | undefined;
c: string | undefined;
d: SerovalDictionaryNode | undefined;
m: string | undefined;
n: SerovalNode | undefined;
a: SerovalNode[] | undefined;
}
export declare class SerovalObjectRecordNode {
export interface SerovalObjectRecordNode {
k: string[];
v: SerovalNode[];
s: number;
constructor(k: string[], v: SerovalNode[], s: number);
}
export declare class SerovalMapRecordNode {
export interface SerovalMapRecordNode {
k: SerovalNode[];
v: SerovalNode[];
s: number;
constructor(k: SerovalNode[], v: SerovalNode[], s: number);
}
export type SerovalDictionaryNode = SerovalObjectRecordNode | SerovalMapRecordNode;
export declare class SerovalPrimitiveNode implements SerovalBaseNode {
export interface SerovalPrimitiveNode extends SerovalBaseNode {
t: SerovalNodeType.Primitive;
s: string | number | null;
constructor(current: string | number | null);
}
export declare class SerovalReferenceNode implements SerovalBaseNode {
export interface SerovalReferenceNode extends SerovalBaseNode {
t: SerovalNodeType.Reference;
i: number;
constructor(id: number);
}
export declare class SerovalBigIntNode implements SerovalBaseNode {
export interface SerovalBigIntNode extends SerovalBaseNode {
t: SerovalNodeType.BigInt;
s: string;
constructor(current: bigint);
}
export declare class SerovalDateNode implements SerovalBaseNode {
export interface SerovalDateNode extends SerovalBaseNode {
t: SerovalNodeType.Date;
i: number;
s: string;
constructor(id: number, current: Date);
}
export declare class SerovalRegExpNode implements SerovalBaseNode {
export interface SerovalRegExpNode extends SerovalBaseNode {
t: SerovalNodeType.RegExp;
i: number;
s: string;
constructor(id: number, current: RegExp);
}
export declare class SerovalTypedArrayNode implements SerovalBaseNode {
export interface SerovalTypedArrayNode extends SerovalBaseNode {
t: SerovalNodeType.TypedArray;

@@ -78,5 +70,4 @@ i: number;

c: string;
constructor(id: number, current: TypedArrayValue);
}
export declare class SerovalBigIntTypedArrayNode implements SerovalBaseNode {
export interface SerovalBigIntTypedArrayNode extends SerovalBaseNode {
t: SerovalNodeType.BigIntTypedArray;

@@ -87,64 +78,54 @@ i: number;

c: string;
constructor(id: number, current: BigIntTypedArrayValue);
}
export type SerovalSemiPrimitiveNode = SerovalBigIntNode | SerovalDateNode | SerovalRegExpNode | SerovalTypedArrayNode | SerovalBigIntTypedArrayNode;
export declare class SerovalSetNode implements SerovalBaseNode {
export interface SerovalSetNode extends SerovalBaseNode {
t: SerovalNodeType.Set;
a: SerovalNode[];
i: number;
a: SerovalNode[];
constructor(id: number, a: SerovalNode[]);
}
export declare class SerovalMapNode implements SerovalBaseNode {
export interface SerovalMapNode extends SerovalBaseNode {
t: SerovalNodeType.Map;
d: SerovalMapRecordNode;
i: number;
d: SerovalMapRecordNode;
constructor(id: number, d: SerovalMapRecordNode);
}
export declare class SerovalArrayNode implements SerovalBaseNode {
export interface SerovalArrayNode extends SerovalBaseNode {
t: SerovalNodeType.Array;
a: SerovalNode[];
i: number;
a: SerovalNode[];
constructor(id: number, a: SerovalNode[]);
}
export declare class SerovalObjectNode implements SerovalBaseNode {
export interface SerovalObjectNode extends SerovalBaseNode {
t: SerovalNodeType.Object;
d: SerovalObjectRecordNode;
i: number;
d: SerovalObjectRecordNode;
constructor(id: number, d: SerovalObjectRecordNode);
}
export declare class SerovalNullConstructorNode implements SerovalBaseNode {
export interface SerovalNullConstructorNode extends SerovalBaseNode {
t: SerovalNodeType.NullConstructor;
d: SerovalObjectRecordNode;
i: number;
d: SerovalObjectRecordNode;
constructor(id: number, d: SerovalObjectRecordNode);
}
export declare class SerovalPromiseNode implements SerovalBaseNode {
export interface SerovalPromiseNode extends SerovalBaseNode {
t: SerovalNodeType.Promise;
n: SerovalNode;
i: number;
n: SerovalNode;
constructor(id: number, n: SerovalNode);
}
export declare class SerovalErrorNode implements SerovalBaseNode {
export interface SerovalErrorNode extends SerovalBaseNode {
t: SerovalNodeType.Error;
i: number;
c: string;
m: string;
d: SerovalObjectRecordNode | undefined;
constructor(id: number, c: string, m: string, d: SerovalObjectRecordNode | undefined);
i: number;
}
export declare class SerovalAggregateErrorNode implements SerovalBaseNode {
export interface SerovalAggregateErrorNode extends SerovalBaseNode {
t: SerovalNodeType.AggregateError;
i: number;
m: string;
d: SerovalObjectRecordNode | undefined;
n: SerovalNode;
constructor(id: number, m: string, d: SerovalObjectRecordNode | undefined, n: SerovalNode);
i: number;
}
export declare class SerovalIterableNode implements SerovalBaseNode {
export interface SerovalIterableNode extends SerovalBaseNode {
t: SerovalNodeType.Iterable;
i: number;
d: SerovalObjectRecordNode | undefined;
a: SerovalNode[];
constructor(id: number, d: SerovalObjectRecordNode | undefined, a: SerovalNode[]);
i: number;
}
export type SerovalNode = SerovalPrimitiveNode | SerovalReferenceNode | SerovalSemiPrimitiveNode | SerovalSetNode | SerovalMapNode | SerovalArrayNode | SerovalObjectNode | SerovalNullConstructorNode | SerovalPromiseNode | SerovalErrorNode | SerovalAggregateErrorNode | SerovalIterableNode;
{
"name": "seroval",
"type": "module",
"version": "0.4.0-alpha.13",
"version": "0.4.0-alpha.14",
"files": [

@@ -67,3 +67,3 @@ "dist",

},
"gitHead": "3f71e898ce27170bade38120eddc9afe96390498"
"gitHead": "7a287f3985c45ba331913f7633ca1ebf31c502ac"
}

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

/* eslint-disable prefer-object-spread */
/* eslint-disable max-classes-per-file */
import { parseTargets } from './compat';

@@ -7,18 +5,20 @@ import getIdentifier from './get-identifier';

interface IndexAssignment {
type: 'index';
source: string;
value: string;
t: 'index';
s: string;
k: undefined;
v: string;
}
interface MapAssignment {
type: 'map';
source: string;
key: string;
value: string;
t: 'map';
s: string;
k: string;
v: string;
}
interface SetAssignment {
type: 'set';
source: string;
value: string;
t: 'set';
s: string;
k: undefined;
v: string;
}

@@ -32,2 +32,23 @@

export interface ParserContext {
refs: Map<unknown, number>;
markedRefs: Set<number>;
features: number;
}
export interface SerializationContext {
stack: number[];
// Map tree refs to actual refs
validRefs: number[];
refSize: number;
// Refs that are...referenced
markedRefs: Set<number>;
// Variables
vars: string[];
// Array of assignments to be done (used for recursion)
assignments: Assignment[];
// Supported features
features: number;
}
export interface Options {

@@ -41,44 +62,27 @@ target: string | string[];

export class ParserContext {
refs = new Map<unknown, number>();
markedRefs: Record<number, number> = {};
features: number;
constructor(options: Partial<Options> = {}) {
const result = Object.assign({}, DEFAULT_OPTIONS, options || {});
this.features = parseTargets(result.target);
}
export function createParserContext(options: Partial<Options> = {}): ParserContext {
// eslint-disable-next-line prefer-object-spread
const result = Object.assign({}, DEFAULT_OPTIONS, options || {});
return {
markedRefs: new Set(),
refs: new Map(),
features: parseTargets(result.target),
};
}
export interface SerializationOptions {
markedRefs: Record<number, number>;
markedRefs: number[] | Set<number>;
features: number;
}
export class SerializationContext {
stack: number[] = [];
// Map tree refs to actual refs
validRefs: number[] = [];
refSize = 0;
// Variables
vars: string[] = [];
// Array of assignments to be done (used for recursion)
assignments: Assignment[] = [];
// Supported features
features: number;
// Refs that are...referenced
markedRefs: Record<number, number>;
constructor(options: SerializationOptions) {
this.features = options.features;
this.markedRefs = options.markedRefs;
}
export function createSerializationContext(options: SerializationOptions): SerializationContext {
return {
stack: [],
vars: [],
assignments: [],
validRefs: [],
refSize: 0,
features: options.features,
markedRefs: new Set(options.markedRefs),
};
}

@@ -90,3 +94,3 @@

export function markRef(ctx: ParserContext | SerializationContext, current: number) {
ctx.markedRefs[current] = 1;
ctx.markedRefs.add(current);
}

@@ -93,0 +97,0 @@

@@ -7,6 +7,7 @@ /* eslint-disable no-await-in-loop */

Options,
ParserContext,
createParserContext,
createSerializationContext,
} from './context';
import parseAsync from './tree/async';
import serializeTree, { resolvePatches } from './tree/serialize';
import SerovalSerializer, { resolvePatches } from './tree/serialize';
import parseSync from './tree/sync';

@@ -73,6 +74,6 @@ import { SerovalNode } from './tree/types';

) {
const ctx = new ParserContext(options);
const ctx = createParserContext(options);
const [tree, rootID, isObject] = parseSync(ctx, source);
const serial = new SerializationContext(ctx);
const result = serializeTree(serial, tree);
const serial = createSerializationContext(ctx);
const result = new SerovalSerializer(serial).serialize(tree);
return finalize(serial, rootID, isObject, result);

@@ -85,6 +86,6 @@ }

) {
const ctx = new ParserContext(options);
const ctx = createParserContext(options);
const [tree, rootID, isObject] = await parseAsync(ctx, source);
const serial = new SerializationContext(ctx);
const result = serializeTree(serial, tree);
const serial = createSerializationContext(ctx);
const result = new SerovalSerializer(serial).serialize(tree);
return finalize(serial, rootID, isObject, result);

@@ -98,9 +99,9 @@ }

type SerovalJSON = [
tree: SerovalNode,
root: number,
isObject: boolean,
feature: number,
markedRefs: Record<number, number>,
];
interface SerovalJSON {
t: SerovalNode,
r: number,
i: boolean,
f: number,
m: number[],
}

@@ -111,11 +112,11 @@ export function toJSON<T extends ServerValue>(

) {
const ctx = new ParserContext(options);
const ctx = createParserContext(options);
const [tree, root, isObject] = parseSync(ctx, source);
return JSON.stringify([
tree,
root,
isObject,
ctx.features,
ctx.markedRefs,
]);
return JSON.stringify({
t: tree,
r: root,
i: isObject,
f: ctx.features,
m: Array.from(ctx.markedRefs),
});
}

@@ -127,11 +128,11 @@

) {
const ctx = new ParserContext(options);
const ctx = createParserContext(options);
const [tree, root, isObject] = await parseAsync(ctx, source);
return JSON.stringify([
tree,
root,
isObject,
ctx.features,
ctx.markedRefs,
]);
return JSON.stringify({
t: tree,
r: root,
i: isObject,
f: ctx.features,
m: Array.from(ctx.markedRefs),
});
}

@@ -141,8 +142,8 @@

const parsed = JSON.parse(source) as SerovalJSON;
const serial = new SerializationContext({
features: parsed[3],
markedRefs: parsed[4],
const serial = createSerializationContext({
features: parsed.f,
markedRefs: parsed.m,
});
const result = serializeTree(serial, parsed[0]);
return finalize(serial, parsed[1], parsed[2], result);
const result = new SerovalSerializer(serial).serialize(parsed.t);
return finalize(serial, parsed.r, parsed.i, result);
}

@@ -149,0 +150,0 @@

@@ -13,5 +13,10 @@ /* eslint-disable no-await-in-loop */

import {
createBigIntNode,
createBigIntTypedArrayNode,
createDateNode,
createPrimitiveNode,
createReferenceNode,
createRegExpNode,
createTypedArrayNode,
FALSE_NODE,
INFINITY_NODE,
NEG_INFINITY_NODE,
NEG_ZERO_NODE,

@@ -31,9 +36,5 @@ NULL_NODE,

SerovalArrayNode,
SerovalBigIntNode,
SerovalBigIntTypedArrayNode,
SerovalDateNode,
SerovalErrorNode,
SerovalIterableNode,
SerovalMapNode,
SerovalMapRecordNode,
SerovalNode,

@@ -44,8 +45,4 @@ SerovalNodeType,

SerovalObjectRecordNode,
SerovalPrimitiveNode,
SerovalPromiseNode,
SerovalReferenceNode,
SerovalRegExpNode,
SerovalSetNode,
SerovalTypedArrayNode,
} from './types';

@@ -100,3 +97,13 @@

): Promise<SerovalArrayNode> {
return new SerovalArrayNode(id, await this.generateNodeList(current));
return {
t: SerovalNodeType.Array,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: await this.generateNodeList(current),
n: undefined,
};
}

@@ -132,3 +139,13 @@

}
return new SerovalMapNode(id, new SerovalMapRecordNode(keyNodes, valueNodes, len));
return {
t: SerovalNodeType.Map,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: { k: keyNodes, v: valueNodes, s: len },
a: undefined,
n: undefined,
};
}

@@ -158,3 +175,13 @@

}
return new SerovalSetNode(id, nodes);
return {
t: SerovalNodeType.Set,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: nodes,
n: undefined,
};
}

@@ -190,3 +217,7 @@

}
return new SerovalObjectRecordNode(keyNodes, valueNodes, size);
return {
k: keyNodes,
v: valueNodes,
s: size,
};
}

@@ -200,10 +231,16 @@

const options = getIterableOptions(current);
return new SerovalIterableNode(
id,
return {
t: SerovalNodeType.Iterable,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
// Parse options first before the items
options
d: options
? await this.generateProperties(options as Record<string, AsyncServerValue>)
: undefined,
await this.generateNodeList(Array.from(current)),
);
a: await this.generateNodeList(Array.from(current)),
n: undefined,
};
}

@@ -216,3 +253,14 @@

assert(this.ctx.features & Feature.Promise, 'Unsupported type "Promise"');
return current.then(async (value) => new SerovalPromiseNode(id, await this.parse(value)));
return current.then(async (value) => ({
t: SerovalNodeType.Promise,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
// Parse options first before the items
d: undefined,
a: undefined,
n: await this.parse(value),
}));
}

@@ -231,7 +279,13 @@

}
const properties = await this.generateProperties(current as Record<string, AsyncServerValue>);
if (empty) {
return new SerovalNullConstructorNode(id, properties);
}
return new SerovalObjectNode(id, properties);
return {
t: empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: await this.generateProperties(current as Record<string, AsyncServerValue>),
a: undefined,
n: undefined,
};
}

@@ -247,8 +301,13 @@

: undefined;
return new SerovalAggregateErrorNode(
id,
current.message,
optionsNode,
await this.parse(current.errors),
);
return {
t: SerovalNodeType.AggregateError,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: current.message,
d: optionsNode,
a: undefined,
n: await this.parse(current.errors),
};
}

@@ -264,3 +323,13 @@

: undefined;
return new SerovalErrorNode(id, getErrorConstructor(current), current.message, optionsNode);
return {
t: SerovalNodeType.Error,
i: id,
s: undefined,
l: undefined,
c: getErrorConstructor(current),
m: current.message,
d: optionsNode,
a: undefined,
n: undefined,
};
}

@@ -275,3 +344,3 @@

case 'string':
return new SerovalPrimitiveNode(quote(current));
return createPrimitiveNode(quote(current));
case 'number':

@@ -282,11 +351,10 @@ if (Object.is(current, -0)) {

if (Object.is(current, Infinity)) {
return INFINITY_NODE;
return createPrimitiveNode('1/0');
}
if (Object.is(current, -Infinity)) {
return NEG_INFINITY_NODE;
return createPrimitiveNode('-1/0');
}
return new SerovalPrimitiveNode(current);
return createPrimitiveNode(current);
case 'bigint':
assert(this.ctx.features & Feature.BigInt, 'Unsupported type "BigInt"');
return new SerovalBigIntNode(current);
return createBigIntNode(this.ctx, current);
case 'object': {

@@ -299,4 +367,4 @@ if (!current) {

const id = createRef(this.ctx, current, true);
if (this.ctx.markedRefs[id]) {
return new SerovalReferenceNode(id);
if (this.ctx.markedRefs.has(id)) {
return createReferenceNode(id);
}

@@ -308,5 +376,5 @@ if (Array.isArray(current)) {

case Date:
return new SerovalDateNode(id, current as Date);
return createDateNode(id, current as Date);
case RegExp:
return new SerovalRegExpNode(id, current as RegExp);
return createRegExpNode(id, current as RegExp);
case Promise:

@@ -323,11 +391,6 @@ return this.generatePromiseNode(id, current as Promise<AsyncServerValue>);

case Float64Array:
assert(this.ctx.features & Feature.TypedArray, `Unsupported value type "${current.constructor.name}"`);
return new SerovalTypedArrayNode(id, current as TypedArrayValue);
return createTypedArrayNode(this.ctx, id, current as TypedArrayValue);
case BigInt64Array:
case BigUint64Array:
assert(
this.ctx.features & (Feature.BigIntTypedArray),
`Unsupported value type "${current.constructor.name}"`,
);
return new SerovalBigIntTypedArrayNode(id, current as BigIntTypedArrayValue);
return createBigIntTypedArrayNode(this.ctx, id, current as BigIntTypedArrayValue);
case Map:

@@ -334,0 +397,0 @@ return this.generateMapNode(id, current as Map<AsyncServerValue, AsyncServerValue>);

@@ -0,11 +1,147 @@

import assert from '../assert';
import { Feature } from '../compat';
import { ParserContext } from '../context';
import { BigIntTypedArrayValue, TypedArrayValue } from '../types';
import {
SerovalBigIntNode,
SerovalBigIntTypedArrayNode,
SerovalDateNode,
SerovalNodeType,
SerovalPrimitiveNode,
SerovalReferenceNode,
SerovalRegExpNode,
SerovalTypedArrayNode,
} from './types';
export const TRUE_NODE = new SerovalPrimitiveNode('!0');
export const FALSE_NODE = new SerovalPrimitiveNode('!1');
export const UNDEFINED_NODE = new SerovalPrimitiveNode('void 0');
export const NULL_NODE = new SerovalPrimitiveNode(null);
export const NEG_ZERO_NODE = new SerovalPrimitiveNode('-0');
export const INFINITY_NODE = new SerovalPrimitiveNode('1/0');
export const NEG_INFINITY_NODE = new SerovalPrimitiveNode('-1/0');
export function createPrimitiveNode(
value: string | number | null,
): SerovalPrimitiveNode {
return {
t: SerovalNodeType.Primitive,
i: undefined,
s: value,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
n: undefined,
};
}
export const TRUE_NODE = createPrimitiveNode('!0');
export const FALSE_NODE = createPrimitiveNode('!1');
export const UNDEFINED_NODE = createPrimitiveNode('void 0');
export const NULL_NODE = createPrimitiveNode(null);
export const NEG_ZERO_NODE = createPrimitiveNode('-0');
export const INFINITY_NODE = createPrimitiveNode('1/0');
export const NEG_INFINITY_NODE = createPrimitiveNode('-1/0');
export function createBigIntNode(
ctx: ParserContext,
current: bigint,
): SerovalBigIntNode {
assert(ctx.features & Feature.BigInt, 'Unsupported type "BigInt"');
return {
t: SerovalNodeType.BigInt,
i: undefined,
s: `${current}n`,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
n: undefined,
};
}
export function createReferenceNode(id: number): SerovalReferenceNode {
return {
t: SerovalNodeType.Reference,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
n: undefined,
};
}
export function createDateNode(id: number, current: Date): SerovalDateNode {
return {
t: SerovalNodeType.Date,
i: id,
s: current.toISOString(),
l: undefined,
c: undefined,
m: undefined,
d: undefined,
n: undefined,
a: undefined,
};
}
export function createRegExpNode(id: number, current: RegExp): SerovalRegExpNode {
return {
t: SerovalNodeType.RegExp,
i: id,
s: String(current),
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: undefined,
n: undefined,
};
}
export function createTypedArrayNode(
ctx: ParserContext,
id: number,
current: TypedArrayValue,
): SerovalTypedArrayNode {
const constructor = current.constructor.name;
assert(ctx.features & Feature.TypedArray, `Unsupported value type "${constructor}"`);
return {
t: SerovalNodeType.TypedArray,
i: id,
s: current.toString(),
l: current.byteOffset,
c: constructor,
m: undefined,
d: undefined,
a: undefined,
n: undefined,
};
}
export function createBigIntTypedArrayNode(
ctx: ParserContext,
id: number,
current: BigIntTypedArrayValue,
): SerovalBigIntTypedArrayNode {
const constructor = current.constructor.name;
assert(
ctx.features & (Feature.BigIntTypedArray),
`Unsupported value type "${constructor}"`,
);
let result = '';
const cap = current.length - 1;
for (let i = 0; i < cap; i++) {
result += `${current[i]}n,`;
}
result += `"${current[cap]}"`;
return {
t: SerovalNodeType.BigIntTypedArray,
i: id,
s: result,
l: (current as BigInt64Array).byteOffset,
c: constructor,
m: undefined,
d: undefined,
a: undefined,
n: undefined,
};
}

@@ -10,3 +10,2 @@ /* eslint-disable @typescript-eslint/no-use-before-define */

import quote from '../quote';
import { isReferenceInStack } from './shared';
import {

@@ -24,2 +23,3 @@ SerovalAggregateErrorNode,

SerovalPromiseNode,
SerovalReferenceNode,
SerovalSetNode,

@@ -30,9 +30,9 @@ SerovalTypedArrayNode,

function getAssignmentExpression(assignment: Assignment): string {
switch (assignment.type) {
switch (assignment.t) {
case 'index':
return `${assignment.source}=${assignment.value}`;
return `${assignment.s}=${assignment.v}`;
case 'map':
return `${assignment.source}.set(${assignment.key},${assignment.value})`;
return `${assignment.s}.set(${assignment.k},${assignment.v})`;
case 'set':
return `${assignment.source}.add(${assignment.value})`;
return `${assignment.s}.add(${assignment.v})`;
default:

@@ -49,25 +49,27 @@ return '';

const item = assignments[i];
if (item.type === prev.type) {
if (item.type === 'index' && item.value === prev.value) {
if (item.t === prev.t) {
if (item.t === 'index' && item.v === prev.v) {
// Merge if the right-hand value is the same
// saves at least 2 chars
current = {
type: 'index',
source: item.source,
value: getAssignmentExpression(current),
t: 'index',
s: item.s,
k: undefined,
v: getAssignmentExpression(current),
};
} else if (item.type === 'map' && item.source === prev.source) {
} else if (item.t === 'map' && item.s === prev.s) {
// Maps has chaining methods, merge if source is the same
current = {
type: 'map',
source: getAssignmentExpression(current),
key: item.key,
value: item.value,
t: 'map',
s: getAssignmentExpression(current),
k: item.k,
v: item.v,
};
} else if (item.type === 'set' && item.source === prev.source) {
} else if (item.t === 'set' && item.s === prev.s) {
// Sets has chaining methods too
current = {
type: 'set',
source: getAssignmentExpression(current),
value: item.value,
t: 'set',
s: getAssignmentExpression(current),
k: undefined,
v: item.v,
};

@@ -112,12 +114,2 @@ } else {

*/
function assignRef(
ctx: SerializationContext,
index: number,
value: string,
) {
if (ctx.markedRefs[index]) {
return `${getRefParam(ctx, index)}=${value}`;
}
return value;
}

@@ -130,5 +122,6 @@ function createAssignment(

ctx.assignments.push({
type: 'index',
source,
value,
t: 'index',
s: source,
k: undefined,
v: value,
});

@@ -144,5 +137,6 @@ }

ctx.assignments.push({
type: 'set',
source: getRefParam(ctx, ref),
value,
t: 'set',
s: getRefParam(ctx, ref),
k: undefined,
v: value,
});

@@ -159,6 +153,6 @@ }

ctx.assignments.push({
type: 'map',
source: getRefParam(ctx, ref),
key,
value,
t: 'map',
s: getRefParam(ctx, ref),
k: key,
v: value,
});

@@ -189,372 +183,377 @@ }

function serializeAssignments(
ctx: SerializationContext,
targetRef: number,
node: SerovalObjectRecordNode,
) {
ctx.stack.push(targetRef);
const mainAssignments: Assignment[] = [];
for (let i = 0; i < node.s; i++) {
const parentStack = ctx.stack;
ctx.stack = [];
const refParam = serializeTree(ctx, node.v[i]);
ctx.stack = parentStack;
const key = node.k[i];
const check = Number(key);
const 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
const isIdentifier = check >= 0 || IDENTIFIER_CHECK.test(key);
if (isIdentifier && Number.isNaN(check)) {
createObjectAssign(ctx, targetRef, key, refParam);
} else {
createArrayAssign(ctx, targetRef, isIdentifier ? key : quote(key), refParam);
}
ctx.assignments = parentAssignment;
export default class SerovalSerializer {
ctx: SerializationContext;
constructor(ctx: SerializationContext) {
this.ctx = ctx;
}
ctx.stack.pop();
return resolveAssignments(mainAssignments);
}
function serializeObject(
ctx: SerializationContext,
sourceID: number,
node: SerovalObjectRecordNode,
) {
if (node.s === 0) {
return '{}';
}
let result = '';
ctx.stack.push(sourceID);
for (let i = 0; i < node.s; i++) {
const key = node.k[i];
const val = node.v[i];
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 || IDENTIFIER_CHECK.test(key);
if (isReferenceInStack(ctx, val)) {
const refParam = getRefParam(ctx, val.i);
if (isIdentifier && Number.isNaN(check)) {
createObjectAssign(ctx, sourceID, key, refParam);
} else {
createArrayAssign(ctx, sourceID, isIdentifier ? key : quote(key), refParam);
}
} else {
result += `${isIdentifier ? key : quote(key)}:${serializeTree(ctx, val)},`;
assignRef(index: number, value: string) {
if (this.ctx.markedRefs.has(index)) {
return `${getRefParam(this.ctx, index)}=${value}`;
}
return value;
}
ctx.stack.pop();
return `{${result.substring(0, result.length - 1)}}`;
}
function serializePromise(
ctx: SerializationContext,
node: SerovalPromiseNode,
) {
let serialized: string;
// Check if resolved value is a parent expression
if (isReferenceInStack(ctx, node.n)) {
// A Promise trick, reference the value
// inside the `then` expression so that
// the Promise evaluates after the parent
// has initialized
serialized = `Promise.resolve().then(()=>${getRefParam(ctx, node.n.i)})`;
} else {
ctx.stack.push(node.i);
const result = serializeTree(ctx, node.n);
ctx.stack.pop();
// just inline the value/reference here
serialized = `Promise.resolve(${result})`;
isReferenceInStack(
node: SerovalNode,
): node is SerovalReferenceNode {
return node.t === SerovalNodeType.Reference && this.ctx.stack.includes(node.i);
}
return assignRef(ctx, node.i, serialized);
}
function serializeTypedArray(
ctx: SerializationContext,
node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
) {
let args = `[${node.s}]`;
if (node.l !== 0) {
args += `,${node.l}`;
}
return assignRef(ctx, node.i, `new ${node.c}(${args})`);
}
function serializeSet(
ctx: SerializationContext,
node: SerovalSetNode,
) {
let serialized = 'new Set';
const size = node.a.length;
if (size) {
let result = '';
ctx.stack.push(node.i);
serializeNodeList(
node: SerovalArrayNode | SerovalIterableNode,
) {
// This is different than Map and Set
// because we also need to serialize
// the holes of the Array
const size = node.a.length;
let values = '';
for (let i = 0; i < size; i++) {
const item = node.a[i];
if (isReferenceInStack(ctx, item)) {
createSetAdd(ctx, node.i, getRefParam(ctx, item.i));
// Check if index is a hole
if (item) {
// Check if item is a parent
if (this.isReferenceInStack(item)) {
createArrayAssign(this.ctx, node.i, i, getRefParam(this.ctx, item.i));
values += ',';
} else {
values += this.serialize(item);
if (i < size - 1) {
values += ',';
}
}
} else {
// Push directly
result += `${serializeTree(ctx, item)},`;
// Add an empty item
values += ',';
}
}
ctx.stack.pop();
if (result) {
serialized += `([${result.substring(0, result.length - 1)}])`;
}
return `[${values}]`;
}
return assignRef(ctx, node.i, serialized);
}
function serializeMap(
ctx: SerializationContext,
node: SerovalMapNode,
) {
let serialized = 'new Map';
if (node.d.s) {
serializeArray(
node: SerovalArrayNode,
) {
this.ctx.stack.push(node.i);
const result = this.serializeNodeList(node);
this.ctx.stack.pop();
return this.assignRef(node.i, result);
}
serializeObject(
sourceID: number,
node: SerovalObjectRecordNode,
) {
if (node.s === 0) {
return '{}';
}
let result = '';
ctx.stack.push(node.i);
for (let i = 0; i < node.d.s; i++) {
// Check if key is a parent
const key = node.d.k[i];
const val = node.d.v[i];
if (isReferenceInStack(ctx, key)) {
// Create reference for the map instance
const keyRef = getRefParam(ctx, key.i);
// Check if value is a parent
if (isReferenceInStack(ctx, val)) {
const valueRef = getRefParam(ctx, val.i);
// Register an assignment since
// both key and value are a parent of this
// Map instance
createMapSet(ctx, node.i, keyRef, valueRef);
this.ctx.stack.push(sourceID);
for (let i = 0; i < node.s; i++) {
const key = node.k[i];
const val = node.v[i];
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 || IDENTIFIER_CHECK.test(key);
if (this.isReferenceInStack(val)) {
const refParam = getRefParam(this.ctx, val.i);
if (isIdentifier && Number.isNaN(check)) {
createObjectAssign(this.ctx, sourceID, key, refParam);
} else {
// Reset the stack
// This is required because the serialized
// value is no longer part of the expression
// tree and has been moved to the deferred
// assignment
const parent = ctx.stack;
ctx.stack = [];
createMapSet(ctx, node.i, keyRef, serializeTree(ctx, val));
ctx.stack = parent;
createArrayAssign(this.ctx, sourceID, isIdentifier ? key : quote(key), refParam);
}
} else if (isReferenceInStack(ctx, val)) {
// Create ref for the Map instance
const valueRef = getRefParam(ctx, val.i);
// Reset stack for the key serialization
const parent = ctx.stack;
ctx.stack = [];
createMapSet(ctx, node.i, serializeTree(ctx, key), valueRef);
ctx.stack = parent;
} else {
result += `[${serializeTree(ctx, key)},${serializeTree(ctx, val)}],`;
result += `${isIdentifier ? key : quote(key)}:${this.serialize(val)},`;
}
}
ctx.stack.pop();
// Check if there are any values
// so that the empty Map constructor
// can be used instead
if (result) {
serialized += `([${result.substring(0, result.length - 1)}])`;
this.ctx.stack.pop();
return `{${result.substring(0, result.length - 1)}}`;
}
serializeWithObjectAssign(
value: SerovalObjectRecordNode,
id: number,
serialized: string,
) {
const fields = this.serializeObject(id, value);
if (fields !== '{}') {
return `Object.assign(${serialized},${fields})`;
}
return serialized;
}
return assignRef(ctx, node.i, serialized);
}
function serializeNodeList(
ctx: SerializationContext,
node: SerovalArrayNode | SerovalIterableNode,
) {
// This is different than Map and Set
// because we also need to serialize
// the holes of the Array
const size = node.a.length;
let values = '';
for (let i = 0; i < size; i++) {
const item = node.a[i];
// Check if index is a hole
if (item) {
// Check if item is a parent
if (isReferenceInStack(ctx, item)) {
createArrayAssign(ctx, node.i, i, getRefParam(ctx, item.i));
values += ',';
serializeAssignments(
sourceID: number,
node: SerovalObjectRecordNode,
) {
this.ctx.stack.push(sourceID);
const mainAssignments: Assignment[] = [];
for (let i = 0; i < node.s; i++) {
const parentStack = this.ctx.stack;
this.ctx.stack = [];
const refParam = this.serialize(node.v[i]);
this.ctx.stack = parentStack;
const key = node.k[i];
const check = Number(key);
const parentAssignment = this.ctx.assignments;
this.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
const isIdentifier = check >= 0 || IDENTIFIER_CHECK.test(key);
if (isIdentifier && Number.isNaN(check)) {
createObjectAssign(this.ctx, sourceID, key, refParam);
} else {
values += serializeTree(ctx, item);
if (i < size - 1) {
values += ',';
}
createArrayAssign(this.ctx, sourceID, isIdentifier ? key : quote(key), refParam);
}
this.ctx.assignments = parentAssignment;
}
this.ctx.stack.pop();
return resolveAssignments(mainAssignments);
}
serializeNullConstructor(
node: SerovalNullConstructorNode,
) {
let serialized = 'Object.create(null)';
if (this.ctx.features & Feature.ObjectAssign) {
serialized = this.serializeWithObjectAssign(node.d, node.i, serialized);
} else {
// Add an empty item
values += ',';
markRef(this.ctx, node.i);
const assignments = this.serializeAssignments(node.i, node.d);
if (assignments) {
const ref = getRefParam(this.ctx, node.i);
return `(${this.assignRef(node.i, serialized)},${assignments}${ref})`;
}
}
return this.assignRef(node.i, serialized);
}
return `[${values}]`;
}
function serializeArray(
ctx: SerializationContext,
node: SerovalArrayNode,
) {
ctx.stack.push(node.i);
const result = serializeNodeList(ctx, node);
ctx.stack.pop();
return assignRef(ctx, node.i, result);
}
serializeSet(
node: SerovalSetNode,
) {
let serialized = 'new Set';
const size = node.a.length;
if (size) {
let result = '';
this.ctx.stack.push(node.i);
for (let i = 0; i < size; i++) {
const item = node.a[i];
if (this.isReferenceInStack(item)) {
createSetAdd(this.ctx, node.i, getRefParam(this.ctx, item.i));
} else {
// Push directly
result += `${this.serialize(item)},`;
}
}
this.ctx.stack.pop();
if (result) {
serialized += `([${result.substring(0, result.length - 1)}])`;
}
}
return this.assignRef(node.i, serialized);
}
function serializeWithObjectAssign(
ctx: SerializationContext,
value: SerovalObjectRecordNode,
id: number,
serialized: string,
) {
const fields = serializeObject(ctx, id, value);
if (fields !== '{}') {
return `Object.assign(${serialized},${fields})`;
serializeMap(
node: SerovalMapNode,
) {
let serialized = 'new Map';
if (node.d.s) {
let result = '';
this.ctx.stack.push(node.i);
for (let i = 0; i < node.d.s; i++) {
// Check if key is a parent
const key = node.d.k[i];
const val = node.d.v[i];
if (this.isReferenceInStack(key)) {
// Create reference for the map instance
const keyRef = getRefParam(this.ctx, key.i);
// Check if value is a parent
if (this.isReferenceInStack(val)) {
const valueRef = getRefParam(this.ctx, val.i);
// Register an assignment since
// both key and value are a parent of this
// Map instance
createMapSet(this.ctx, node.i, keyRef, valueRef);
} else {
// Reset the stack
// This is required because the serialized
// value is no longer part of the expression
// tree and has been moved to the deferred
// assignment
const parent = this.ctx.stack;
this.ctx.stack = [];
createMapSet(this.ctx, node.i, keyRef, this.serialize(val));
this.ctx.stack = parent;
}
} else if (this.isReferenceInStack(val)) {
// Create ref for the Map instance
const valueRef = getRefParam(this.ctx, val.i);
// Reset stack for the key serialization
const parent = this.ctx.stack;
this.ctx.stack = [];
createMapSet(this.ctx, node.i, this.serialize(key), valueRef);
this.ctx.stack = parent;
} else {
result += `[${this.serialize(key)},${this.serialize(val)}],`;
}
}
this.ctx.stack.pop();
// Check if there are any values
// so that the empty Map constructor
// can be used instead
if (result) {
serialized += `([${result.substring(0, result.length - 1)}])`;
}
}
return this.assignRef(node.i, serialized);
}
return serialized;
}
function serializeAggregateError(
ctx: SerializationContext,
node: SerovalAggregateErrorNode,
) {
// Serialize the required arguments
ctx.stack.push(node.i);
let serialized = `new AggregateError(${serializeTree(ctx, node.n)},${quote(node.m)})`;
ctx.stack.pop();
// `AggregateError` might've been extended
// either through class or custom properties
// Make sure to assign extra properties
if (node.d) {
if (ctx.features & Feature.ObjectAssign) {
serialized = serializeWithObjectAssign(ctx, node.d, node.i, serialized);
} else {
markRef(ctx, node.i);
const assignments = serializeAssignments(ctx, node.i, node.d);
if (assignments) {
const ref = getRefParam(ctx, node.i);
return `(${assignRef(ctx, node.i, serialized)},${assignments}${ref})`;
serializeAggregateError(
node: SerovalAggregateErrorNode,
) {
// Serialize the required arguments
this.ctx.stack.push(node.i);
let serialized = `new AggregateError(${this.serialize(node.n)},${quote(node.m)})`;
this.ctx.stack.pop();
// `AggregateError` might've been extended
// either through class or custom properties
// Make sure to assign extra properties
if (node.d) {
if (this.ctx.features & Feature.ObjectAssign) {
serialized = this.serializeWithObjectAssign(node.d, node.i, serialized);
} else {
markRef(this.ctx, node.i);
const assignments = this.serializeAssignments(node.i, node.d);
if (assignments) {
const ref = getRefParam(this.ctx, node.i);
return `(${this.assignRef(node.i, serialized)},${assignments}${ref})`;
}
}
}
return this.assignRef(node.i, serialized);
}
return assignRef(ctx, node.i, serialized);
}
function serializeError(
ctx: SerializationContext,
node: SerovalErrorNode,
) {
let serialized = `new ${node.c}(${quote(node.m)})`;
if (node.d) {
if (ctx.features & Feature.ObjectAssign) {
serialized = serializeWithObjectAssign(ctx, node.d, node.i, serialized);
} else {
markRef(ctx, node.i);
const assignments = serializeAssignments(ctx, node.i, node.d);
if (assignments) {
const ref = getRefParam(ctx, node.i);
return `(${assignRef(ctx, node.i, serialized)},${assignments}${ref})`;
serializeError(
node: SerovalErrorNode,
) {
let serialized = `new ${node.c}(${quote(node.m)})`;
if (node.d) {
if (this.ctx.features & Feature.ObjectAssign) {
serialized = this.serializeWithObjectAssign(node.d, node.i, serialized);
} else {
markRef(this.ctx, node.i);
const assignments = this.serializeAssignments(node.i, node.d);
if (assignments) {
const ref = getRefParam(this.ctx, node.i);
return `(${this.assignRef(node.i, serialized)},${assignments}${ref})`;
}
}
}
return this.assignRef(node.i, serialized);
}
return assignRef(ctx, node.i, serialized);
}
function serializeIterable(
ctx: SerializationContext,
node: SerovalIterableNode,
) {
const parent = ctx.stack;
ctx.stack = [];
const values = serializeNodeList(ctx, node);
ctx.stack = parent;
let serialized: string;
if (ctx.features & Feature.ArrayPrototypeValues) {
serialized = `${values}.values()`;
} else {
serialized = `${values}[Symbol.iterator]()`;
serializePromise(
node: SerovalPromiseNode,
) {
let serialized: string;
// Check if resolved value is a parent expression
if (this.isReferenceInStack(node.n)) {
// A Promise trick, reference the value
// inside the `then` expression so that
// the Promise evaluates after the parent
// has initialized
serialized = `Promise.resolve().then(()=>${getRefParam(this.ctx, node.n.i)})`;
} else {
this.ctx.stack.push(node.i);
const result = this.serialize(node.n);
this.ctx.stack.pop();
// just inline the value/reference here
serialized = `Promise.resolve(${result})`;
}
return this.assignRef(node.i, serialized);
}
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}}}`;
serializeTypedArray(
node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
) {
let args = `[${node.s}]`;
if (node.l !== 0) {
args += `,${node.l}`;
}
return this.assignRef(node.i, `new ${node.c}(${args})`);
}
if (node.d) {
if (ctx.features & Feature.ObjectAssign) {
serialized = serializeWithObjectAssign(ctx, node.d, node.i, serialized);
serializeIterable(
node: SerovalIterableNode,
) {
const parent = this.ctx.stack;
this.ctx.stack = [];
const values = this.serializeNodeList(node);
this.ctx.stack = parent;
let serialized: string;
if (this.ctx.features & Feature.ArrayPrototypeValues) {
serialized = `${values}.values()`;
} else {
markRef(ctx, node.i);
const assignments = serializeAssignments(ctx, node.i, node.d);
if (assignments) {
const ref = getRefParam(ctx, node.i);
return `(${assignRef(ctx, node.i, serialized)},${assignments}${ref})`;
serialized = `${values}[Symbol.iterator]()`;
}
if (this.ctx.features & Feature.ArrowFunction) {
serialized = `{[Symbol.iterator]:()=>${serialized}}`;
} else if (this.ctx.features & Feature.MethodShorthand) {
serialized = `{[Symbol.iterator](){return ${serialized}}}`;
} else {
serialized = `{[Symbol.iterator]:function(){return ${serialized}}}`;
}
if (node.d) {
if (this.ctx.features & Feature.ObjectAssign) {
serialized = this.serializeWithObjectAssign(node.d, node.i, serialized);
} else {
markRef(this.ctx, node.i);
const assignments = this.serializeAssignments(node.i, node.d);
if (assignments) {
const ref = getRefParam(this.ctx, node.i);
return `(${this.assignRef(node.i, serialized)},${assignments}${ref})`;
}
}
}
return this.assignRef(node.i, serialized);
}
return assignRef(ctx, node.i, serialized);
}
function serializeNullConstructor(
ctx: SerializationContext,
node: SerovalNullConstructorNode,
) {
let serialized = 'Object.create(null)';
if (ctx.features & Feature.ObjectAssign) {
serialized = serializeWithObjectAssign(ctx, node.d, node.i, serialized);
} else {
markRef(ctx, node.i);
const assignments = serializeAssignments(ctx, node.i, node.d);
if (assignments) {
const ref = getRefParam(ctx, node.i);
return `(${assignRef(ctx, node.i, serialized)},${assignments}${ref})`;
serialize(node: SerovalNode): string {
switch (node.t) {
case SerovalNodeType.Primitive:
return String(node.s);
case SerovalNodeType.BigInt:
return node.s;
case SerovalNodeType.Reference:
return getRefParam(this.ctx, node.i);
case SerovalNodeType.Array:
return this.serializeArray(node);
case SerovalNodeType.Object:
return this.assignRef(node.i, this.serializeObject(node.i, node.d));
case SerovalNodeType.NullConstructor:
return this.serializeNullConstructor(node);
case SerovalNodeType.Date:
return this.assignRef(node.i, `new Date("${node.s}")`);
case SerovalNodeType.RegExp:
return this.assignRef(node.i, node.s);
case SerovalNodeType.Set:
return this.serializeSet(node);
case SerovalNodeType.Map:
return this.serializeMap(node);
case SerovalNodeType.BigIntTypedArray:
case SerovalNodeType.TypedArray:
return this.serializeTypedArray(node);
case SerovalNodeType.AggregateError:
return this.serializeAggregateError(node);
case SerovalNodeType.Error:
return this.serializeError(node);
case SerovalNodeType.Iterable:
return this.serializeIterable(node);
case SerovalNodeType.Promise:
return this.serializePromise(node);
default:
throw new Error('Unsupported type');
}
}
return assignRef(ctx, node.i, serialized);
}
export default function serializeTree(
ctx: SerializationContext,
node: SerovalNode,
): string {
switch (node.t) {
case SerovalNodeType.Primitive:
return String(node.s);
case SerovalNodeType.Reference:
return getRefParam(ctx, node.i);
case SerovalNodeType.Promise:
return serializePromise(ctx, node);
case SerovalNodeType.BigInt:
return node.s;
case SerovalNodeType.Date:
return assignRef(ctx, node.i, `new Date("${node.s}")`);
case SerovalNodeType.RegExp:
return assignRef(ctx, node.i, node.s);
case SerovalNodeType.BigIntTypedArray:
case SerovalNodeType.TypedArray:
return serializeTypedArray(ctx, node);
case SerovalNodeType.Set:
return serializeSet(ctx, node);
case SerovalNodeType.Map:
return serializeMap(ctx, node);
case SerovalNodeType.Array:
return serializeArray(ctx, node);
case SerovalNodeType.AggregateError:
return serializeAggregateError(ctx, node);
case SerovalNodeType.Error:
return serializeError(ctx, node);
case SerovalNodeType.Iterable:
return serializeIterable(ctx, node);
case SerovalNodeType.NullConstructor:
return serializeNullConstructor(ctx, node);
case SerovalNodeType.Object:
return assignRef(ctx, node.i, serializeObject(ctx, node.i, node.d));
default:
throw new Error('Unsupported type');
}
}

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

import { SerializationContext } from '../context';
import {

@@ -6,7 +5,2 @@ AsyncServerValue,

} from '../types';
import {
SerovalNode,
SerovalReferenceNode,
SerovalNodeType,
} from './types';

@@ -70,9 +64,2 @@ export function getErrorConstructor(error: ErrorValue) {

export function isReferenceInStack(
ctx: SerializationContext,
node: SerovalNode,
): node is SerovalReferenceNode {
return node.t === SerovalNodeType.Reference && ctx.stack.includes(node.i);
}
export function isIterable(

@@ -79,0 +66,0 @@ value: unknown,

@@ -8,5 +8,10 @@ /* eslint-disable @typescript-eslint/no-use-before-define */

import {
createBigIntNode,
createBigIntTypedArrayNode,
createDateNode,
createPrimitiveNode,
createReferenceNode,
createRegExpNode,
createTypedArrayNode,
FALSE_NODE,
INFINITY_NODE,
NEG_INFINITY_NODE,
NEG_ZERO_NODE,

@@ -26,9 +31,5 @@ NULL_NODE,

SerovalArrayNode,
SerovalBigIntNode,
SerovalBigIntTypedArrayNode,
SerovalDateNode,
SerovalErrorNode,
SerovalIterableNode,
SerovalMapNode,
SerovalMapRecordNode,
SerovalNode,

@@ -39,7 +40,3 @@ SerovalNodeType,

SerovalObjectRecordNode,
SerovalPrimitiveNode,
SerovalReferenceNode,
SerovalRegExpNode,
SerovalSetNode,
SerovalTypedArrayNode,
} from './types';

@@ -80,3 +77,13 @@

generateArrayNode(id: number, current: ServerValue[]): SerovalArrayNode {
return new SerovalArrayNode(id, this.generateNodeList(current));
return {
t: SerovalNodeType.Array,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: this.generateNodeList(current),
n: undefined,
};
}

@@ -112,3 +119,13 @@

}
return new SerovalMapNode(id, new SerovalMapRecordNode(keyNodes, valueNodes, len));
return {
t: SerovalNodeType.Map,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: { k: keyNodes, v: valueNodes, s: len },
a: undefined,
n: undefined,
};
}

@@ -138,3 +155,13 @@

}
return new SerovalSetNode(id, nodes);
return {
t: SerovalNodeType.Set,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: undefined,
a: nodes,
n: undefined,
};
}

@@ -181,10 +208,16 @@

const options = getIterableOptions(current);
return new SerovalIterableNode(
id,
return {
t: SerovalNodeType.Iterable,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
// Parse options first before the items
options
d: options
? this.generateProperties(options as Record<string, ServerValue>)
: undefined,
this.generateNodeList(Array.from(current)),
);
a: this.generateNodeList(Array.from(current)),
n: undefined,
};
}

@@ -200,6 +233,13 @@

}
if (empty) {
return new SerovalNullConstructorNode(id, this.generateProperties(current));
}
return new SerovalObjectNode(id, this.generateProperties(current));
return {
t: empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: this.generateProperties(current),
a: undefined,
n: undefined,
};
}

@@ -215,8 +255,13 @@

: undefined;
return new SerovalAggregateErrorNode(
id,
current.message,
optionsNode,
this.parse(current.errors),
);
return {
t: SerovalNodeType.AggregateError,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: current.message,
d: optionsNode,
a: undefined,
n: this.parse(current.errors),
};
}

@@ -232,3 +277,13 @@

: undefined;
return new SerovalErrorNode(id, getErrorConstructor(current), current.message, optionsNode);
return {
t: SerovalNodeType.Error,
i: id,
s: undefined,
l: undefined,
c: getErrorConstructor(current),
m: current.message,
d: optionsNode,
a: undefined,
n: undefined,
};
}

@@ -243,3 +298,3 @@

case 'string':
return new SerovalPrimitiveNode(quote(current));
return createPrimitiveNode(quote(current));
case 'number':

@@ -250,11 +305,10 @@ if (Object.is(current, -0)) {

if (Object.is(current, Infinity)) {
return INFINITY_NODE;
return createPrimitiveNode('1/0');
}
if (Object.is(current, -Infinity)) {
return NEG_INFINITY_NODE;
return createPrimitiveNode('-1/0');
}
return new SerovalPrimitiveNode(current);
return createPrimitiveNode(current);
case 'bigint':
assert(this.ctx.features & Feature.BigInt, 'Unsupported type "BigInt"');
return new SerovalBigIntNode(current);
return createBigIntNode(this.ctx, current);
case 'object': {

@@ -267,4 +321,4 @@ if (!current) {

const id = createRef(this.ctx, current, true);
if (this.ctx.markedRefs[id]) {
return new SerovalReferenceNode(id);
if (this.ctx.markedRefs.has(id)) {
return createReferenceNode(id);
}

@@ -276,5 +330,5 @@ if (Array.isArray(current)) {

case Date:
return new SerovalDateNode(id, current as Date);
return createDateNode(id, current as Date);
case RegExp:
return new SerovalRegExpNode(id, current as RegExp);
return createRegExpNode(id, current as RegExp);
case Int8Array:

@@ -289,11 +343,6 @@ case Int16Array:

case Float64Array:
assert(this.ctx.features & Feature.TypedArray, `Unsupported value type "${current.constructor.name}"`);
return new SerovalTypedArrayNode(id, current as TypedArrayValue);
return createTypedArrayNode(this.ctx, id, current as TypedArrayValue);
case BigInt64Array:
case BigUint64Array:
assert(
this.ctx.features & (Feature.BigIntTypedArray),
`Unsupported value type "${current.constructor.name}"`,
);
return new SerovalBigIntTypedArrayNode(id, current as BigIntTypedArrayValue);
return createBigIntTypedArrayNode(this.ctx, id, current as BigIntTypedArrayValue);
case Map:

@@ -300,0 +349,0 @@ return this.generateMapNode(id, current as Map<ServerValue, ServerValue>);

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

/* eslint-disable max-classes-per-file */
import { BigIntTypedArrayValue, PrimitiveValue, TypedArrayValue } from '../types';
import { PrimitiveValue } from '../types';

@@ -25,47 +24,31 @@ export const enum SerovalNodeType {

// Type of the node
t?: SerovalNodeType;
t: SerovalNodeType;
// Serialized value
s?: PrimitiveValue;
s: PrimitiveValue | undefined;
// Reference ID
i?: number;
i: number | undefined;
// Size/Byte offset
l?: number;
l: number | undefined;
// Constructor name
c?: string;
c: string | undefined;
// dictionary
d?: SerovalDictionaryNode;
d: SerovalDictionaryNode | undefined;
// message
m?: string;
m: string | undefined;
// next node
n?: SerovalNode;
n: SerovalNode | undefined;
// array of nodes
a?: SerovalNode[];
a: SerovalNode[] | undefined;
}
export class SerovalObjectRecordNode {
export interface SerovalObjectRecordNode {
k: string[];
v: SerovalNode[];
s: number;
constructor(k: string[], v: SerovalNode[], s: number) {
this.k = k;
this.v = v;
this.s = s;
}
}
export class SerovalMapRecordNode {
export interface SerovalMapRecordNode {
k: SerovalNode[];
v: SerovalNode[];
s: number;
constructor(k: SerovalNode[], v: SerovalNode[], s: number) {
this.k = k;
this.v = v;
this.s = s;
}
}

@@ -77,101 +60,42 @@

export class SerovalPrimitiveNode implements SerovalBaseNode {
t: SerovalNodeType.Primitive = SerovalNodeType.Primitive;
s: string | number | null;
constructor(current: string | number | null) {
this.s = current;
}
export interface SerovalPrimitiveNode extends SerovalBaseNode {
t: SerovalNodeType.Primitive;
}
export class SerovalReferenceNode implements SerovalBaseNode {
t: SerovalNodeType.Reference = SerovalNodeType.Reference;
export interface SerovalReferenceNode extends SerovalBaseNode {
t: SerovalNodeType.Reference;
i: number;
constructor(id: number) {
this.i = id;
}
}
export class SerovalBigIntNode implements SerovalBaseNode {
t: SerovalNodeType.BigInt = SerovalNodeType.BigInt;
export interface SerovalBigIntNode extends SerovalBaseNode {
t: SerovalNodeType.BigInt;
s: string;
constructor(current: bigint) {
this.s = `${current}n`;
}
}
export class SerovalDateNode implements SerovalBaseNode {
t: SerovalNodeType.Date = SerovalNodeType.Date;
export interface SerovalDateNode extends SerovalBaseNode {
t: SerovalNodeType.Date;
i: number;
s: string;
constructor(id: number, current: Date) {
this.i = id;
this.s = current.toISOString();
}
}
export class SerovalRegExpNode implements SerovalBaseNode {
t: SerovalNodeType.RegExp = SerovalNodeType.RegExp;
export interface SerovalRegExpNode extends SerovalBaseNode {
t: SerovalNodeType.RegExp;
i: number;
s: string;
constructor(id: number, current: RegExp) {
this.i = id;
this.s = String(current);
}
}
export class SerovalTypedArrayNode implements SerovalBaseNode {
t: SerovalNodeType.TypedArray = SerovalNodeType.TypedArray;
export interface SerovalTypedArrayNode extends SerovalBaseNode {
t: SerovalNodeType.TypedArray;
i: number;
s: string;
l: number;
c: string;
constructor(id: number, current: TypedArrayValue) {
this.i = id;
this.s = current.toString();
this.l = current.byteOffset;
this.c = current.constructor.name;
}
}
export class SerovalBigIntTypedArrayNode implements SerovalBaseNode {
t: SerovalNodeType.BigIntTypedArray = SerovalNodeType.BigIntTypedArray;
export interface SerovalBigIntTypedArrayNode extends SerovalBaseNode {
t: SerovalNodeType.BigIntTypedArray;
i: number;
s: string;
l: number;
c: string;
constructor(id: number, current: BigIntTypedArrayValue) {
let result = '';
const cap = current.length - 1;
for (let i = 0; i < cap; i++) {
result += `${current[i]}n,`;
}
result += `"${current[cap]}"`;
this.i = id;
this.s = result;
this.l = current.byteOffset;
this.c = current.constructor.name;
}
}

@@ -186,132 +110,59 @@

export class SerovalSetNode implements SerovalBaseNode {
t: SerovalNodeType.Set = SerovalNodeType.Set;
export interface SerovalSetNode extends SerovalBaseNode {
t: SerovalNodeType.Set;
a: SerovalNode[];
i: number;
a: SerovalNode[];
constructor(id: number, a: SerovalNode[]) {
this.i = id;
this.a = a;
}
}
export class SerovalMapNode implements SerovalBaseNode {
t: SerovalNodeType.Map = SerovalNodeType.Map;
export interface SerovalMapNode extends SerovalBaseNode {
t: SerovalNodeType.Map;
d: SerovalMapRecordNode;
i: number;
d: SerovalMapRecordNode;
constructor(id: number, d: SerovalMapRecordNode) {
this.i = id;
this.d = d;
}
}
export class SerovalArrayNode implements SerovalBaseNode {
t: SerovalNodeType.Array = SerovalNodeType.Array;
export interface SerovalArrayNode extends SerovalBaseNode {
t: SerovalNodeType.Array;
a: SerovalNode[];
i: number;
a: SerovalNode[];
constructor(id: number, a: SerovalNode[]) {
this.i = id;
this.a = a;
}
}
export class SerovalObjectNode implements SerovalBaseNode {
t: SerovalNodeType.Object = SerovalNodeType.Object;
export interface SerovalObjectNode extends SerovalBaseNode {
t: SerovalNodeType.Object;
d: SerovalObjectRecordNode;
i: number;
}
export interface SerovalNullConstructorNode extends SerovalBaseNode {
t: SerovalNodeType.NullConstructor;
d: SerovalObjectRecordNode;
constructor(id: number, d: SerovalObjectRecordNode) {
this.i = id;
this.d = d;
}
}
export class SerovalNullConstructorNode implements SerovalBaseNode {
t: SerovalNodeType.NullConstructor = SerovalNodeType.NullConstructor;
i: number;
d: SerovalObjectRecordNode;
constructor(id: number, d: SerovalObjectRecordNode) {
this.i = id;
this.d = d;
}
}
export class SerovalPromiseNode implements SerovalBaseNode {
t: SerovalNodeType.Promise = SerovalNodeType.Promise;
export interface SerovalPromiseNode extends SerovalBaseNode {
t: SerovalNodeType.Promise;
n: SerovalNode;
i: number;
n: SerovalNode;
constructor(id: number, n: SerovalNode) {
this.i = id;
this.n = n;
}
}
export class SerovalErrorNode implements SerovalBaseNode {
t: SerovalNodeType.Error = SerovalNodeType.Error;
i: number;
export interface SerovalErrorNode extends SerovalBaseNode {
t: SerovalNodeType.Error;
c: string;
m: string;
d: SerovalObjectRecordNode | undefined;
constructor(id: number, c: string, m: string, d: SerovalObjectRecordNode | undefined) {
this.i = id;
this.c = c;
this.m = m;
this.d = d;
}
i: number;
}
export class SerovalAggregateErrorNode implements SerovalBaseNode {
t: SerovalNodeType.AggregateError = SerovalNodeType.AggregateError;
i: number;
export interface SerovalAggregateErrorNode extends SerovalBaseNode {
t: SerovalNodeType.AggregateError;
m: string;
d: SerovalObjectRecordNode | undefined;
n: SerovalNode;
constructor(id: number, m: string, d: SerovalObjectRecordNode | undefined, n: SerovalNode) {
this.i = id;
this.m = m;
this.d = d;
this.n = n;
}
i: number;
}
export class SerovalIterableNode implements SerovalBaseNode {
t: SerovalNodeType.Iterable = SerovalNodeType.Iterable;
i: number;
export interface SerovalIterableNode extends SerovalBaseNode {
t: SerovalNodeType.Iterable;
d: SerovalObjectRecordNode | undefined;
a: SerovalNode[];
constructor(id: number, d: SerovalObjectRecordNode | undefined, a: SerovalNode[]) {
this.i = id;
this.d = d;
this.a = a;
}
i: number;
}

@@ -318,0 +169,0 @@

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