diff --git a/docs/compatibility.md b/docs/compatibility.md index d745a90f..8df80187 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -46,11 +46,10 @@ By default, all feature flags are enabled. The following are the feature flags a - [`AggregateError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError) - Compiles down to `Error` instead. -- [`ArrayPrototypeValues`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values) - - Used for `Iterable`, uses `Symbol.iterator` instead. - [`ArrowFunction`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) - Uses function expressions for top-level and for deferred `Promise` values - - method shorthands (if `MethodShortand` is not set) or function expressions for `Iterable`. + - Uses function expressions for `Iterable` + - Uses function expressions for `AsyncIterable` - [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) - Disables serialization of `BigInt`, `BigInt64Array` and `BigUint64Array` - [`ErrorPrototypeStack`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack) @@ -58,9 +57,6 @@ By default, all feature flags are enabled. The following are the feature flags a - Affects both `Error` and `AggregateError` - [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) - Disables serialization of `Map` -- [`MethodShorthand`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions) - - Uses function expressions instead. - - Only affects `Iterable` - [`ObjectAssign`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) - Uses manual object assignments instead. - Affects `Iterable`, `Error`, `AggregateError` and `Object.create(null)` @@ -91,9 +87,9 @@ By default, all feature flags are enabled. The following are the feature flags a ## Supported Types -- sync = `serialize`, `toJSON`, `crossSerialize` -- async = `serializeAsync`, `toJSONAsync`, `crossSerializeAsync` -- streaming = `crossSerializeStream`, `Serializer` +- sync = `serialize`, `toJSON`, `crossSerialize`, `toCrossJSON` +- async = `serializeAsync`, `toJSONAsync`, `crossSerializeAsync`, `toCrossJSONAsync` +- streaming = `crossSerializeStream`, `toCrossJSONStream`, `Serializer` | Type | sync | async | streaming | | --- | --- | --- | --- | diff --git a/docs/serialization.md b/docs/serialization.md index 9bc28050..93a2b085 100644 --- a/docs/serialization.md +++ b/docs/serialization.md @@ -9,6 +9,9 @@ - `crossSerialize` - `crossSerializeAsync` - `crossSerializeStream` +- `toCrossJSON` +- `toCrossJSONAsync` +- `toCrossJSONStream` ## Basic serialization @@ -117,8 +120,5 @@ const BufferPlugin = createPlugin({ deserialize(node, ctx) { return Buffer.from(ctx.deserialize(node) as string, 'base64'); }, - isIterable() { - return true; - }, }); ``` diff --git a/packages/seroval/assets/global-header.js b/packages/seroval/assets/global-header.js index 3f4b93a6..82a5764e 100644 --- a/packages/seroval/assets/global-header.js +++ b/packages/seroval/assets/global-header.js @@ -36,17 +36,16 @@ self._$ = self._$ || { uS(stream) { delete stream.c; }, - Se(stream, type, data, controller) { - controller = stream.c; - switch (type) { - case 0: return controller.enqueue(data); - case 1: - this.uS(stream); - return controller.error(data); - case 2: - this.uS(stream); - return controller.close(); - } + Se(stream, data) { + stream.c.enqueue(data); + }, + St(stream, data) { + stream.c.error(data); + this.uS(stream); + }, + Sc(stream) { + stream.c.close(); + this.uS(stream); }, // ReadableStream constructor S(stream, controller) { diff --git a/packages/seroval/src/core/base-primitives.ts b/packages/seroval/src/core/base-primitives.ts index a60e744d..8e63c2a7 100644 --- a/packages/seroval/src/core/base-primitives.ts +++ b/packages/seroval/src/core/base-primitives.ts @@ -1,4 +1,5 @@ -import assert from './assert'; +import type { BigIntTypedArrayValue, TypedArrayValue } from '../types'; +import assert from './utils/assert'; import type { WellKnownSymbols } from './constants'; import { INV_SYMBOL_REF, SerovalNodeType } from './constants'; import { @@ -8,20 +9,34 @@ import { NEG_ZERO_NODE, } from './literals'; import { getReferenceID } from './reference'; +import { getErrorConstructor } from './utils/error'; import { serializeString } from './string'; import type { + SerovalAggregateErrorNode, SerovalArrayBufferNode, + SerovalArrayNode, + SerovalAsyncIteratorFactoryInstanceNode, SerovalBigIntNode, + SerovalBigIntTypedArrayNode, + SerovalBoxedNode, SerovalConstantNode, + SerovalDataViewNode, SerovalDateNode, + SerovalErrorNode, SerovalIndexedValueNode, + SerovalIteratorFactoryInstanceNode, + SerovalNode, SerovalNumberNode, + SerovalObjectRecordNode, SerovalPluginNode, SerovalReferenceNode, SerovalRegExpNode, + SerovalSetNode, SerovalStringNode, + SerovalTypedArrayNode, SerovalWKSymbolNode, } from './types'; +import { getObjectFlag } from './utils/get-object-flag'; export function createNumberNode(value: number): SerovalConstantNode | SerovalNumberNode { switch (value) { @@ -228,3 +243,216 @@ export function createPluginNode( o: undefined, }; } + +export function createArrayNode( + id: number, + current: unknown[], + parsedItems: SerovalNode[], +): SerovalArrayNode { + return { + t: SerovalNodeType.Array, + i: id, + s: undefined, + l: current.length, + c: undefined, + m: undefined, + p: undefined, + e: undefined, + a: parsedItems, + f: undefined, + b: undefined, + o: getObjectFlag(current), + }; +} + +export function createBoxedNode( + id: number, + boxed: SerovalNode, +): SerovalBoxedNode { + return { + t: SerovalNodeType.Boxed, + i: id, + s: undefined, + l: undefined, + c: undefined, + m: undefined, + p: undefined, + e: undefined, + a: undefined, + f: boxed, + b: undefined, + o: undefined, + }; +} + +export function createTypedArrayNode( + id: number, + current: TypedArrayValue, + buffer: SerovalNode, +): SerovalTypedArrayNode { + return { + t: SerovalNodeType.TypedArray, + i: id, + s: undefined, + l: current.length, + c: current.constructor.name, + m: undefined, + p: undefined, + e: undefined, + a: undefined, + f: buffer, + b: current.byteOffset, + o: undefined, + }; +} + +export function createBigIntTypedArrayNode( + id: number, + current: BigIntTypedArrayValue, + buffer: SerovalNode, +): SerovalBigIntTypedArrayNode { + return { + t: SerovalNodeType.BigIntTypedArray, + i: id, + s: undefined, + l: current.length, + c: current.constructor.name, + m: undefined, + p: undefined, + e: undefined, + a: undefined, + f: buffer, + b: current.byteOffset, + o: undefined, + }; +} + +export function createDataViewNode( + id: number, + current: DataView, + buffer: SerovalNode, +): SerovalDataViewNode { + return { + t: SerovalNodeType.DataView, + i: id, + s: undefined, + l: current.byteLength, + c: undefined, + m: undefined, + p: undefined, + e: undefined, + a: undefined, + f: buffer, + b: current.byteOffset, + o: undefined, + }; +} + +export function createErrorNode( + id: number, + current: Error, + options: SerovalObjectRecordNode | undefined, +): SerovalErrorNode { + return { + t: SerovalNodeType.Error, + i: id, + s: getErrorConstructor(current), + l: undefined, + c: undefined, + m: serializeString(current.message), + p: options, + e: undefined, + a: undefined, + f: undefined, + b: undefined, + o: undefined, + }; +} + +export function createAggregateErrorNode( + id: number, + current: AggregateError, + options: SerovalObjectRecordNode | undefined, +): SerovalAggregateErrorNode { + return { + t: SerovalNodeType.AggregateError, + i: id, + s: getErrorConstructor(current), + l: undefined, + c: undefined, + m: serializeString(current.message), + p: options, + e: undefined, + a: undefined, + f: undefined, + b: undefined, + o: undefined, + }; +} + +export function createSetNode( + id: number, + size: number, + items: SerovalNode[], +): SerovalSetNode { + return { + t: SerovalNodeType.Set, + i: id, + s: undefined, + l: size, + c: undefined, + m: undefined, + p: undefined, + e: undefined, + a: items, + f: undefined, + b: undefined, + o: undefined, + }; +} + +export function createIteratorFactoryInstanceNode( + factory: SerovalNode, + items: SerovalNode, +): SerovalIteratorFactoryInstanceNode { + return { + t: SerovalNodeType.IteratorFactoryInstance, + i: undefined, + s: undefined, + l: undefined, + c: undefined, + m: undefined, + p: undefined, + e: undefined, + a: [ + factory, + items, + ], + f: undefined, + b: undefined, + o: undefined, + }; +} + +export function createAsyncIteratorFactoryInstanceNode( + factory: SerovalNode, + items: SerovalNode, +): SerovalAsyncIteratorFactoryInstanceNode { + return { + t: SerovalNodeType.AsyncIteratorFactoryInstance, + i: undefined, + s: undefined, + l: undefined, + c: undefined, + m: undefined, + p: undefined, + e: undefined, + a: [ + factory, + items, + ], + f: undefined, + b: undefined, + o: undefined, + }; +} diff --git a/packages/seroval/src/core/compat.ts b/packages/seroval/src/core/compat.ts index 9b341462..32eaff9d 100644 --- a/packages/seroval/src/core/compat.ts +++ b/packages/seroval/src/core/compat.ts @@ -6,12 +6,10 @@ export const enum Feature { AggregateError = 0x01, - ArrayPrototypeValues = 0x02, ArrowFunction = 0x04, BigInt = 0x08, ErrorPrototypeStack = 0x10, Map = 0x20, - MethodShorthand = 0x40, ObjectAssign = 0x80, Promise = 0x100, Set = 0x200, diff --git a/packages/seroval/src/core/constants.ts b/packages/seroval/src/core/constants.ts index f20ca6d1..17c2e10d 100644 --- a/packages/seroval/src/core/constants.ts +++ b/packages/seroval/src/core/constants.ts @@ -51,6 +51,13 @@ export const enum SerovalNodeType { CustomEvent = 38, DOMException = 39, Plugin = 40, + MapSentinel = 41, + IteratorFactory = 42, + IteratorFactoryInstance = 43, + AsyncIteratorFactory = 44, + AsyncIteratorFactoryInstance = 45, + ReadableStream = 46, + ReadableStreamFactory = 47, } export const enum SerovalObjectFlags { @@ -186,5 +193,3 @@ export const ERROR_CONSTRUCTOR: Record = [ErrorConstructorTag.TypeError]: TypeError, [ErrorConstructorTag.URIError]: URIError, }; - -export const UNIVERSAL_SENTINEL = Symbol('why'); diff --git a/packages/seroval/src/core/tree/deserialize.ts b/packages/seroval/src/core/context/deserializer.ts similarity index 68% rename from packages/seroval/src/core/tree/deserialize.ts rename to packages/seroval/src/core/context/deserializer.ts index 12965b6c..9ee6d506 100644 --- a/packages/seroval/src/core/tree/deserialize.ts +++ b/packages/seroval/src/core/context/deserializer.ts @@ -2,11 +2,11 @@ import { deserializeString } from '../string'; import type { BigIntTypedArrayValue, TypedArrayValue } from '../../types'; import { getReference } from '../reference'; -import { getTypedArrayConstructor } from '../shared'; import type { SerovalAggregateErrorNode, SerovalArrayBufferNode, SerovalArrayNode, + SerovalAsyncIteratorFactoryInstanceNode, SerovalBigIntTypedArrayNode, SerovalBlobNode, SerovalBoxedNode, @@ -19,6 +19,7 @@ import type { SerovalFileNode, SerovalFormDataNode, SerovalHeadersNode, + SerovalIteratorFactoryInstanceNode, SerovalMapNode, SerovalNode, SerovalNullConstructorNode, @@ -26,7 +27,15 @@ import type { SerovalObjectRecordKey, SerovalObjectRecordNode, SerovalPluginNode, + SerovalPromiseConstructorNode, SerovalPromiseNode, + SerovalPromiseRejectNode, + SerovalPromiseResolveNode, + SerovalReadableStreamCloseNode, + SerovalReadableStreamConstructorNode, + SerovalReadableStreamEnqueueNode, + SerovalReadableStreamErrorNode, + SerovalReadableStreamNode, SerovalReferenceNode, SerovalRegExpNode, SerovalRequestNode, @@ -36,9 +45,6 @@ import type { SerovalURLNode, SerovalURLSearchParamsNode, } from '../types'; -import { - SerovalObjectRecordSpecialKey, -} from '../types'; import { CONSTANT_VAL, ERROR_CONSTRUCTOR, @@ -46,7 +52,18 @@ import { SerovalNodeType, SerovalObjectFlags, } from '../constants'; -import type { Plugin, PluginAccessOptions } from '../plugin'; +import type { Plugin, PluginAccessOptions, SerovalMode } from '../plugin'; +import type { Sequence, SerializedAsyncIteratorResult } from '../utils/iterator-to-sequence'; +import { + readableStreamToAsyncIterator, + sequenceToAsyncIterator, + sequenceToIterator, + sequenceToReadableStream, +} from '../utils/iterator-to-sequence'; +import { getTypedArrayConstructor } from '../utils/typed-array'; +import type { Deferred, DeferredStream } from '../utils/deferred'; +import { createDeferred, createDeferredStream } from '../utils/deferred'; +import assert from '../utils/assert'; function applyObjectFlag(obj: unknown, flag: SerovalObjectFlags): unknown { switch (flag) { @@ -64,62 +81,30 @@ function applyObjectFlag(obj: unknown, flag: SerovalObjectFlags): unknown { type AssignableValue = AggregateError | Error | Iterable type AssignableNode = SerovalAggregateErrorNode | SerovalErrorNode; -interface Deferred { - resolve(value: unknown): void; - reject(value: unknown): void; - promise: Promise; +export interface BaseDeserializerOptions extends PluginAccessOptions { + refs?: Map; } -function createDeferred(): Deferred { - let resolve: Deferred['resolve']; - let reject: Deferred['reject']; - return { - resolve(v): void { - resolve(v); - }, - reject(v): void { - reject(v); - }, - promise: new Promise((res, rej) => { - resolve = res as Deferred['resolve']; - reject = rej as Deferred['reject']; - }), - }; -} +export default abstract class BaseDeserializerContext implements PluginAccessOptions { + abstract readonly mode: SerovalMode; -export interface DeserializerOptions extends PluginAccessOptions { - markedRefs: number[] | Set; -} - -export default class VanillaDeserializerContext implements PluginAccessOptions { /** * Mapping ids to values * @private */ - values: Map = new Map(); - - /** - * Which refs are pre-marked - * @private - */ - refs: Set; + refs: Map; plugins?: Plugin[] | undefined; - constructor(options: DeserializerOptions) { + constructor(options: BaseDeserializerOptions) { this.plugins = options.plugins; - this.refs = new Set(options.markedRefs); + this.refs = options.refs || new Map(); } - assignIndexedValue( - index: number, + protected abstract assignIndexedValue( + id: number, value: T, - ): T { - if (this.refs.has(index)) { - this.values.set(index, value); - } - return value; - } + ): T; private deserializeReference( node: SerovalReferenceNode, @@ -152,22 +137,14 @@ export default class VanillaDeserializerContext implements PluginAccessOptions { ): Record { 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++) { + for (let i = 0, key: SerovalObjectRecordKey; i < len; i++) { key = keys[i]; - value = this.deserialize(vals[i]); - switch (key) { - case SerovalObjectRecordSpecialKey.SymbolIterator: { - const current = value as unknown[]; - result[Symbol.iterator] = (): IterableIterator => current.values(); - } - break; - default: - result[deserializeString(key)] = value; - break; + if (typeof key === 'string') { + result[deserializeString(key)] = this.deserialize(vals[i]); + } else { + result[this.deserialize(key) as symbol] = this.deserialize(vals[i]); } } } @@ -302,14 +279,14 @@ export default class VanillaDeserializerContext implements PluginAccessOptions { node: SerovalPromiseNode, ): Promise { const deferred = createDeferred(); - const result = this.assignIndexedValue(node.i, deferred.promise); + const result = this.assignIndexedValue(node.i, deferred); const deserialized = this.deserialize(node.f); if (node.s) { deferred.resolve(deserialized); } else { deferred.reject(deserialized); } - return result; + return result.promise; } private deserializeURL( @@ -449,15 +426,107 @@ export default class VanillaDeserializerContext implements PluginAccessOptions { for (let i = 0, len = currentPlugins.length; i < len; i++) { const plugin = currentPlugins[i]; if (plugin.tag === node.c) { - return plugin.deserialize(node.s, this, { - id: node.i, - }); + return this.assignIndexedValue( + node.i, + plugin.deserialize(node.s, this, { + id: node.i, + }), + ); } } } throw new Error('Missing plugin for tag "' + node.c + '".'); } + private deserializePromiseConstructor(node: SerovalPromiseConstructorNode): unknown { + return this.assignIndexedValue( + node.i, + createDeferred(), + ).promise; + } + + private deserializePromiseResolve(node: SerovalPromiseResolveNode): unknown { + const deferred = this.refs.get(node.i) as Deferred | undefined; + assert(deferred, new Error('Missing Promise instance.')); + deferred.resolve( + this.deserialize(node.f), + ); + return undefined; + } + + private deserializePromiseReject(node: SerovalPromiseRejectNode): unknown { + const deferred = this.refs.get(node.i) as Deferred | undefined; + assert(deferred, new Error('Missing Promise instance.')); + deferred.reject( + this.deserialize(node.f), + ); + return undefined; + } + + private deserializeReadableStreamConstructor( + node: SerovalReadableStreamConstructorNode, + ): unknown { + return this.assignIndexedValue( + node.i, + createDeferredStream(), + ).stream; + } + + private deserializeReadableStreamEnqueue(node: SerovalReadableStreamEnqueueNode): unknown { + const deferred = this.refs.get(node.i) as DeferredStream | undefined; + assert(deferred, new Error('Missing ReadableStream instance.')); + deferred.enqueue( + this.deserialize(node.f), + ); + return undefined; + } + + private deserializeReadableStreamError(node: SerovalReadableStreamErrorNode): unknown { + const deferred = this.refs.get(node.i) as DeferredStream | undefined; + assert(deferred, new Error('Missing Promise instance.')); + deferred.error( + this.deserialize(node.f), + ); + return undefined; + } + + private deserializeReadableStreamClose(node: SerovalReadableStreamCloseNode): unknown { + const deferred = this.refs.get(node.i) as DeferredStream | undefined; + assert(deferred, new Error('Missing Promise instance.')); + deferred.close(); + return undefined; + } + + private deserializeIteratorFactoryInstance( + node: SerovalIteratorFactoryInstanceNode, + ): unknown { + const source = this.deserialize(node.a[1]); + return sequenceToIterator(source as Sequence); + } + + private deserializeAsyncIteratorFactoryInstance( + node: SerovalAsyncIteratorFactoryInstanceNode, + ): unknown { + const source = this.deserialize(node.a[1]); + if ((source as object).constructor === ReadableStream) { + return readableStreamToAsyncIterator( + source as ReadableStream>, + ); + } + return sequenceToAsyncIterator(source as Sequence); + } + + private deserializeReadableStream( + node: SerovalReadableStreamNode, + ): unknown { + return this.assignIndexedValue( + node.i, + sequenceToReadableStream( + this.deserialize(node.a[1]) as Sequence, + ), + ); + } + deserialize(node: SerovalNode): unknown { switch (node.t) { case SerovalNodeType.Constant: @@ -469,7 +538,7 @@ export default class VanillaDeserializerContext implements PluginAccessOptions { case SerovalNodeType.BigInt: return BigInt(node.s); case SerovalNodeType.IndexedValue: - return this.values.get(node.i); + return this.refs.get(node.i); case SerovalNodeType.Reference: return this.deserializeReference(node); case SerovalNodeType.Array: @@ -526,6 +595,30 @@ export default class VanillaDeserializerContext implements PluginAccessOptions { return this.deserializeDOMException(node); case SerovalNodeType.Plugin: return this.deserializePlugin(node); + case SerovalNodeType.PromiseConstructor: + return this.deserializePromiseConstructor(node); + case SerovalNodeType.PromiseResolve: + return this.deserializePromiseResolve(node); + case SerovalNodeType.PromiseReject: + return this.deserializePromiseReject(node); + case SerovalNodeType.ReadableStreamConstructor: + return this.deserializeReadableStreamConstructor(node); + case SerovalNodeType.ReadableStreamEnqueue: + return this.deserializeReadableStreamEnqueue(node); + case SerovalNodeType.ReadableStreamError: + return this.deserializeReadableStreamError(node); + case SerovalNodeType.ReadableStreamClose: + return this.deserializeReadableStreamClose(node); + case SerovalNodeType.IteratorFactoryInstance: + return this.deserializeIteratorFactoryInstance(node); + case SerovalNodeType.AsyncIteratorFactoryInstance: + return this.deserializeAsyncIteratorFactoryInstance(node); + case SerovalNodeType.ReadableStream: + return this.deserializeReadableStream(node); + case SerovalNodeType.MapSentinel: + case SerovalNodeType.IteratorFactory: + case SerovalNodeType.AsyncIteratorFactory: + case SerovalNodeType.ReadableStreamFactory: default: throw new Error('invariant'); } diff --git a/packages/seroval/src/core/context/parser.ts b/packages/seroval/src/core/context/parser.ts new file mode 100644 index 00000000..41a48457 --- /dev/null +++ b/packages/seroval/src/core/context/parser.ts @@ -0,0 +1,259 @@ +import UnsupportedTypeError from '../UnsupportedTypeError'; +import assert from '../utils/assert'; +import { + createIndexedValueNode, + createReferenceNode, + createWKSymbolNode, +} from '../base-primitives'; +import { ALL_ENABLED, Feature } from '../compat'; +import type { WellKnownSymbols } from '../constants'; +import { + INV_SYMBOL_REF, + SerovalNodeType, +} from '../constants'; +import type { Plugin, PluginAccessOptions, SerovalMode } from '../plugin'; +import { hasReferenceID } from '../reference'; +import { + ASYNC_ITERATOR, + ITERATOR, + MAP_SENTINEL, + READABLE_STREAM, +} from '../special-reference'; +import type { + SerovalAsyncIteratorFactoryNode, + SerovalIndexedValueNode, + SerovalIteratorFactoryNode, + SerovalMapNode, + SerovalMapSentinelNode, + SerovalNode, + SerovalNullConstructorNode, + SerovalObjectNode, + SerovalObjectRecordNode, + SerovalReadableStreamFactoryNode, + SerovalReferenceNode, + SerovalWKSymbolNode, +} from '../types'; +import { getObjectFlag } from '../utils/get-object-flag'; + +export interface BaseParserContextOptions extends PluginAccessOptions { + disabledFeatures?: number; + refs?: Map; +} + +export abstract class BaseParserContext implements PluginAccessOptions { + abstract readonly mode: SerovalMode; + + features: number; + + marked = new Set(); + + refs: Map; + + plugins?: Plugin[] | undefined; + + constructor(options: BaseParserContextOptions) { + this.plugins = options.plugins; + this.features = ALL_ENABLED ^ (options.disabledFeatures || 0); + this.refs = options.refs || new Map(); + } + + protected markRef(id: number): void { + this.marked.add(id); + } + + protected isMarked(id: number): boolean { + return this.marked.has(id); + } + + protected getReference(current: T): number | SerovalIndexedValueNode | SerovalReferenceNode { + const registeredID = this.refs.get(current); + if (registeredID != null) { + this.markRef(registeredID); + return createIndexedValueNode(registeredID); + } + const id = this.refs.size; + this.refs.set(current, id); + if (hasReferenceID(current)) { + return createReferenceNode(id, current); + } + return id; + } + + protected getStrictReference(current: T): SerovalIndexedValueNode | SerovalReferenceNode { + const registeredID = this.refs.get(current); + if (registeredID != null) { + this.markRef(registeredID); + return createIndexedValueNode(registeredID); + } + const id = this.refs.size; + this.refs.set(current, id); + return createReferenceNode(id, current); + } + + // eslint-disable-next-line @typescript-eslint/ban-types + protected parseFunction(current: Function): SerovalNode { + assert(hasReferenceID(current), new Error('Cannot serialize function without reference ID.')); + return this.getStrictReference(current); + } + + protected parseWKSymbol( + current: symbol, + ): SerovalIndexedValueNode | SerovalWKSymbolNode | SerovalReferenceNode { + assert(this.features & Feature.Symbol, new UnsupportedTypeError(current)); + const registeredID = this.refs.get(current); + if (registeredID != null) { + this.markRef(registeredID); + return createIndexedValueNode(registeredID); + } + const isValid = current in INV_SYMBOL_REF; + assert(current in INV_SYMBOL_REF || hasReferenceID(current), new Error('Cannot serialize symbol without reference ID.')); + const id = this.refs.size; + this.refs.set(current, id); + if (isValid) { + return createWKSymbolNode(id, current as WellKnownSymbols); + } + return createReferenceNode(id, current); + } + + protected parseMapSentinel(): SerovalIndexedValueNode | SerovalMapSentinelNode { + const registeredID = this.refs.get(MAP_SENTINEL); + if (registeredID != null) { + this.markRef(registeredID); + return createIndexedValueNode(registeredID); + } + const id = this.refs.size; + this.refs.set(MAP_SENTINEL, id); + return { + t: SerovalNodeType.MapSentinel, + i: id, + s: undefined, + l: undefined, + c: undefined, + m: undefined, + p: undefined, + e: undefined, + a: undefined, + f: undefined, + b: undefined, + o: undefined, + }; + } + + protected parseIteratorFactory(): SerovalIndexedValueNode | SerovalIteratorFactoryNode { + const registeredID = this.refs.get(ITERATOR); + if (registeredID != null) { + this.markRef(registeredID); + return createIndexedValueNode(registeredID); + } + const id = this.refs.size; + this.refs.set(ITERATOR, id); + return { + t: SerovalNodeType.IteratorFactory, + i: id, + s: undefined, + l: undefined, + c: undefined, + m: undefined, + p: undefined, + e: undefined, + a: undefined, + f: this.parseWKSymbol(Symbol.iterator), + b: undefined, + o: undefined, + }; + } + + protected parseAsyncIteratorFactory(): SerovalIndexedValueNode | SerovalAsyncIteratorFactoryNode { + const registeredID = this.refs.get(ASYNC_ITERATOR); + if (registeredID != null) { + this.markRef(registeredID); + return createIndexedValueNode(registeredID); + } + const id = this.refs.size; + this.refs.set(ASYNC_ITERATOR, id); + return { + t: SerovalNodeType.AsyncIteratorFactory, + i: id, + s: undefined, + l: undefined, + c: undefined, + m: undefined, + p: undefined, + e: undefined, + a: undefined, + f: this.parseWKSymbol(Symbol.asyncIterator), + b: undefined, + o: undefined, + }; + } + + protected createObjectNode( + id: number, + current: Record, + empty: boolean, + record: SerovalObjectRecordNode, + ): SerovalObjectNode | SerovalNullConstructorNode { + return { + t: empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object, + i: id, + s: undefined, + l: undefined, + c: undefined, + m: undefined, + p: record, + e: undefined, + a: undefined, + f: undefined, + b: undefined, + o: getObjectFlag(current), + }; + } + + protected createMapNode( + id: number, + k: SerovalNode[], + v: SerovalNode[], + s: number, + ): SerovalMapNode { + return { + t: SerovalNodeType.Map, + i: id, + s: undefined, + l: undefined, + c: undefined, + m: undefined, + p: undefined, + e: { k, v, s }, + a: undefined, + f: this.parseMapSentinel(), + b: undefined, + o: undefined, + }; + } + + protected parseReadableStreamFactory(): ( + SerovalIndexedValueNode | SerovalReadableStreamFactoryNode + ) { + const registeredID = this.refs.get(READABLE_STREAM); + if (registeredID != null) { + this.markRef(registeredID); + return createIndexedValueNode(registeredID); + } + const id = this.refs.size; + this.refs.set(READABLE_STREAM, id); + return { + t: SerovalNodeType.ReadableStreamFactory, + i: id, + s: undefined, + l: undefined, + c: undefined, + m: undefined, + p: undefined, + e: undefined, + a: undefined, + f: undefined, + b: undefined, + o: undefined, + }; + } +} diff --git a/packages/seroval/src/core/base/async.ts b/packages/seroval/src/core/context/parser/async.ts similarity index 63% rename from packages/seroval/src/core/base/async.ts rename to packages/seroval/src/core/context/parser/async.ts index 108bbf17..a642d9a5 100644 --- a/packages/seroval/src/core/base/async.ts +++ b/packages/seroval/src/core/context/parser/async.ts @@ -1,39 +1,48 @@ /* eslint-disable prefer-destructuring */ /* eslint-disable no-await-in-loop */ -import type { BigIntTypedArrayValue, TypedArrayValue } from '../../types'; -import UnsupportedTypeError from '../UnsupportedTypeError'; -import assert from '../assert'; +import type { BigIntTypedArrayValue, TypedArrayValue } from '../../../types'; +import UnsupportedTypeError from '../../UnsupportedTypeError'; +import assert from '../../utils/assert'; import { createPluginNode, createDateNode, createRegExpNode, createArrayBufferNode, - createWKSymbolNode, createBigIntNode, createStringNode, createNumberNode, -} from '../base-primitives'; -import { BIGINT_FLAG, Feature } from '../compat'; -import type { WellKnownSymbols } from '../constants'; -import { SerovalNodeType, UNIVERSAL_SENTINEL } from '../constants'; + createArrayNode, + createBoxedNode, + createTypedArrayNode, + createBigIntTypedArrayNode, + createDataViewNode, + createErrorNode, + createSetNode, + createAggregateErrorNode, + createIteratorFactoryInstanceNode, + createAsyncIteratorFactoryInstanceNode, +} from '../../base-primitives'; +import { BIGINT_FLAG, Feature } from '../../compat'; +import { + SerovalNodeType, +} from '../../constants'; import { createRequestOptions, createResponseOptions, createEventOptions, createCustomEventOptions, -} from '../constructors'; +} from '../../utils/constructors'; import { NULL_NODE, TRUE_NODE, FALSE_NODE, UNDEFINED_NODE, -} from '../literals'; -import { BaseParserContext } from '../parser-context'; -import promiseToResult from '../promise-to-result'; -import { hasReferenceID } from '../reference'; -import { getErrorConstructor, getErrorOptions, getObjectFlag } from '../shared'; -import { serializeString } from '../string'; -import { SerovalObjectRecordSpecialKey } from '../types'; +} from '../../literals'; +import { asyncIteratorToSequence, iteratorToSequence, readableStreamToSequence } from '../../utils/iterator-to-sequence'; +import { BaseParserContext } from '../parser'; +import promiseToResult from '../../utils/promise-to-result'; +import { getErrorOptions } from '../../utils/error'; +import { serializeString } from '../../string'; import type { SerovalErrorNode, SerovalArrayNode, @@ -60,8 +69,17 @@ import type { SerovalResponseNode, SerovalSetNode, SerovalDataViewNode, -} from '../types'; -import { createURLNode, createURLSearchParamsNode, createDOMExceptionNode } from '../web-api'; + SerovalReadableStreamNode, +} from '../../types'; +import { + createURLNode, + createURLSearchParamsNode, + createDOMExceptionNode, + createEventNode, + createCustomEventNode, + createReadableStreamNode, +} from '../../web-api'; +import { UNIVERSAL_SENTINEL } from '../../special-reference'; type ObjectLikeNode = | SerovalObjectNode @@ -72,22 +90,10 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext { private async parseItems( current: unknown[], ): Promise { - const size = current.length; const nodes = []; - const deferred = []; - for (let i = 0, item: unknown; i < size; i++) { + for (let i = 0, len = current.length; i < len; i++) { if (i in current) { - item = current[i]; - if (this.isIterable(item)) { - deferred[i] = item; - } else { - nodes[i] = await this.parse(item); - } - } - } - for (let i = 0; i < size; i++) { - if (i in deferred) { - nodes[i] = await this.parse(deferred[i]); + nodes[i] = await this.parse(current[i]); } } return nodes; @@ -97,136 +103,66 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext { id: number, current: unknown[], ): Promise { - return { - t: SerovalNodeType.Array, - i: id, - s: undefined, - l: current.length, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: await this.parseItems(current), - f: undefined, - b: undefined, - o: getObjectFlag(current), - }; - } - - private async parseBoxed( - id: number, - current: object, - ): Promise { - return { - t: SerovalNodeType.Boxed, - i: id, - s: undefined, - l: undefined, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: await this.parse(current.valueOf()), - b: undefined, - o: undefined, - }; - } - - private async parseTypedArray( - id: number, - current: TypedArrayValue, - ): Promise { - return { - t: SerovalNodeType.TypedArray, - i: id, - s: undefined, - l: current.length, - c: current.constructor.name, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: await this.parse(current.buffer), - b: current.byteOffset, - o: undefined, - }; - } - - private async parseBigIntTypedArray( - id: number, - current: BigIntTypedArrayValue, - ): Promise { - return { - t: SerovalNodeType.BigIntTypedArray, - i: id, - s: undefined, - l: current.length, - c: current.constructor.name, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: await this.parse(current.buffer), - b: current.byteOffset, - o: undefined, - }; - } - - private async parseDataView( - id: number, - current: DataView, - ): Promise { - return { - t: SerovalNodeType.DataView, - i: id, - s: undefined, - l: current.byteLength, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: await this.parse(current.buffer), - b: current.byteOffset, - o: undefined, - }; + return createArrayNode( + id, + current, + await this.parseItems(current), + ); } private async parseProperties( - properties: Record, + properties: Record, ): Promise { const entries = Object.entries(properties); const keyNodes: SerovalObjectRecordKey[] = []; const valueNodes: SerovalNode[] = []; - const deferredKeys: string[] = []; - const deferredValues: unknown[] = []; for ( - let i = 0, len = entries.length, key: string, item: unknown; + let i = 0, len = entries.length; i < len; i++ ) { - key = serializeString(entries[i][0]); - item = entries[i][1]; - // Defer iterables since iterables have lazy evaluation. - // Of course this doesn't include types seroval supports. - if (this.isIterable(item)) { - deferredKeys.push(key); - deferredValues.push(item); - } else { - keyNodes.push(key); - valueNodes.push(await this.parse(item)); - } - } - for (let i = 0, len = deferredKeys.length; i < len; i++) { - keyNodes.push(deferredKeys[i]); - valueNodes.push(await this.parse(deferredValues[i])); + keyNodes.push(serializeString(entries[i][0])); + valueNodes.push(await this.parse(entries[i][1])); } // Check special properties if (this.features & Feature.Symbol) { - if (Symbol.iterator in properties) { - keyNodes.push(SerovalObjectRecordSpecialKey.SymbolIterator); - valueNodes.push(await this.parse(Array.from(properties as Iterable))); + let symbol = Symbol.iterator; + if (symbol in properties) { + keyNodes.push( + this.parseWKSymbol(symbol), + ); + valueNodes.push( + createIteratorFactoryInstanceNode( + this.parseIteratorFactory(), + await this.parse( + iteratorToSequence(properties as unknown as Iterable), + ), + ), + ); + } + symbol = Symbol.asyncIterator; + if (symbol in properties) { + keyNodes.push( + this.parseWKSymbol(symbol), + ); + valueNodes.push( + createAsyncIteratorFactoryInstanceNode( + this.parseAsyncIteratorFactory(), + await this.parse( + await asyncIteratorToSequence(properties as unknown as AsyncIterable), + ), + ), + ); + } + symbol = Symbol.toStringTag; + if (symbol in properties) { + keyNodes.push(this.parseWKSymbol(symbol)); + valueNodes.push(createStringNode(properties[symbol] as string)); + } + symbol = Symbol.isConcatSpreadable; + if (symbol in properties) { + keyNodes.push(this.parseWKSymbol(symbol)); + valueNodes.push(properties[symbol] ? TRUE_NODE : FALSE_NODE); } } return { @@ -241,20 +177,40 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext { current: Record, empty: boolean, ): Promise { - return { - t: empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object, - i: id, - s: undefined, - l: undefined, - c: undefined, - m: undefined, - p: await this.parseProperties(current), - e: undefined, - a: undefined, - f: undefined, - b: undefined, - o: getObjectFlag(current), - }; + return this.createObjectNode( + id, + current, + empty, + await this.parseProperties(current), + ); + } + + private async parseBoxed( + id: number, + current: object, + ): Promise { + return createBoxedNode(id, await this.parse(current.valueOf())); + } + + private async parseTypedArray( + id: number, + current: TypedArrayValue, + ): Promise { + return createTypedArrayNode(id, current, await this.parse(current.buffer)); + } + + private async parseBigIntTypedArray( + id: number, + current: BigIntTypedArrayValue, + ): Promise { + return createBigIntTypedArrayNode(id, current, await this.parse(current.buffer)); + } + + private async parseDataView( + id: number, + current: DataView, + ): Promise { + return createDataViewNode(id, current, await this.parse(current.buffer)); } private async parseError( @@ -262,23 +218,27 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext { current: Error, ): Promise { const options = getErrorOptions(current, this.features); - const optionsNode = options - ? await this.parseProperties(options) - : undefined; - return { - t: SerovalNodeType.Error, - i: id, - s: getErrorConstructor(current), - l: undefined, - c: undefined, - m: serializeString(current.message), - p: optionsNode, - e: undefined, - a: undefined, - f: undefined, - b: undefined, - o: undefined, - }; + return createErrorNode( + id, + current, + options + ? await this.parseProperties(options) + : undefined, + ); + } + + private async parseAggregateError( + id: number, + current: AggregateError, + ): Promise { + const options = getErrorOptions(current, this.features); + return createAggregateErrorNode( + id, + current, + options + ? await this.parseProperties(options) + : undefined, + ); } private async parseMap( @@ -287,70 +247,27 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext { ): Promise { const keyNodes: SerovalNode[] = []; const valueNodes: SerovalNode[] = []; - const deferredKey: unknown[] = []; - const deferredValue: unknown[] = []; for (const [key, value] of current.entries()) { - // Either key or value might be an iterable - if (this.isIterable(key) || this.isIterable(value)) { - deferredKey.push(key); - deferredValue.push(value); - } else { - keyNodes.push(await this.parse(key)); - valueNodes.push(await this.parse(value)); - } + keyNodes.push(await this.parse(key)); + valueNodes.push(await this.parse(value)); } - for (let i = 0, len = deferredKey.length; i < len; i++) { - keyNodes.push(await this.parse(deferredKey[i])); - valueNodes.push(await this.parse(deferredValue[i])); - } - return { - t: SerovalNodeType.Map, - i: id, - s: undefined, - l: undefined, - c: undefined, - m: undefined, - p: undefined, - e: { k: keyNodes, v: valueNodes, s: current.size }, - a: undefined, - f: undefined, - b: undefined, - o: undefined, - }; + return this.createMapNode( + id, + keyNodes, + valueNodes, + current.size, + ); } private async parseSet( id: number, current: Set, ): Promise { - const nodes: SerovalNode[] = []; - const deferred: unknown[] = []; + const items: SerovalNode[] = []; for (const item of current.keys()) { - // Iterables are lazy, so the evaluation must be deferred - if (this.isIterable(item)) { - deferred.push(item); - } else { - nodes.push(await this.parse(item)); - } + items.push(await this.parse(item)); } - // Parse deferred items - for (let i = 0, len = deferred.length; i < len; i++) { - nodes.push(await this.parse(deferred[i])); - } - return { - t: SerovalNodeType.Set, - i: id, - s: undefined, - l: current.size, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: nodes, - f: undefined, - b: undefined, - o: undefined, - }; + return createSetNode(id, current.size, items); } private async parseBlob( @@ -399,22 +316,9 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext { const size = entries.length; const keyNodes: string[] = []; const valueNodes: SerovalNode[] = []; - const deferredKeys: string[] = []; - const deferredValues: unknown[] = []; - for (let i = 0, key: string, item: unknown; i < size; i++) { - key = serializeString(entries[i][0]); - item = entries[i][1]; - if (this.isIterable(item)) { - deferredKeys.push(key); - deferredValues.push(item); - } else { - keyNodes.push(key); - valueNodes.push(await this.parse(item)); - } - } - for (let i = 0, len = deferredKeys.length; i < len; i++) { - keyNodes.push(deferredKeys[i]); - valueNodes.push(await this.parse(deferredValues[i])); + for (let i = 0; i < size; i++) { + keyNodes.push(serializeString(entries[i][0])); + valueNodes.push(await this.parse(entries[i][1])); } return { k: keyNodes, @@ -522,64 +426,18 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext { id: number, current: Event, ): Promise { - return { - t: SerovalNodeType.Event, - i: id, - s: serializeString(current.type), - l: undefined, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: await this.parse(createEventOptions(current)), - b: undefined, - o: undefined, - }; + return createEventNode(id, current.type, await this.parse(createEventOptions(current))); } private async parseCustomEvent( id: number, current: CustomEvent, ): Promise { - return { - t: SerovalNodeType.CustomEvent, - i: id, - s: serializeString(current.type), - l: undefined, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: await this.parse(createCustomEventOptions(current)), - b: undefined, - o: undefined, - }; - } - - private async parseAggregateError( - id: number, - current: AggregateError, - ): Promise { - const options = getErrorOptions(current, this.features); - const optionsNode = options - ? await this.parseProperties(options) - : undefined; - return { - t: SerovalNodeType.AggregateError, - i: id, - s: undefined, - l: undefined, - c: undefined, - m: serializeString(current.message), - p: optionsNode, - e: undefined, - a: undefined, - f: undefined, - b: undefined, - o: undefined, - }; + return createCustomEventNode( + id, + current.type, + await this.parse(createCustomEventOptions(current)), + ); } private async parsePromise( @@ -625,6 +483,19 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext { return undefined; } + private async parseReadableStream( + id: number, + current: ReadableStream, + ): Promise { + return createReadableStreamNode( + id, + this.parseReadableStreamFactory(), + await this.parse( + await readableStreamToSequence(current), + ), + ); + } + private async parseObject( id: number, current: object, @@ -743,6 +614,8 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext { return this.parseCustomEvent(id, current as unknown as CustomEvent); case (typeof DOMException !== 'undefined' ? DOMException : UNIVERSAL_SENTINEL): return createDOMExceptionNode(id, current as unknown as DOMException); + case (typeof ReadableStream !== 'undefined' ? ReadableStream : UNIVERSAL_SENTINEL): + return this.parseReadableStream(id, current as unknown as ReadableStream); default: break; } @@ -765,7 +638,10 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext { } // Generator functions don't have a global constructor // despite existing - if (currentFeatures & Feature.Symbol && Symbol.iterator in current) { + if ( + currentFeatures & Feature.Symbol + && (Symbol.iterator in current || Symbol.asyncIterator in current) + ) { return this.parsePlainObject(id, current, !!currentClass); } throw new UnsupportedTypeError(current); @@ -789,14 +665,10 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext { const id = this.getReference(current); return typeof id === 'number' ? this.parseObject(id, current as object) : id; } - case 'symbol': { - assert(this.features & Feature.Symbol, new UnsupportedTypeError(current)); - const id = this.getReference(current); - return typeof id === 'number' ? createWKSymbolNode(id, current as WellKnownSymbols) : id; - } + case 'symbol': + return this.parseWKSymbol(current); case 'function': - assert(hasReferenceID(current), new Error('Cannot serialize function without reference ID.')); - return this.getStrictReference(current); + return this.parseFunction(current); default: throw new UnsupportedTypeError(current); } diff --git a/packages/seroval/src/core/base/stream.ts b/packages/seroval/src/core/context/parser/stream.ts similarity index 82% rename from packages/seroval/src/core/base/stream.ts rename to packages/seroval/src/core/context/parser/stream.ts index 5a4e59c1..0866a0ce 100644 --- a/packages/seroval/src/core/base/stream.ts +++ b/packages/seroval/src/core/context/parser/stream.ts @@ -1,27 +1,34 @@ -import type { BigIntTypedArrayValue, TypedArrayValue } from '../../types'; -import UnsupportedTypeError from '../UnsupportedTypeError'; +import type { BigIntTypedArrayValue, TypedArrayValue } from '../../../types'; +import UnsupportedTypeError from '../../UnsupportedTypeError'; import { createArrayBufferNode, + createAsyncIteratorFactoryInstanceNode, createDateNode, + createIteratorFactoryInstanceNode, createPluginNode, createRegExpNode, -} from '../base-primitives'; + createStringNode, +} from '../../base-primitives'; import type { BaseSyncParserContextOptions } from './sync'; import BaseSyncParserContext from './sync'; -import { BIGINT_FLAG, Feature } from '../compat'; -import { SerovalNodeType, UNIVERSAL_SENTINEL } from '../constants'; -import { createRequestOptions, createResponseOptions } from '../constructors'; -import { NULL_NODE } from '../literals'; -import { serializeString } from '../string'; +import { BIGINT_FLAG, Feature } from '../../compat'; +import { SerovalNodeType } from '../../constants'; +import { createRequestOptions, createResponseOptions } from '../../utils/constructors'; +import { FALSE_NODE, NULL_NODE, TRUE_NODE } from '../../literals'; +import { serializeString } from '../../string'; import type { SerovalNode, + SerovalObjectRecordKey, + SerovalObjectRecordNode, SerovalPluginNode, SerovalPromiseConstructorNode, SerovalReadableStreamConstructorNode, SerovalRequestNode, SerovalResponseNode, -} from '../types'; -import { createDOMExceptionNode, createURLNode, createURLSearchParamsNode } from '../web-api'; +} from '../../types'; +import { createDOMExceptionNode, createURLNode, createURLSearchParamsNode } from '../../web-api'; +import { asyncIteratorToReadableStream, iteratorToSequence } from '../../utils/iterator-to-sequence'; +import { UNIVERSAL_SENTINEL } from '../../special-reference'; export interface BaseStreamParserContextOptions extends BaseSyncParserContextOptions { onParse: (node: SerovalNode, initial: boolean) => void; @@ -84,6 +91,71 @@ export default abstract class BaseStreamParserContext extends BaseSyncParserCont } } + protected parseProperties( + properties: Record, + ): SerovalObjectRecordNode { + const entries = Object.entries(properties); + const keyNodes: SerovalObjectRecordKey[] = []; + const valueNodes: SerovalNode[] = []; + for ( + let i = 0, len = entries.length; + i < len; + i++ + ) { + keyNodes.push(serializeString(entries[i][0])); + valueNodes.push(this.parse(entries[i][1])); + } + // Check special properties, symbols in this case + if (this.features & Feature.Symbol) { + let symbol = Symbol.iterator; + if (symbol in properties) { + keyNodes.push( + this.parseWKSymbol(symbol), + ); + valueNodes.push( + createIteratorFactoryInstanceNode( + this.parseIteratorFactory(), + this.parse( + iteratorToSequence(properties as unknown as Iterable), + ), + ), + ); + } + symbol = Symbol.asyncIterator; + if (symbol in properties) { + keyNodes.push( + this.parseWKSymbol(symbol), + ); + valueNodes.push( + createAsyncIteratorFactoryInstanceNode( + this.parseAsyncIteratorFactory(), + this.parse( + asyncIteratorToReadableStream( + properties as unknown as AsyncIterable, + this, + ), + ), + ), + ); + } + symbol = Symbol.toStringTag; + if (symbol in properties) { + keyNodes.push(this.parseWKSymbol(symbol)); + valueNodes.push(createStringNode(properties[symbol] as string)); + } + symbol = Symbol.isConcatSpreadable; + if (symbol in properties) { + keyNodes.push(this.parseWKSymbol(symbol)); + valueNodes.push(properties[symbol] ? TRUE_NODE : FALSE_NODE); + } + } + return { + k: keyNodes, + v: valueNodes, + s: keyNodes.length, + }; + } + private pushReadableStreamReader( id: number, reader: ReadableStreamDefaultReader, @@ -450,7 +522,10 @@ export default abstract class BaseStreamParserContext extends BaseSyncParserCont } // Generator functions don't have a global constructor // despite existing - if (currentFeatures & Feature.Symbol && Symbol.iterator in current) { + if ( + currentFeatures & Feature.Symbol + && (Symbol.iterator in current || Symbol.asyncIterator in current) + ) { return this.parsePlainObject(id, current, !!currentClass); } throw new UnsupportedTypeError(current); diff --git a/packages/seroval/src/core/base/sync.ts b/packages/seroval/src/core/context/parser/sync.ts similarity index 58% rename from packages/seroval/src/core/base/sync.ts rename to packages/seroval/src/core/context/parser/sync.ts index 6cee70ad..10ed1fab 100644 --- a/packages/seroval/src/core/base/sync.ts +++ b/packages/seroval/src/core/context/parser/sync.ts @@ -1,35 +1,44 @@ /* eslint-disable prefer-destructuring */ -import type { BigIntTypedArrayValue, TypedArrayValue } from '../../types'; -import UnsupportedTypeError from '../UnsupportedTypeError'; -import assert from '../assert'; +import type { BigIntTypedArrayValue, TypedArrayValue } from '../../../types'; +import UnsupportedTypeError from '../../UnsupportedTypeError'; +import assert from '../../utils/assert'; import { + createAggregateErrorNode, createArrayBufferNode, + createArrayNode, createBigIntNode, + createBigIntTypedArrayNode, + createBoxedNode, + createDataViewNode, createDateNode, + createErrorNode, + createIteratorFactoryInstanceNode, createNumberNode, createPluginNode, createRegExpNode, + createSetNode, createStringNode, + createTypedArrayNode, createWKSymbolNode, -} from '../base-primitives'; -import { BIGINT_FLAG, Feature } from '../compat'; -import type { WellKnownSymbols } from '../constants'; +} from '../../base-primitives'; +import { BIGINT_FLAG, Feature } from '../../compat'; +import type { WellKnownSymbols } from '../../constants'; import { - SerovalNodeType, UNIVERSAL_SENTINEL, -} from '../constants'; -import { createCustomEventOptions, createEventOptions } from '../constructors'; + SerovalNodeType, +} from '../../constants'; +import { createCustomEventOptions, createEventOptions } from '../../utils/constructors'; import { FALSE_NODE, NULL_NODE, TRUE_NODE, UNDEFINED_NODE, -} from '../literals'; -import type { BaseParserContextOptions } from '../parser-context'; -import { BaseParserContext } from '../parser-context'; -import { hasReferenceID } from '../reference'; -import { getErrorConstructor, getErrorOptions, getObjectFlag } from '../shared'; -import { serializeString } from '../string'; -import { SerovalObjectRecordSpecialKey } from '../types'; +} from '../../literals'; +import { iteratorToSequence } from '../../utils/iterator-to-sequence'; +import type { BaseParserContextOptions } from '../parser'; +import { BaseParserContext } from '../parser'; +import { hasReferenceID } from '../../reference'; +import { getErrorOptions } from '../../utils/error'; +import { serializeString } from '../../string'; import type { SerovalBoxedNode, SerovalArrayNode, @@ -51,37 +60,30 @@ import type { SerovalTypedArrayNode, SerovalBigIntTypedArrayNode, SerovalDataViewNode, -} from '../types'; -import { createDOMExceptionNode, createURLNode, createURLSearchParamsNode } from '../web-api'; +} from '../../types'; +import { + createCustomEventNode, + createDOMExceptionNode, + createEventNode, + createURLNode, + createURLSearchParamsNode, +} from '../../web-api'; +import { UNIVERSAL_SENTINEL } from '../../special-reference'; type ObjectLikeNode = | SerovalObjectNode | SerovalNullConstructorNode; -export interface BaseSyncParserContextOptions extends BaseParserContextOptions { - refs?: Map; -} +export type BaseSyncParserContextOptions = BaseParserContextOptions export default abstract class BaseSyncParserContext extends BaseParserContext { protected parseItems( current: unknown[], ): SerovalNode[] { - const size = current.length; const nodes = []; - const deferred = []; - for (let i = 0, item: unknown; i < size; i++) { + for (let i = 0, len = current.length; i < len; i++) { if (i in current) { - item = current[i]; - if (this.isIterable(item)) { - deferred[i] = item; - } else { - nodes[i] = this.parse(item); - } - } - } - for (let i = 0; i < size; i++) { - if (i in deferred) { - nodes[i] = this.parse(deferred[i]); + nodes[i] = this.parse(current[i]); } } return nodes; @@ -91,56 +93,52 @@ export default abstract class BaseSyncParserContext extends BaseParserContext { id: number, current: unknown[], ): SerovalArrayNode { - return { - t: SerovalNodeType.Array, - i: id, - s: undefined, - l: current.length, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: this.parseItems(current), - f: undefined, - b: undefined, - o: getObjectFlag(current), - }; + return createArrayNode( + id, + current, + this.parseItems(current), + ); } protected parseProperties( - properties: Record, + properties: Record, ): SerovalObjectRecordNode { const entries = Object.entries(properties); const keyNodes: SerovalObjectRecordKey[] = []; const valueNodes: SerovalNode[] = []; - const deferredKeys: string[] = []; - const deferredValues: unknown[] = []; for ( - let i = 0, len = entries.length, key: string, item: unknown; + let i = 0, len = entries.length; i < len; i++ ) { - key = serializeString(entries[i][0]); - item = entries[i][1]; - // Defer iterables since iterables have lazy evaluation. - // Of course this doesn't include types seroval supports. - if (this.isIterable(item)) { - deferredKeys.push(key); - deferredValues.push(item); - } else { - keyNodes.push(key); - valueNodes.push(this.parse(item)); - } - } - for (let i = 0, len = deferredKeys.length; i < len; i++) { - keyNodes.push(deferredKeys[i]); - valueNodes.push(this.parse(deferredValues[i])); + keyNodes.push(serializeString(entries[i][0])); + valueNodes.push(this.parse(entries[i][1])); } // Check special properties, symbols in this case if (this.features & Feature.Symbol) { - if (Symbol.iterator in properties) { - keyNodes.push(SerovalObjectRecordSpecialKey.SymbolIterator); - valueNodes.push(this.parse(Array.from(properties as Iterable))); + let symbol = Symbol.iterator; + if (symbol in properties) { + keyNodes.push( + this.parseWKSymbol(symbol), + ); + valueNodes.push( + createIteratorFactoryInstanceNode( + this.parseIteratorFactory(), + this.parse( + iteratorToSequence(properties as unknown as Iterable), + ), + ), + ); + } + symbol = Symbol.toStringTag; + if (symbol in properties) { + keyNodes.push(this.parseWKSymbol(symbol)); + valueNodes.push(createStringNode(properties[symbol] as string)); + } + symbol = Symbol.isConcatSpreadable; + if (symbol in properties) { + keyNodes.push(this.parseWKSymbol(symbol)); + valueNodes.push(properties[symbol] ? TRUE_NODE : FALSE_NODE); } } return { @@ -155,100 +153,40 @@ export default abstract class BaseSyncParserContext extends BaseParserContext { current: Record, empty: boolean, ): ObjectLikeNode { - return { - t: empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object, - i: id, - s: undefined, - l: undefined, - c: undefined, - m: undefined, - p: this.parseProperties(current), - e: undefined, - a: undefined, - f: undefined, - b: undefined, - o: getObjectFlag(current), - }; + return this.createObjectNode( + id, + current, + empty, + this.parseProperties(current), + ); } protected parseBoxed( id: number, current: object, ): SerovalBoxedNode { - return { - t: SerovalNodeType.Boxed, - i: id, - s: undefined, - l: undefined, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: this.parse(current.valueOf()), - b: undefined, - o: undefined, - }; + return createBoxedNode(id, this.parse(current.valueOf())); } protected parseTypedArray( id: number, current: TypedArrayValue, ): SerovalTypedArrayNode { - return { - t: SerovalNodeType.TypedArray, - i: id, - s: undefined, - l: current.length, - c: current.constructor.name, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: this.parse(current.buffer), - b: current.byteOffset, - o: undefined, - }; + return createTypedArrayNode(id, current, this.parse(current.buffer)); } protected parseBigIntTypedArray( id: number, current: BigIntTypedArrayValue, ): SerovalBigIntTypedArrayNode { - return { - t: SerovalNodeType.BigIntTypedArray, - i: id, - s: undefined, - l: current.length, - c: current.constructor.name, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: this.parse(current.buffer), - b: current.byteOffset, - o: undefined, - }; + return createBigIntTypedArrayNode(id, current, this.parse(current.buffer)); } protected parseDataView( id: number, current: DataView, ): SerovalDataViewNode { - return { - t: SerovalNodeType.DataView, - i: id, - s: undefined, - l: current.byteLength, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: this.parse(current.buffer), - b: current.byteOffset, - o: undefined, - }; + return createDataViewNode(id, current, this.parse(current.buffer)); } protected parseError( @@ -256,23 +194,27 @@ export default abstract class BaseSyncParserContext extends BaseParserContext { current: Error, ): SerovalErrorNode { const options = getErrorOptions(current, this.features); - const optionsNode = options - ? this.parseProperties(options) - : undefined; - return { - t: SerovalNodeType.Error, - i: id, - s: getErrorConstructor(current), - l: undefined, - c: undefined, - m: serializeString(current.message), - p: optionsNode, - e: undefined, - a: undefined, - f: undefined, - b: undefined, - o: undefined, - }; + return createErrorNode( + id, + current, + options + ? this.parseProperties(options) + : undefined, + ); + } + + protected parseAggregateError( + id: number, + current: AggregateError, + ): SerovalAggregateErrorNode { + const options = getErrorOptions(current, this.features); + return createAggregateErrorNode( + id, + current, + options + ? this.parseProperties(options) + : undefined, + ); } protected parseMap( @@ -281,70 +223,27 @@ export default abstract class BaseSyncParserContext extends BaseParserContext { ): SerovalMapNode { const keyNodes: SerovalNode[] = []; const valueNodes: SerovalNode[] = []; - const deferredKey: unknown[] = []; - const deferredValue: unknown[] = []; for (const [key, value] of current.entries()) { - // Either key or value might be an iterable - if (this.isIterable(key) || this.isIterable(value)) { - deferredKey.push(key); - deferredValue.push(value); - } else { - keyNodes.push(this.parse(key)); - valueNodes.push(this.parse(value)); - } + keyNodes.push(this.parse(key)); + valueNodes.push(this.parse(value)); } - for (let i = 0, len = deferredKey.length; i < len; i++) { - keyNodes.push(this.parse(deferredKey[i])); - valueNodes.push(this.parse(deferredValue[i])); - } - return { - t: SerovalNodeType.Map, - i: id, - s: undefined, - l: undefined, - c: undefined, - m: undefined, - p: undefined, - e: { k: keyNodes, v: valueNodes, s: current.size }, - a: undefined, - f: undefined, - b: undefined, - o: undefined, - }; + return this.createMapNode( + id, + keyNodes, + valueNodes, + current.size, + ); } protected parseSet( id: number, current: Set, ): SerovalSetNode { - const nodes: SerovalNode[] = []; - const deferred: unknown[] = []; + const items: SerovalNode[] = []; for (const item of current.keys()) { - // Iterables are lazy, so the evaluation must be deferred - if (this.isIterable(item)) { - deferred.push(item); - } else { - nodes.push(this.parse(item)); - } + items.push(this.parse(item)); } - // Parse deferred items - for (let i = 0, len = deferred.length; i < len; i++) { - nodes.push(this.parse(deferred[i])); - } - return { - t: SerovalNodeType.Set, - i: id, - s: undefined, - l: current.size, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: nodes, - f: undefined, - b: undefined, - o: undefined, - }; + return createSetNode(id, current.size, items); } protected parsePlainProperties( @@ -353,22 +252,9 @@ export default abstract class BaseSyncParserContext extends BaseParserContext { const size = entries.length; const keyNodes: string[] = []; const valueNodes: SerovalNode[] = []; - const deferredKeys: string[] = []; - const deferredValues: unknown[] = []; - for (let i = 0, key: string, item: unknown; i < size; i++) { - key = serializeString(entries[i][0]); - item = entries[i][1]; - if (this.isIterable(item)) { - deferredKeys.push(key); - deferredValues.push(item); - } else { - keyNodes.push(key); - valueNodes.push(this.parse(item)); - } - } - for (let i = 0, len = deferredKeys.length; i < len; i++) { - keyNodes.push(deferredKeys[i]); - valueNodes.push(this.parse(deferredValues[i])); + for (let i = 0; i < size; i++) { + keyNodes.push(serializeString(entries[i][0])); + valueNodes.push(this.parse(entries[i][1])); } return { k: keyNodes, @@ -429,64 +315,14 @@ export default abstract class BaseSyncParserContext extends BaseParserContext { id: number, current: Event, ): SerovalEventNode { - return { - t: SerovalNodeType.Event, - i: id, - s: serializeString(current.type), - l: undefined, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: this.parse(createEventOptions(current)), - b: undefined, - o: undefined, - }; + return createEventNode(id, current.type, this.parse(createEventOptions(current))); } protected parseCustomEvent( id: number, current: CustomEvent, ): SerovalCustomEventNode { - return { - t: SerovalNodeType.CustomEvent, - i: id, - s: serializeString(current.type), - l: undefined, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: this.parse(createCustomEventOptions(current)), - b: undefined, - o: undefined, - }; - } - - protected parseAggregateError( - id: number, - current: AggregateError, - ): SerovalAggregateErrorNode { - const options = getErrorOptions(current, this.features); - const optionsNode = options - ? this.parseProperties(options) - : undefined; - return { - t: SerovalNodeType.AggregateError, - i: id, - s: undefined, - l: undefined, - c: undefined, - m: serializeString(current.message), - p: optionsNode, - e: undefined, - a: undefined, - f: undefined, - b: undefined, - o: undefined, - }; + return createCustomEventNode(id, current.type, this.parse(createCustomEventOptions(current))); } protected parsePlugin( @@ -636,7 +472,10 @@ export default abstract class BaseSyncParserContext extends BaseParserContext { } // Generator functions don't have a global constructor // despite existing - if (currentFeatures & Feature.Symbol && Symbol.iterator in current) { + if ( + currentFeatures & Feature.Symbol + && Symbol.iterator in current + ) { return this.parsePlainObject(id, current, !!currentClass); } throw new UnsupportedTypeError(current); diff --git a/packages/seroval/src/core/serializer-context.old.ts b/packages/seroval/src/core/context/serializer.ts similarity index 74% rename from packages/seroval/src/core/serializer-context.old.ts rename to packages/seroval/src/core/context/serializer.ts index cff1c5b5..0c14f0c5 100644 --- a/packages/seroval/src/core/serializer-context.old.ts +++ b/packages/seroval/src/core/context/serializer.ts @@ -1,14 +1,13 @@ -import { Feature } from './compat'; +import { Feature } from '../compat'; import { CONSTANT_STRING, ERROR_CONSTRUCTOR_STRING, SYMBOL_STRING, SerovalNodeType, SerovalObjectFlags, -} from './constants'; -import { REFERENCES_KEY } from './keys'; -import type { Plugin, PluginAccessOptions, SerovalMode } from './plugin'; -import { isValidIdentifier } from './shared'; +} from '../constants'; +import { REFERENCES_KEY } from '../keys'; +import type { Plugin, PluginAccessOptions, SerovalMode } from '../plugin'; import type { SerovalArrayNode, SerovalIndexedValueNode, @@ -50,10 +49,15 @@ import type { SerovalReadableStreamEnqueueNode, SerovalReadableStreamErrorNode, SerovalReadableStreamCloseNode, -} from './types'; -import { - SerovalObjectRecordSpecialKey, -} from './types'; + SerovalMapSentinelNode, + SerovalIteratorFactoryInstanceNode, + SerovalIteratorFactoryNode, + SerovalAsyncIteratorFactoryInstanceNode, + SerovalAsyncIteratorFactoryNode, + SerovalReadableStreamNode, + SerovalReadableStreamFactoryNode, +} from '../types'; +import { isValidIdentifier } from '../utils/is-valid-identifier'; interface IndexAssignment { t: 'index'; @@ -180,16 +184,6 @@ const MAP_CONSTRUCTOR = 'new Map'; const PROMISE_RESOLVE = 'Promise.resolve'; const PROMISE_REJECT = 'Promise.reject'; -const SYMBOL_ITERATOR = 'Symbol.iterator'; - -const enum SpecialReference { - Sentinel = 0, -} - -const SPECIAL_REFERENCE_VALUE: Record = { - [SpecialReference.Sentinel]: '[]', -}; - const OBJECT_FLAG_CONSTRUCTOR: Record = { [SerovalObjectFlags.Frozen]: 'Object.freeze', [SerovalObjectFlags.Sealed]: 'Object.seal', @@ -197,6 +191,13 @@ const OBJECT_FLAG_CONSTRUCTOR: Record = [SerovalObjectFlags.None]: undefined, }; +type SerovalNodeWithProperties = + | SerovalObjectNode + | SerovalNullConstructorNode + | SerovalAggregateErrorNode + | SerovalErrorNode + | SerovalHeadersNode; + export interface BaseSerializerContextOptions extends PluginAccessOptions { features: number; markedRefs: number[] | Set; @@ -242,6 +243,32 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio abstract readonly mode: SerovalMode; + protected createFunction( + parameters: string[], + body: string, + ): string { + if (this.features & Feature.ArrowFunction) { + const joined = parameters.length === 1 + ? parameters[0] + : '(' + parameters.join(',') + ')'; + return joined + '=>' + body; + } + return 'function(' + parameters.join(',') + '){return ' + body + '}'; + } + + protected createEffectfulFunction( + parameters: string[], + body: string, + ): string { + if (this.features & Feature.ArrowFunction) { + const joined = parameters.length === 1 + ? parameters[0] + : '(' + parameters.join(',') + ')'; + return joined + '=>{' + body + '}'; + } + return 'function(' + parameters.join(',') + '){' + body + '}'; + } + /** * A tiny function that tells if a reference * is to be accessed. This is a requirement for @@ -263,21 +290,6 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio */ abstract getRefParam(id: number | string): string; - private specials = new Set(); - - /** - * Generates special references that isn't provided by the user - * but by the script. - */ - protected getSpecialReference(ref: SpecialReference): string { - const param = this.getRefParam('_' + ref); - if (this.specials.has(ref)) { - return param; - } - this.specials.add(ref); - return param + '=' + SPECIAL_REFERENCE_VALUE[ref]; - } - protected pushObjectFlag(flag: SerovalObjectFlags, id: number): void { if (flag !== SerovalObjectFlags.None) { this.markRef(id); @@ -406,30 +418,6 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio return this.assignIndexedValue(node.i, REFERENCES_KEY + '.get("' + node.s + '")'); } - protected getIterableAccess(): string { - return this.features & Feature.ArrayPrototypeValues - ? '.values()' - : '[' + SYMBOL_ITERATOR + ']()'; - } - - protected serializeIterable( - node: SerovalNode, - ): string { - const key = '[' + SYMBOL_ITERATOR + ']'; - const parent = this.stack; - this.stack = []; - let serialized = this.serialize(node) + this.getIterableAccess(); - this.stack = parent; - if (this.features & Feature.ArrowFunction) { - serialized = ':()=>' + serialized; - } else if (this.features & Feature.MethodShorthand) { - serialized = '(){return ' + serialized + '}'; - } else { - serialized = ':function(){return ' + serialized + '}'; - } - return key + serialized; - } - protected serializeArrayItem( id: number, item: SerovalNode | undefined, @@ -473,50 +461,43 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio } protected serializeProperty( - id: number, + source: SerovalNodeWithProperties, key: SerovalObjectRecordKey, val: SerovalNode, ): string { - // Only reason this is a switch is so that - // in the future, maybe other Symbols are going - // to be introduced and/or has merit to be added - // E.g. Symbol.asyncIterator - switch (key) { - case SerovalObjectRecordSpecialKey.SymbolIterator: - return this.serializeIterable(val); - default: { - 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 (this.isIndexedValueInStack(val)) { - const refParam = this.getRefParam((val as SerovalIndexedValueNode).i); - this.markRef(id); - // eslint-disable-next-line no-self-compare - if (isIdentifier && check !== check) { - this.createObjectAssign(id, key, refParam); - } else { - this.createArrayAssign(id, isIdentifier ? key : ('"' + key + '"'), refParam); - } - return ''; + if (typeof key === 'string') { + 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 (this.isIndexedValueInStack(val)) { + const refParam = this.getRefParam((val as SerovalIndexedValueNode).i); + this.markRef(source.i); + // eslint-disable-next-line no-self-compare + if (isIdentifier && check !== check) { + this.createObjectAssign(source.i, key, refParam); + } else { + this.createArrayAssign(source.i, isIdentifier ? key : ('"' + key + '"'), refParam); } - return (isIdentifier ? key : ('"' + key + '"')) + ':' + this.serialize(val); + return ''; } + return (isIdentifier ? key : ('"' + key + '"')) + ':' + this.serialize(val); } + return '[' + this.serialize(key) + ']:' + this.serialize(val); } protected serializeProperties( - sourceID: number, - node: SerovalObjectRecordNode, + source: SerovalNodeWithProperties, + record: SerovalObjectRecordNode, ): string { - const len = node.s; + const len = record.s; if (len) { - this.stack.push(sourceID); - const keys = node.k; - const values = node.v; - let result = this.serializeProperty(sourceID, keys[0], values[0]); + this.stack.push(source.i); + const keys = record.k; + const values = record.v; + let result = this.serializeProperty(source, keys[0], values[0]); for (let i = 1, item = result; i < len; i++) { - item = this.serializeProperty(sourceID, keys[i], values[i]); + item = this.serializeProperty(source, keys[i], values[i]); result += (item && result && ',') + item; } this.stack.pop(); @@ -529,15 +510,15 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio node: SerovalObjectNode, ): string { this.pushObjectFlag(node.o, node.i); - return this.assignIndexedValue(node.i, this.serializeProperties(node.i, node.p)); + return this.assignIndexedValue(node.i, this.serializeProperties(node, node.p)); } protected serializeWithObjectAssign( + source: SerovalNodeWithProperties, value: SerovalObjectRecordNode, - id: number, serialized: string, ): string { - const fields = this.serializeProperties(id, value); + const fields = this.serializeProperties(source, value); if (fields !== '{}') { return 'Object.assign(' + serialized + ',' + fields + ')'; } @@ -545,68 +526,62 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio } protected serializeAssignment( - sourceID: number, + source: SerovalNodeWithProperties, mainAssignments: Assignment[], key: SerovalObjectRecordKey, value: SerovalNode, ): void { - switch (key) { - case SerovalObjectRecordSpecialKey.SymbolIterator: { - const parent = this.stack; - this.stack = []; - const serialized = this.serialize(value) + this.getIterableAccess(); - this.stack = parent; + if (typeof key === 'string') { + const serialized = this.serialize(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 (this.isIndexedValueInStack(value)) { + // eslint-disable-next-line no-self-compare + if (isIdentifier && check !== check) { + this.createObjectAssign(source.i, key, serialized); + } else { + this.createArrayAssign(source.i, isIdentifier ? key : ('"' + key + '"'), serialized); + } + } else { const parentAssignment = this.assignments; this.assignments = mainAssignments; - this.createArrayAssign( - sourceID, - this.getSpecialReference(SpecialReference.Sentinel), - this.features & Feature.ArrowFunction - ? '()=>' + serialized - : 'function(){return ' + serialized + '}', - ); - this.assignments = parentAssignment; - } - break; - default: { - const serialized = this.serialize(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 (this.isIndexedValueInStack(value)) { - // eslint-disable-next-line no-self-compare - if (isIdentifier && check !== check) { - this.createObjectAssign(sourceID, key, serialized); - } else { - this.createArrayAssign(sourceID, isIdentifier ? key : ('"' + key + '"'), serialized); - } + if (isIdentifier) { + this.createObjectAssign(source.i, key, serialized); } else { - const parentAssignment = this.assignments; - this.assignments = mainAssignments; - if (isIdentifier) { - this.createObjectAssign(sourceID, key, serialized); - } else { - this.createArrayAssign(sourceID, isIdentifier ? key : ('"' + key + '"'), serialized); - } - this.assignments = parentAssignment; + this.createArrayAssign(source.i, isIdentifier ? key : ('"' + key + '"'), serialized); } + this.assignments = parentAssignment; } + } else { + const parent = this.stack; + this.stack = []; + const serialized = this.serialize(value); + this.stack = parent; + const parentAssignment = this.assignments; + this.assignments = mainAssignments; + this.createArrayAssign( + source.i, + this.serialize(key), + serialized, + ); + this.assignments = parentAssignment; } } protected serializeAssignments( - sourceID: number, + source: SerovalNodeWithProperties, node: SerovalObjectRecordNode, ): string | undefined { const len = node.s; if (len) { - this.stack.push(sourceID); + this.stack.push(source.i); const mainAssignments: Assignment[] = []; const keys = node.k; const values = node.v; for (let i = 0; i < len; i++) { - this.serializeAssignment(sourceID, mainAssignments, keys[i], values[i]); + this.serializeAssignment(source, mainAssignments, keys[i], values[i]); } this.stack.pop(); return resolveAssignments(mainAssignments); @@ -615,29 +590,28 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio } protected serializeDictionary( - i: number, - p: SerovalObjectRecordNode | undefined, + node: SerovalNodeWithProperties, init: string, ): string { - if (p) { + if (node.p) { if (this.features & Feature.ObjectAssign) { - init = this.serializeWithObjectAssign(p, i, init); + init = this.serializeWithObjectAssign(node, node.p, init); } else { - this.markRef(i); - const assignments = this.serializeAssignments(i, p); + this.markRef(node.i); + const assignments = this.serializeAssignments(node, node.p); if (assignments) { - return '(' + this.assignIndexedValue(i, init) + ',' + assignments + this.getRefParam(i) + ')'; + return '(' + this.assignIndexedValue(node.i, init) + ',' + assignments + this.getRefParam(node.i) + ')'; } } } - return this.assignIndexedValue(i, init); + return this.assignIndexedValue(node.i, init); } protected serializeNullConstructor( node: SerovalNullConstructorNode, ): string { this.pushObjectFlag(node.o, node.i); - return this.serializeDictionary(node.i, node.p, NULL_CONSTRUCTOR); + return this.serializeDictionary(node, NULL_CONSTRUCTOR); } protected serializeDate( @@ -690,6 +664,7 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio id: number, key: SerovalNode, val: SerovalNode, + sentinel: string, ): string { if (this.isIndexedValueInStack(key)) { // Create reference for the map instance @@ -714,9 +689,9 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio // basically we serialize the intended object in place WITHOUT // actually returning it, this is by returning a placeholder // value that we will remove sometime after. - const serialized = '(' + this.serialize(val) + ',[' + this.getSpecialReference(SpecialReference.Sentinel) + ',' + this.getSpecialReference(SpecialReference.Sentinel) + '])'; + const serialized = '(' + this.serialize(val) + ',[' + sentinel + ',' + sentinel + '])'; this.createSetAssignment(id, keyRef, this.getRefParam(val.i)); - this.createDeleteAssignment(id, this.getSpecialReference(SpecialReference.Sentinel)); + this.createDeleteAssignment(id, sentinel); return serialized; } const parent = this.stack; @@ -730,9 +705,9 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio const valueRef = this.getRefParam((val as SerovalIndexedValueNode).i); this.markRef(id); if (key.t !== SerovalNodeType.IndexedValue && key.i != null && this.isMarked(key.i)) { - const serialized = '(' + this.serialize(key) + ',[' + this.getSpecialReference(SpecialReference.Sentinel) + ',' + this.getSpecialReference(SpecialReference.Sentinel) + '])'; + const serialized = '(' + this.serialize(key) + ',[' + sentinel + ',' + sentinel + '])'; this.createSetAssignment(id, this.getRefParam(key.i), valueRef); - this.createDeleteAssignment(id, this.getSpecialReference(SpecialReference.Sentinel)); + this.createDeleteAssignment(id, sentinel); return serialized; } // Reset stack for the key serialization @@ -752,13 +727,15 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio let serialized = MAP_CONSTRUCTOR; const size = node.e.s; const id = node.i; + const sentinel = node.f; + const sentinelID = this.getRefParam(sentinel.i); if (size) { const keys = node.e.k; const vals = node.e.v; this.stack.push(id); - let result = this.serializeMapEntry(id, keys[0], vals[0]); + let result = this.serializeMapEntry(id, keys[0], vals[0], sentinelID); for (let i = 1, item = result; i < size; i++) { - item = this.serializeMapEntry(id, keys[i], vals[i]); + item = this.serializeMapEntry(id, keys[i], vals[i], sentinelID); result += (item && result && ',') + item; } this.stack.pop(); @@ -769,6 +746,10 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio serialized += '([' + result + '])'; } } + if (sentinel.t === SerovalNodeType.MapSentinel) { + this.markRef(sentinel.i); + serialized = '(' + this.serialize(sentinel) + ',' + serialized + ')'; + } return this.assignIndexedValue(id, serialized); } @@ -817,13 +798,13 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio // `AggregateError` might've been extended // either through class or custom properties // Make sure to assign extra properties - return this.serializeDictionary(id, node.p, serialized); + return this.serializeDictionary(node, serialized); } protected serializeError( node: SerovalErrorNode, ): string { - return this.serializeDictionary(node.i, node.p, 'new ' + ERROR_CONSTRUCTOR_STRING[node.s] + '("' + node.m + '")'); + return this.serializeDictionary(node, 'new ' + ERROR_CONSTRUCTOR_STRING[node.s] + '("' + node.m + '")'); } protected serializePromise( @@ -840,17 +821,11 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio // the Promise evaluates after the parent // has initialized const ref = this.getRefParam((fulfilled as SerovalIndexedValueNode).i); - if (this.features & Feature.ArrowFunction) { - if (node.s) { - serialized = constructor + '().then(()=>' + ref + ')'; - } else { - serialized = constructor + '().catch(()=>{throw ' + ref + '})'; - } - } else if (node.s) { - serialized = constructor + '().then(function(){return ' + ref + '})'; - } else { - serialized = constructor + '().catch(function(){throw ' + ref + '})'; - } + serialized = constructor + ( + node.s + ? '().then(' + this.createFunction([], ref) + ')' + : '().catch(' + this.createEffectfulFunction([], 'throw ' + ref) + ')' + ); } else { this.stack.push(id); const result = this.serialize(fulfilled); @@ -905,7 +880,7 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio ): string { return this.assignIndexedValue( node.i, - 'new Headers(' + this.serializeProperties(node.i, node.e) + ')', + 'new Headers(' + this.serializeProperties(node, node.e) + ')', ); } @@ -999,9 +974,12 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio for (let i = 0, len = currentPlugins.length; i < len; i++) { const plugin = currentPlugins[i]; if (plugin.tag === node.c) { - return plugin.serialize(node.s, this, { - id: node.i, - }); + return this.assignIndexedValue( + node.i, + plugin.serialize(node.s, this, { + id: node.i, + }), + ); } } } @@ -1036,6 +1014,89 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio node: SerovalReadableStreamCloseNode, ): string; + protected serializeMapSentinel(node: SerovalMapSentinelNode): string { + return this.assignIndexedValue( + node.i, + '[]', + ); + } + + protected serializeIteratorFactory(node: SerovalIteratorFactoryNode): string { + return this.assignIndexedValue( + node.i, + this.createFunction( + ['s'], + this.createFunction( + ['i', 'c', 'd', 't'], + '(i=0,t={[' + this.serialize(node.f) + ']:' + this.createFunction([], 't') + ',' + + 'next:' + this.createEffectfulFunction([], 'if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}') + '})', + ), + ), + ); + } + + protected serializeIteratorFactoryInstance( + node: SerovalIteratorFactoryInstanceNode, + ): string { + return '(' + this.serialize(node.a[0]) + ')(' + this.serialize(node.a[1]) + ')'; + } + + protected serializeAsyncIteratorFactory(node: SerovalAsyncIteratorFactoryNode): string { + return this.assignIndexedValue( + node.i, + this.createFunction( + ['s'], + this.createFunction( + ['i', 't'], + '(i=0,t={[' + this.serialize(node.f) + ']:' + this.createFunction([], 't') + ',' + + 'next:' + this.createFunction( + [], + 'Promise.resolve().then(' + this.createEffectfulFunction( + ['c', 'd'], + 'if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}', + ) + ')', + ) + '})', + ), + ), + ); + } + + protected serializeAsyncIteratorFactoryInstance( + node: SerovalAsyncIteratorFactoryInstanceNode, + ): string { + return '(' + this.serialize(node.a[0]) + ')(' + this.serialize(node.a[1]) + ')'; + } + + protected serializeReadableStream( + node: SerovalReadableStreamNode, + ): string { + this.stack.push(node.i); + const result = '(' + this.serialize(node.a[0]) + ')(' + this.serialize(node.a[1]) + ')'; + this.stack.pop(); + return this.assignIndexedValue( + node.i, + result, + ); + } + + protected serializeReadableStreamFactory( + node: SerovalReadableStreamFactoryNode, + ): string { + return this.assignIndexedValue( + node.i, + this.createFunction( + ['s'], + 'new ReadableStream({start:' + this.createFunction( + ['c'], + 'Promise.resolve().then(' + this.createEffectfulFunction( + ['i', 'v'], + 'for(i=0;i; -} - -export interface CrossContextOptions { - scopeId?: string; -} diff --git a/packages/seroval/src/core/cross/deserializer.ts b/packages/seroval/src/core/cross/deserializer.ts new file mode 100644 index 00000000..44e6b3d1 --- /dev/null +++ b/packages/seroval/src/core/cross/deserializer.ts @@ -0,0 +1,19 @@ +import BaseDeserializerContext from '../context/deserializer'; +import type { BaseDeserializerOptions } from '../context/deserializer'; +import type { SerovalMode } from '../plugin'; + +export type CrossDeserializerContextOptions = BaseDeserializerOptions; + +export default class CrossDeserializerContext extends BaseDeserializerContext { + readonly mode: SerovalMode = 'cross'; + + assignIndexedValue( + index: number, + value: T, + ): T { + if (!this.refs.has(index)) { + this.refs.set(index, value); + } + return value; + } +} diff --git a/packages/seroval/src/core/cross/index.ts b/packages/seroval/src/core/cross/index.ts index 3898bab4..9f0e40e0 100644 --- a/packages/seroval/src/core/cross/index.ts +++ b/packages/seroval/src/core/cross/index.ts @@ -1,7 +1,10 @@ +import type { SerovalNode } from '../types'; import type { CrossAsyncParserContextOptions } from './async'; import AsyncCrossParserContext from './async'; -import type { CrossContextOptions } from './cross-parser'; -import CrossSerializerContext from './serialize'; +import type { CrossDeserializerContextOptions } from './deserializer'; +import CrossDeserializerContext from './deserializer'; +import type { CrossContextOptions, CrossParserContextOptions } from './parser'; +import CrossSerializerContext from './serializer'; import type { CrossStreamParserContextOptions } from './stream'; import StreamCrossParserContext from './stream'; import type { CrossSyncParserContextOptions } from './sync'; @@ -53,51 +56,33 @@ export async function crossSerializeAsync( return serial.serializeTop(tree); } -// export interface SerovalCrossJSON { -// t: SerovalNode; -// f: number; -// } - -// export function toCrossJSON( -// source: T, -// options?: CrossParserContextOptions, -// ): SerovalCrossJSON { -// const ctx = createCrossParserContext(options); -// return { -// t: parseSync(ctx, source), -// f: ctx.features, -// }; -// } - -// export async function toCrossJSONAsync( -// source: T, -// options?: CrossParserContextOptions, -// ): Promise { -// const ctx = createCrossParserContext(options); -// return { -// t: await parseAsync(ctx, source), -// f: ctx.features, -// }; -// } - -// export function compileCrossJSON(source: SerovalCrossJSON): string { -// const serial = createCrossSerializerContext({ -// features: source.f, -// }); -// const result = crossSerializeTree(serial, source.t); -// return finalize( -// serial, -// source.t.i, -// result, -// ); -// } - -// export function fromJSON(source: SerovalJSON): T { -// const serial = createDeserializerContext({ -// markedRefs: source.m, -// }); -// return deserializeTree(serial, source.t) as T; -// } +export type ToCrossJSONOptions = CrossParserContextOptions; + +export function toCrossJSON( + source: T, + options: CrossParserContextOptions = {}, +): SerovalNode { + const ctx = new SyncCrossParserContext({ + plugins: options.plugins, + disabledFeatures: options.disabledFeatures, + refs: options.refs, + }); + return ctx.parse(source); +} + +export type ToCrossJSONAsyncOptions = CrossParserContextOptions; + +export async function toCrossJSONAsync( + source: T, + options: CrossParserContextOptions = {}, +): Promise { + const ctx = new AsyncCrossParserContext({ + plugins: options.plugins, + disabledFeatures: options.disabledFeatures, + refs: options.refs, + }); + return ctx.parse(source); +} export interface CrossSerializeStreamOptions extends Omit, CrossContextOptions { @@ -109,6 +94,7 @@ export function crossSerializeStream( options: CrossSerializeStreamOptions, ): () => void { const ctx = new StreamCrossParserContext({ + plugins: options.plugins, refs: options.refs, disabledFeatures: options.disabledFeatures, onParse(node, initial): void { @@ -145,3 +131,38 @@ export function crossSerializeStream( ctx.destroy(); }; } + +export type ToCrossJSONStreamOptions = CrossStreamParserContextOptions; + +export function toCrossJSONStream( + source: T, + options: ToCrossJSONStreamOptions, +): () => void { + const ctx = new StreamCrossParserContext({ + plugins: options.plugins, + refs: options.refs, + disabledFeatures: options.disabledFeatures, + onParse: options.onParse, + onError: options.onError, + onDone: options.onDone, + }); + + ctx.start(source); + + return () => { + ctx.destroy(); + }; +} + +export type FromCrossJSONOptions = CrossDeserializerContextOptions; + +export function fromCrossJSON( + source: SerovalNode, + options: FromCrossJSONOptions, +): T { + const ctx = new CrossDeserializerContext({ + plugins: options.plugins, + refs: options.refs, + }); + return ctx.deserialize(source) as T; +} diff --git a/packages/seroval/src/core/cross/parser.ts b/packages/seroval/src/core/cross/parser.ts new file mode 100644 index 00000000..631de6bc --- /dev/null +++ b/packages/seroval/src/core/cross/parser.ts @@ -0,0 +1,7 @@ +import type { BaseParserContextOptions } from '../context/parser'; + +export type CrossParserContextOptions = BaseParserContextOptions + +export interface CrossContextOptions { + scopeId?: string; +} diff --git a/packages/seroval/src/core/cross/serialize.ts b/packages/seroval/src/core/cross/serializer.ts similarity index 68% rename from packages/seroval/src/core/cross/serialize.ts rename to packages/seroval/src/core/cross/serializer.ts index b359a6db..41851a91 100644 --- a/packages/seroval/src/core/cross/serialize.ts +++ b/packages/seroval/src/core/cross/serializer.ts @@ -7,6 +7,7 @@ import type { SerovalReadableStreamErrorNode, SerovalReadableStreamConstructorNode, SerovalNode, + SerovalAsyncIteratorFactoryNode, } from '../types'; import { GLOBAL_CONTEXT_PROMISE_REJECT, @@ -14,15 +15,16 @@ import { GLOBAL_CONTEXT_PROMISE_CONSTRUCTOR, GLOBAL_CONTEXT_REFERENCES, GLOBAL_CONTEXT_STREAM_CONSTRUCTOR, - GLOBAL_CONTEXT_STREAM_EMIT, + GLOBAL_CONTEXT_STREAM_ENQUEUE, + GLOBAL_CONTEXT_STREAM_CLOSE, + GLOBAL_CONTEXT_STREAM_ERROR, GLOBAL_CONTEXT_API, } from '../keys'; -import type { BaseSerializerContextOptions } from '../serializer-context.old'; -import BaseSerializerContext from '../serializer-context.old'; +import type { BaseSerializerContextOptions } from '../context/serializer'; +import BaseSerializerContext from '../context/serializer'; import type { SerovalMode } from '../plugin'; -import { Feature } from '../compat'; import { serializeString } from '../string'; -import type { CrossContextOptions } from './cross-parser'; +import type { CrossContextOptions } from './parser'; export interface CrossSerializerContextOptions extends BaseSerializerContextOptions, CrossContextOptions { @@ -79,19 +81,39 @@ export default class CrossSerializerContext extends BaseSerializerContext { protected serializeReadableStreamEnqueue( node: SerovalReadableStreamEnqueueNode, ): string { - return GLOBAL_CONTEXT_API + '.' + GLOBAL_CONTEXT_STREAM_EMIT + '(' + this.getRefParam(node.i) + ',0,' + this.serialize(node.f) + ')'; + return GLOBAL_CONTEXT_API + '.' + GLOBAL_CONTEXT_STREAM_ENQUEUE + '(' + this.getRefParam(node.i) + ',' + this.serialize(node.f) + ')'; } protected serializeReadableStreamError( node: SerovalReadableStreamErrorNode, ): string { - return GLOBAL_CONTEXT_API + '.' + GLOBAL_CONTEXT_STREAM_EMIT + '(' + this.getRefParam(node.i) + ',1,' + this.serialize(node.f) + ')'; + return GLOBAL_CONTEXT_API + '.' + GLOBAL_CONTEXT_STREAM_ERROR + '(' + this.getRefParam(node.i) + ',' + this.serialize(node.f) + ')'; } protected serializeReadableStreamClose( node: SerovalReadableStreamCloseNode, ): string { - return GLOBAL_CONTEXT_API + '.' + GLOBAL_CONTEXT_STREAM_EMIT + '(' + this.getRefParam(node.i) + ',2)'; + return GLOBAL_CONTEXT_API + '.' + GLOBAL_CONTEXT_STREAM_CLOSE + '(' + this.getRefParam(node.i) + ')'; + } + + protected serializeAsyncIteratorFactory(node: SerovalAsyncIteratorFactoryNode): string { + return this.assignIndexedValue( + node.i, + this.createFunction( + ['s'], + this.createFunction( + ['b', 't'], + '(b=s.tee(),s=b[0],b=b[1].getReader(),t={[' + this.serialize(node.f) + ']:' + this.createFunction([], 't') + ',' + + 'next:' + this.createFunction( + [], + 'b.read().then(' + this.createEffectfulFunction( + ['d'], + 'if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}', + ) + ')', + ) + '})', + ), + ), + ); } serializeTop(tree: SerovalNode): string { @@ -109,9 +131,6 @@ export default class CrossSerializerContext extends BaseSerializerContext { } const args = this.scopeId == null ? '()' : '(' + GLOBAL_CONTEXT_REFERENCES + '["' + serializeString(this.scopeId) + '"])'; const body = mainBody + (patches ? ref : ''); - if (this.features & Feature.ArrowFunction) { - return '(' + params + '=>(' + body + '))' + args; - } - return '(function(' + params + '){return ' + body + '})' + args; + return '(' + this.createFunction([params], body) + ')' + args; } } diff --git a/packages/seroval/src/core/cross/stream.ts b/packages/seroval/src/core/cross/stream.ts index 018f4d59..407637da 100644 --- a/packages/seroval/src/core/cross/stream.ts +++ b/packages/seroval/src/core/cross/stream.ts @@ -1,5 +1,5 @@ -import type { BaseStreamParserContextOptions } from '../base/stream'; -import BaseStreamParserContext from '../base/stream'; +import type { BaseStreamParserContextOptions } from '../context/parser/stream'; +import BaseStreamParserContext from '../context/parser/stream'; import type { SerovalMode } from '../plugin'; export type CrossStreamParserContextOptions = BaseStreamParserContextOptions diff --git a/packages/seroval/src/core/cross/sync.ts b/packages/seroval/src/core/cross/sync.ts index 4698c90d..3d148fc1 100644 --- a/packages/seroval/src/core/cross/sync.ts +++ b/packages/seroval/src/core/cross/sync.ts @@ -1,6 +1,6 @@ -import BaseSyncParserContext from '../base/sync'; +import BaseSyncParserContext from '../context/parser/sync'; import type { SerovalMode } from '../plugin'; -import type { CrossParserContextOptions } from './cross-parser'; +import type { CrossParserContextOptions } from './parser'; export type CrossSyncParserContextOptions = CrossParserContextOptions diff --git a/packages/seroval/src/core/is-serializable.new.ts b/packages/seroval/src/core/is-serializable.new.ts index a2ba15ff..b83816f8 100644 --- a/packages/seroval/src/core/is-serializable.new.ts +++ b/packages/seroval/src/core/is-serializable.new.ts @@ -2,7 +2,7 @@ import { ALL_ENABLED, BIGINT_FLAG, Feature } from './compat'; import { INV_SYMBOL_REF, UNIVERSAL_SENTINEL } from './constants'; import type { Plugin, PluginAccessOptions } from './plugin'; import { hasReferenceID } from './reference'; -import { getErrorOptions } from './shared'; +import { getErrorOptions } from './utils/error'; export type SerializationMode = 'sync' | 'async' | 'stream'; diff --git a/packages/seroval/src/core/keys.ts b/packages/seroval/src/core/keys.ts index 92f9c855..5c6c2716 100644 --- a/packages/seroval/src/core/keys.ts +++ b/packages/seroval/src/core/keys.ts @@ -21,7 +21,11 @@ export const LOCAL_CONTEXT_STREAM_CONTROLLER = 'c'; export const GLOBAL_CONTEXT_STREAM_CONSTRUCTOR = 'S'; -export const GLOBAL_CONTEXT_STREAM_EMIT = 'Se'; +export const GLOBAL_CONTEXT_STREAM_ENQUEUE = 'Se'; + +export const GLOBAL_CONTEXT_STREAM_ERROR = 'St'; + +export const GLOBAL_CONTEXT_STREAM_CLOSE = 'Sc'; const GLOBAL_CONTEXT_API_REF = `self.${GLOBAL_CONTEXT_API}`; @@ -31,7 +35,9 @@ export const GLOBAL_CONTEXT_API_SCRIPT = `${GLOBAL_CONTEXT_API_REF}=${GLOBAL_CON + `${GLOBAL_CONTEXT_PROMISE_RESOLVE}:function(p,d){p.${LOCAL_CONTEXT_PROMISE_RESOLVE}(d),p.status="success",p.value=d,this.uP(p)},` + `${GLOBAL_CONTEXT_PROMISE_REJECT}:function(p,d){p.${LOCAL_CONTEXT_PROMISE_REJECT}(d),p.status="failure",p.value=d,this.uP(p)},` + `uS:function(s){delete s.${LOCAL_CONTEXT_STREAM_CONTROLLER}},` - + `${GLOBAL_CONTEXT_STREAM_EMIT}:function(s,t,d,c){switch(c=s.${LOCAL_CONTEXT_STREAM_CONTROLLER},t){case 0:return c.enqueue(d);case 1:return(this.uS(s),c.error(d));case 2:return(this.uS(s),c.close())}},` + + `${GLOBAL_CONTEXT_STREAM_CLOSE}:function(s){s.${LOCAL_CONTEXT_STREAM_CONTROLLER}.close(),this.uS(s)},` + + `${GLOBAL_CONTEXT_STREAM_ERROR}:function(s,e){s.${LOCAL_CONTEXT_STREAM_CONTROLLER}.error(e),this.uS(s)},` + + `${GLOBAL_CONTEXT_STREAM_ENQUEUE}:function(s,d){s.${LOCAL_CONTEXT_STREAM_CONTROLLER}.enqueue(d)},` + `${GLOBAL_CONTEXT_STREAM_CONSTRUCTOR}:function(s,c){return(s=new ReadableStream({start:function(x){c=x}})).${LOCAL_CONTEXT_STREAM_CONTROLLER}=c,s}` + '}'; diff --git a/packages/seroval/src/core/parser-context.ts b/packages/seroval/src/core/parser-context.ts deleted file mode 100644 index 9f697c4f..00000000 --- a/packages/seroval/src/core/parser-context.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { createIndexedValueNode, createReferenceNode } from './base-primitives'; -import { ALL_ENABLED, BIGINT_FLAG, Feature } from './compat'; -import type { Plugin, PluginAccessOptions, SerovalMode } from './plugin'; -import { hasReferenceID } from './reference'; -import type { SerovalIndexedValueNode, SerovalReferenceNode } from './types'; - -export interface BaseParserContextOptions extends PluginAccessOptions { - disabledFeatures?: number; - refs?: Map; -} - -export abstract class BaseParserContext implements PluginAccessOptions { - abstract readonly mode: SerovalMode; - - features: number; - - marked = new Set(); - - refs: Map; - - plugins?: Plugin[] | undefined; - - constructor(options: BaseParserContextOptions) { - this.plugins = options.plugins; - this.features = ALL_ENABLED ^ (options.disabledFeatures || 0); - this.refs = options.refs || new Map(); - } - - protected markRef(id: number): void { - this.marked.add(id); - } - - protected isMarked(id: number): boolean { - return this.marked.has(id); - } - - protected getReference(current: T): number | SerovalIndexedValueNode | SerovalReferenceNode { - const registeredID = this.refs.get(current); - if (registeredID != null) { - this.markRef(registeredID); - return createIndexedValueNode(registeredID); - } - const id = this.refs.size; - this.refs.set(current, id); - if (hasReferenceID(current)) { - return createReferenceNode(id, current); - } - return id; - } - - protected getStrictReference(current: T): SerovalIndexedValueNode | SerovalReferenceNode { - const registeredID = this.refs.get(current); - if (registeredID != null) { - this.markRef(registeredID); - return createIndexedValueNode(registeredID); - } - const id = this.refs.size; - this.refs.set(current, id); - return createReferenceNode(id, current); - } - - /** - * @private - */ - protected isIterable( - value: unknown, - ): value is Iterable { - if (!value || typeof value !== 'object') { - return false; - } - if (Array.isArray(value)) { - return false; - } - const currentClass = value.constructor; - const currentFeatures = this.features; - if (currentFeatures & Feature.TypedArray) { - switch (currentClass) { - case Int8Array: - case Int16Array: - case Int32Array: - case Uint8Array: - case Uint16Array: - case Uint32Array: - case Uint8ClampedArray: - case Float32Array: - case Float64Array: - return false; - default: - break; - } - } - // BigInt Typed Arrays - if ((currentFeatures & BIGINT_FLAG) === BIGINT_FLAG) { - switch (currentClass) { - case BigInt64Array: - case BigUint64Array: - return false; - default: - break; - } - } - // ES Collection - if (currentFeatures & Feature.Map && currentClass === Map) { - return false; - } - if (currentFeatures & Feature.Set && currentClass === Set) { - return false; - } - if (currentFeatures & Feature.WebAPI) { - if (typeof Headers !== 'undefined' && currentClass === Headers) { - return false; - } - if (typeof File !== 'undefined' && currentClass === File) { - return false; - } - } - const currentPlugins = this.plugins; - if (currentPlugins) { - for (let i = 0, len = currentPlugins.length; i < len; i++) { - const plugin = currentPlugins[i]; - if (plugin.test(value) && plugin.isIterable && plugin.isIterable(value)) { - return false; - } - } - } - if (currentFeatures & Feature.Symbol) { - return Symbol.iterator in value; - } - return false; - } -} diff --git a/packages/seroval/src/core/plugin.ts b/packages/seroval/src/core/plugin.ts index cc63a76a..b302294c 100644 --- a/packages/seroval/src/core/plugin.ts +++ b/packages/seroval/src/core/plugin.ts @@ -1,8 +1,8 @@ -import type BaseAsyncParserContext from './base/async'; -import type BaseStreamParserContext from './base/stream'; -import type BaseSyncParserContext from './base/sync'; -import type BaseSerializerContext from './serializer-context.old'; -import type VanillaDeserializerContext from './tree/deserialize'; +import type BaseAsyncParserContext from './context/parser/async'; +import type BaseStreamParserContext from './context/parser/stream'; +import type BaseSyncParserContext from './context/parser/sync'; +import type BaseSerializerContext from './context/serializer'; +import type BaseDeserializerContext from './context/deserializer'; export type SerovalMode = 'vanilla' | 'cross'; @@ -37,10 +37,10 @@ export interface Plugin { ): string; deserialize( node: Node, - ctx: VanillaDeserializerContext, + ctx: BaseDeserializerContext, data: PluginData, ): Value; - isIterable?: (value: Value) => boolean; + // isIterable?: (value: Value) => boolean; // isSerializable?: (value: Value) => boolean; } diff --git a/packages/seroval/src/core/reference.ts b/packages/seroval/src/core/reference.ts index 7ba8808c..7fa4a2dd 100644 --- a/packages/seroval/src/core/reference.ts +++ b/packages/seroval/src/core/reference.ts @@ -1,5 +1,5 @@ /* eslint-disable no-restricted-globals */ -import assert from './assert'; +import assert from './utils/assert'; import { REFERENCES_KEY } from './keys'; const REFERENCE = new Map(); diff --git a/packages/seroval/src/core/serializer-context.new.ts b/packages/seroval/src/core/serializer-context.new.ts deleted file mode 100644 index a97dbd71..00000000 --- a/packages/seroval/src/core/serializer-context.new.ts +++ /dev/null @@ -1,1168 +0,0 @@ -import { Feature } from './compat'; -import { - CONSTANT_STRING, - ERROR_CONSTRUCTOR_STRING, - SYMBOL_STRING, - SerovalNodeType, - SerovalObjectFlags, -} from './constants'; -import getIdentifier from './get-identifier'; -import { REFERENCES_KEY } from './keys'; -import type { Plugin, PluginAccessOptions, SerovalMode } from './plugin'; -import { isValidIdentifier } from './shared'; -import type { - SerovalArrayNode, - SerovalIndexedValueNode, - SerovalNode, - SerovalObjectRecordKey, - SerovalObjectRecordNode, - SerovalReferenceNode, - SerovalObjectNode, - SerovalNullConstructorNode, - SerovalRegExpNode, - SerovalDateNode, - SerovalSetNode, - SerovalMapNode, - SerovalArrayBufferNode, - SerovalTypedArrayNode, - SerovalBigIntTypedArrayNode, - SerovalDataViewNode, - SerovalAggregateErrorNode, - SerovalErrorNode, - SerovalPromiseNode, - SerovalWKSymbolNode, - SerovalURLNode, - SerovalURLSearchParamsNode, - SerovalBlobNode, - SerovalFileNode, - SerovalHeadersNode, - SerovalFormDataNode, - SerovalBoxedNode, - SerovalRequestNode, - SerovalResponseNode, - SerovalEventNode, - SerovalCustomEventNode, - SerovalDOMExceptionNode, - SerovalPluginNode, - SerovalPromiseConstructorNode, - SerovalPromiseResolveNode, - SerovalPromiseRejectNode, - SerovalReadableStreamConstructorNode, - SerovalReadableStreamEnqueueNode, - SerovalReadableStreamErrorNode, - SerovalReadableStreamCloseNode, -} from './types'; -import { - SerovalObjectRecordSpecialKey, -} from './types'; - -interface IndexAssignment { - t: 'index'; - s: string; - k: undefined; - v: string; -} - -interface SetAssignment { - t: 'set'; - s: string; - k: string; - v: string; -} - -interface AddAssignment { - t: 'add'; - s: string; - k: undefined; - v: string; -} - -interface DeleteAssignment { - t: 'delete'; - s: string; - k: string; - v: undefined; -} - -// Array of assignments to be done (used for recursion) -type Assignment = - | IndexAssignment - | AddAssignment - | SetAssignment - | DeleteAssignment; - -export interface FlaggedObject { - type: SerovalObjectFlags; - value: string; -} - -function getAssignmentExpression(assignment: Assignment): string { - switch (assignment.t) { - case 'index': - return assignment.s + '=' + assignment.v; - case 'set': - return assignment.s + '.set(' + assignment.k + ',' + assignment.v + ')'; - case 'add': - return assignment.s + '.add(' + assignment.v + ')'; - case 'delete': - return assignment.s + '.delete(' + assignment.k + ')'; - default: - return ''; - } -} - -function mergeAssignments(assignments: Assignment[]): Assignment[] { - const newAssignments: Assignment[] = []; - let current = assignments[0]; - for (let i = 1, len = assignments.length, item: Assignment, prev = current; i < len; i++) { - item = assignments[i]; - if (item.t === 'index' && item.v === prev.v) { - // Merge if the right-hand value is the same - // saves at least 2 chars - current = { - t: 'index', - s: item.s, - k: undefined, - v: getAssignmentExpression(current), - } as IndexAssignment; - } else if (item.t === 'set' && item.s === prev.s) { - // Maps has chaining methods, merge if source is the same - current = { - t: 'set', - s: getAssignmentExpression(current), - k: item.k, - v: item.v, - } as SetAssignment; - } else if (item.t === 'add' && item.s === prev.s) { - // Sets has chaining methods too - current = { - t: 'add', - s: getAssignmentExpression(current), - k: undefined, - v: item.v, - } as AddAssignment; - } else if (item.t === 'delete' && item.s === prev.s) { - // Maps has chaining methods, merge if source is the same - current = { - t: 'delete', - s: getAssignmentExpression(current), - k: item.k, - v: undefined, - } as DeleteAssignment; - } else { - // Different assignment, push current - newAssignments.push(current); - current = item; - } - prev = item; - } - - newAssignments.push(current); - - return newAssignments; -} - -function resolveAssignments(assignments: Assignment[]): string | undefined { - if (assignments.length) { - let result = ''; - const merged = mergeAssignments(assignments); - for (let i = 0, len = merged.length; i < len; i++) { - result += getAssignmentExpression(merged[i]) + ','; - } - return result; - } - return undefined; -} - -const SET_CONSTRUCTOR = 'new Set'; -const MAP_CONSTRUCTOR = 'new Map'; - -const enum SpecialReference { - Sentinel = 0, - Symbol = 1, - SymbolIterator = 2, - Object = 3, - ObjectFreeze = 4, - ObjectSeal = 5, - ObjectPreventExtensions = 6, - ObjectAssign = 7, - ObjectCreate = 8, - Promise = 9, - PromiseResolve = 10, - PromiseReject = 11, -} - -const OBJECT_FLAG_CONSTRUCTOR: Record = { - [SerovalObjectFlags.Frozen]: SpecialReference.ObjectFreeze, - [SerovalObjectFlags.Sealed]: SpecialReference.ObjectSeal, - [SerovalObjectFlags.NonExtensible]: SpecialReference.ObjectPreventExtensions, - [SerovalObjectFlags.None]: undefined, -}; - -export interface BaseSerializerContextOptions extends PluginAccessOptions { - features: number; - markedRefs: number[] | Set; -} - -export default abstract class BaseSerializerContext implements PluginAccessOptions { - /** - * @private - */ - features: number; - - /** - * To check if an object is synchronously referencing itself - * @private - */ - stack: number[] = []; - - /** - * Array of object mutations - * @private - */ - flags: FlaggedObject[] = []; - - /** - * Array of assignments to be done (used for recursion) - * @private - */ - assignments: Assignment[] = []; - - plugins?: Plugin[] | undefined; - - /** - * Refs that are...referenced - * @private - */ - marked: Set; - - constructor(options: BaseSerializerContextOptions) { - this.plugins = options.plugins; - this.features = options.features; - this.marked = new Set(options.markedRefs); - } - - abstract readonly mode: SerovalMode; - - /** - * A tiny function that tells if a reference - * is to be accessed. This is a requirement for - * deciding whether or not we should generate - * an identifier for the object - */ - protected markRef(id: number): void { - this.marked.add(id); - } - - protected isMarked(id: number): boolean { - return this.marked.has(id); - } - - /** - * Converts the ID of a reference into a identifier string - * that is used to refer to the object instance in the - * generated script. - */ - abstract getRefParam(id: number | string): string; - - private specials = new Set(); - - protected getSpecialReferenceValue(ref: SpecialReference): string { - switch (ref) { - case SpecialReference.Sentinel: - return '[]'; - case SpecialReference.Symbol: - return 'Symbol'; - case SpecialReference.SymbolIterator: - return this.getSpecialReference(SpecialReference.Symbol, true) + '.iterator'; - case SpecialReference.Object: - return 'Object'; - case SpecialReference.ObjectFreeze: - return this.getSpecialReference(SpecialReference.Object, true) + '.freeze'; - case SpecialReference.ObjectSeal: - return this.getSpecialReference(SpecialReference.Object, true) + '.seal'; - case SpecialReference.ObjectPreventExtensions: - return this.getSpecialReference(SpecialReference.Object, true) + '.preventExtensions'; - case SpecialReference.ObjectAssign: - return this.getSpecialReference(SpecialReference.Object, true) + '.assign'; - case SpecialReference.ObjectCreate: - return this.getSpecialReference(SpecialReference.Object, true) + '.create'; - case SpecialReference.Promise: - return 'Promise'; - case SpecialReference.PromiseResolve: - return this.getSpecialReference(SpecialReference.Promise, true) + '.resolve.bind(' + this.getSpecialReference(SpecialReference.Promise, false) + ')'; - case SpecialReference.PromiseReject: - return this.getSpecialReference(SpecialReference.Promise, true) + '.reject.bind(' + this.getSpecialReference(SpecialReference.Promise, false) + ')'; - default: - throw new Error('unknown special reference'); - } - } - - /** - * Generates special references that isn't provided by the user - * but by the script. - */ - protected getSpecialReference(ref: SpecialReference, call: boolean): string { - const param = this.getRefParam('_' + getIdentifier(ref)); - if (this.specials.has(ref)) { - return param; - } - this.specials.add(ref); - const expr = param + '=' + this.getSpecialReferenceValue(ref); - if (call) { - return '(' + expr + ')'; - } - return expr; - } - - protected pushObjectFlag(flag: SerovalObjectFlags, id: number): void { - if (flag !== SerovalObjectFlags.None) { - this.markRef(id); - this.flags.push({ - type: flag, - value: this.getRefParam(id), - }); - } - } - - private resolveFlags(): string | undefined { - let result = ''; - for (let i = 0, current = this.flags, len = current.length; i < len; i++) { - const flag = current[i]; - const constructor = OBJECT_FLAG_CONSTRUCTOR[flag.type]; - if (constructor) { - const ref = this.getSpecialReference(constructor, true); - result += ref + '(' + flag.value + '),'; - } - } - return result; - } - - protected resolvePatches(): string | undefined { - const assignments = resolveAssignments(this.assignments); - const flags = this.resolveFlags(); - if (assignments) { - if (flags) { - return assignments + flags; - } - return assignments; - } - return flags; - } - - /** - * Generates the inlined assignment for the reference - * This is different from the assignments array as this one - * signifies creation rather than mutation - */ - protected createAssignment( - source: string, - value: string, - ): void { - this.assignments.push({ - t: 'index', - s: source, - k: undefined, - v: value, - }); - } - - protected createAddAssignment( - ref: number, - value: string, - ): void { - this.assignments.push({ - t: 'add', - s: this.getRefParam(ref), - k: undefined, - v: value, - }); - } - - protected createSetAssignment( - ref: number, - key: string, - value: string, - ): void { - this.assignments.push({ - t: 'set', - s: this.getRefParam(ref), - k: key, - v: value, - }); - } - - protected createDeleteAssignment( - ref: number, - key: string, - ): void { - this.assignments.push({ - t: 'delete', - s: this.getRefParam(ref), - k: key, - v: undefined, - }); - } - - protected createArrayAssign( - ref: number, - index: number | string, - value: string, - ): void { - this.createAssignment(this.getRefParam(ref) + '[' + index + ']', value); - } - - protected createObjectAssign( - ref: number, - key: string, - value: string, - ): void { - this.createAssignment(this.getRefParam(ref) + '.' + key, value); - } - - /** - * Checks if the value is in the stack. Stack here is a reference - * structure to know if a object is to be accessed in a TDZ. - */ - isIndexedValueInStack( - node: SerovalNode, - ): boolean { - return node.t === SerovalNodeType.IndexedValue && this.stack.includes(node.i); - } - - /** - * Produces an assignment expression. `id` generates a reference - * parameter (through `getRefParam`) and has the option to - * return the reference parameter directly or assign a value to - * it. - */ - protected abstract assignIndexedValue( - id: number, - value: string, - ): string; - - protected serializeReference( - node: SerovalReferenceNode, - ): string { - return this.assignIndexedValue(node.i, REFERENCES_KEY + '.get("' + node.s + '")'); - } - - protected getIterableAccess(): string { - return this.features & Feature.ArrayPrototypeValues - ? '.values()' - : '[' + this.getSpecialReference(SpecialReference.SymbolIterator, false) + ']()'; - } - - protected serializeIterable( - node: SerovalNode, - ): string { - const key = '[' + this.getSpecialReference(SpecialReference.SymbolIterator, false) + ']'; - const parent = this.stack; - this.stack = []; - let serialized = this.serialize(node) + this.getIterableAccess(); - this.stack = parent; - if (this.features & Feature.ArrowFunction) { - serialized = ':()=>' + serialized; - } else if (this.features & Feature.MethodShorthand) { - serialized = '(){return ' + serialized + '}'; - } else { - serialized = ':function(){return ' + serialized + '}'; - } - return key + serialized; - } - - protected serializeArrayItem( - id: number, - item: SerovalNode | undefined, - index: number, - ): string { - // Check if index is a hole - if (item) { - // Check if item is a parent - if (this.isIndexedValueInStack(item)) { - this.markRef(id); - this.createArrayAssign(id, index, this.getRefParam((item as SerovalIndexedValueNode).i)); - return ''; - } - return this.serialize(item); - } - return ''; - } - - protected serializeArray( - node: SerovalArrayNode, - ): string { - const id = node.i; - if (node.l) { - this.stack.push(id); - // This is different than Map and Set - // because we also need to serialize - // the holes of the Array - const list = node.a; - let values = this.serializeArrayItem(id, list[0], 0); - let isHoley = values === ''; - for (let i = 1, len = node.l, item: string; i < len; i++) { - item = this.serializeArrayItem(id, list[i], i); - values += ',' + item; - isHoley = item === ''; - } - this.stack.pop(); - this.pushObjectFlag(node.o, node.i); - return this.assignIndexedValue(id, '[' + values + (isHoley ? ',]' : ']')); - } - return this.assignIndexedValue(id, '[]'); - } - - protected serializeProperty( - id: number, - key: SerovalObjectRecordKey, - val: SerovalNode, - ): string { - // Only reason this is a switch is so that - // in the future, maybe other Symbols are going - // to be introduced and/or has merit to be added - // E.g. Symbol.asyncIterator - switch (key) { - case SerovalObjectRecordSpecialKey.SymbolIterator: - return this.serializeIterable(val); - default: { - 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 (this.isIndexedValueInStack(val)) { - const refParam = this.getRefParam((val as SerovalIndexedValueNode).i); - this.markRef(id); - // eslint-disable-next-line no-self-compare - if (isIdentifier && check !== check) { - this.createObjectAssign(id, key, refParam); - } else { - this.createArrayAssign(id, isIdentifier ? key : ('"' + key + '"'), refParam); - } - return ''; - } - return (isIdentifier ? key : ('"' + key + '"')) + ':' + this.serialize(val); - } - } - } - - protected serializeProperties( - sourceID: number, - node: SerovalObjectRecordNode, - ): string { - const len = node.s; - if (len) { - this.stack.push(sourceID); - const keys = node.k; - const values = node.v; - let result = this.serializeProperty(sourceID, keys[0], values[0]); - for (let i = 1, item = result; i < len; i++) { - item = this.serializeProperty(sourceID, keys[i], values[i]); - result += (item && result && ',') + item; - } - this.stack.pop(); - return '{' + result + '}'; - } - return '{}'; - } - - protected serializeObject( - node: SerovalObjectNode, - ): string { - this.pushObjectFlag(node.o, node.i); - return this.assignIndexedValue(node.i, this.serializeProperties(node.i, node.p)); - } - - protected serializeWithObjectAssign( - value: SerovalObjectRecordNode, - id: number, - serialized: string, - ): string { - const fields = this.serializeProperties(id, value); - if (fields !== '{}') { - return this.getSpecialReference(SpecialReference.ObjectAssign, true) + '(' + serialized + ',' + fields + ')'; - } - return serialized; - } - - protected serializeAssignment( - sourceID: number, - mainAssignments: Assignment[], - key: SerovalObjectRecordKey, - value: SerovalNode, - ): void { - switch (key) { - case SerovalObjectRecordSpecialKey.SymbolIterator: { - const parent = this.stack; - this.stack = []; - const serialized = this.serialize(value) + this.getIterableAccess(); - this.stack = parent; - const parentAssignment = this.assignments; - this.assignments = mainAssignments; - this.createArrayAssign( - sourceID, - this.getSpecialReference(SpecialReference.Sentinel, false), - this.features & Feature.ArrowFunction - ? '()=>' + serialized - : 'function(){return ' + serialized + '}', - ); - this.assignments = parentAssignment; - } - break; - default: { - const serialized = this.serialize(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 (this.isIndexedValueInStack(value)) { - // eslint-disable-next-line no-self-compare - if (isIdentifier && check !== check) { - this.createObjectAssign(sourceID, key, serialized); - } else { - this.createArrayAssign(sourceID, isIdentifier ? key : ('"' + key + '"'), serialized); - } - } else { - const parentAssignment = this.assignments; - this.assignments = mainAssignments; - if (isIdentifier) { - this.createObjectAssign(sourceID, key, serialized); - } else { - this.createArrayAssign(sourceID, isIdentifier ? key : ('"' + key + '"'), serialized); - } - this.assignments = parentAssignment; - } - } - } - } - - protected serializeAssignments( - sourceID: number, - node: SerovalObjectRecordNode, - ): string | undefined { - const len = node.s; - if (len) { - this.stack.push(sourceID); - const mainAssignments: Assignment[] = []; - const keys = node.k; - const values = node.v; - for (let i = 0; i < len; i++) { - this.serializeAssignment(sourceID, mainAssignments, keys[i], values[i]); - } - this.stack.pop(); - return resolveAssignments(mainAssignments); - } - return undefined; - } - - protected serializeDictionary( - i: number, - p: SerovalObjectRecordNode | undefined, - init: string, - ): string { - if (p) { - if (this.features & Feature.ObjectAssign) { - init = this.serializeWithObjectAssign(p, i, init); - } else { - this.markRef(i); - const assignments = this.serializeAssignments(i, p); - if (assignments) { - return '(' + this.assignIndexedValue(i, init) + ',' + assignments + this.getRefParam(i) + ')'; - } - } - } - return this.assignIndexedValue(i, init); - } - - protected serializeNullConstructor( - node: SerovalNullConstructorNode, - ): string { - this.pushObjectFlag(node.o, node.i); - return this.serializeDictionary(node.i, node.p, this.getSpecialReference(SpecialReference.ObjectCreate, true) + '(null)'); - } - - protected serializeDate( - node: SerovalDateNode, - ): string { - return this.assignIndexedValue(node.i, 'new Date("' + node.s + '")'); - } - - protected serializeRegExp( - node: SerovalRegExpNode, - ): string { - return this.assignIndexedValue(node.i, '/' + node.c + '/' + node.m); - } - - protected serializeSetItem( - id: number, - item: SerovalNode, - ): string { - if (this.isIndexedValueInStack(item)) { - this.markRef(id); - this.createAddAssignment(id, this.getRefParam((item as SerovalIndexedValueNode).i)); - return ''; - } - return this.serialize(item); - } - - protected serializeSet( - node: SerovalSetNode, - ): string { - let serialized = SET_CONSTRUCTOR; - const size = node.l; - const id = node.i; - if (size) { - const items = node.a; - this.stack.push(id); - let result = this.serializeSetItem(id, items[0]); - for (let i = 1, item = result; i < size; i++) { - item = this.serializeSetItem(id, items[i]); - result += (item && result && ',') + item; - } - this.stack.pop(); - if (result) { - serialized += '([' + result + '])'; - } - } - return this.assignIndexedValue(id, serialized); - } - - protected serializeMapEntry( - id: number, - key: SerovalNode, - val: SerovalNode, - ): string { - if (this.isIndexedValueInStack(key)) { - // Create reference for the map instance - const keyRef = this.getRefParam((key as SerovalIndexedValueNode).i); - this.markRef(id); - // Check if value is a parent - if (this.isIndexedValueInStack(val)) { - const valueRef = this.getRefParam((val as SerovalIndexedValueNode).i); - // Register an assignment since - // both key and value are a parent of this - // Map instance - this.createSetAssignment(id, keyRef, valueRef); - return ''; - } - // 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 - if (val.t !== SerovalNodeType.IndexedValue && val.i != null && this.isMarked(val.i)) { - // We use a trick here using sequence (or comma) expressions - // basically we serialize the intended object in place WITHOUT - // actually returning it, this is by returning a placeholder - // value that we will remove sometime after. - const serialized = '(' + this.serialize(val) + ',[' + this.getSpecialReference(SpecialReference.Sentinel, false) + ',' + this.getSpecialReference(SpecialReference.Sentinel, false) + '])'; - this.createSetAssignment(id, keyRef, this.getRefParam(val.i)); - this.createDeleteAssignment(id, this.getSpecialReference(SpecialReference.Sentinel, false)); - return serialized; - } - const parent = this.stack; - this.stack = []; - this.createSetAssignment(id, keyRef, this.serialize(val)); - this.stack = parent; - return ''; - } - if (this.isIndexedValueInStack(val)) { - // Create ref for the Map instance - const valueRef = this.getRefParam((val as SerovalIndexedValueNode).i); - this.markRef(id); - if (key.t !== SerovalNodeType.IndexedValue && key.i != null && this.isMarked(key.i)) { - const serialized = '(' + this.serialize(key) + ',[' + this.getSpecialReference(SpecialReference.Sentinel, false) + ',' + this.getSpecialReference(SpecialReference.Sentinel, false) + '])'; - this.createSetAssignment(id, this.getRefParam(key.i), valueRef); - this.createDeleteAssignment(id, this.getSpecialReference(SpecialReference.Sentinel, false)); - return serialized; - } - // Reset stack for the key serialization - const parent = this.stack; - this.stack = []; - this.createSetAssignment(id, this.serialize(key), valueRef); - this.stack = parent; - return ''; - } - - return '[' + this.serialize(key) + ',' + this.serialize(val) + ']'; - } - - protected serializeMap( - node: SerovalMapNode, - ): string { - let serialized = MAP_CONSTRUCTOR; - const size = node.e.s; - const id = node.i; - if (size) { - const keys = node.e.k; - const vals = node.e.v; - this.stack.push(id); - let result = this.serializeMapEntry(id, keys[0], vals[0]); - for (let i = 1, item = result; i < size; i++) { - item = this.serializeMapEntry(id, keys[i], vals[i]); - result += (item && result && ',') + item; - } - this.stack.pop(); - // Check if there are any values - // so that the empty Map constructor - // can be used instead - if (result) { - serialized += '([' + result + '])'; - } - } - return this.assignIndexedValue(id, serialized); - } - - protected serializeArrayBuffer( - node: SerovalArrayBufferNode, - ): string { - let result = 'new Uint8Array('; - const buffer = node.s; - const len = buffer.length; - if (len) { - result += '[' + buffer[0]; - for (let i = 1; i < len; i++) { - result += ',' + buffer[i]; - } - result += ']'; - } - return this.assignIndexedValue(node.i, result + ').buffer'); - } - - protected serializeTypedArray( - node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode, - ): string { - return this.assignIndexedValue( - node.i, - 'new ' + node.c + '(' + this.serialize(node.f) + ',' + node.b + ',' + node.l + ')', - ); - } - - protected serializeDataView( - node: SerovalDataViewNode, - ): string { - return this.assignIndexedValue( - node.i, - 'new DataView(' + this.serialize(node.f) + ',' + node.b + ',' + node.l + ')', - ); - } - - protected serializeAggregateError( - node: SerovalAggregateErrorNode, - ): string { - // Serialize the required arguments - const id = node.i; - this.stack.push(id); - const serialized = 'new AggregateError([],"' + node.m + '")'; - this.stack.pop(); - // `AggregateError` might've been extended - // either through class or custom properties - // Make sure to assign extra properties - return this.serializeDictionary(id, node.p, serialized); - } - - protected serializeError( - node: SerovalErrorNode, - ): string { - return this.serializeDictionary(node.i, node.p, 'new ' + ERROR_CONSTRUCTOR_STRING[node.s] + '("' + node.m + '")'); - } - - protected serializePromise( - node: SerovalPromiseNode, - ): string { - let serialized: string; - // Check if resolved value is a parent expression - const fulfilled = node.f; - const id = node.i; - const specialRef = node.s ? SpecialReference.PromiseResolve : SpecialReference.PromiseReject; - const constructor = this.getSpecialReference(specialRef, true); - if (this.isIndexedValueInStack(fulfilled)) { - // A Promise trick, reference the value - // inside the `then` expression so that - // the Promise evaluates after the parent - // has initialized - const ref = this.getRefParam((fulfilled as SerovalIndexedValueNode).i); - if (this.features & Feature.ArrowFunction) { - if (node.s) { - serialized = constructor + '().then(()=>' + ref + ')'; - } else { - serialized = constructor + '().catch(()=>{throw ' + ref + '})'; - } - } else if (node.s) { - serialized = constructor + '().then(function(){return ' + ref + '})'; - } else { - serialized = constructor + '().catch(function(){throw ' + ref + '})'; - } - } else { - this.stack.push(id); - const result = this.serialize(fulfilled); - this.stack.pop(); - // just inline the value/reference here - serialized = constructor + '(' + result + ')'; - } - return this.assignIndexedValue(id, serialized); - } - - protected serializeWKSymbol( - node: SerovalWKSymbolNode, - ): string { - return this.assignIndexedValue(node.i, SYMBOL_STRING[node.s]); - } - - protected serializeURL( - node: SerovalURLNode, - ): string { - return this.assignIndexedValue(node.i, 'new URL("' + node.s + '")'); - } - - protected serializeURLSearchParams( - node: SerovalURLSearchParamsNode, - ): string { - return this.assignIndexedValue( - node.i, - node.s ? 'new URLSearchParams("' + node.s + '")' : 'new URLSearchParams', - ); - } - - protected serializeBlob( - node: SerovalBlobNode, - ): string { - return this.assignIndexedValue( - node.i, - 'new Blob([' + this.serialize(node.f) + '],{type:"' + node.c + '"})', - ); - } - - protected serializeFile( - node: SerovalFileNode, - ): string { - return this.assignIndexedValue( - node.i, - 'new File([' + this.serialize(node.f) + '],"' + node.m + '",{type:"' + node.c + '",lastModified:' + node.b + '})', - ); - } - - protected serializeHeaders( - node: SerovalHeadersNode, - ): string { - return this.assignIndexedValue( - node.i, - 'new Headers(' + this.serializeProperties(node.i, node.e) + ')', - ); - } - - protected serializeFormDataEntry(id: number, key: string, value: SerovalNode): string { - return this.getRefParam(id) + '.append("' + key + '",' + this.serialize(value) + ')'; - } - - protected serializeFormDataEntries( - node: SerovalFormDataNode, - size: number, - ): string { - const keys = node.e.k; - const vals = node.e.v; - const id = node.i; - let result = this.serializeFormDataEntry(id, keys[0], vals[0]); - for (let i = 1; i < size; i++) { - result += ',' + this.serializeFormDataEntry(id, keys[i], vals[i]); - } - return result; - } - - protected serializeFormData( - node: SerovalFormDataNode, - ): string { - const size = node.e.s; - const id = node.i; - if (size) { - this.markRef(id); - } - const result = this.assignIndexedValue(id, 'new FormData()'); - if (size) { - const entries = this.serializeFormDataEntries(node, size); - return '(' + result + ',' + (entries ? entries + ',' : '') + this.getRefParam(id) + ')'; - } - return result; - } - - protected serializeBoxed( - node: SerovalBoxedNode, - ): string { - return this.assignIndexedValue(node.i, 'Object(' + this.serialize(node.f) + ')'); - } - - protected serializeRequest( - node: SerovalRequestNode, - ): string { - return this.assignIndexedValue(node.i, 'new Request("' + node.s + '",' + this.serialize(node.f) + ')'); - } - - protected serializeResponse( - node: SerovalResponseNode, - ): string { - return this.assignIndexedValue( - node.i, - 'new Response(' + this.serialize(node.a[0]) + ',' + this.serialize(node.a[1]) + ')', - ); - } - - protected serializeEvent( - node: SerovalEventNode, - ): string { - return this.assignIndexedValue( - node.i, - 'new Event("' + node.s + '",' + this.serialize(node.f) + ')', - ); - } - - protected serializeCustomEvent( - node: SerovalCustomEventNode, - ): string { - return this.assignIndexedValue( - node.i, - 'new CustomEvent("' + node.s + '",' + this.serialize(node.f) + ')', - ); - } - - protected serializeDOMException( - node: SerovalDOMExceptionNode, - ): string { - return this.assignIndexedValue( - node.i, - 'new DOMException("' + node.s + '","' + node.c + '")', - ); - } - - protected serializePlugin( - node: SerovalPluginNode, - ): string { - const currentPlugins = this.plugins; - if (currentPlugins) { - for (let i = 0, len = currentPlugins.length; i < len; i++) { - const plugin = currentPlugins[i]; - if (plugin.tag === node.c) { - return plugin.serialize(node.s, this, { - id: node.i, - }); - } - } - } - throw new Error('Missing plugin for tag "' + node.c + '".'); - } - - protected abstract serializePromiseConstructor( - node: SerovalPromiseConstructorNode, - ): string; - - protected abstract serializePromiseResolve( - node: SerovalPromiseResolveNode, - ): string; - - protected abstract serializePromiseReject( - node: SerovalPromiseRejectNode, - ): string; - - protected abstract serializeReadableStreamConstructor( - node: SerovalReadableStreamConstructorNode, - ): string; - - protected abstract serializeReadableStreamEnqueue( - node: SerovalReadableStreamEnqueueNode, - ): string; - - protected abstract serializeReadableStreamError( - node: SerovalReadableStreamErrorNode, - ): string; - - protected abstract serializeReadableStreamClose( - node: SerovalReadableStreamCloseNode, - ): string; - - serialize(node: SerovalNode): string { - switch (node.t) { - case SerovalNodeType.Constant: - return CONSTANT_STRING[node.s]; - case SerovalNodeType.Number: - return '' + node.s; - case SerovalNodeType.String: - return '"' + node.s + '"'; - case SerovalNodeType.BigInt: - return node.s + 'n'; - case SerovalNodeType.IndexedValue: - return this.getRefParam(node.i); - case SerovalNodeType.Reference: - return this.serializeReference(node); - case SerovalNodeType.Array: - return this.serializeArray(node); - case SerovalNodeType.Object: - return this.serializeObject(node); - case SerovalNodeType.NullConstructor: - return this.serializeNullConstructor(node); - case SerovalNodeType.Date: - return this.serializeDate(node); - case SerovalNodeType.RegExp: - return this.serializeRegExp(node); - case SerovalNodeType.Set: - return this.serializeSet(node); - case SerovalNodeType.Map: - return this.serializeMap(node); - case SerovalNodeType.ArrayBuffer: - return this.serializeArrayBuffer(node); - case SerovalNodeType.BigIntTypedArray: - case SerovalNodeType.TypedArray: - return this.serializeTypedArray(node); - case SerovalNodeType.DataView: - return this.serializeDataView(node); - case SerovalNodeType.AggregateError: - return this.serializeAggregateError(node); - case SerovalNodeType.Error: - return this.serializeError(node); - case SerovalNodeType.Promise: - return this.serializePromise(node); - case SerovalNodeType.WKSymbol: - return this.serializeWKSymbol(node); - case SerovalNodeType.URL: - return this.serializeURL(node); - case SerovalNodeType.URLSearchParams: - return this.serializeURLSearchParams(node); - case SerovalNodeType.Blob: - return this.serializeBlob(node); - case SerovalNodeType.File: - return this.serializeFile(node); - case SerovalNodeType.Headers: - return this.serializeHeaders(node); - case SerovalNodeType.FormData: - return this.serializeFormData(node); - case SerovalNodeType.Boxed: - return this.serializeBoxed(node); - case SerovalNodeType.PromiseConstructor: - return this.serializePromiseConstructor(node); - case SerovalNodeType.PromiseResolve: - return this.serializePromiseResolve(node); - case SerovalNodeType.PromiseReject: - return this.serializePromiseReject(node); - case SerovalNodeType.ReadableStreamConstructor: - return this.serializeReadableStreamConstructor(node); - case SerovalNodeType.ReadableStreamEnqueue: - return this.serializeReadableStreamEnqueue(node); - case SerovalNodeType.ReadableStreamError: - return this.serializeReadableStreamError(node); - case SerovalNodeType.ReadableStreamClose: - return this.serializeReadableStreamClose(node); - case SerovalNodeType.Request: - return this.serializeRequest(node); - case SerovalNodeType.Response: - return this.serializeResponse(node); - case SerovalNodeType.Event: - return this.serializeEvent(node); - case SerovalNodeType.CustomEvent: - return this.serializeCustomEvent(node); - case SerovalNodeType.DOMException: - return this.serializeDOMException(node); - case SerovalNodeType.Plugin: - return this.serializePlugin(node); - default: - throw new Error('invariant'); - } - } -} diff --git a/packages/seroval/src/core/special-reference.ts b/packages/seroval/src/core/special-reference.ts new file mode 100644 index 00000000..af3aff35 --- /dev/null +++ b/packages/seroval/src/core/special-reference.ts @@ -0,0 +1,9 @@ +export const MAP_SENTINEL = {}; + +export const ITERATOR = {}; + +export const ASYNC_ITERATOR = {}; + +export const READABLE_STREAM = {}; + +export const UNIVERSAL_SENTINEL = {}; diff --git a/packages/seroval/src/core/tree/async.ts b/packages/seroval/src/core/tree/async.ts index 52ce872f..312d9bbb 100644 --- a/packages/seroval/src/core/tree/async.ts +++ b/packages/seroval/src/core/tree/async.ts @@ -1,5 +1,5 @@ -import BaseAsyncParserContext from '../base/async'; -import type { BaseParserContextOptions } from '../parser-context'; +import BaseAsyncParserContext from '../context/parser/async'; +import type { BaseParserContextOptions } from '../context/parser'; import type { SerovalMode } from '../plugin'; export type AsyncParserContextOptions = Omit diff --git a/packages/seroval/src/core/tree/deserializer.ts b/packages/seroval/src/core/tree/deserializer.ts new file mode 100644 index 00000000..07603418 --- /dev/null +++ b/packages/seroval/src/core/tree/deserializer.ts @@ -0,0 +1,31 @@ +import BaseDeserializerContext from '../context/deserializer'; +import type { BaseDeserializerOptions } from '../context/deserializer'; +import type { SerovalMode } from '../plugin'; + +export interface VanillaDeserializerContextOptions extends Omit { + markedRefs: number[] | Set; +} + +export default class VanillaDeserializerContext extends BaseDeserializerContext { + readonly mode: SerovalMode = 'vanilla'; + + marked: Set; + + constructor(options: VanillaDeserializerContextOptions) { + super({ + plugins: options.plugins, + refs: undefined, + }); + this.marked = new Set(options.markedRefs); + } + + assignIndexedValue( + index: number, + value: T, + ): T { + if (this.marked.has(index)) { + this.refs.set(index, value); + } + return value; + } +} diff --git a/packages/seroval/src/core/tree/index.ts b/packages/seroval/src/core/tree/index.ts index 22ba6e7e..3521f984 100644 --- a/packages/seroval/src/core/tree/index.ts +++ b/packages/seroval/src/core/tree/index.ts @@ -2,8 +2,8 @@ import type { PluginAccessOptions } from '../plugin'; import type { SerovalNode } from '../types'; import type { AsyncParserContextOptions } from './async'; import AsyncParserContext from './async'; -import VanillaDeserializerContext from './deserialize'; -import VanillaSerializerContext from './serialize'; +import VanillaDeserializerContext from './deserializer'; +import VanillaSerializerContext from './serializer'; import type { SyncParserContextOptions } from './sync'; import SyncParserContext from './sync'; diff --git a/packages/seroval/src/core/tree/parser.ts b/packages/seroval/src/core/tree/parser.ts deleted file mode 100644 index 97e037be..00000000 --- a/packages/seroval/src/core/tree/parser.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { createIndexedValueNode, createReferenceNode } from '../base-primitives'; -import { hasReferenceID } from '../reference'; -import type { SerovalIndexedValueNode, SerovalReferenceNode } from '../types'; - -function createIndexedValue( - ids: Map, - marked: Set, - current: T, -): number { - const ref = ids.get(current); - if (ref == null) { - const id = ids.size; - ids.set(current, id); - return id; - } - marked.add(ref); - return ref; -} - -export function getVanillaReference( - ids: Map, - marked: Set, - current: T, -): number | SerovalIndexedValueNode | SerovalReferenceNode { - const id = createIndexedValue(ids, marked, current); - if (marked.has(id)) { - return createIndexedValueNode(id); - } - if (hasReferenceID(current)) { - return createReferenceNode(id, current); - } - return id; -} - -export function getStrictVanillaReference( - ids: Map, - marked: Set, - current: T, -): SerovalIndexedValueNode | SerovalReferenceNode { - const id = createIndexedValue(ids, marked, current); - if (marked.has(id)) { - return createIndexedValueNode(id); - } - return createReferenceNode(id, current); -} diff --git a/packages/seroval/src/core/tree/serialize.ts b/packages/seroval/src/core/tree/serializer.ts similarity index 83% rename from packages/seroval/src/core/tree/serialize.ts rename to packages/seroval/src/core/tree/serializer.ts index 5f45073b..391493c7 100644 --- a/packages/seroval/src/core/tree/serialize.ts +++ b/packages/seroval/src/core/tree/serializer.ts @@ -8,11 +8,10 @@ import type { SerovalReadableStreamEnqueueNode, SerovalReadableStreamErrorNode, } from '../types'; -import type { BaseSerializerContextOptions } from '../serializer-context.old'; -import BaseSerializerContext from '../serializer-context.old'; -import getIdentifier from '../get-identifier'; +import type { BaseSerializerContextOptions } from '../context/serializer'; +import BaseSerializerContext from '../context/serializer'; +import getIdentifier from '../utils/get-identifier'; import type { SerovalMode } from '../plugin'; -import { Feature } from '../compat'; import { SerovalNodeType } from '../constants'; export type VanillaSerializerContextOptions = BaseSerializerContextOptions @@ -30,7 +29,7 @@ export default class VanillaSerializerContext extends BaseSerializerContext { * Variables * @private */ - vars: (string | undefined)[] = []; + vars: string[] = []; /** * Increments the number of references the referenced value has @@ -131,17 +130,7 @@ export default class VanillaSerializerContext extends BaseSerializerContext { body = index + '=' + body; } } - let params = this.vars.length > 1 - ? this.vars.join(',') - : this.vars[0]; - // Source is probably already assigned - if (this.features & Feature.ArrowFunction) { - params = this.vars.length > 1 || this.vars.length === 0 - ? '(' + params + ')' - : params; - return '(' + params + '=>(' + body + '))()'; - } - return '(function(' + params + '){return ' + body + '})()'; + return '(' + this.createFunction(this.vars, '(' + body + ')') + ')()'; } if (tree.t === SerovalNodeType.Object) { return '(' + result + ')'; diff --git a/packages/seroval/src/core/tree/sync.ts b/packages/seroval/src/core/tree/sync.ts index 8e730bfd..87b90907 100644 --- a/packages/seroval/src/core/tree/sync.ts +++ b/packages/seroval/src/core/tree/sync.ts @@ -1,5 +1,5 @@ -import BaseSyncParserContext from '../base/sync'; -import type { BaseParserContextOptions } from '../parser-context'; +import BaseSyncParserContext from '../context/parser/sync'; +import type { BaseParserContextOptions } from '../context/parser'; import type { SerovalMode } from '../plugin'; export type SyncParserContextOptions = Omit; diff --git a/packages/seroval/src/core/types.ts b/packages/seroval/src/core/types.ts index 4a3ebd42..26e83e3b 100644 --- a/packages/seroval/src/core/types.ts +++ b/packages/seroval/src/core/types.ts @@ -33,13 +33,9 @@ export interface SerovalBaseNode { o: SerovalObjectFlags | undefined; } -export const enum SerovalObjectRecordSpecialKey { - SymbolIterator = 0, -} - export type SerovalObjectRecordKey = | string - | SerovalObjectRecordSpecialKey; + | SerovalNode; export interface SerovalPlainRecordNode { k: string[]; @@ -166,6 +162,7 @@ export interface SerovalMapNode extends SerovalBaseNode { i: number; // key/value pairs e: SerovalMapRecordNode; + f: SerovalMapSentinelNode | SerovalIndexedValueNode; } export interface SerovalArrayNode extends SerovalBaseNode { @@ -392,6 +389,53 @@ export interface SerovalPluginNode extends SerovalBaseNode { c: string; } +export interface SerovalMapSentinelNode extends SerovalBaseNode { + t: SerovalNodeType.MapSentinel; + i: number; +} + +export interface SerovalIteratorFactoryNode extends SerovalBaseNode { + t: SerovalNodeType.IteratorFactory; + i: number; + f: SerovalNode; +} + +export interface SerovalIteratorFactoryInstanceNode extends SerovalBaseNode { + t: SerovalNodeType.IteratorFactoryInstance; + a: [ + instance: SerovalNode, + sequence: SerovalNode, + ]; +} + +export interface SerovalAsyncIteratorFactoryNode extends SerovalBaseNode { + t: SerovalNodeType.AsyncIteratorFactory; + i: number; + f: SerovalNode; +} + +export interface SerovalAsyncIteratorFactoryInstanceNode extends SerovalBaseNode { + t: SerovalNodeType.AsyncIteratorFactoryInstance; + a: [ + instance: SerovalNode, + sequence: SerovalNode, + ]; +} + +export interface SerovalReadableStreamNode extends SerovalBaseNode { + t: SerovalNodeType.ReadableStream; + i: number; + a: [ + instance: SerovalNode, + sequence: SerovalNode, + ]; +} + +export interface SerovalReadableStreamFactoryNode extends SerovalBaseNode { + t: SerovalNodeType.ReadableStreamFactory; + i: number; +} + export type SerovalSyncNode = | SerovalPrimitiveNode | SerovalIndexedValueNode @@ -418,7 +462,12 @@ export type SerovalSyncNode = | SerovalEventNode | SerovalCustomEventNode | SerovalDOMExceptionNode - | SerovalPluginNode; + | SerovalPluginNode + | SerovalMapSentinelNode + | SerovalIteratorFactoryNode + | SerovalIteratorFactoryInstanceNode + | SerovalAsyncIteratorFactoryNode + | SerovalAsyncIteratorFactoryInstanceNode; export type SerovalAsyncNode = | SerovalPromiseNode @@ -432,8 +481,12 @@ export type SerovalAsyncNode = | SerovalReadableStreamCloseNode | SerovalReadableStreamErrorNode | SerovalRequestNode - | SerovalResponseNode; + | SerovalResponseNode + | SerovalReadableStreamNode + | SerovalReadableStreamFactoryNode; export type SerovalNode = | SerovalSyncNode | SerovalAsyncNode; + +export type SerovalNodeWithID = Extract; diff --git a/packages/seroval/src/core/assert.ts b/packages/seroval/src/core/utils/assert.ts similarity index 100% rename from packages/seroval/src/core/assert.ts rename to packages/seroval/src/core/utils/assert.ts diff --git a/packages/seroval/src/core/constructors.ts b/packages/seroval/src/core/utils/constructors.ts similarity index 100% rename from packages/seroval/src/core/constructors.ts rename to packages/seroval/src/core/utils/constructors.ts diff --git a/packages/seroval/src/core/utils/deferred.ts b/packages/seroval/src/core/utils/deferred.ts new file mode 100644 index 00000000..6906b6ce --- /dev/null +++ b/packages/seroval/src/core/utils/deferred.ts @@ -0,0 +1,49 @@ +export interface Deferred { + promise: Promise; + resolve(value: unknown): void; + reject(value: unknown): void; +} + +export function createDeferred(): Deferred { + let resolve: Deferred['resolve']; + let reject: Deferred['reject']; + return { + promise: new Promise((res, rej) => { + resolve = res; + reject = rej; + }), + resolve(value): void { + resolve(value); + }, + reject(value): void { + reject(value); + }, + }; +} + +export interface DeferredStream { + stream: ReadableStream; + close(): void; + enqueue(chunk?: unknown): void; + error(e?: any): void; +} + +export function createDeferredStream(): DeferredStream { + let controller: ReadableStreamDefaultController; + return { + stream: new ReadableStream({ + start(current): void { + controller = current; + }, + }), + close(): void { + controller.close(); + }, + enqueue(data): void { + controller.enqueue(data); + }, + error(e): void { + controller.error(e); + }, + }; +} diff --git a/packages/seroval/src/core/shared.ts b/packages/seroval/src/core/utils/error.ts similarity index 50% rename from packages/seroval/src/core/shared.ts rename to packages/seroval/src/core/utils/error.ts index 6c60d72f..88a4abeb 100644 --- a/packages/seroval/src/core/shared.ts +++ b/packages/seroval/src/core/utils/error.ts @@ -1,12 +1,11 @@ import type { ErrorValue, -} from '../types'; -import { Feature } from './compat'; +} from '../../types'; +import { Feature } from '../compat'; import { ERROR_CONSTRUCTOR_STRING, ErrorConstructorTag, - SerovalObjectFlags, -} from './constants'; +} from '../constants'; export function getErrorConstructor(error: ErrorValue): ErrorConstructorTag { if (error instanceof EvalError) { @@ -30,62 +29,6 @@ export function getErrorConstructor(error: ErrorValue): ErrorConstructorTag { return ErrorConstructorTag.Error; } -type TypedArrayConstructor = - | Int8ArrayConstructor - | Int16ArrayConstructor - | Int32ArrayConstructor - | Uint8ArrayConstructor - | Uint16ArrayConstructor - | Uint32ArrayConstructor - | Uint8ClampedArrayConstructor - | Float32ArrayConstructor - | Float64ArrayConstructor - | BigInt64ArrayConstructor - | BigUint64ArrayConstructor; - -export function getTypedArrayConstructor(name: string): TypedArrayConstructor { - switch (name) { - case 'Int8Array': return Int8Array; - case 'Int16Array': return Int16Array; - case 'Int32Array': return Int32Array; - case 'Uint8Array': return Uint8Array; - case 'Uint16Array': return Uint16Array; - case 'Uint32Array': return Uint32Array; - case 'Uint8ClampedArray': return Uint8ClampedArray; - case 'Float32Array': return Float32Array; - case 'Float64Array': return Float64Array; - case 'BigInt64Array': return BigInt64Array; - case 'BigUint64Array': return BigUint64Array; - default: - throw new Error(`Unknown TypedArray "${name}"`); - } -} - -const IDENTIFIER_CHECK = /^[$A-Z_][0-9A-Z_$]*$/i; - -export function isValidIdentifier(name: string): boolean { - const char = name[0]; - return ( - char === '$' - || char === '_' - || (char >= 'A' && char <= 'Z') - || (char >= 'a' && char <= 'z') - ) && IDENTIFIER_CHECK.test(name); -} - -export function getObjectFlag(obj: unknown): SerovalObjectFlags { - if (Object.isFrozen(obj)) { - return SerovalObjectFlags.Frozen; - } - if (Object.isSealed(obj)) { - return SerovalObjectFlags.Sealed; - } - if (Object.isExtensible(obj)) { - return SerovalObjectFlags.None; - } - return SerovalObjectFlags.NonExtensible; -} - export function getErrorOptions( error: Error, features: number, diff --git a/packages/seroval/src/core/get-identifier.ts b/packages/seroval/src/core/utils/get-identifier.ts similarity index 100% rename from packages/seroval/src/core/get-identifier.ts rename to packages/seroval/src/core/utils/get-identifier.ts diff --git a/packages/seroval/src/core/utils/get-object-flag.ts b/packages/seroval/src/core/utils/get-object-flag.ts new file mode 100644 index 00000000..c8b0d771 --- /dev/null +++ b/packages/seroval/src/core/utils/get-object-flag.ts @@ -0,0 +1,14 @@ +import { SerovalObjectFlags } from '../constants'; + +export function getObjectFlag(obj: unknown): SerovalObjectFlags { + if (Object.isFrozen(obj)) { + return SerovalObjectFlags.Frozen; + } + if (Object.isSealed(obj)) { + return SerovalObjectFlags.Sealed; + } + if (Object.isExtensible(obj)) { + return SerovalObjectFlags.None; + } + return SerovalObjectFlags.NonExtensible; +} diff --git a/packages/seroval/src/core/utils/is-valid-identifier.ts b/packages/seroval/src/core/utils/is-valid-identifier.ts new file mode 100644 index 00000000..4e8a8fd5 --- /dev/null +++ b/packages/seroval/src/core/utils/is-valid-identifier.ts @@ -0,0 +1,11 @@ +const IDENTIFIER_CHECK = /^[$A-Z_][0-9A-Z_$]*$/i; + +export function isValidIdentifier(name: string): boolean { + const char = name[0]; + return ( + char === '$' + || char === '_' + || (char >= 'A' && char <= 'Z') + || (char >= 'a' && char <= 'z') + ) && IDENTIFIER_CHECK.test(name); +} diff --git a/packages/seroval/src/core/utils/iterator-to-sequence.ts b/packages/seroval/src/core/utils/iterator-to-sequence.ts new file mode 100644 index 00000000..b22e6472 --- /dev/null +++ b/packages/seroval/src/core/utils/iterator-to-sequence.ts @@ -0,0 +1,238 @@ +import type BaseStreamParserContext from '../context/parser/stream'; + +/* eslint-disable no-await-in-loop */ +export interface Sequence { + v: unknown[]; + t: number; + d: number; +} + +export function iteratorToSequence(source: Iterable): Sequence { + const values: unknown[] = []; + let throwsAt = -1; + let doneAt = -1; + + const iterator = source[Symbol.iterator](); + + while (true) { + try { + const value = iterator.next(); + values.push(value.value); + if (value.done) { + doneAt = values.length - 1; + break; + } + } catch (error) { + throwsAt = values.length; + values.push(error); + } + } + + return { + v: values, + t: throwsAt, + d: doneAt, + }; +} + +export function sequenceToIterator( + sequence: Sequence, +): () => IterableIterator { + return (): IterableIterator => { + let index = 0; + + return { + [Symbol.iterator](): IterableIterator { + return this; + }, + next(): IteratorResult { + if (index > sequence.d) { + return { + done: true, + value: undefined, + }; + } + const currentIndex = index++; + const currentItem = sequence.v[currentIndex]; + if (currentIndex === sequence.t) { + throw currentItem; + } + return { + done: currentIndex === sequence.d, + value: currentItem as T, + }; + }, + }; + }; +} + +export async function asyncIteratorToSequence(source: AsyncIterable): Promise { + const values: unknown[] = []; + let throwsAt = -1; + let doneAt = -1; + + const iterator = source[Symbol.asyncIterator](); + + while (true) { + try { + const value = await iterator.next(); + values.push(value.value); + if (value.done) { + doneAt = values.length - 1; + break; + } + } catch (error) { + throwsAt = values.length; + values.push(error); + } + } + + return { + v: values, + t: throwsAt, + d: doneAt, + }; +} + +export function sequenceToAsyncIterator( + sequence: Sequence, +): () => AsyncIterableIterator { + return (): AsyncIterableIterator => { + let index = 0; + return { + [Symbol.asyncIterator](): AsyncIterableIterator { + return this; + }, + async next(): Promise> { + if (index > sequence.d) { + return { + done: true, + value: undefined, + }; + } + const currentIndex = index++; + const currentItem = sequence.v[currentIndex]; + if (currentIndex === sequence.t) { + throw currentItem; + } + return Promise.resolve({ + done: currentIndex === sequence.d, + value: currentItem as T, + }); + }, + }; + }; +} + +export function asyncIteratorToReadableStream( + source: AsyncIterable, + parser: BaseStreamParserContext, +): ReadableStream { + return new ReadableStream({ + async start(controller): Promise { + const iterator = source[Symbol.asyncIterator](); + while (parser.isAlive()) { + try { + const result = await iterator.next(); + controller.enqueue([result.done ? 2 : 0, result.value]); + if (result.done) { + controller.close(); + return; + } + } catch (error) { + controller.enqueue([1, error]); + } + } + controller.close(); + }, + }); +} + +type RSNext = [0, T]; +type RSThrow = [1, any]; +type RSReturn = [2, T]; + +export type SerializedAsyncIteratorResult = RSNext | RSThrow | RSReturn; + +export function readableStreamToAsyncIterator( + source: ReadableStream>, +): () => AsyncIterableIterator { + let current = source; + return (): AsyncIterableIterator => { + const [left, right] = current.tee(); + const clone = left; + current = right; + const reader = clone.getReader(); + return { + [Symbol.asyncIterator](): AsyncIterableIterator { + return this; + }, + async next(): Promise> { + const result = await reader.read(); + if (result.done) { + return { + done: true, + value: undefined, + }; + } + const [status, value] = result.value; + if (status === 1) { + throw value; + } + return { + done: status === 2, + value, + }; + }, + }; + }; +} + +export async function readableStreamToSequence( + stream: ReadableStream, +): Promise { + const values: unknown[] = []; + let throwsAt = -1; + let doneAt = -1; + + const iterator = stream.getReader(); + + while (true) { + try { + const value = await iterator.read(); + values.push(value.value); + if (value.done) { + doneAt = values.length - 1; + break; + } + } catch (error) { + throwsAt = values.length; + doneAt = throwsAt; + values.push(error); + break; + } + } + + return { + v: values, + t: throwsAt, + d: doneAt, + }; +} + +export function sequenceToReadableStream( + sequence: Sequence, +): ReadableStream { + return new ReadableStream({ + start(controller): void { + for (let i = 0; i < sequence.d; i++) { + controller.enqueue(sequence.v[i] as T); + } + if (sequence.t === -1) { + controller.close(); + } else { + controller.error(sequence.v[sequence.t] as T); + } + }, + }); +} diff --git a/packages/seroval/src/core/promise-to-result.ts b/packages/seroval/src/core/utils/promise-to-result.ts similarity index 100% rename from packages/seroval/src/core/promise-to-result.ts rename to packages/seroval/src/core/utils/promise-to-result.ts diff --git a/packages/seroval/src/core/utils/typed-array.ts b/packages/seroval/src/core/utils/typed-array.ts new file mode 100644 index 00000000..9189436d --- /dev/null +++ b/packages/seroval/src/core/utils/typed-array.ts @@ -0,0 +1,30 @@ +type TypedArrayConstructor = + | Int8ArrayConstructor + | Int16ArrayConstructor + | Int32ArrayConstructor + | Uint8ArrayConstructor + | Uint16ArrayConstructor + | Uint32ArrayConstructor + | Uint8ClampedArrayConstructor + | Float32ArrayConstructor + | Float64ArrayConstructor + | BigInt64ArrayConstructor + | BigUint64ArrayConstructor; + +export function getTypedArrayConstructor(name: string): TypedArrayConstructor { + switch (name) { + case 'Int8Array': return Int8Array; + case 'Int16Array': return Int16Array; + case 'Int32Array': return Int32Array; + case 'Uint8Array': return Uint8Array; + case 'Uint16Array': return Uint16Array; + case 'Uint32Array': return Uint32Array; + case 'Uint8ClampedArray': return Uint8ClampedArray; + case 'Float32Array': return Float32Array; + case 'Float64Array': return Float64Array; + case 'BigInt64Array': return BigInt64Array; + case 'BigUint64Array': return BigUint64Array; + default: + throw new Error(`Unknown TypedArray "${name}"`); + } +} diff --git a/packages/seroval/src/core/web-api.ts b/packages/seroval/src/core/web-api.ts index 4609b310..ff093a03 100644 --- a/packages/seroval/src/core/web-api.ts +++ b/packages/seroval/src/core/web-api.ts @@ -1,6 +1,14 @@ import { SerovalNodeType } from './constants'; import { serializeString } from './string'; -import type { SerovalDOMExceptionNode, SerovalURLNode, SerovalURLSearchParamsNode } from './types'; +import type { + SerovalCustomEventNode, + SerovalDOMExceptionNode, + SerovalEventNode, + SerovalNode, + SerovalReadableStreamNode, + SerovalURLNode, + SerovalURLSearchParamsNode, +} from './types'; export function createURLNode( id: number, @@ -61,3 +69,69 @@ export function createDOMExceptionNode( o: undefined, }; } + +export function createEventNode( + id: number, + type: string, + options: SerovalNode, +): SerovalEventNode { + return { + t: SerovalNodeType.Event, + i: id, + s: serializeString(type), + l: undefined, + c: undefined, + m: undefined, + p: undefined, + e: undefined, + a: undefined, + f: options, + b: undefined, + o: undefined, + }; +} + +export function createCustomEventNode( + id: number, + type: string, + options: SerovalNode, +): SerovalCustomEventNode { + return { + t: SerovalNodeType.CustomEvent, + i: id, + s: serializeString(type), + l: undefined, + c: undefined, + m: undefined, + p: undefined, + e: undefined, + a: undefined, + f: options, + b: undefined, + o: undefined, + }; +} + +export function createReadableStreamNode( + id: number, + factory: SerovalNode, + items: SerovalNode, +): SerovalReadableStreamNode { + return { + t: SerovalNodeType.ReadableStream, + i: id, + s: undefined, + l: undefined, + c: undefined, + m: undefined, + p: undefined, + e: undefined, + a: [ + factory, + items, + ], + f: undefined, + b: undefined, + o: undefined, + }; +} diff --git a/packages/seroval/src/example.ts b/packages/seroval/src/example.ts index d64ff487..1b5cc079 100644 --- a/packages/seroval/src/example.ts +++ b/packages/seroval/src/example.ts @@ -22,7 +22,4 @@ const BufferPlugin = createPlugin({ deserialize(node, ctx) { return Buffer.from(ctx.deserialize(node) as string, 'base64'); }, - isIterable() { - return true; - }, }); diff --git a/packages/seroval/test/__snapshots__/array.test.ts.snap b/packages/seroval/test/__snapshots__/array.test.ts.snap index ee3d7aea..128ec4d6 100644 --- a/packages/seroval/test/__snapshots__/array.test.ts.snap +++ b/packages/seroval/test/__snapshots__/array.test.ts.snap @@ -1,30 +1,30 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`arrays > crossSerialize > scoped > supports Arrays 1`] = `"($R=>($R[0]=[1,2,3]))($R[\\"example\\"])"`; +exports[`arrays > crossSerialize > scoped > supports Arrays 1`] = `"($R=>$R[0]=[1,2,3])($R[\\"example\\"])"`; -exports[`arrays > crossSerialize > scoped > supports self recursion 1`] = `"($R=>($R[0]=[,,],$R[0][1]=$R[0][0]=$R[0],$R[0]))($R[\\"example\\"])"`; +exports[`arrays > crossSerialize > scoped > supports self recursion 1`] = `"($R=>$R[0]=[,,],$R[0][1]=$R[0][0]=$R[0],$R[0])($R[\\"example\\"])"`; exports[`arrays > crossSerialize > supports Arrays 1`] = `"$R[0]=[1,2,3]"`; exports[`arrays > crossSerialize > supports self recursion 1`] = `"($R[0]=[,,],$R[0][1]=$R[0][0]=$R[0],$R[0])"`; -exports[`arrays > crossSerializeAsync > scoped > supports Arrays 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=[1,2,3])))($R[\\"example\\"])"`; +exports[`arrays > crossSerializeAsync > scoped > supports Arrays 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=[1,2,3]))($R[\\"example\\"])"`; -exports[`arrays > crossSerializeAsync > scoped > supports self recursion 1`] = `"($R=>($R[0]=[$R[1]=Promise.resolve().then(()=>$R[0]),$R[2]=Promise.resolve().then(()=>$R[0])]))($R[\\"example\\"])"`; +exports[`arrays > crossSerializeAsync > scoped > supports self recursion 1`] = `"($R=>$R[0]=[$R[1]=Promise.resolve().then(()=>$R[0]),$R[2]=Promise.resolve().then(()=>$R[0])])($R[\\"example\\"])"`; exports[`arrays > crossSerializeAsync > supports Arrays 1`] = `"$R[0]=Promise.resolve($R[1]=[1,2,3])"`; exports[`arrays > crossSerializeAsync > supports self recursion 1`] = `"$R[0]=[$R[1]=Promise.resolve().then(()=>$R[0]),$R[2]=Promise.resolve().then(()=>$R[0])]"`; -exports[`arrays > crossSerializeStream > scoped > supports Arrays 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`arrays > crossSerializeStream > scoped > supports Arrays 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`arrays > crossSerializeStream > scoped > supports Arrays 2`] = `"($R=>(_$.Ps($R[0],$R[1]=[1,2,3])))($R[\\"example\\"])"`; +exports[`arrays > crossSerializeStream > scoped > supports Arrays 2`] = `"($R=>_$.Ps($R[0],$R[1]=[1,2,3]))($R[\\"example\\"])"`; -exports[`arrays > crossSerializeStream > scoped > supports self recursion 1`] = `"($R=>($R[0]=[$R[1]=_$.P(),$R[2]=_$.P()]))($R[\\"example\\"])"`; +exports[`arrays > crossSerializeStream > scoped > supports self recursion 1`] = `"($R=>$R[0]=[$R[1]=_$.P(),$R[2]=_$.P()])($R[\\"example\\"])"`; -exports[`arrays > crossSerializeStream > scoped > supports self recursion 2`] = `"($R=>(_$.Ps($R[1],$R[0])))($R[\\"example\\"])"`; +exports[`arrays > crossSerializeStream > scoped > supports self recursion 2`] = `"($R=>_$.Ps($R[1],$R[0]))($R[\\"example\\"])"`; -exports[`arrays > crossSerializeStream > scoped > supports self recursion 3`] = `"($R=>(_$.Ps($R[2],$R[0])))($R[\\"example\\"])"`; +exports[`arrays > crossSerializeStream > scoped > supports self recursion 3`] = `"($R=>_$.Ps($R[2],$R[0]))($R[\\"example\\"])"`; exports[`arrays > crossSerializeStream > supports Arrays 1`] = `"$R[0]=_$.P()"`; @@ -44,6 +44,24 @@ exports[`arrays > serializeAsync > supports Arrays 1`] = `"Promise.resolve([1,2, exports[`arrays > serializeAsync > supports self recursion 1`] = `"(h=>(h=[Promise.resolve().then(()=>h),Promise.resolve().then(()=>h)]))()"`; +exports[`arrays > toCrossJSON > supports Arrays 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}"`; + +exports[`arrays > toCrossJSON > supports self recursion 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":4,\\"i\\":0},{\\"t\\":4,\\"i\\":0}],\\"o\\":0}"`; + +exports[`arrays > toCrossJSONAsync > supports Arrays 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":9,\\"i\\":1,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}}"`; + +exports[`arrays > toCrossJSONAsync > supports self recursion 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}},{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"o\\":0}"`; + +exports[`arrays > toCrossJSONStream > supports Arrays 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`arrays > toCrossJSONStream > supports Arrays 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":9,\\"i\\":1,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}}"`; + +exports[`arrays > toCrossJSONStream > supports self recursion 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":28,\\"i\\":1},{\\"t\\":28,\\"i\\":2}],\\"o\\":0}"`; + +exports[`arrays > toCrossJSONStream > supports self recursion 2`] = `"{\\"t\\":29,\\"i\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}"`; + +exports[`arrays > toCrossJSONStream > supports self recursion 3`] = `"{\\"t\\":29,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":0}}"`; + exports[`arrays > toJSON > supports Arrays 1`] = `"{\\"t\\":{\\"t\\":9,\\"i\\":0,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0},\\"f\\":16383,\\"m\\":[]}"`; exports[`arrays > toJSON > supports self recursion 1`] = `"{\\"t\\":{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":4,\\"i\\":0},{\\"t\\":4,\\"i\\":0}],\\"o\\":0},\\"f\\":16383,\\"m\\":[0]}"`; diff --git a/packages/seroval/test/__snapshots__/async-iterable.test.ts.snap b/packages/seroval/test/__snapshots__/async-iterable.test.ts.snap new file mode 100644 index 00000000..690dcd96 --- /dev/null +++ b/packages/seroval/test/__snapshots__/async-iterable.test.ts.snap @@ -0,0 +1,53 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`AsyncIterable > compat > should use function expressions instead of arrow functions. 1`] = `"(function(h){return ({title:\\"Hello World\\",[h=Symbol.asyncIterator]:(function(s){return function(i,t){return (i=0,t={[h]:function(){return t},next:function(){return Promise.resolve().then(function(c,d){if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}})}})}})({v:[1,2,3,void 0],t:-1,d:3})})})()"`; + +exports[`AsyncIterable > compat#toJSONAsync > should use function expression instead of arrow functions. 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"title\\",{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":1,\\"s\\":\\"Hello World\\"},{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":2},\\"o\\":0},\\"f\\":16379,\\"m\\":[1]}"`; + +exports[`AsyncIterable > compat#toJSONAsync > should use function expression instead of arrow functions. 2`] = `"(function(h){return ({title:\\"Hello World\\",[h=Symbol.asyncIterator]:(function(s){return function(i,t){return (i=0,t={[h]:function(){return t},next:function(){return Promise.resolve().then(function(c,d){if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}})}})}})({v:[1,2,3,void 0],t:-1,d:3})})})()"`; + +exports[`AsyncIterable > crossSerializeAsync > scoped > supports AsyncIterables 1`] = `"($R=>$R[0]={title:\\"Hello World\\",[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})})($R[\\"example\\"])"`; + +exports[`AsyncIterable > crossSerializeAsync > supports AsyncIterables 1`] = `"$R[0]={title:\\"Hello World\\",[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})}"`; + +exports[`AsyncIterable > crossSerializeStream > scoped > supports AsyncIterables 1`] = `"($R=>$R[0]={title:\\"Hello World\\",[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]=_$.S())})($R[\\"example\\"])"`; + +exports[`AsyncIterable > crossSerializeStream > scoped > supports AsyncIterables 2`] = `"($R=>_$.Se($R[3],$R[4]=[0,1]))($R[\\"example\\"])"`; + +exports[`AsyncIterable > crossSerializeStream > scoped > supports AsyncIterables 3`] = `"($R=>_$.Se($R[3],$R[5]=[0,2]))($R[\\"example\\"])"`; + +exports[`AsyncIterable > crossSerializeStream > scoped > supports AsyncIterables 4`] = `"($R=>_$.Se($R[3],$R[6]=[0,3]))($R[\\"example\\"])"`; + +exports[`AsyncIterable > crossSerializeStream > scoped > supports AsyncIterables 5`] = `"($R=>_$.Se($R[3],$R[7]=[2,void 0]))($R[\\"example\\"])"`; + +exports[`AsyncIterable > crossSerializeStream > scoped > supports AsyncIterables 6`] = `"($R=>_$.Sc($R[3]))($R[\\"example\\"])"`; + +exports[`AsyncIterable > crossSerializeStream > supports AsyncIterables 1`] = `"$R[0]={title:\\"Hello World\\",[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]=_$.S())}"`; + +exports[`AsyncIterable > crossSerializeStream > supports AsyncIterables 2`] = `"_$.Se($R[3],$R[4]=[0,1])"`; + +exports[`AsyncIterable > crossSerializeStream > supports AsyncIterables 3`] = `"_$.Se($R[3],$R[5]=[0,2])"`; + +exports[`AsyncIterable > crossSerializeStream > supports AsyncIterables 4`] = `"_$.Se($R[3],$R[6]=[0,3])"`; + +exports[`AsyncIterable > crossSerializeStream > supports AsyncIterables 5`] = `"_$.Se($R[3],$R[7]=[2,void 0])"`; + +exports[`AsyncIterable > crossSerializeStream > supports AsyncIterables 6`] = `"_$.Sc($R[3])"`; + +exports[`AsyncIterable > serializeAsync > supports AsyncIterables 1`] = `"(h=>({title:\\"Hello World\\",[h=Symbol.asyncIterator]:(s=>(i,t)=>(i=0,t={[h]:()=>t,next:()=>Promise.resolve().then((c,d)=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}})}))({v:[1,2,3,void 0],t:-1,d:3})}))()"`; + +exports[`AsyncIterable > toCrossJSONAsync > supports AsyncIterables 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"title\\",{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":1,\\"s\\":\\"Hello World\\"},{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":2},\\"o\\":0}"`; + +exports[`AsyncIterable > toCrossJSONStream > supports AsyncIterables 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"title\\",{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":1,\\"s\\":\\"Hello World\\"},{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":31,\\"i\\":3}]}],\\"s\\":2},\\"o\\":0}"`; + +exports[`AsyncIterable > toCrossJSONStream > supports AsyncIterables 2`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":4,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":1}],\\"o\\":0}}"`; + +exports[`AsyncIterable > toCrossJSONStream > supports AsyncIterables 3`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":5,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":2}],\\"o\\":0}}"`; + +exports[`AsyncIterable > toCrossJSONStream > supports AsyncIterables 4`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":6,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}}"`; + +exports[`AsyncIterable > toCrossJSONStream > supports AsyncIterables 5`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":7,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":2},{\\"t\\":2,\\"s\\":1}],\\"o\\":0}}"`; + +exports[`AsyncIterable > toCrossJSONStream > supports AsyncIterables 6`] = `"{\\"t\\":33,\\"i\\":3}"`; + +exports[`AsyncIterable > toJSONAsync > supports AsyncIterables 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"title\\",{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":1,\\"s\\":\\"Hello World\\"},{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":2},\\"o\\":0},\\"f\\":16383,\\"m\\":[1]}"`; diff --git a/packages/seroval/test/__snapshots__/bigint.test.ts.snap b/packages/seroval/test/__snapshots__/bigint.test.ts.snap index c803bef9..a0862f46 100644 --- a/packages/seroval/test/__snapshots__/bigint.test.ts.snap +++ b/packages/seroval/test/__snapshots__/bigint.test.ts.snap @@ -16,6 +16,14 @@ exports[`bigint > serialize > supports bigint 1`] = `"9007199254740991n"`; exports[`bigint > serializeAsync > supports bigint 1`] = `"Promise.resolve(9007199254740991n)"`; +exports[`bigint > toCrossJSON > supports bigint 1`] = `"{\\"t\\":3,\\"s\\":\\"9007199254740991\\"}"`; + +exports[`bigint > toCrossJSONAsync > supports bigint 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":3,\\"s\\":\\"9007199254740991\\"}}"`; + +exports[`bigint > toCrossJSONStream > supports bigint 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`bigint > toCrossJSONStream > supports bigint 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":3,\\"s\\":\\"9007199254740991\\"}}"`; + exports[`bigint > toJSON > supports bigint 1`] = `"{\\"t\\":{\\"t\\":3,\\"s\\":\\"9007199254740991\\"},\\"f\\":16383,\\"m\\":[]}"`; exports[`bigint > toJSONAsync > supports bigint 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":3,\\"s\\":\\"9007199254740991\\"}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/boolean.test.ts.snap b/packages/seroval/test/__snapshots__/boolean.test.ts.snap index 220227f1..f360003e 100644 --- a/packages/seroval/test/__snapshots__/boolean.test.ts.snap +++ b/packages/seroval/test/__snapshots__/boolean.test.ts.snap @@ -8,18 +8,34 @@ exports[`boolean > crossSerializeAsync > supports boolean 1`] = `"$R[0]=Promise. exports[`boolean > crossSerializeAsync > supports boolean 2`] = `"$R[0]=Promise.resolve(!1)"`; -exports[`boolean > crossSerializeAsync > supports false value 1`] = `"$R[0]=_$.P()"`; +exports[`boolean > crossSerializeStream > supports false value 1`] = `"$R[0]=_$.P()"`; -exports[`boolean > crossSerializeAsync > supports false value 2`] = `"_$.Ps($R[0],!1)"`; +exports[`boolean > crossSerializeStream > supports false value 2`] = `"_$.Ps($R[0],!1)"`; -exports[`boolean > crossSerializeAsync > supports true value 1`] = `"$R[0]=_$.P()"`; +exports[`boolean > crossSerializeStream > supports true value 1`] = `"$R[0]=_$.P()"`; -exports[`boolean > crossSerializeAsync > supports true value 2`] = `"_$.Ps($R[0],!0)"`; +exports[`boolean > crossSerializeStream > supports true value 2`] = `"_$.Ps($R[0],!0)"`; -exports[`boolean > serializeAsync > supports boolean 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":2,\\"s\\":2}},\\"f\\":16383,\\"m\\":[]}"`; +exports[`boolean > toCrossJSON > supports boolean 1`] = `"{\\"t\\":2,\\"s\\":2}"`; -exports[`boolean > serializeAsync > supports boolean 2`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":2,\\"s\\":3}},\\"f\\":16383,\\"m\\":[]}"`; +exports[`boolean > toCrossJSON > supports boolean 2`] = `"{\\"t\\":2,\\"s\\":3}"`; + +exports[`boolean > toCrossJSONAsync > supports boolean 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":2,\\"s\\":2}}"`; + +exports[`boolean > toCrossJSONAsync > supports boolean 2`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":2,\\"s\\":3}}"`; + +exports[`boolean > toCrossJSONStream > supports false value 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`boolean > toCrossJSONStream > supports false value 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":3}}"`; + +exports[`boolean > toCrossJSONStream > supports true value 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`boolean > toCrossJSONStream > supports true value 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":2}}"`; exports[`boolean > toJSON > supports boolean 1`] = `"{\\"t\\":{\\"t\\":2,\\"s\\":2},\\"f\\":16383,\\"m\\":[]}"`; exports[`boolean > toJSON > supports boolean 2`] = `"{\\"t\\":{\\"t\\":2,\\"s\\":3},\\"f\\":16383,\\"m\\":[]}"`; + +exports[`boolean > toJSONAsync > supports boolean 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":2,\\"s\\":2}},\\"f\\":16383,\\"m\\":[]}"`; + +exports[`boolean > toJSONAsync > supports boolean 2`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":2,\\"s\\":3}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/boxed-bigint.test.ts.snap b/packages/seroval/test/__snapshots__/boxed-bigint.test.ts.snap index 6c12cf8e..827dcdd7 100644 --- a/packages/seroval/test/__snapshots__/boxed-bigint.test.ts.snap +++ b/packages/seroval/test/__snapshots__/boxed-bigint.test.ts.snap @@ -4,17 +4,17 @@ exports[`boxed bigint > compat > should throw an error for unsupported target 1` exports[`boxed bigint > compat#toJSON > should throw an error for unsupported target 1`] = `"Unsupported type \\"[object BigInt]\\""`; -exports[`boxed bigint > crossSerialize > scoped > supports boxed bigint 1`] = `"($R=>($R[0]=Object(9007199254740991n)))($R[\\"example\\"])"`; +exports[`boxed bigint > crossSerialize > scoped > supports boxed bigint 1`] = `"($R=>$R[0]=Object(9007199254740991n))($R[\\"example\\"])"`; exports[`boxed bigint > crossSerialize > supports boxed bigint 1`] = `"$R[0]=Object(9007199254740991n)"`; -exports[`boxed bigint > crossSerializeAsync > scoped > supports boxed bigint 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=Object(9007199254740991n))))($R[\\"example\\"])"`; +exports[`boxed bigint > crossSerializeAsync > scoped > supports boxed bigint 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=Object(9007199254740991n)))($R[\\"example\\"])"`; exports[`boxed bigint > crossSerializeAsync > supports boxed bigint 1`] = `"$R[0]=Promise.resolve($R[1]=Object(9007199254740991n))"`; -exports[`boxed bigint > crossSerializeStream > scoped > supports boxed bigint 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`boxed bigint > crossSerializeStream > scoped > supports boxed bigint 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`boxed bigint > crossSerializeStream > scoped > supports boxed bigint 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object(9007199254740991n))))($R[\\"example\\"])"`; +exports[`boxed bigint > crossSerializeStream > scoped > supports boxed bigint 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object(9007199254740991n)))($R[\\"example\\"])"`; exports[`boxed bigint > crossSerializeStream > supports boxed bigint 1`] = `"$R[0]=_$.P()"`; @@ -24,6 +24,14 @@ exports[`boxed bigint > serialize > supports boxed bigint 1`] = `"Object(9007199 exports[`boxed bigint > serializeAsync > supports boxed bigint 1`] = `"Promise.resolve(Object(9007199254740991n))"`; +exports[`boxed bigint > toCrossJSON > supports boxed bigint 1`] = `"{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":3,\\"s\\":\\"9007199254740991\\"}}"`; + +exports[`boxed bigint > toCrossJSONAsync > supports boxed bigint 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":3,\\"s\\":\\"9007199254740991\\"}}}"`; + +exports[`boxed bigint > toCrossJSONStream > supports boxed bigint 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`boxed bigint > toCrossJSONStream > supports boxed bigint 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":3,\\"s\\":\\"9007199254740991\\"}}}"`; + exports[`boxed bigint > toJSON > supports boxed bigint 1`] = `"{\\"t\\":{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":3,\\"s\\":\\"9007199254740991\\"}},\\"f\\":16383,\\"m\\":[]}"`; exports[`boxed bigint > toJSONAsync > supports boxed bigint 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":3,\\"s\\":\\"9007199254740991\\"}}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/boxed-boolean.test.ts.snap b/packages/seroval/test/__snapshots__/boxed-boolean.test.ts.snap index bb03e6d0..227bd127 100644 --- a/packages/seroval/test/__snapshots__/boxed-boolean.test.ts.snap +++ b/packages/seroval/test/__snapshots__/boxed-boolean.test.ts.snap @@ -1,21 +1,29 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`boxed boolean > crossSerialize > scoped > supports boolean 1`] = `"($R=>($R[0]=Object(!0)))($R[\\"example\\"])"`; +exports[`boxed boolean > crossSerialize > scoped > supports boolean 1`] = `"($R=>$R[0]=Object(!0))($R[\\"example\\"])"`; -exports[`boxed boolean > crossSerialize > scoped > supports boolean 2`] = `"($R=>($R[0]=Object(!1)))($R[\\"example\\"])"`; +exports[`boxed boolean > crossSerialize > scoped > supports boolean 2`] = `"($R=>$R[0]=Object(!1))($R[\\"example\\"])"`; exports[`boxed boolean > crossSerialize > supports boolean 1`] = `"$R[0]=Object(!0)"`; exports[`boxed boolean > crossSerialize > supports boolean 2`] = `"$R[0]=Object(!1)"`; -exports[`boxed boolean > crossSerializeAsync > scoped > supports boolean 1`] = `"($R=>($R[0]=Object(!0)))($R[\\"example\\"])"`; +exports[`boxed boolean > crossSerializeAsync > scoped > supports boolean 1`] = `"($R=>$R[0]=Object(!0))($R[\\"example\\"])"`; -exports[`boxed boolean > crossSerializeAsync > scoped > supports boolean 2`] = `"($R=>($R[0]=Object(!1)))($R[\\"example\\"])"`; +exports[`boxed boolean > crossSerializeAsync > scoped > supports boolean 2`] = `"($R=>$R[0]=Object(!1))($R[\\"example\\"])"`; exports[`boxed boolean > crossSerializeAsync > supports boolean 1`] = `"$R[0]=Object(!0)"`; exports[`boxed boolean > crossSerializeAsync > supports boolean 2`] = `"$R[0]=Object(!1)"`; +exports[`boxed boolean > crossSerializeStream > scoped > supports boxed false 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; + +exports[`boxed boolean > crossSerializeStream > scoped > supports boxed false 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object(!1)))($R[\\"example\\"])"`; + +exports[`boxed boolean > crossSerializeStream > scoped > supports boxed true 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; + +exports[`boxed boolean > crossSerializeStream > scoped > supports boxed true 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object(!0)))($R[\\"example\\"])"`; + exports[`boxed boolean > crossSerializeStream > supports boxed false 1`] = `"$R[0]=_$.P()"`; exports[`boxed boolean > crossSerializeStream > supports boxed false 2`] = `"_$.Ps($R[0],$R[1]=Object(!1))"`; @@ -24,10 +32,26 @@ exports[`boxed boolean > crossSerializeStream > supports boxed true 1`] = `"$R[0 exports[`boxed boolean > crossSerializeStream > supports boxed true 2`] = `"_$.Ps($R[0],$R[1]=Object(!0))"`; -exports[`boxed boolean > scoped > supports boxed false 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`boxed boolean > toCrossJSON > supports boolean 1`] = `"{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":2}}"`; + +exports[`boxed boolean > toCrossJSON > supports boolean 2`] = `"{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":3}}"`; + +exports[`boxed boolean > toCrossJSONAsync > supports boolean 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":2}}}"`; + +exports[`boxed boolean > toCrossJSONAsync > supports boolean 2`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":3}}}"`; + +exports[`boxed boolean > toCrossJSONStream > supports boxed false 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`boxed boolean > toCrossJSONStream > supports boxed false 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":3}}}"`; + +exports[`boxed boolean > toCrossJSONStream > supports boxed true 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`boxed boolean > toCrossJSONStream > supports boxed true 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":2}}}"`; + +exports[`boxed boolean > toJSON > supports boolean 1`] = `"{\\"t\\":{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":2}},\\"f\\":16383,\\"m\\":[]}"`; -exports[`boxed boolean > scoped > supports boxed false 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object(!1))))($R[\\"example\\"])"`; +exports[`boxed boolean > toJSON > supports boolean 2`] = `"{\\"t\\":{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":3}},\\"f\\":16383,\\"m\\":[]}"`; -exports[`boxed boolean > scoped > supports boxed true 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`boxed boolean > toJSONAsync > supports boolean 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":2}}},\\"f\\":16383,\\"m\\":[]}"`; -exports[`boxed boolean > scoped > supports boxed true 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object(!0))))($R[\\"example\\"])"`; +exports[`boxed boolean > toJSONAsync > supports boolean 2`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":3}}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/boxed-number.test.ts.snap b/packages/seroval/test/__snapshots__/boxed-number.test.ts.snap index 0085c836..52c539bb 100644 --- a/packages/seroval/test/__snapshots__/boxed-number.test.ts.snap +++ b/packages/seroval/test/__snapshots__/boxed-number.test.ts.snap @@ -1,14 +1,14 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`boxed number > crossSerialize > scoped > supports boxed numbers 1`] = `"($R=>($R[0]=Object(3735928559)))($R[\\"example\\"])"`; +exports[`boxed number > crossSerialize > scoped > supports boxed numbers 1`] = `"($R=>$R[0]=Object(3735928559))($R[\\"example\\"])"`; -exports[`boxed number > crossSerialize > scoped > supports boxed numbers 2`] = `"($R=>($R[0]=Object(0/0)))($R[\\"example\\"])"`; +exports[`boxed number > crossSerialize > scoped > supports boxed numbers 2`] = `"($R=>$R[0]=Object(0/0))($R[\\"example\\"])"`; -exports[`boxed number > crossSerialize > scoped > supports boxed numbers 3`] = `"($R=>($R[0]=Object(1/0)))($R[\\"example\\"])"`; +exports[`boxed number > crossSerialize > scoped > supports boxed numbers 3`] = `"($R=>$R[0]=Object(1/0))($R[\\"example\\"])"`; -exports[`boxed number > crossSerialize > scoped > supports boxed numbers 4`] = `"($R=>($R[0]=Object(-1/0)))($R[\\"example\\"])"`; +exports[`boxed number > crossSerialize > scoped > supports boxed numbers 4`] = `"($R=>$R[0]=Object(-1/0))($R[\\"example\\"])"`; -exports[`boxed number > crossSerialize > scoped > supports boxed numbers 5`] = `"($R=>($R[0]=Object(-0)))($R[\\"example\\"])"`; +exports[`boxed number > crossSerialize > scoped > supports boxed numbers 5`] = `"($R=>$R[0]=Object(-0))($R[\\"example\\"])"`; exports[`boxed number > crossSerialize > supports boxed numbers 1`] = `"$R[0]=Object(3735928559)"`; @@ -20,15 +20,15 @@ exports[`boxed number > crossSerialize > supports boxed numbers 4`] = `"$R[0]=Ob exports[`boxed number > crossSerialize > supports boxed numbers 5`] = `"$R[0]=Object(-0)"`; -exports[`boxed number > crossSerializeAsync > scoped > supports boxed numbers 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=Object(3735928559))))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeAsync > scoped > supports boxed numbers 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=Object(3735928559)))($R[\\"example\\"])"`; -exports[`boxed number > crossSerializeAsync > scoped > supports boxed numbers 2`] = `"($R=>($R[0]=Promise.resolve($R[1]=Object(0/0))))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeAsync > scoped > supports boxed numbers 2`] = `"($R=>$R[0]=Promise.resolve($R[1]=Object(0/0)))($R[\\"example\\"])"`; -exports[`boxed number > crossSerializeAsync > scoped > supports boxed numbers 3`] = `"($R=>($R[0]=Promise.resolve($R[1]=Object(1/0))))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeAsync > scoped > supports boxed numbers 3`] = `"($R=>$R[0]=Promise.resolve($R[1]=Object(1/0)))($R[\\"example\\"])"`; -exports[`boxed number > crossSerializeAsync > scoped > supports boxed numbers 4`] = `"($R=>($R[0]=Promise.resolve($R[1]=Object(-1/0))))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeAsync > scoped > supports boxed numbers 4`] = `"($R=>$R[0]=Promise.resolve($R[1]=Object(-1/0)))($R[\\"example\\"])"`; -exports[`boxed number > crossSerializeAsync > scoped > supports boxed numbers 5`] = `"($R=>($R[0]=Promise.resolve($R[1]=Object(-0))))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeAsync > scoped > supports boxed numbers 5`] = `"($R=>$R[0]=Promise.resolve($R[1]=Object(-0)))($R[\\"example\\"])"`; exports[`boxed number > crossSerializeAsync > supports boxed numbers 1`] = `"$R[0]=Promise.resolve($R[1]=Object(3735928559))"`; @@ -40,25 +40,25 @@ exports[`boxed number > crossSerializeAsync > supports boxed numbers 4`] = `"$R[ exports[`boxed number > crossSerializeAsync > supports boxed numbers 5`] = `"$R[0]=Promise.resolve($R[1]=Object(-0))"`; -exports[`boxed number > crossSerializeStream > scoped > supports boxed -0 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeStream > scoped > supports boxed -0 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`boxed number > crossSerializeStream > scoped > supports boxed -0 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object(-0))))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeStream > scoped > supports boxed -0 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object(-0)))($R[\\"example\\"])"`; -exports[`boxed number > crossSerializeStream > scoped > supports boxed -Infinity 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeStream > scoped > supports boxed -Infinity 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`boxed number > crossSerializeStream > scoped > supports boxed -Infinity 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object(-1/0))))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeStream > scoped > supports boxed -Infinity 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object(-1/0)))($R[\\"example\\"])"`; -exports[`boxed number > crossSerializeStream > scoped > supports boxed Infinity 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeStream > scoped > supports boxed Infinity 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`boxed number > crossSerializeStream > scoped > supports boxed Infinity 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object(1/0))))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeStream > scoped > supports boxed Infinity 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object(1/0)))($R[\\"example\\"])"`; -exports[`boxed number > crossSerializeStream > scoped > supports boxed NaN 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeStream > scoped > supports boxed NaN 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`boxed number > crossSerializeStream > scoped > supports boxed NaN 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object(0/0))))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeStream > scoped > supports boxed NaN 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object(0/0)))($R[\\"example\\"])"`; -exports[`boxed number > crossSerializeStream > scoped > supports boxed numbers 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeStream > scoped > supports boxed numbers 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`boxed number > crossSerializeStream > scoped > supports boxed numbers 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object(3735928559))))($R[\\"example\\"])"`; +exports[`boxed number > crossSerializeStream > scoped > supports boxed numbers 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object(3735928559)))($R[\\"example\\"])"`; exports[`boxed number > crossSerializeStream > supports boxed -0 1`] = `"$R[0]=_$.P()"`; @@ -80,6 +80,46 @@ exports[`boxed number > crossSerializeStream > supports boxed numbers 1`] = `"$R exports[`boxed number > crossSerializeStream > supports boxed numbers 2`] = `"_$.Ps($R[0],$R[1]=Object(3735928559))"`; +exports[`boxed number > toCrossJSON > supports boxed numbers 1`] = `"{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":0,\\"s\\":3735928559}}"`; + +exports[`boxed number > toCrossJSON > supports boxed numbers 2`] = `"{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":7}}"`; + +exports[`boxed number > toCrossJSON > supports boxed numbers 3`] = `"{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":5}}"`; + +exports[`boxed number > toCrossJSON > supports boxed numbers 4`] = `"{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":6}}"`; + +exports[`boxed number > toCrossJSON > supports boxed numbers 5`] = `"{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":4}}"`; + +exports[`boxed number > toCrossJSONAsync > supports boxed numbers 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":0,\\"s\\":3735928559}}}"`; + +exports[`boxed number > toCrossJSONAsync > supports boxed numbers 2`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":7}}}"`; + +exports[`boxed number > toCrossJSONAsync > supports boxed numbers 3`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":5}}}"`; + +exports[`boxed number > toCrossJSONAsync > supports boxed numbers 4`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":6}}}"`; + +exports[`boxed number > toCrossJSONAsync > supports boxed numbers 5`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":4}}}"`; + +exports[`boxed number > toCrossJSONStream > supports boxed -0 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`boxed number > toCrossJSONStream > supports boxed -0 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":4}}}"`; + +exports[`boxed number > toCrossJSONStream > supports boxed -Infinity 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`boxed number > toCrossJSONStream > supports boxed -Infinity 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":6}}}"`; + +exports[`boxed number > toCrossJSONStream > supports boxed Infinity 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`boxed number > toCrossJSONStream > supports boxed Infinity 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":5}}}"`; + +exports[`boxed number > toCrossJSONStream > supports boxed NaN 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`boxed number > toCrossJSONStream > supports boxed NaN 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":2,\\"s\\":7}}}"`; + +exports[`boxed number > toCrossJSONStream > supports boxed numbers 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`boxed number > toCrossJSONStream > supports boxed numbers 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":0,\\"s\\":3735928559}}}"`; + exports[`boxed number > toJSON > supports boxed numbers 1`] = `"{\\"t\\":{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":0,\\"s\\":3735928559}},\\"f\\":16383,\\"m\\":[]}"`; exports[`boxed number > toJSON > supports boxed numbers 2`] = `"{\\"t\\":{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":7}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/boxed-string.test.ts.snap b/packages/seroval/test/__snapshots__/boxed-string.test.ts.snap index f9234e24..d09ed0e0 100644 --- a/packages/seroval/test/__snapshots__/boxed-string.test.ts.snap +++ b/packages/seroval/test/__snapshots__/boxed-string.test.ts.snap @@ -1,28 +1,28 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`boxed string > crossSerialize > scoped > supports boxed strings 1`] = `"($R=>($R[0]=Object(\\"\\\\\\"hello\\\\\\"\\")))($R[\\"example\\"])"`; +exports[`boxed string > crossSerialize > scoped > supports boxed strings 1`] = `"($R=>$R[0]=Object(\\"\\\\\\"hello\\\\\\"\\"))($R[\\"example\\"])"`; -exports[`boxed string > crossSerialize > scoped > supports boxed strings 2`] = `"($R=>($R[0]=Object(\\"\\\\x3Cscript>\\\\x3C/script>\\")))($R[\\"example\\"])"`; +exports[`boxed string > crossSerialize > scoped > supports boxed strings 2`] = `"($R=>$R[0]=Object(\\"\\\\x3Cscript>\\\\x3C/script>\\"))($R[\\"example\\"])"`; exports[`boxed string > crossSerialize > supports boxed strings 1`] = `"$R[0]=Object(\\"\\\\\\"hello\\\\\\"\\")"`; exports[`boxed string > crossSerialize > supports boxed strings 2`] = `"$R[0]=Object(\\"\\\\x3Cscript>\\\\x3C/script>\\")"`; -exports[`boxed string > crossSerializeAsync > scoped > supports boxed strings 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=Object(\\"\\\\\\"hello\\\\\\"\\"))))($R[\\"example\\"])"`; +exports[`boxed string > crossSerializeAsync > scoped > supports boxed strings 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=Object(\\"\\\\\\"hello\\\\\\"\\")))($R[\\"example\\"])"`; -exports[`boxed string > crossSerializeAsync > scoped > supports boxed strings 2`] = `"($R=>($R[0]=Promise.resolve($R[1]=Object(\\"\\\\x3Cscript>\\\\x3C/script>\\"))))($R[\\"example\\"])"`; +exports[`boxed string > crossSerializeAsync > scoped > supports boxed strings 2`] = `"($R=>$R[0]=Promise.resolve($R[1]=Object(\\"\\\\x3Cscript>\\\\x3C/script>\\")))($R[\\"example\\"])"`; exports[`boxed string > crossSerializeAsync > supports boxed strings 1`] = `"$R[0]=Promise.resolve($R[1]=Object(\\"\\\\\\"hello\\\\\\"\\"))"`; exports[`boxed string > crossSerializeAsync > supports boxed strings 2`] = `"$R[0]=Promise.resolve($R[1]=Object(\\"\\\\x3Cscript>\\\\x3C/script>\\"))"`; -exports[`boxed string > crossSerializeStream > scoped > supports boxed sanitized strings 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`boxed string > crossSerializeStream > scoped > supports boxed sanitized strings 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`boxed string > crossSerializeStream > scoped > supports boxed sanitized strings 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object(\\"\\\\x3Cscript>\\\\x3C/script>\\"))))($R[\\"example\\"])"`; +exports[`boxed string > crossSerializeStream > scoped > supports boxed sanitized strings 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object(\\"\\\\x3Cscript>\\\\x3C/script>\\")))($R[\\"example\\"])"`; -exports[`boxed string > crossSerializeStream > scoped > supports boxed strings 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`boxed string > crossSerializeStream > scoped > supports boxed strings 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`boxed string > crossSerializeStream > scoped > supports boxed strings 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object(\\"\\\\\\"hello\\\\\\"\\"))))($R[\\"example\\"])"`; +exports[`boxed string > crossSerializeStream > scoped > supports boxed strings 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object(\\"\\\\\\"hello\\\\\\"\\")))($R[\\"example\\"])"`; exports[`boxed string > crossSerializeStream > supports boxed sanitized strings 1`] = `"$R[0]=_$.P()"`; @@ -40,6 +40,22 @@ exports[`boxed string > serializeAsync > supports boxed strings 1`] = `"Promise. exports[`boxed string > serializeAsync > supports boxed strings 2`] = `"Promise.resolve(Object(\\"\\\\x3Cscript>\\\\x3C/script>\\"))"`; +exports[`boxed string > toCrossJSON > supports boxed strings 1`] = `"{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\\\\\\\"hello\\\\\\\\\\\\\\"\\"}}"`; + +exports[`boxed string > toCrossJSON > supports boxed strings 2`] = `"{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\x3Cscript>\\\\\\\\x3C/script>\\"}}"`; + +exports[`boxed string > toCrossJSONAsync > supports boxed strings 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\\\\\\\"hello\\\\\\\\\\\\\\"\\"}}}"`; + +exports[`boxed string > toCrossJSONAsync > supports boxed strings 2`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\x3Cscript>\\\\\\\\x3C/script>\\"}}}"`; + +exports[`boxed string > toCrossJSONStream > supports boxed sanitized strings 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`boxed string > toCrossJSONStream > supports boxed sanitized strings 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\x3Cscript>\\\\\\\\x3C/script>\\"}}}"`; + +exports[`boxed string > toCrossJSONStream > supports boxed strings 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`boxed string > toCrossJSONStream > supports boxed strings 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":27,\\"i\\":1,\\"f\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\\\\\\\"hello\\\\\\\\\\\\\\"\\"}}}"`; + exports[`boxed string > toJSON > supports boxed strings 1`] = `"{\\"t\\":{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\\\\\\\"hello\\\\\\\\\\\\\\"\\"}},\\"f\\":16383,\\"m\\":[]}"`; exports[`boxed string > toJSON > supports boxed strings 2`] = `"{\\"t\\":{\\"t\\":27,\\"i\\":0,\\"f\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\x3Cscript>\\\\\\\\x3C/script>\\"}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/data-view.test.ts.snap b/packages/seroval/test/__snapshots__/data-view.test.ts.snap index 87ce3634..0840cc69 100644 --- a/packages/seroval/test/__snapshots__/data-view.test.ts.snap +++ b/packages/seroval/test/__snapshots__/data-view.test.ts.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`DataView > crossSerialize > scoped > supports DataView 1`] = `"($R=>($R[0]=new DataView($R[1]=new Uint8Array([0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]).buffer,0,16)))($R[\\"example\\"])"`; +exports[`DataView > crossSerialize > scoped > supports DataView 1`] = `"($R=>$R[0]=new DataView($R[1]=new Uint8Array([0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]).buffer,0,16))($R[\\"example\\"])"`; exports[`DataView > crossSerialize > supports DataView 1`] = `"$R[0]=new DataView($R[1]=new Uint8Array([0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]).buffer,0,16)"`; -exports[`DataView > crossSerializeAsync > scoped > supports DataView 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=new DataView($R[2]=new Uint8Array([0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]).buffer,0,16))))($R[\\"example\\"])"`; +exports[`DataView > crossSerializeAsync > scoped > supports DataView 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=new DataView($R[2]=new Uint8Array([0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]).buffer,0,16)))($R[\\"example\\"])"`; exports[`DataView > crossSerializeAsync > supports DataView 1`] = `"$R[0]=Promise.resolve($R[1]=new DataView($R[2]=new Uint8Array([0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]).buffer,0,16))"`; -exports[`DataView > crossSerializeStream > scoped > supports DataView 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`DataView > crossSerializeStream > scoped > supports DataView 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`DataView > crossSerializeStream > scoped > supports DataView 2`] = `"($R=>(_$.Ps($R[0],$R[1]=new DataView($R[2]=new Uint8Array([0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]).buffer,0,16))))($R[\\"example\\"])"`; +exports[`DataView > crossSerializeStream > scoped > supports DataView 2`] = `"($R=>_$.Ps($R[0],$R[1]=new DataView($R[2]=new Uint8Array([0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]).buffer,0,16)))($R[\\"example\\"])"`; exports[`DataView > crossSerializeStream > supports DataView 1`] = `"$R[0]=_$.P()"`; @@ -20,6 +20,14 @@ exports[`DataView > serialize > supports DataView 1`] = `"new DataView(new Uint8 exports[`DataView > serializeAsync > supports DataView 1`] = `"Promise.resolve(new DataView(new Uint8Array([0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]).buffer,0,16))"`; +exports[`DataView > toCrossJSON > supports DataView 1`] = `"{\\"t\\":22,\\"i\\":0,\\"l\\":16,\\"f\\":{\\"t\\":21,\\"i\\":1,\\"s\\":[0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]},\\"b\\":0}"`; + +exports[`DataView > toCrossJSONAsync > supports DataView 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":22,\\"i\\":1,\\"l\\":16,\\"f\\":{\\"t\\":21,\\"i\\":2,\\"s\\":[0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]},\\"b\\":0}}"`; + +exports[`DataView > toCrossJSONStream > supports DataView 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`DataView > toCrossJSONStream > supports DataView 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":22,\\"i\\":1,\\"l\\":16,\\"f\\":{\\"t\\":21,\\"i\\":2,\\"s\\":[0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]},\\"b\\":0}}"`; + exports[`DataView > toJSON > supports DataView 1`] = `"{\\"t\\":{\\"t\\":22,\\"i\\":0,\\"l\\":16,\\"f\\":{\\"t\\":21,\\"i\\":1,\\"s\\":[0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]},\\"b\\":0},\\"f\\":16383,\\"m\\":[]}"`; exports[`DataView > toJSONAsync > supports DataView 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":22,\\"i\\":1,\\"l\\":16,\\"f\\":{\\"t\\":21,\\"i\\":2,\\"s\\":[0,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0]},\\"b\\":0}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/date.test.ts.snap b/packages/seroval/test/__snapshots__/date.test.ts.snap index 521b4435..94cbcc9f 100644 --- a/packages/seroval/test/__snapshots__/date.test.ts.snap +++ b/packages/seroval/test/__snapshots__/date.test.ts.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Date > crossSerialize > scoped > supports Date 1`] = `"($R=>($R[0]=new Date(\\"2023-03-14T11:16:24.879Z\\")))($R[\\"example\\"])"`; +exports[`Date > crossSerialize > scoped > supports Date 1`] = `"($R=>$R[0]=new Date(\\"2023-03-14T11:16:24.879Z\\"))($R[\\"example\\"])"`; exports[`Date > crossSerialize > supports Date 1`] = `"$R[0]=new Date(\\"2023-03-14T11:16:24.879Z\\")"`; -exports[`Date > crossSerializeAsync > scoped > supports Date 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=new Date(\\"2023-03-14T11:16:24.879Z\\"))))($R[\\"example\\"])"`; +exports[`Date > crossSerializeAsync > scoped > supports Date 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=new Date(\\"2023-03-14T11:16:24.879Z\\")))($R[\\"example\\"])"`; exports[`Date > crossSerializeAsync > supports Date 1`] = `"$R[0]=Promise.resolve($R[1]=new Date(\\"2023-03-14T11:16:24.879Z\\"))"`; -exports[`Date > crossSerializeStream > scoped > supports Date 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`Date > crossSerializeStream > scoped > supports Date 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`Date > crossSerializeStream > scoped > supports Date 2`] = `"($R=>(_$.Ps($R[0],$R[1]=new Date(\\"2023-03-14T11:16:24.879Z\\"))))($R[\\"example\\"])"`; +exports[`Date > crossSerializeStream > scoped > supports Date 2`] = `"($R=>_$.Ps($R[0],$R[1]=new Date(\\"2023-03-14T11:16:24.879Z\\")))($R[\\"example\\"])"`; exports[`Date > crossSerializeStream > supports Date 1`] = `"$R[0]=_$.P()"`; @@ -20,6 +20,14 @@ exports[`Date > serialize > supports Date 1`] = `"new Date(\\"2023-03-14T11:16:2 exports[`Date > serializeAsync > supports Date 1`] = `"Promise.resolve(new Date(\\"2023-03-14T11:16:24.879Z\\"))"`; +exports[`Date > toCrossJSON > supports Date 1`] = `"{\\"t\\":5,\\"i\\":0,\\"s\\":\\"2023-03-14T11:16:24.879Z\\"}"`; + +exports[`Date > toCrossJSONAsync > supports Date 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":5,\\"i\\":1,\\"s\\":\\"2023-03-14T11:16:24.879Z\\"}}"`; + +exports[`Date > toCrossJSONStream > supports Date 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`Date > toCrossJSONStream > supports Date 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":5,\\"i\\":1,\\"s\\":\\"2023-03-14T11:16:24.879Z\\"}}"`; + exports[`Date > toJSON > supports Date 1`] = `"{\\"t\\":{\\"t\\":5,\\"i\\":0,\\"s\\":\\"2023-03-14T11:16:24.879Z\\"},\\"f\\":16383,\\"m\\":[]}"`; exports[`Date > toJSONAsync > supports Date 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":5,\\"i\\":1,\\"s\\":\\"2023-03-14T11:16:24.879Z\\"}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/error.test.ts.snap b/packages/seroval/test/__snapshots__/error.test.ts.snap index 74b6d7e9..9bcd70d2 100644 --- a/packages/seroval/test/__snapshots__/error.test.ts.snap +++ b/packages/seroval/test/__snapshots__/error.test.ts.snap @@ -1,10 +1,10 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Error > crossSerialize > scoped > supports Error.prototype.cause 1`] = `"($R=>($R[0]=Object.assign(new Error(\\"B\\"),{stack:\\"\\",cause:$R[1]=Object.assign(new Error(\\"A\\"),{stack:\\"\\"})})))($R[\\"example\\"])"`; +exports[`Error > crossSerialize > scoped > supports Error.prototype.cause 1`] = `"($R=>$R[0]=Object.assign(new Error(\\"B\\"),{stack:\\"\\",cause:$R[1]=Object.assign(new Error(\\"A\\"),{stack:\\"\\"})}))($R[\\"example\\"])"`; -exports[`Error > crossSerialize > scoped > supports Error.prototype.name 1`] = `"($R=>($R[0]=Object.assign(new Error(\\"A\\"),{name:\\"ExampleError\\",stack:\\"\\"})))($R[\\"example\\"])"`; +exports[`Error > crossSerialize > scoped > supports Error.prototype.name 1`] = `"($R=>$R[0]=Object.assign(new Error(\\"A\\"),{name:\\"ExampleError\\",stack:\\"\\"}))($R[\\"example\\"])"`; -exports[`Error > crossSerialize > scoped > supports other Error classes 1`] = `"($R=>($R[0]=Object.assign(new ReferenceError(\\"A\\"),{stack:\\"\\"})))($R[\\"example\\"])"`; +exports[`Error > crossSerialize > scoped > supports other Error classes 1`] = `"($R=>$R[0]=Object.assign(new ReferenceError(\\"A\\"),{stack:\\"\\"}))($R[\\"example\\"])"`; exports[`Error > crossSerialize > supports Error.prototype.cause 1`] = `"$R[0]=Object.assign(new Error(\\"B\\"),{stack:\\"\\",cause:$R[1]=Object.assign(new Error(\\"A\\"),{stack:\\"\\"})})"`; @@ -12,11 +12,11 @@ exports[`Error > crossSerialize > supports Error.prototype.name 1`] = `"$R[0]=Ob exports[`Error > crossSerialize > supports other Error classes 1`] = `"$R[0]=Object.assign(new ReferenceError(\\"A\\"),{stack:\\"\\"})"`; -exports[`Error > crossSerializeAsync > scoped > supports Error.prototype.cause 1`] = `"($R=>($R[0]=Object.assign(new Error(\\"B\\"),{stack:\\"\\",cause:$R[1]=Promise.resolve($R[2]=Object.assign(new Error(\\"A\\"),{stack:\\"\\"}))})))($R[\\"example\\"])"`; +exports[`Error > crossSerializeAsync > scoped > supports Error.prototype.cause 1`] = `"($R=>$R[0]=Object.assign(new Error(\\"B\\"),{stack:\\"\\",cause:$R[1]=Promise.resolve($R[2]=Object.assign(new Error(\\"A\\"),{stack:\\"\\"}))}))($R[\\"example\\"])"`; -exports[`Error > crossSerializeAsync > scoped > supports Error.prototype.name 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=Object.assign(new Error(\\"A\\"),{name:\\"ExampleError\\",stack:\\"\\"}))))($R[\\"example\\"])"`; +exports[`Error > crossSerializeAsync > scoped > supports Error.prototype.name 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=Object.assign(new Error(\\"A\\"),{name:\\"ExampleError\\",stack:\\"\\"})))($R[\\"example\\"])"`; -exports[`Error > crossSerializeAsync > scoped > supports other Error classes 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=Object.assign(new ReferenceError(\\"A\\"),{stack:\\"\\"}))))($R[\\"example\\"])"`; +exports[`Error > crossSerializeAsync > scoped > supports other Error classes 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=Object.assign(new ReferenceError(\\"A\\"),{stack:\\"\\"})))($R[\\"example\\"])"`; exports[`Error > crossSerializeAsync > supports Error.prototype.cause 1`] = `"$R[0]=Object.assign(new Error(\\"B\\"),{stack:\\"\\",cause:$R[1]=Promise.resolve($R[2]=Object.assign(new Error(\\"A\\"),{stack:\\"\\"}))})"`; @@ -24,19 +24,19 @@ exports[`Error > crossSerializeAsync > supports Error.prototype.name 1`] = `"$R[ exports[`Error > crossSerializeAsync > supports other Error classes 1`] = `"$R[0]=Promise.resolve($R[1]=Object.assign(new ReferenceError(\\"A\\"),{stack:\\"\\"}))"`; -exports[`Error > crossSerializeStream > scoped > supports Error.prototype.cause 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`Error > crossSerializeStream > scoped > supports Error.prototype.cause 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`Error > crossSerializeStream > scoped > supports Error.prototype.cause 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object.assign(new Error(\\"B\\"),{stack:\\"\\",cause:$R[2]=_$.P()}))))($R[\\"example\\"])"`; +exports[`Error > crossSerializeStream > scoped > supports Error.prototype.cause 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object.assign(new Error(\\"B\\"),{stack:\\"\\",cause:$R[2]=_$.P()})))($R[\\"example\\"])"`; -exports[`Error > crossSerializeStream > scoped > supports Error.prototype.cause 3`] = `"($R=>(_$.Ps($R[2],$R[3]=Object.assign(new Error(\\"A\\"),{stack:\\"\\"}))))($R[\\"example\\"])"`; +exports[`Error > crossSerializeStream > scoped > supports Error.prototype.cause 3`] = `"($R=>_$.Ps($R[2],$R[3]=Object.assign(new Error(\\"A\\"),{stack:\\"\\"})))($R[\\"example\\"])"`; -exports[`Error > crossSerializeStream > scoped > supports Error.prototype.name 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`Error > crossSerializeStream > scoped > supports Error.prototype.name 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`Error > crossSerializeStream > scoped > supports Error.prototype.name 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object.assign(new Error(\\"A\\"),{name:\\"ExampleError\\",stack:\\"\\"}))))($R[\\"example\\"])"`; +exports[`Error > crossSerializeStream > scoped > supports Error.prototype.name 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object.assign(new Error(\\"A\\"),{name:\\"ExampleError\\",stack:\\"\\"})))($R[\\"example\\"])"`; -exports[`Error > crossSerializeStream > scoped > supports other Error classes 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`Error > crossSerializeStream > scoped > supports other Error classes 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`Error > crossSerializeStream > scoped > supports other Error classes 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object.assign(new ReferenceError(\\"A\\"),{stack:\\"\\"}))))($R[\\"example\\"])"`; +exports[`Error > crossSerializeStream > scoped > supports other Error classes 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object.assign(new ReferenceError(\\"A\\"),{stack:\\"\\"})))($R[\\"example\\"])"`; exports[`Error > crossSerializeStream > supports Error.prototype.cause 1`] = `"$R[0]=_$.P()"`; @@ -64,6 +64,32 @@ exports[`Error > serializeAsync > supports Error.prototype.name 1`] = `"Promise. exports[`Error > serializeAsync > supports other Error classes 1`] = `"Promise.resolve(Object.assign(new ReferenceError(\\"A\\"),{stack:\\"\\"}))"`; +exports[`Error > toCrossJSON > supports Error.prototype.cause 1`] = `"{\\"t\\":13,\\"i\\":0,\\"s\\":0,\\"m\\":\\"B\\",\\"p\\":{\\"k\\":[\\"stack\\",\\"cause\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"},{\\"t\\":13,\\"i\\":1,\\"s\\":0,\\"m\\":\\"A\\",\\"p\\":{\\"k\\":[\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":1}}],\\"s\\":2}}"`; + +exports[`Error > toCrossJSON > supports Error.prototype.name 1`] = `"{\\"t\\":13,\\"i\\":0,\\"s\\":0,\\"m\\":\\"A\\",\\"p\\":{\\"k\\":[\\"name\\",\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"ExampleError\\"},{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":2}}"`; + +exports[`Error > toCrossJSON > supports other Error classes 1`] = `"{\\"t\\":13,\\"i\\":0,\\"s\\":3,\\"m\\":\\"A\\",\\"p\\":{\\"k\\":[\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":1}}"`; + +exports[`Error > toCrossJSONAsync > supports Error.prototype.cause 1`] = `"{\\"t\\":13,\\"i\\":0,\\"s\\":0,\\"m\\":\\"B\\",\\"p\\":{\\"k\\":[\\"stack\\",\\"cause\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"},{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":13,\\"i\\":2,\\"s\\":0,\\"m\\":\\"A\\",\\"p\\":{\\"k\\":[\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":1}}}],\\"s\\":2}}"`; + +exports[`Error > toCrossJSONAsync > supports Error.prototype.name 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":13,\\"i\\":1,\\"s\\":0,\\"m\\":\\"A\\",\\"p\\":{\\"k\\":[\\"name\\",\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"ExampleError\\"},{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":2}}}"`; + +exports[`Error > toCrossJSONAsync > supports other Error classes 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":13,\\"i\\":1,\\"s\\":3,\\"m\\":\\"A\\",\\"p\\":{\\"k\\":[\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":1}}}"`; + +exports[`Error > toCrossJSONStream > supports Error.prototype.cause 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`Error > toCrossJSONStream > supports Error.prototype.cause 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":13,\\"i\\":1,\\"s\\":0,\\"m\\":\\"B\\",\\"p\\":{\\"k\\":[\\"stack\\",\\"cause\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"},{\\"t\\":28,\\"i\\":2}],\\"s\\":2}}}"`; + +exports[`Error > toCrossJSONStream > supports Error.prototype.cause 3`] = `"{\\"t\\":29,\\"i\\":2,\\"f\\":{\\"t\\":13,\\"i\\":3,\\"s\\":0,\\"m\\":\\"A\\",\\"p\\":{\\"k\\":[\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":1}}}"`; + +exports[`Error > toCrossJSONStream > supports Error.prototype.name 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`Error > toCrossJSONStream > supports Error.prototype.name 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":13,\\"i\\":1,\\"s\\":0,\\"m\\":\\"A\\",\\"p\\":{\\"k\\":[\\"name\\",\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"ExampleError\\"},{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":2}}}"`; + +exports[`Error > toCrossJSONStream > supports other Error classes 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`Error > toCrossJSONStream > supports other Error classes 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":13,\\"i\\":1,\\"s\\":3,\\"m\\":\\"A\\",\\"p\\":{\\"k\\":[\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":1}}}"`; + exports[`Error > toJSON > supports Error.prototype.cause 1`] = `"{\\"t\\":{\\"t\\":13,\\"i\\":0,\\"s\\":0,\\"m\\":\\"B\\",\\"p\\":{\\"k\\":[\\"stack\\",\\"cause\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"},{\\"t\\":13,\\"i\\":1,\\"s\\":0,\\"m\\":\\"A\\",\\"p\\":{\\"k\\":[\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":1}}],\\"s\\":2}},\\"f\\":16383,\\"m\\":[]}"`; exports[`Error > toJSON > supports Error.prototype.name 1`] = `"{\\"t\\":{\\"t\\":13,\\"i\\":0,\\"s\\":0,\\"m\\":\\"A\\",\\"p\\":{\\"k\\":[\\"name\\",\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"ExampleError\\"},{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":2}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/frozen-object.test.ts.snap b/packages/seroval/test/__snapshots__/frozen-object.test.ts.snap index cf3e35eb..ddc246fc 100644 --- a/packages/seroval/test/__snapshots__/frozen-object.test.ts.snap +++ b/packages/seroval/test/__snapshots__/frozen-object.test.ts.snap @@ -1,81 +1,149 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`frozen object > crossSerialize > scoped > supports Objects 1`] = `"($R=>($R[0]={hello:\\"world\\"},Object.freeze($R[0]),$R[0]))($R[\\"example\\"])"`; +exports[`frozen object > crossSerialize > scoped > supports Objects 1`] = `"($R=>$R[0]={hello:\\"world\\"},Object.freeze($R[0]),$R[0])($R[\\"example\\"])"`; -exports[`frozen object > crossSerialize > scoped > supports Symbol.iterator 1`] = `"($R=>($R[0]={[Symbol.iterator]:()=>$R[1]=[1,2,3].values()},Object.freeze($R[0]),$R[0]))($R[\\"example\\"])"`; +exports[`frozen object > crossSerialize > scoped > supports Symbol.iterator 1`] = `"($R=>$R[0]={[$R[1]=Symbol.iterator]:($R[2]=s=>(i,c,d,t)=>(i=0,t={[$R[1]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})},Object.freeze($R[0]),$R[0])($R[\\"example\\"])"`; -exports[`frozen object > crossSerialize > scoped > supports self-recursion 1`] = `"($R=>($R[0]={},$R[0].b=$R[0].a=$R[0],Object.freeze($R[0]),$R[0]))($R[\\"example\\"])"`; +exports[`frozen object > crossSerialize > scoped > supports self-recursion 1`] = `"($R=>$R[0]={},$R[0].b=$R[0].a=$R[0],Object.freeze($R[0]),$R[0])($R[\\"example\\"])"`; exports[`frozen object > crossSerialize > supports Objects 1`] = `"($R[0]={hello:\\"world\\"},Object.freeze($R[0]),$R[0])"`; -exports[`frozen object > crossSerialize > supports Symbol.iterator 1`] = `"($R[0]={[Symbol.iterator]:()=>$R[1]=[1,2,3].values()},Object.freeze($R[0]),$R[0])"`; +exports[`frozen object > crossSerialize > supports Symbol.iterator 1`] = `"($R[0]={[$R[1]=Symbol.iterator]:($R[2]=s=>(i,c,d,t)=>(i=0,t={[$R[1]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})},Object.freeze($R[0]),$R[0])"`; exports[`frozen object > crossSerialize > supports self-recursion 1`] = `"($R[0]={},$R[0].b=$R[0].a=$R[0],Object.freeze($R[0]),$R[0])"`; -exports[`frozen object > crossSerializeAsync > scoped > supports Objects 1`] = `"($R=>($R[0]=Promise.resolve($R[1]={hello:\\"world\\"}),Object.freeze($R[1]),$R[0]))($R[\\"example\\"])"`; +exports[`frozen object > crossSerializeAsync > scoped > supports Objects 1`] = `"($R=>$R[0]=Promise.resolve($R[1]={hello:\\"world\\"}),Object.freeze($R[1]),$R[0])($R[\\"example\\"])"`; -exports[`frozen object > crossSerializeAsync > scoped > supports Symbol.iterator 1`] = `"($R=>($R[0]=Promise.resolve($R[1]={[Symbol.iterator]:()=>$R[2]=[1,2,3].values()}),Object.freeze($R[1]),$R[0]))($R[\\"example\\"])"`; +exports[`frozen object > crossSerializeAsync > scoped > supports Symbol.asyncIterator 1`] = `"($R=>$R[0]={[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})},Object.freeze($R[0]),$R[0])($R[\\"example\\"])"`; -exports[`frozen object > crossSerializeAsync > scoped > supports self-recursion 1`] = `"($R=>($R[0]={a:$R[1]=Promise.resolve().then(()=>$R[0]),b:$R[2]=Promise.resolve().then(()=>$R[0])},Object.freeze($R[0]),$R[0]))($R[\\"example\\"])"`; +exports[`frozen object > crossSerializeAsync > scoped > supports Symbol.iterator 1`] = `"($R=>$R[0]=Promise.resolve($R[1]={[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}),Object.freeze($R[1]),$R[0])($R[\\"example\\"])"`; + +exports[`frozen object > crossSerializeAsync > scoped > supports self-recursion 1`] = `"($R=>$R[0]={a:$R[1]=Promise.resolve().then(()=>$R[0]),b:$R[2]=Promise.resolve().then(()=>$R[0])},Object.freeze($R[0]),$R[0])($R[\\"example\\"])"`; exports[`frozen object > crossSerializeAsync > supports Objects 1`] = `"($R[0]=Promise.resolve($R[1]={hello:\\"world\\"}),Object.freeze($R[1]),$R[0])"`; -exports[`frozen object > crossSerializeAsync > supports Symbol.iterator 1`] = `"($R[0]=Promise.resolve($R[1]={[Symbol.iterator]:()=>$R[2]=[1,2,3].values()}),Object.freeze($R[1]),$R[0])"`; +exports[`frozen object > crossSerializeAsync > supports Symbol.asyncIterator 1`] = `"($R[0]={[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})},Object.freeze($R[0]),$R[0])"`; + +exports[`frozen object > crossSerializeAsync > supports Symbol.iterator 1`] = `"($R[0]=Promise.resolve($R[1]={[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}),Object.freeze($R[1]),$R[0])"`; exports[`frozen object > crossSerializeAsync > supports self-recursion 1`] = `"($R[0]={a:$R[1]=Promise.resolve().then(()=>$R[0]),b:$R[2]=Promise.resolve().then(()=>$R[0])},Object.freeze($R[0]),$R[0])"`; -exports[`frozen object > crossSerializeStream > scoped > supports Objects 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`frozen object > crossSerializeStream > scoped > supports Objects 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; + +exports[`frozen object > crossSerializeStream > scoped > supports Objects 2`] = `"($R=>_$.Ps($R[0],$R[1]={hello:\\"world\\"}),Object.freeze($R[1]),$R[0])($R[\\"example\\"])"`; + +exports[`frozen object > crossSerializeStream > scoped > supports Symbol.asyncIterator 1`] = `"($R=>$R[0]={[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]=_$.S())},Object.freeze($R[0]),$R[0])($R[\\"example\\"])"`; + +exports[`frozen object > crossSerializeStream > scoped > supports Symbol.asyncIterator 2`] = `"($R=>_$.Se($R[3],$R[4]=[0,1]))($R[\\"example\\"])"`; -exports[`frozen object > crossSerializeStream > scoped > supports Objects 2`] = `"($R=>(_$.Ps($R[0],$R[1]={hello:\\"world\\"}),Object.freeze($R[1]),$R[0]))($R[\\"example\\"])"`; +exports[`frozen object > crossSerializeStream > scoped > supports Symbol.asyncIterator 3`] = `"($R=>_$.Se($R[3],$R[5]=[0,2]))($R[\\"example\\"])"`; -exports[`frozen object > crossSerializeStream > scoped > supports Symbol.iterator 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`frozen object > crossSerializeStream > scoped > supports Symbol.asyncIterator 4`] = `"($R=>_$.Se($R[3],$R[6]=[0,3]))($R[\\"example\\"])"`; -exports[`frozen object > crossSerializeStream > scoped > supports Symbol.iterator 2`] = `"($R=>(_$.Ps($R[0],$R[1]={[Symbol.iterator]:()=>$R[2]=[1,2,3].values()}),Object.freeze($R[1]),$R[0]))($R[\\"example\\"])"`; +exports[`frozen object > crossSerializeStream > scoped > supports Symbol.asyncIterator 5`] = `"($R=>_$.Se($R[3],$R[7]=[2,void 0]))($R[\\"example\\"])"`; -exports[`frozen object > crossSerializeStream > scoped > supports self-recursion 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`frozen object > crossSerializeStream > scoped > supports Symbol.asyncIterator 6`] = `"($R=>_$.Sc($R[3]))($R[\\"example\\"])"`; -exports[`frozen object > crossSerializeStream > scoped > supports self-recursion 2`] = `"($R=>(_$.Ps($R[0],$R[1]={a:$R[2]=_$.P(),b:$R[3]=_$.P()}),Object.freeze($R[1]),$R[0]))($R[\\"example\\"])"`; +exports[`frozen object > crossSerializeStream > scoped > supports Symbol.iterator 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`frozen object > crossSerializeStream > scoped > supports self-recursion 3`] = `"($R=>(_$.Ps($R[2],$R[1])))($R[\\"example\\"])"`; +exports[`frozen object > crossSerializeStream > scoped > supports Symbol.iterator 2`] = `"($R=>_$.Ps($R[0],$R[1]={[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}),Object.freeze($R[1]),$R[0])($R[\\"example\\"])"`; -exports[`frozen object > crossSerializeStream > scoped > supports self-recursion 4`] = `"($R=>(_$.Ps($R[3],$R[1])))($R[\\"example\\"])"`; +exports[`frozen object > crossSerializeStream > scoped > supports self-recursion 1`] = `"($R=>$R[0]={a:$R[1]=_$.P(),b:$R[2]=_$.P()},Object.freeze($R[0]),$R[0])($R[\\"example\\"])"`; + +exports[`frozen object > crossSerializeStream > scoped > supports self-recursion 2`] = `"($R=>_$.Ps($R[1],$R[0]))($R[\\"example\\"])"`; + +exports[`frozen object > crossSerializeStream > scoped > supports self-recursion 3`] = `"($R=>_$.Ps($R[2],$R[0]))($R[\\"example\\"])"`; exports[`frozen object > crossSerializeStream > supports Objects 1`] = `"$R[0]=_$.P()"`; exports[`frozen object > crossSerializeStream > supports Objects 2`] = `"(_$.Ps($R[0],$R[1]={hello:\\"world\\"}),Object.freeze($R[1]),$R[0])"`; -exports[`frozen object > crossSerializeStream > supports Symbol.iterator 1`] = `"$R[0]=_$.P()"`; +exports[`frozen object > crossSerializeStream > supports Symbol.asyncIterator 1`] = `"($R[0]={[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]=_$.S())},Object.freeze($R[0]),$R[0])"`; + +exports[`frozen object > crossSerializeStream > supports Symbol.asyncIterator 2`] = `"_$.Se($R[3],$R[4]=[0,1])"`; -exports[`frozen object > crossSerializeStream > supports Symbol.iterator 2`] = `"(_$.Ps($R[0],$R[1]={[Symbol.iterator]:()=>$R[2]=[1,2,3].values()}),Object.freeze($R[1]),$R[0])"`; +exports[`frozen object > crossSerializeStream > supports Symbol.asyncIterator 3`] = `"_$.Se($R[3],$R[5]=[0,2])"`; -exports[`frozen object > crossSerializeStream > supports self-recursion 1`] = `"$R[0]=_$.P()"`; +exports[`frozen object > crossSerializeStream > supports Symbol.asyncIterator 4`] = `"_$.Se($R[3],$R[6]=[0,3])"`; -exports[`frozen object > crossSerializeStream > supports self-recursion 2`] = `"(_$.Ps($R[0],$R[1]={a:$R[2]=_$.P(),b:$R[3]=_$.P()}),Object.freeze($R[1]),$R[0])"`; +exports[`frozen object > crossSerializeStream > supports Symbol.asyncIterator 5`] = `"_$.Se($R[3],$R[7]=[2,void 0])"`; -exports[`frozen object > crossSerializeStream > supports self-recursion 3`] = `"_$.Ps($R[2],$R[1])"`; +exports[`frozen object > crossSerializeStream > supports Symbol.asyncIterator 6`] = `"_$.Sc($R[3])"`; -exports[`frozen object > crossSerializeStream > supports self-recursion 4`] = `"_$.Ps($R[3],$R[1])"`; +exports[`frozen object > crossSerializeStream > supports Symbol.iterator 1`] = `"$R[0]=_$.P()"`; + +exports[`frozen object > crossSerializeStream > supports Symbol.iterator 2`] = `"(_$.Ps($R[0],$R[1]={[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}),Object.freeze($R[1]),$R[0])"`; + +exports[`frozen object > crossSerializeStream > supports self-recursion 1`] = `"($R[0]={a:$R[1]=_$.P(),b:$R[2]=_$.P()},Object.freeze($R[0]),$R[0])"`; + +exports[`frozen object > crossSerializeStream > supports self-recursion 2`] = `"_$.Ps($R[1],$R[0])"`; + +exports[`frozen object > crossSerializeStream > supports self-recursion 3`] = `"_$.Ps($R[2],$R[0])"`; exports[`frozen object > serialize > supports Objects 1`] = `"(h=>(h={hello:\\"world\\"},Object.freeze(h),h))()"`; -exports[`frozen object > serialize > supports Symbol.iterator 1`] = `"(h=>(h={[Symbol.iterator]:()=>[1,2,3].values()},Object.freeze(h),h))()"`; +exports[`frozen object > serialize > supports Symbol.iterator 1`] = `"((h,j)=>(h={[j=Symbol.iterator]:(s=>(i,c,d,t)=>(i=0,t={[j]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))({v:[1,2,3,void 0],t:-1,d:3})},Object.freeze(h),h))()"`; exports[`frozen object > serialize > supports self-recursion 1`] = `"(h=>(h={},h.b=h.a=h,Object.freeze(h),h))()"`; exports[`frozen object > serializeAsync > supports Objects 1`] = `"((h,j)=>(j=Promise.resolve(h={hello:\\"world\\"}),Object.freeze(h),j))()"`; -exports[`frozen object > serializeAsync > supports Symbol.iterator 1`] = `"((h,j)=>(j=Promise.resolve(h={[Symbol.iterator]:()=>[1,2,3].values()}),Object.freeze(h),j))()"`; +exports[`frozen object > serializeAsync > supports Symbol.asyncIterator 1`] = `"((h,j)=>(h={[j=Symbol.asyncIterator]:(s=>(i,t)=>(i=0,t={[j]:()=>t,next:()=>Promise.resolve().then((c,d)=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}})}))({v:[1,2,3,void 0],t:-1,d:3})},Object.freeze(h),h))()"`; + +exports[`frozen object > serializeAsync > supports Symbol.iterator 1`] = `"((h,j,k)=>(k=Promise.resolve(h={[j=Symbol.iterator]:(s=>(i,c,d,t)=>(i=0,t={[j]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))({v:[1,2,3,void 0],t:-1,d:3})}),Object.freeze(h),k))()"`; exports[`frozen object > serializeAsync > supports self-recursion 1`] = `"(h=>(h={a:Promise.resolve().then(()=>h),b:Promise.resolve().then(()=>h)},Object.freeze(h),h))()"`; +exports[`frozen object > toCrossJSON > supports Objects 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":3}"`; + +exports[`frozen object > toCrossJSON > supports Symbol.iterator 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":3}"`; + +exports[`frozen object > toCrossJSON > supports self-recursion 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":4,\\"i\\":0},{\\"t\\":4,\\"i\\":0}],\\"s\\":2},\\"o\\":3}"`; + +exports[`frozen object > toCrossJSONAsync > supports Objects 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":3}}"`; + +exports[`frozen object > toCrossJSONAsync > supports Symbol.asyncIterator 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":3}"`; + +exports[`frozen object > toCrossJSONAsync > supports Symbol.iterator 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":3}}"`; + +exports[`frozen object > toCrossJSONAsync > supports self-recursion 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}},{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"s\\":2},\\"o\\":3}"`; + +exports[`frozen object > toCrossJSONStream > supports Objects 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`frozen object > toCrossJSONStream > supports Objects 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":3}}"`; + +exports[`frozen object > toCrossJSONStream > supports Symbol.asyncIterator 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":31,\\"i\\":3}]}],\\"s\\":1},\\"o\\":3}"`; + +exports[`frozen object > toCrossJSONStream > supports Symbol.asyncIterator 2`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":4,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":1}],\\"o\\":0}}"`; + +exports[`frozen object > toCrossJSONStream > supports Symbol.asyncIterator 3`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":5,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":2}],\\"o\\":0}}"`; + +exports[`frozen object > toCrossJSONStream > supports Symbol.asyncIterator 4`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":6,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}}"`; + +exports[`frozen object > toCrossJSONStream > supports Symbol.asyncIterator 5`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":7,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":2},{\\"t\\":2,\\"s\\":1}],\\"o\\":0}}"`; + +exports[`frozen object > toCrossJSONStream > supports Symbol.asyncIterator 6`] = `"{\\"t\\":33,\\"i\\":3}"`; + +exports[`frozen object > toCrossJSONStream > supports Symbol.iterator 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`frozen object > toCrossJSONStream > supports Symbol.iterator 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":3}}"`; + +exports[`frozen object > toCrossJSONStream > supports self-recursion 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":28,\\"i\\":1},{\\"t\\":28,\\"i\\":2}],\\"s\\":2},\\"o\\":3}"`; + +exports[`frozen object > toCrossJSONStream > supports self-recursion 2`] = `"{\\"t\\":29,\\"i\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}"`; + +exports[`frozen object > toCrossJSONStream > supports self-recursion 3`] = `"{\\"t\\":29,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":0}}"`; + exports[`frozen object > toJSON > supports Objects 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":3},\\"f\\":16383,\\"m\\":[]}"`; -exports[`frozen object > toJSON > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[0],\\"v\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}],\\"s\\":1},\\"o\\":3},\\"f\\":16383,\\"m\\":[]}"`; +exports[`frozen object > toJSON > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":3},\\"f\\":16383,\\"m\\":[1]}"`; exports[`frozen object > toJSON > supports self-recursion 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":4,\\"i\\":0},{\\"t\\":4,\\"i\\":0}],\\"s\\":2},\\"o\\":3},\\"f\\":16383,\\"m\\":[0]}"`; exports[`frozen object > toJSONAsync > supports Objects 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":3}},\\"f\\":16383,\\"m\\":[]}"`; -exports[`frozen object > toJSONAsync > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[0],\\"v\\":[{\\"t\\":9,\\"i\\":2,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}],\\"s\\":1},\\"o\\":3}},\\"f\\":16383,\\"m\\":[]}"`; +exports[`frozen object > toJSONAsync > supports Symbol.asyncIterator 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":3},\\"f\\":16383,\\"m\\":[1]}"`; + +exports[`frozen object > toJSONAsync > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":3}},\\"f\\":16383,\\"m\\":[2]}"`; exports[`frozen object > toJSONAsync > supports self-recursion 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}},{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"s\\":2},\\"o\\":3},\\"f\\":16383,\\"m\\":[0]}"`; diff --git a/packages/seroval/test/__snapshots__/iterable.test.ts.snap b/packages/seroval/test/__snapshots__/iterable.test.ts.snap index 9791a3a4..31a3cdb0 100644 --- a/packages/seroval/test/__snapshots__/iterable.test.ts.snap +++ b/packages/seroval/test/__snapshots__/iterable.test.ts.snap @@ -1,43 +1,39 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Iterable > compat > should use Symbol.iterator instead of Array.values. 1`] = `"(h=>(h={[Symbol.iterator]:()=>[h][Symbol.iterator]()}))()"`; +exports[`Iterable > compat > should use function expression instead of arrow functions. 1`] = `"(function(h){return ({title:\\"Hello World\\",[h=Symbol.iterator]:(function(s){return function(i,c,d,t){return (i=0,t={[h]:function(){return t},next:function(){if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}})}})({v:[1,2,3,void 0],t:-1,d:3})})})()"`; -exports[`Iterable > compat > should use functions instead of method shorthand. 1`] = `"(function(h){return h={[Symbol.iterator]:function(){return [h].values()}}})()"`; +exports[`Iterable > compat#toJSON > should use function expression instead of arrow functions. 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"title\\",{\\"t\\":17,\\"i\\":1,\\"s\\":3}],\\"v\\":[{\\"t\\":1,\\"s\\":\\"Hello World\\"},{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":2},\\"o\\":0},\\"f\\":16379,\\"m\\":[1]}"`; -exports[`Iterable > compat > should use method shorthand instead of arrow functions. 1`] = `"(function(h){return h={[Symbol.iterator](){return [h].values()}}})()"`; +exports[`Iterable > compat#toJSON > should use function expression instead of arrow functions. 2`] = `"(function(h){return ({title:\\"Hello World\\",[h=Symbol.iterator]:(function(s){return function(i,c,d,t){return (i=0,t={[h]:function(){return t},next:function(){if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}})}})({v:[1,2,3,void 0],t:-1,d:3})})})()"`; -exports[`Iterable > compat#toJSON > should use Symbol.iterator instead of Array.values. 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[0],\\"v\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":1,\\"a\\":[{\\"t\\":4,\\"i\\":0}],\\"o\\":0}],\\"s\\":1},\\"o\\":0},\\"f\\":16381,\\"m\\":[0]}"`; +exports[`Iterable > crossSerialize > scoped > supports Iterables 1`] = `"($R=>$R[0]={title:\\"Hello World\\",[$R[1]=Symbol.iterator]:($R[2]=s=>(i,c,d,t)=>(i=0,t={[$R[1]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})})($R[\\"example\\"])"`; -exports[`Iterable > compat#toJSON > should use Symbol.iterator instead of Array.values. 2`] = `"(h=>(h={[Symbol.iterator]:()=>[h][Symbol.iterator]()}))()"`; +exports[`Iterable > crossSerialize > supports Iterables 1`] = `"$R[0]={title:\\"Hello World\\",[$R[1]=Symbol.iterator]:($R[2]=s=>(i,c,d,t)=>(i=0,t={[$R[1]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})}"`; -exports[`Iterable > compat#toJSON > should use functions instead of method shorthand. 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[0],\\"v\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":1,\\"a\\":[{\\"t\\":4,\\"i\\":0}],\\"o\\":0}],\\"s\\":1},\\"o\\":0},\\"f\\":16315,\\"m\\":[0]}"`; +exports[`Iterable > crossSerializeAsync > scoped > supports Iterables 1`] = `"($R=>$R[0]=Promise.resolve($R[1]={title:\\"Hello World\\",[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}))($R[\\"example\\"])"`; -exports[`Iterable > compat#toJSON > should use functions instead of method shorthand. 2`] = `"(function(h){return h={[Symbol.iterator]:function(){return [h].values()}}})()"`; +exports[`Iterable > crossSerializeAsync > supports Iterables 1`] = `"$R[0]=Promise.resolve($R[1]={title:\\"Hello World\\",[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})})"`; -exports[`Iterable > compat#toJSON > should use method shorthand instead of arrow functions. 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[0],\\"v\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":1,\\"a\\":[{\\"t\\":4,\\"i\\":0}],\\"o\\":0}],\\"s\\":1},\\"o\\":0},\\"f\\":16379,\\"m\\":[0]}"`; +exports[`Iterable > crossSerializeStream > scoped > supports Iterables 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`Iterable > compat#toJSON > should use method shorthand instead of arrow functions. 2`] = `"(function(h){return h={[Symbol.iterator](){return [h].values()}}})()"`; +exports[`Iterable > crossSerializeStream > scoped > supports Iterables 2`] = `"($R=>_$.Ps($R[0],$R[1]={title:\\"Hello World\\",[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}))($R[\\"example\\"])"`; -exports[`Iterable > crossSerialize > scoped > supports Iterables 1`] = `"($R=>($R[0]={title:\\"Hello World\\",[Symbol.iterator]:()=>$R[1]=[1,2,3].values()}))($R[\\"example\\"])"`; - -exports[`Iterable > crossSerialize > supports Iterables 1`] = `"$R[0]={title:\\"Hello World\\",[Symbol.iterator]:()=>$R[1]=[1,2,3].values()}"`; - -exports[`Iterable > crossSerializeAsync > scoped > supports Iterables 1`] = `"($R=>($R[0]=Promise.resolve($R[1]={title:\\"Hello World\\",[Symbol.iterator]:()=>$R[2]=[1,2,3].values()})))($R[\\"example\\"])"`; +exports[`Iterable > crossSerializeStream > supports Iterables 1`] = `"$R[0]=_$.P()"`; -exports[`Iterable > crossSerializeAsync > supports Iterables 1`] = `"$R[0]=Promise.resolve($R[1]={title:\\"Hello World\\",[Symbol.iterator]:()=>$R[2]=[1,2,3].values()})"`; +exports[`Iterable > crossSerializeStream > supports Iterables 2`] = `"_$.Ps($R[0],$R[1]={title:\\"Hello World\\",[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})})"`; -exports[`Iterable > crossSerializeStream > scoped > supports Iterables 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`Iterable > serialize > supports Iterables 1`] = `"(h=>({title:\\"Hello World\\",[h=Symbol.iterator]:(s=>(i,c,d,t)=>(i=0,t={[h]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))({v:[1,2,3,void 0],t:-1,d:3})}))()"`; -exports[`Iterable > crossSerializeStream > scoped > supports Iterables 2`] = `"($R=>(_$.Ps($R[0],$R[1]={title:\\"Hello World\\",[Symbol.iterator]:()=>$R[2]=[1,2,3].values()})))($R[\\"example\\"])"`; +exports[`Iterable > serializeAsync > supports Iterables 1`] = `"(h=>(Promise.resolve({title:\\"Hello World\\",[h=Symbol.iterator]:(s=>(i,c,d,t)=>(i=0,t={[h]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))({v:[1,2,3,void 0],t:-1,d:3})})))()"`; -exports[`Iterable > crossSerializeStream > supports Iterables 1`] = `"$R[0]=_$.P()"`; +exports[`Iterable > toCrossJSON > supports Iterables 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"title\\",{\\"t\\":17,\\"i\\":1,\\"s\\":3}],\\"v\\":[{\\"t\\":1,\\"s\\":\\"Hello World\\"},{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":2},\\"o\\":0}"`; -exports[`Iterable > crossSerializeStream > supports Iterables 2`] = `"_$.Ps($R[0],$R[1]={title:\\"Hello World\\",[Symbol.iterator]:()=>$R[2]=[1,2,3].values()})"`; +exports[`Iterable > toCrossJSONAsync > supports Iterables 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"title\\",{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":1,\\"s\\":\\"Hello World\\"},{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":2},\\"o\\":0}}"`; -exports[`Iterable > serialize > supports Iterables 1`] = `"({title:\\"Hello World\\",[Symbol.iterator]:()=>[1,2,3].values()})"`; +exports[`Iterable > toCrossJSONStream > supports Iterables 1`] = `"{\\"t\\":28,\\"i\\":0}"`; -exports[`Iterable > serializeAsync > supports Iterables 1`] = `"Promise.resolve({title:\\"Hello World\\",[Symbol.iterator]:()=>[1,2,3].values()})"`; +exports[`Iterable > toCrossJSONStream > supports Iterables 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"title\\",{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":1,\\"s\\":\\"Hello World\\"},{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":2},\\"o\\":0}}"`; -exports[`Iterable > toJSON > supports Iterables 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"title\\",0],\\"v\\":[{\\"t\\":1,\\"s\\":\\"Hello World\\"},{\\"t\\":9,\\"i\\":1,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}],\\"s\\":2},\\"o\\":0},\\"f\\":16383,\\"m\\":[]}"`; +exports[`Iterable > toJSON > supports Iterables 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"title\\",{\\"t\\":17,\\"i\\":1,\\"s\\":3}],\\"v\\":[{\\"t\\":1,\\"s\\":\\"Hello World\\"},{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":2},\\"o\\":0},\\"f\\":16383,\\"m\\":[1]}"`; -exports[`Iterable > toJSONAsync > supports Iterables 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"title\\",0],\\"v\\":[{\\"t\\":1,\\"s\\":\\"Hello World\\"},{\\"t\\":9,\\"i\\":2,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}],\\"s\\":2},\\"o\\":0}},\\"f\\":16383,\\"m\\":[]}"`; +exports[`Iterable > toJSONAsync > supports Iterables 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"title\\",{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":1,\\"s\\":\\"Hello World\\"},{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":2},\\"o\\":0}},\\"f\\":16383,\\"m\\":[2]}"`; diff --git a/packages/seroval/test/__snapshots__/map.test.ts.snap b/packages/seroval/test/__snapshots__/map.test.ts.snap index 78004061..a86eab8a 100644 --- a/packages/seroval/test/__snapshots__/map.test.ts.snap +++ b/packages/seroval/test/__snapshots__/map.test.ts.snap @@ -1,61 +1,79 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Map > compat > should fallback to Symbol.iterator 1`] = `"Object.assign(Object.create(null),{[Symbol.iterator]:()=>[].values()})"`; +exports[`Map > compat > should fallback to Symbol.iterator 1`] = `"(h=>(Object.assign(Object.create(null),{[h=Symbol.iterator]:(s=>(i,c,d,t)=>(i=0,t={[h]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))({v:[[1,2],[3,4],void 0],t:-1,d:2}),[Symbol.toStringTag]:\\"Map\\"})))()"`; exports[`Map > compat > should throw an error for unsupported target 1`] = `"Unsupported type \\"[object Map]\\""`; -exports[`Map > compat#toJSON > should fallback to Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[0],\\"v\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":0,\\"a\\":[],\\"o\\":0}],\\"s\\":1},\\"o\\":0},\\"f\\":16351,\\"m\\":[]}"`; +exports[`Map > compat#toJSON > should fallback to Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":3},{\\"t\\":17,\\"i\\":7,\\"s\\":11}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":3,\\"a\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2}],\\"o\\":0},{\\"t\\":9,\\"i\\":6,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":3},{\\"t\\":0,\\"s\\":4}],\\"o\\":0},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":2}],\\"s\\":3},\\"o\\":0}]},{\\"t\\":1,\\"s\\":\\"Map\\"}],\\"s\\":2},\\"o\\":0},\\"f\\":16351,\\"m\\":[1]}"`; exports[`Map > compat#toJSON > should throw an error for unsupported target 1`] = `"Unsupported type \\"[object Map]\\""`; -exports[`Map > crossSerialize > scoped > supports Map 1`] = `"($R=>($R[0]=new Map([[1,2],[3,4]])))($R[\\"example\\"])"`; +exports[`Map > crossSerialize > scoped > supports Map 1`] = `"($R=>$R[0]=($R[1]=[],new Map([[1,2],[3,4]])))($R[\\"example\\"])"`; -exports[`Map > crossSerialize > scoped > supports self-recursion 1`] = `"($R=>($R[0]=new Map,$R[0].set($R[0],$R[0]),$R[0]))($R[\\"example\\"])"`; +exports[`Map > crossSerialize > scoped > supports self-recursion 1`] = `"($R=>$R[0]=($R[1]=[],new Map),$R[0].set($R[0],$R[0]),$R[0])($R[\\"example\\"])"`; -exports[`Map > crossSerialize > supports Map 1`] = `"$R[0]=new Map([[1,2],[3,4]])"`; +exports[`Map > crossSerialize > supports Map 1`] = `"$R[0]=($R[1]=[],new Map([[1,2],[3,4]]))"`; -exports[`Map > crossSerialize > supports self-recursion 1`] = `"($R[0]=new Map,$R[0].set($R[0],$R[0]),$R[0])"`; +exports[`Map > crossSerialize > supports self-recursion 1`] = `"($R[0]=($R[1]=[],new Map),$R[0].set($R[0],$R[0]),$R[0])"`; -exports[`Map > crossSerializeAsync > scoped > supports Map 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=new Map([[1,2],[3,4]]))))($R[\\"example\\"])"`; +exports[`Map > crossSerializeAsync > scoped > supports Map 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=($R[2]=[],new Map([[1,2],[3,4]]))))($R[\\"example\\"])"`; -exports[`Map > crossSerializeAsync > scoped > supports self-recursion 1`] = `"($R=>($R[0]=new Map([[$R[1]=Promise.resolve().then(()=>$R[0]),$R[2]=Promise.resolve().then(()=>$R[0])]])))($R[\\"example\\"])"`; +exports[`Map > crossSerializeAsync > scoped > supports self-recursion 1`] = `"($R=>$R[0]=($R[3]=[],new Map([[$R[1]=Promise.resolve().then(()=>$R[0]),$R[2]=Promise.resolve().then(()=>$R[0])]])))($R[\\"example\\"])"`; -exports[`Map > crossSerializeAsync > supports Map 1`] = `"$R[0]=Promise.resolve($R[1]=new Map([[1,2],[3,4]]))"`; +exports[`Map > crossSerializeAsync > supports Map 1`] = `"$R[0]=Promise.resolve($R[1]=($R[2]=[],new Map([[1,2],[3,4]])))"`; -exports[`Map > crossSerializeAsync > supports self-recursion 1`] = `"$R[0]=new Map([[$R[1]=Promise.resolve().then(()=>$R[0]),$R[2]=Promise.resolve().then(()=>$R[0])]])"`; +exports[`Map > crossSerializeAsync > supports self-recursion 1`] = `"$R[0]=($R[3]=[],new Map([[$R[1]=Promise.resolve().then(()=>$R[0]),$R[2]=Promise.resolve().then(()=>$R[0])]]))"`; -exports[`Map > crossSerializeStream > scoped > supports Map 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`Map > crossSerializeStream > scoped > supports Map 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`Map > crossSerializeStream > scoped > supports Map 2`] = `"($R=>(_$.Ps($R[0],$R[1]=new Map([[1,2],[3,4]]))))($R[\\"example\\"])"`; +exports[`Map > crossSerializeStream > scoped > supports Map 2`] = `"($R=>_$.Ps($R[0],$R[1]=($R[2]=[],new Map([[1,2],[3,4]]))))($R[\\"example\\"])"`; -exports[`Map > crossSerializeStream > scoped > supports self-recursion 1`] = `"($R=>($R[0]=new Map([[$R[1]=_$.P(),$R[2]=_$.P()]])))($R[\\"example\\"])"`; +exports[`Map > crossSerializeStream > scoped > supports self-recursion 1`] = `"($R=>$R[0]=($R[3]=[],new Map([[$R[1]=_$.P(),$R[2]=_$.P()]])))($R[\\"example\\"])"`; -exports[`Map > crossSerializeStream > scoped > supports self-recursion 2`] = `"($R=>(_$.Ps($R[1],$R[0])))($R[\\"example\\"])"`; +exports[`Map > crossSerializeStream > scoped > supports self-recursion 2`] = `"($R=>_$.Ps($R[1],$R[0]))($R[\\"example\\"])"`; -exports[`Map > crossSerializeStream > scoped > supports self-recursion 3`] = `"($R=>(_$.Ps($R[2],$R[0])))($R[\\"example\\"])"`; +exports[`Map > crossSerializeStream > scoped > supports self-recursion 3`] = `"($R=>_$.Ps($R[2],$R[0]))($R[\\"example\\"])"`; exports[`Map > crossSerializeStream > supports Map 1`] = `"$R[0]=_$.P()"`; -exports[`Map > crossSerializeStream > supports Map 2`] = `"_$.Ps($R[0],$R[1]=new Map([[1,2],[3,4]]))"`; +exports[`Map > crossSerializeStream > supports Map 2`] = `"_$.Ps($R[0],$R[1]=($R[2]=[],new Map([[1,2],[3,4]])))"`; -exports[`Map > crossSerializeStream > supports self-recursion 1`] = `"$R[0]=new Map([[$R[1]=_$.P(),$R[2]=_$.P()]])"`; +exports[`Map > crossSerializeStream > supports Map 3`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`Map > crossSerializeStream > supports Map 4`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":8,\\"i\\":1,\\"e\\":{\\"k\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":3}],\\"v\\":[{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":4}],\\"s\\":2},\\"f\\":{\\"t\\":41,\\"i\\":2}}}"`; + +exports[`Map > crossSerializeStream > supports self-recursion 1`] = `"$R[0]=($R[3]=[],new Map([[$R[1]=_$.P(),$R[2]=_$.P()]]))"`; exports[`Map > crossSerializeStream > supports self-recursion 2`] = `"_$.Ps($R[1],$R[0])"`; exports[`Map > crossSerializeStream > supports self-recursion 3`] = `"_$.Ps($R[2],$R[0])"`; -exports[`Map > serialize > supports Map 1`] = `"new Map([[1,2],[3,4]])"`; +exports[`Map > crossSerializeStream > supports self-recursion 4`] = `"{\\"t\\":8,\\"i\\":0,\\"e\\":{\\"k\\":[{\\"t\\":28,\\"i\\":1}],\\"v\\":[{\\"t\\":28,\\"i\\":2}],\\"s\\":1},\\"f\\":{\\"t\\":41,\\"i\\":3}}"`; + +exports[`Map > crossSerializeStream > supports self-recursion 5`] = `"{\\"t\\":29,\\"i\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}"`; + +exports[`Map > crossSerializeStream > supports self-recursion 6`] = `"{\\"t\\":29,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":0}}"`; + +exports[`Map > serialize > supports Map 1`] = `"(h=>((h=[],new Map([[1,2],[3,4]]))))()"`; + +exports[`Map > serialize > supports self-recursion 1`] = `"((h,j)=>(j=(h=[],new Map),j.set(j,j),j))()"`; + +exports[`Map > serializeAsync > supports Map 1`] = `"(h=>(Promise.resolve((h=[],new Map([[1,2],[3,4]])))))()"`; + +exports[`Map > serializeAsync > supports self-recursion 1`] = `"((h,j)=>(j=(h=[],new Map([[Promise.resolve().then(()=>j),Promise.resolve().then(()=>j)]]))))()"`; + +exports[`Map > toCrossJSON > supports Map 1`] = `"{\\"t\\":8,\\"i\\":0,\\"e\\":{\\"k\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":3}],\\"v\\":[{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":4}],\\"s\\":2},\\"f\\":{\\"t\\":41,\\"i\\":1}}"`; -exports[`Map > serialize > supports self-recursion 1`] = `"(h=>(h=new Map,h.set(h,h),h))()"`; +exports[`Map > toCrossJSON > supports self-recursion 1`] = `"{\\"t\\":8,\\"i\\":0,\\"e\\":{\\"k\\":[{\\"t\\":4,\\"i\\":0}],\\"v\\":[{\\"t\\":4,\\"i\\":0}],\\"s\\":1},\\"f\\":{\\"t\\":41,\\"i\\":1}}"`; -exports[`Map > serializeAsync > supports Map 1`] = `"Promise.resolve(new Map([[1,2],[3,4]]))"`; +exports[`Map > toCrossJSONAsync > supports Map 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":8,\\"i\\":1,\\"e\\":{\\"k\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":3}],\\"v\\":[{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":4}],\\"s\\":2},\\"f\\":{\\"t\\":41,\\"i\\":2}}}"`; -exports[`Map > serializeAsync > supports self-recursion 1`] = `"(h=>(h=new Map([[Promise.resolve().then(()=>h),Promise.resolve().then(()=>h)]])))()"`; +exports[`Map > toCrossJSONAsync > supports self-recursion 1`] = `"{\\"t\\":8,\\"i\\":0,\\"e\\":{\\"k\\":[{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"v\\":[{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"s\\":1},\\"f\\":{\\"t\\":41,\\"i\\":3}}"`; -exports[`Map > toJSON > supports Map 1`] = `"{\\"t\\":{\\"t\\":8,\\"i\\":0,\\"e\\":{\\"k\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":3}],\\"v\\":[{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":4}],\\"s\\":2}},\\"f\\":16383,\\"m\\":[]}"`; +exports[`Map > toJSON > supports Map 1`] = `"{\\"t\\":{\\"t\\":8,\\"i\\":0,\\"e\\":{\\"k\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":3}],\\"v\\":[{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":4}],\\"s\\":2},\\"f\\":{\\"t\\":41,\\"i\\":1}},\\"f\\":16383,\\"m\\":[]}"`; -exports[`Map > toJSON > supports self-recursion 1`] = `"{\\"t\\":{\\"t\\":8,\\"i\\":0,\\"e\\":{\\"k\\":[{\\"t\\":4,\\"i\\":0}],\\"v\\":[{\\"t\\":4,\\"i\\":0}],\\"s\\":1}},\\"f\\":16383,\\"m\\":[0]}"`; +exports[`Map > toJSON > supports self-recursion 1`] = `"{\\"t\\":{\\"t\\":8,\\"i\\":0,\\"e\\":{\\"k\\":[{\\"t\\":4,\\"i\\":0}],\\"v\\":[{\\"t\\":4,\\"i\\":0}],\\"s\\":1},\\"f\\":{\\"t\\":41,\\"i\\":1}},\\"f\\":16383,\\"m\\":[0]}"`; -exports[`Map > toJSONAsync > supports Map 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":8,\\"i\\":1,\\"e\\":{\\"k\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":3}],\\"v\\":[{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":4}],\\"s\\":2}}},\\"f\\":16383,\\"m\\":[]}"`; +exports[`Map > toJSONAsync > supports Map 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":8,\\"i\\":1,\\"e\\":{\\"k\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":3}],\\"v\\":[{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":4}],\\"s\\":2},\\"f\\":{\\"t\\":41,\\"i\\":2}}},\\"f\\":16383,\\"m\\":[]}"`; -exports[`Map > toJSONAsync > supports self-recursion 1`] = `"{\\"t\\":{\\"t\\":8,\\"i\\":0,\\"e\\":{\\"k\\":[{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"v\\":[{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"s\\":1}},\\"f\\":16383,\\"m\\":[0]}"`; +exports[`Map > toJSONAsync > supports self-recursion 1`] = `"{\\"t\\":{\\"t\\":8,\\"i\\":0,\\"e\\":{\\"k\\":[{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"v\\":[{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"s\\":1},\\"f\\":{\\"t\\":41,\\"i\\":3}},\\"f\\":16383,\\"m\\":[0]}"`; diff --git a/packages/seroval/test/__snapshots__/mutual-cycle.test.ts.snap b/packages/seroval/test/__snapshots__/mutual-cycle.test.ts.snap index 847e51ba..f646e150 100644 --- a/packages/seroval/test/__snapshots__/mutual-cycle.test.ts.snap +++ b/packages/seroval/test/__snapshots__/mutual-cycle.test.ts.snap @@ -1,10 +1,10 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`mutual cyclic references > crossSerialize > scoped > supports Arrays and Arrays 1`] = `"($R=>($R[0]=[$R[1]=[$R[2]=[,]],$R[2]],$R[2][0]=$R[1],$R[0]))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerialize > scoped > supports Arrays and Arrays 1`] = `"($R=>$R[0]=[$R[1]=[$R[2]=[,]],$R[2]],$R[2][0]=$R[1],$R[0])($R[\\"example\\"])"`; -exports[`mutual cyclic references > crossSerialize > scoped > supports Arrays and Objects 1`] = `"($R=>($R[0]=[$R[1]=[$R[2]={}],$R[2]],$R[2][0]=$R[1],$R[0]))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerialize > scoped > supports Arrays and Objects 1`] = `"($R=>$R[0]=[$R[1]=[$R[2]={}],$R[2]],$R[2][0]=$R[1],$R[0])($R[\\"example\\"])"`; -exports[`mutual cyclic references > crossSerialize > scoped > supports Objects and Objects 1`] = `"($R=>($R[0]=[$R[1]={0:$R[2]={}},$R[2]],$R[2][0]=$R[1],$R[0]))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerialize > scoped > supports Objects and Objects 1`] = `"($R=>$R[0]=[$R[1]={0:$R[2]={}},$R[2]],$R[2][0]=$R[1],$R[0])($R[\\"example\\"])"`; exports[`mutual cyclic references > crossSerialize > supports Arrays and Arrays 1`] = `"($R[0]=[$R[1]=[$R[2]=[,]],$R[2]],$R[2][0]=$R[1],$R[0])"`; @@ -12,11 +12,11 @@ exports[`mutual cyclic references > crossSerialize > supports Arrays and Objects exports[`mutual cyclic references > crossSerialize > supports Objects and Objects 1`] = `"($R[0]=[$R[1]={0:$R[2]={}},$R[2]],$R[2][0]=$R[1],$R[0])"`; -exports[`mutual cyclic references > crossSerializeAsync > scoped > supports Arrays and Arrays 1`] = `"($R=>($R[0]=[$R[1]=[$R[2]=Promise.resolve($R[3]=[$R[4]=Promise.resolve().then(()=>$R[1])])],$R[3]]))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerializeAsync > scoped > supports Arrays and Arrays 1`] = `"($R=>$R[0]=[$R[1]=[$R[2]=Promise.resolve($R[3]=[$R[4]=Promise.resolve().then(()=>$R[1])])],$R[3]])($R[\\"example\\"])"`; -exports[`mutual cyclic references > crossSerializeAsync > scoped > supports Arrays and Objects 1`] = `"($R=>($R[0]=[$R[1]=[$R[2]=Promise.resolve($R[3]={0:$R[4]=Promise.resolve().then(()=>$R[1])})],$R[3]]))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerializeAsync > scoped > supports Arrays and Objects 1`] = `"($R=>$R[0]=[$R[1]=[$R[2]=Promise.resolve($R[3]={0:$R[4]=Promise.resolve().then(()=>$R[1])})],$R[3]])($R[\\"example\\"])"`; -exports[`mutual cyclic references > crossSerializeAsync > scoped > supports Objects and Objects 1`] = `"($R=>($R[0]=[$R[1]={0:$R[2]=Promise.resolve($R[3]={0:$R[4]=Promise.resolve().then(()=>$R[1])})},$R[3]]))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerializeAsync > scoped > supports Objects and Objects 1`] = `"($R=>$R[0]=[$R[1]={0:$R[2]=Promise.resolve($R[3]={0:$R[4]=Promise.resolve().then(()=>$R[1])})},$R[3]])($R[\\"example\\"])"`; exports[`mutual cyclic references > crossSerializeAsync > supports Arrays and Arrays 1`] = `"$R[0]=[$R[1]=[$R[2]=Promise.resolve($R[3]=[$R[4]=Promise.resolve().then(()=>$R[1])])],$R[3]]"`; @@ -24,23 +24,23 @@ exports[`mutual cyclic references > crossSerializeAsync > supports Arrays and Ob exports[`mutual cyclic references > crossSerializeAsync > supports Objects and Objects 1`] = `"$R[0]=[$R[1]={0:$R[2]=Promise.resolve($R[3]={0:$R[4]=Promise.resolve().then(()=>$R[1])})},$R[3]]"`; -exports[`mutual cyclic references > crossSerializeStream > scoped > supports Arrays and Arrays 1`] = `"($R=>($R[0]=[$R[1]=[$R[2]=_$.P()],$R[3]=[$R[4]=_$.P()]]))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerializeStream > scoped > supports Arrays and Arrays 1`] = `"($R=>$R[0]=[$R[1]=[$R[2]=_$.P()],$R[3]=[$R[4]=_$.P()]])($R[\\"example\\"])"`; -exports[`mutual cyclic references > crossSerializeStream > scoped > supports Arrays and Arrays 2`] = `"($R=>(_$.Ps($R[2],$R[3])))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerializeStream > scoped > supports Arrays and Arrays 2`] = `"($R=>_$.Ps($R[2],$R[3]))($R[\\"example\\"])"`; -exports[`mutual cyclic references > crossSerializeStream > scoped > supports Arrays and Arrays 3`] = `"($R=>(_$.Ps($R[4],$R[1])))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerializeStream > scoped > supports Arrays and Arrays 3`] = `"($R=>_$.Ps($R[4],$R[1]))($R[\\"example\\"])"`; -exports[`mutual cyclic references > crossSerializeStream > scoped > supports Arrays and Objects 1`] = `"($R=>($R[0]=[$R[1]=[$R[2]=_$.P()],$R[3]={0:$R[4]=_$.P()}]))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerializeStream > scoped > supports Arrays and Objects 1`] = `"($R=>$R[0]=[$R[1]=[$R[2]=_$.P()],$R[3]={0:$R[4]=_$.P()}])($R[\\"example\\"])"`; -exports[`mutual cyclic references > crossSerializeStream > scoped > supports Arrays and Objects 2`] = `"($R=>(_$.Ps($R[2],$R[3])))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerializeStream > scoped > supports Arrays and Objects 2`] = `"($R=>_$.Ps($R[2],$R[3]))($R[\\"example\\"])"`; -exports[`mutual cyclic references > crossSerializeStream > scoped > supports Arrays and Objects 3`] = `"($R=>(_$.Ps($R[4],$R[1])))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerializeStream > scoped > supports Arrays and Objects 3`] = `"($R=>_$.Ps($R[4],$R[1]))($R[\\"example\\"])"`; -exports[`mutual cyclic references > crossSerializeStream > scoped > supports Objects and Objects 1`] = `"($R=>($R[0]=[$R[1]={0:$R[2]=_$.P()},$R[3]={0:$R[4]=_$.P()}]))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerializeStream > scoped > supports Objects and Objects 1`] = `"($R=>$R[0]=[$R[1]={0:$R[2]=_$.P()},$R[3]={0:$R[4]=_$.P()}])($R[\\"example\\"])"`; -exports[`mutual cyclic references > crossSerializeStream > scoped > supports Objects and Objects 2`] = `"($R=>(_$.Ps($R[2],$R[3])))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerializeStream > scoped > supports Objects and Objects 2`] = `"($R=>_$.Ps($R[2],$R[3]))($R[\\"example\\"])"`; -exports[`mutual cyclic references > crossSerializeStream > scoped > supports Objects and Objects 3`] = `"($R=>(_$.Ps($R[4],$R[1])))($R[\\"example\\"])"`; +exports[`mutual cyclic references > crossSerializeStream > scoped > supports Objects and Objects 3`] = `"($R=>_$.Ps($R[4],$R[1]))($R[\\"example\\"])"`; exports[`mutual cyclic references > crossSerializeStream > supports Arrays and Arrays 1`] = `"$R[0]=[$R[1]=[$R[2]=_$.P()],$R[3]=[$R[4]=_$.P()]]"`; @@ -72,6 +72,36 @@ exports[`mutual cyclic references > serializeAsync > supports Arrays and Objects exports[`mutual cyclic references > serializeAsync > supports Objects and Objects 1`] = `"((h,j)=>([h={0:Promise.resolve(j={0:Promise.resolve().then(()=>h)})},j]))()"`; +exports[`mutual cyclic references > toCrossJSON > supports Arrays and Arrays 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":1,\\"a\\":[{\\"t\\":9,\\"i\\":2,\\"l\\":1,\\"a\\":[{\\"t\\":4,\\"i\\":1}],\\"o\\":0}],\\"o\\":0},{\\"t\\":4,\\"i\\":2}],\\"o\\":0}"`; + +exports[`mutual cyclic references > toCrossJSON > supports Arrays and Objects 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":1,\\"a\\":[{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"0\\"],\\"v\\":[{\\"t\\":4,\\"i\\":1}],\\"s\\":1},\\"o\\":0}],\\"o\\":0},{\\"t\\":4,\\"i\\":2}],\\"o\\":0}"`; + +exports[`mutual cyclic references > toCrossJSON > supports Objects and Objects 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"0\\"],\\"v\\":[{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"0\\"],\\"v\\":[{\\"t\\":4,\\"i\\":1}],\\"s\\":1},\\"o\\":0}],\\"s\\":1},\\"o\\":0},{\\"t\\":4,\\"i\\":2}],\\"o\\":0}"`; + +exports[`mutual cyclic references > toCrossJSONAsync > supports Arrays and Arrays 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":1,\\"a\\":[{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":9,\\"i\\":3,\\"l\\":1,\\"a\\":[{\\"t\\":12,\\"i\\":4,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":1}}],\\"o\\":0}}],\\"o\\":0},{\\"t\\":4,\\"i\\":3}],\\"o\\":0}"`; + +exports[`mutual cyclic references > toCrossJSONAsync > supports Arrays and Objects 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":1,\\"a\\":[{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"0\\"],\\"v\\":[{\\"t\\":12,\\"i\\":4,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":1}}],\\"s\\":1},\\"o\\":0}}],\\"o\\":0},{\\"t\\":4,\\"i\\":3}],\\"o\\":0}"`; + +exports[`mutual cyclic references > toCrossJSONAsync > supports Objects and Objects 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"0\\"],\\"v\\":[{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"0\\"],\\"v\\":[{\\"t\\":12,\\"i\\":4,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":1}}],\\"s\\":1},\\"o\\":0}}],\\"s\\":1},\\"o\\":0},{\\"t\\":4,\\"i\\":3}],\\"o\\":0}"`; + +exports[`mutual cyclic references > toCrossJSONStream > supports Arrays and Arrays 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":1,\\"a\\":[{\\"t\\":28,\\"i\\":2}],\\"o\\":0},{\\"t\\":9,\\"i\\":3,\\"l\\":1,\\"a\\":[{\\"t\\":28,\\"i\\":4}],\\"o\\":0}],\\"o\\":0}"`; + +exports[`mutual cyclic references > toCrossJSONStream > supports Arrays and Arrays 2`] = `"{\\"t\\":29,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":3}}"`; + +exports[`mutual cyclic references > toCrossJSONStream > supports Arrays and Arrays 3`] = `"{\\"t\\":29,\\"i\\":4,\\"f\\":{\\"t\\":4,\\"i\\":1}}"`; + +exports[`mutual cyclic references > toCrossJSONStream > supports Arrays and Objects 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":1,\\"a\\":[{\\"t\\":28,\\"i\\":2}],\\"o\\":0},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"0\\"],\\"v\\":[{\\"t\\":28,\\"i\\":4}],\\"s\\":1},\\"o\\":0}],\\"o\\":0}"`; + +exports[`mutual cyclic references > toCrossJSONStream > supports Arrays and Objects 2`] = `"{\\"t\\":29,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":3}}"`; + +exports[`mutual cyclic references > toCrossJSONStream > supports Arrays and Objects 3`] = `"{\\"t\\":29,\\"i\\":4,\\"f\\":{\\"t\\":4,\\"i\\":1}}"`; + +exports[`mutual cyclic references > toCrossJSONStream > supports Objects and Objects 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"0\\"],\\"v\\":[{\\"t\\":28,\\"i\\":2}],\\"s\\":1},\\"o\\":0},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"0\\"],\\"v\\":[{\\"t\\":28,\\"i\\":4}],\\"s\\":1},\\"o\\":0}],\\"o\\":0}"`; + +exports[`mutual cyclic references > toCrossJSONStream > supports Objects and Objects 2`] = `"{\\"t\\":29,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":3}}"`; + +exports[`mutual cyclic references > toCrossJSONStream > supports Objects and Objects 3`] = `"{\\"t\\":29,\\"i\\":4,\\"f\\":{\\"t\\":4,\\"i\\":1}}"`; + exports[`mutual cyclic references > toJSON > supports Arrays and Arrays 1`] = `"{\\"t\\":{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":1,\\"a\\":[{\\"t\\":9,\\"i\\":2,\\"l\\":1,\\"a\\":[{\\"t\\":4,\\"i\\":1}],\\"o\\":0}],\\"o\\":0},{\\"t\\":4,\\"i\\":2}],\\"o\\":0},\\"f\\":16383,\\"m\\":[1,2]}"`; exports[`mutual cyclic references > toJSON > supports Arrays and Objects 1`] = `"{\\"t\\":{\\"t\\":9,\\"i\\":0,\\"l\\":2,\\"a\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":1,\\"a\\":[{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"0\\"],\\"v\\":[{\\"t\\":4,\\"i\\":1}],\\"s\\":1},\\"o\\":0}],\\"o\\":0},{\\"t\\":4,\\"i\\":2}],\\"o\\":0},\\"f\\":16383,\\"m\\":[1,2]}"`; diff --git a/packages/seroval/test/__snapshots__/null-constructor.test.ts.snap b/packages/seroval/test/__snapshots__/null-constructor.test.ts.snap index d020ff66..f99bd98d 100644 --- a/packages/seroval/test/__snapshots__/null-constructor.test.ts.snap +++ b/packages/seroval/test/__snapshots__/null-constructor.test.ts.snap @@ -6,82 +6,150 @@ exports[`null-constructor > compat#toJSON > should use manual assignment instead exports[`null-constructor > compat#toJSON > should use manual assignment instead of Object.assign 2`] = `"(h=>((h=Object.create(null),h.hello=\\"world\\",h)))()"`; -exports[`null-constructor > crossSerialize > scoped > supports Objects 1`] = `"($R=>($R[0]=Object.assign(Object.create(null),{hello:\\"world\\"})))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerialize > scoped > supports Object.create(null) 1`] = `"($R=>$R[0]=Object.assign(Object.create(null),{hello:\\"world\\"}))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerialize > scoped > supports Symbol.iterator 1`] = `"($R=>($R[0]=Object.assign(Object.create(null),{[Symbol.iterator]:()=>$R[1]=[1,2,3].values()})))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerialize > scoped > supports Symbol.iterator 1`] = `"($R=>$R[0]=Object.assign(Object.create(null),{[$R[1]=Symbol.iterator]:($R[2]=s=>(i,c,d,t)=>(i=0,t={[$R[1]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})}))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerialize > scoped > supports self-recursion 1`] = `"($R=>($R[0]=Object.create(null),$R[0].b=$R[0].a=$R[0],$R[0]))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerialize > scoped > supports self-recursion 1`] = `"($R=>$R[0]=Object.create(null),$R[0].b=$R[0].a=$R[0],$R[0])($R[\\"example\\"])"`; -exports[`null-constructor > crossSerialize > supports Objects 1`] = `"$R[0]=Object.assign(Object.create(null),{hello:\\"world\\"})"`; +exports[`null-constructor > crossSerialize > supports Object.create(null) 1`] = `"($R[0]={hello:\\"world\\"},Object.freeze($R[0]),$R[0])"`; -exports[`null-constructor > crossSerialize > supports Symbol.iterator 1`] = `"$R[0]=Object.assign(Object.create(null),{[Symbol.iterator]:()=>$R[1]=[1,2,3].values()})"`; +exports[`null-constructor > crossSerialize > supports Symbol.iterator 1`] = `"$R[0]=Object.assign(Object.create(null),{[$R[1]=Symbol.iterator]:($R[2]=s=>(i,c,d,t)=>(i=0,t={[$R[1]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})})"`; exports[`null-constructor > crossSerialize > supports self-recursion 1`] = `"($R[0]=Object.create(null),$R[0].b=$R[0].a=$R[0],$R[0])"`; -exports[`null-constructor > crossSerializeAsync > scoped > supports Objects 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=Object.assign(Object.create(null),{hello:\\"world\\"}))))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerializeAsync > scoped > supports Object.create(null) 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=Object.assign(Object.create(null),{hello:\\"world\\"})))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeAsync > scoped > supports Symbol.iterator 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=Object.assign(Object.create(null),{[Symbol.iterator]:()=>$R[2]=[1,2,3].values()}))))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerializeAsync > scoped > supports Symbol.asyncIterator 1`] = `"($R=>$R[0]=Object.assign(Object.create(null),{[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})}))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeAsync > scoped > supports self-recursion 1`] = `"($R=>($R[0]=Object.assign(Object.create(null),{a:$R[1]=Promise.resolve().then(()=>$R[0]),b:$R[2]=Promise.resolve().then(()=>$R[0])})))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerializeAsync > scoped > supports Symbol.iterator 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=Object.assign(Object.create(null),{[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})})))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeAsync > supports Objects 1`] = `"$R[0]=Promise.resolve($R[1]=Object.assign(Object.create(null),{hello:\\"world\\"}))"`; +exports[`null-constructor > crossSerializeAsync > scoped > supports self-recursion 1`] = `"($R=>$R[0]=Object.assign(Object.create(null),{a:$R[1]=Promise.resolve().then(()=>$R[0]),b:$R[2]=Promise.resolve().then(()=>$R[0])}))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeAsync > supports Symbol.iterator 1`] = `"$R[0]=Promise.resolve($R[1]=Object.assign(Object.create(null),{[Symbol.iterator]:()=>$R[2]=[1,2,3].values()}))"`; +exports[`null-constructor > crossSerializeAsync > supports Object.create(null) 1`] = `"$R[0]=Promise.resolve($R[1]=Object.assign(Object.create(null),{hello:\\"world\\"}))"`; + +exports[`null-constructor > crossSerializeAsync > supports Symbol.asyncIterator 1`] = `"$R[0]=Object.assign(Object.create(null),{[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})})"`; + +exports[`null-constructor > crossSerializeAsync > supports Symbol.iterator 1`] = `"$R[0]=Promise.resolve($R[1]=Object.assign(Object.create(null),{[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}))"`; exports[`null-constructor > crossSerializeAsync > supports self-recursion 1`] = `"$R[0]=Object.assign(Object.create(null),{a:$R[1]=Promise.resolve().then(()=>$R[0]),b:$R[2]=Promise.resolve().then(()=>$R[0])})"`; -exports[`null-constructor > crossSerializeStream > scoped > supports Objects 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerializeStream > scoped > supports Object.create(null) 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeStream > scoped > supports Objects 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object.assign(Object.create(null),{hello:\\"world\\"}))))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerializeStream > scoped > supports Object.create(null) 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object.assign(Object.create(null),{hello:\\"world\\"})))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeStream > scoped > supports Symbol.iterator 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerializeStream > scoped > supports Symbol.asyncIterator 1`] = `"($R=>$R[0]=Object.assign(Object.create(null),{[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]=_$.S())}))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeStream > scoped > supports Symbol.iterator 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object.assign(Object.create(null),{[Symbol.iterator]:()=>$R[2]=[1,2,3].values()}))))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerializeStream > scoped > supports Symbol.asyncIterator 2`] = `"($R=>_$.Se($R[3],$R[4]=[0,1]))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeStream > scoped > supports self-recursion 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerializeStream > scoped > supports Symbol.asyncIterator 3`] = `"($R=>_$.Se($R[3],$R[5]=[0,2]))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeStream > scoped > supports self-recursion 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Object.assign(Object.create(null),{a:$R[2]=_$.P(),b:$R[3]=_$.P()}))))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerializeStream > scoped > supports Symbol.asyncIterator 4`] = `"($R=>_$.Se($R[3],$R[6]=[0,3]))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeStream > scoped > supports self-recursion 3`] = `"($R=>(_$.Ps($R[2],$R[1])))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerializeStream > scoped > supports Symbol.asyncIterator 5`] = `"($R=>_$.Se($R[3],$R[7]=[2,void 0]))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeStream > scoped > supports self-recursion 4`] = `"($R=>(_$.Ps($R[3],$R[1])))($R[\\"example\\"])"`; +exports[`null-constructor > crossSerializeStream > scoped > supports Symbol.asyncIterator 6`] = `"($R=>_$.Sc($R[3]))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeStream > supports Objects 1`] = `"$R[0]=_$.P()"`; +exports[`null-constructor > crossSerializeStream > scoped > supports Symbol.iterator 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeStream > supports Objects 2`] = `"_$.Ps($R[0],$R[1]=Object.assign(Object.create(null),{hello:\\"world\\"}))"`; +exports[`null-constructor > crossSerializeStream > scoped > supports Symbol.iterator 2`] = `"($R=>_$.Ps($R[0],$R[1]=Object.assign(Object.create(null),{[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})})))($R[\\"example\\"])"`; -exports[`null-constructor > crossSerializeStream > supports Symbol.iterator 1`] = `"$R[0]=_$.P()"`; +exports[`null-constructor > crossSerializeStream > scoped > supports self-recursion 1`] = `"($R=>$R[0]=Object.assign(Object.create(null),{a:$R[1]=_$.P(),b:$R[2]=_$.P()}))($R[\\"example\\"])"`; + +exports[`null-constructor > crossSerializeStream > scoped > supports self-recursion 2`] = `"($R=>_$.Ps($R[1],$R[0]))($R[\\"example\\"])"`; + +exports[`null-constructor > crossSerializeStream > scoped > supports self-recursion 3`] = `"($R=>_$.Ps($R[2],$R[0]))($R[\\"example\\"])"`; + +exports[`null-constructor > crossSerializeStream > supports Object.create(null) 1`] = `"$R[0]=_$.P()"`; + +exports[`null-constructor > crossSerializeStream > supports Object.create(null) 2`] = `"_$.Ps($R[0],$R[1]=Object.assign(Object.create(null),{hello:\\"world\\"}))"`; + +exports[`null-constructor > crossSerializeStream > supports Symbol.asyncIterator 1`] = `"$R[0]=Object.assign(Object.create(null),{[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]=_$.S())})"`; + +exports[`null-constructor > crossSerializeStream > supports Symbol.asyncIterator 2`] = `"_$.Se($R[3],$R[4]=[0,1])"`; -exports[`null-constructor > crossSerializeStream > supports Symbol.iterator 2`] = `"_$.Ps($R[0],$R[1]=Object.assign(Object.create(null),{[Symbol.iterator]:()=>$R[2]=[1,2,3].values()}))"`; +exports[`null-constructor > crossSerializeStream > supports Symbol.asyncIterator 3`] = `"_$.Se($R[3],$R[5]=[0,2])"`; -exports[`null-constructor > crossSerializeStream > supports self-recursion 1`] = `"$R[0]=_$.P()"`; +exports[`null-constructor > crossSerializeStream > supports Symbol.asyncIterator 4`] = `"_$.Se($R[3],$R[6]=[0,3])"`; -exports[`null-constructor > crossSerializeStream > supports self-recursion 2`] = `"_$.Ps($R[0],$R[1]=Object.assign(Object.create(null),{a:$R[2]=_$.P(),b:$R[3]=_$.P()}))"`; +exports[`null-constructor > crossSerializeStream > supports Symbol.asyncIterator 5`] = `"_$.Se($R[3],$R[7]=[2,void 0])"`; -exports[`null-constructor > crossSerializeStream > supports self-recursion 3`] = `"_$.Ps($R[2],$R[1])"`; +exports[`null-constructor > crossSerializeStream > supports Symbol.asyncIterator 6`] = `"_$.Sc($R[3])"`; -exports[`null-constructor > crossSerializeStream > supports self-recursion 4`] = `"_$.Ps($R[3],$R[1])"`; +exports[`null-constructor > crossSerializeStream > supports Symbol.iterator 1`] = `"$R[0]=_$.P()"`; + +exports[`null-constructor > crossSerializeStream > supports Symbol.iterator 2`] = `"_$.Ps($R[0],$R[1]=Object.assign(Object.create(null),{[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}))"`; + +exports[`null-constructor > crossSerializeStream > supports self-recursion 1`] = `"$R[0]=Object.assign(Object.create(null),{a:$R[1]=_$.P(),b:$R[2]=_$.P()})"`; + +exports[`null-constructor > crossSerializeStream > supports self-recursion 2`] = `"_$.Ps($R[1],$R[0])"`; + +exports[`null-constructor > crossSerializeStream > supports self-recursion 3`] = `"_$.Ps($R[2],$R[0])"`; exports[`null-constructor > serialize > supports Object.create(null) 1`] = `"Object.assign(Object.create(null),{hello:\\"world\\"})"`; -exports[`null-constructor > serialize > supports Symbol.iterator 1`] = `"Object.assign(Object.create(null),{[Symbol.iterator]:()=>[1,2,3].values()})"`; +exports[`null-constructor > serialize > supports Symbol.iterator 1`] = `"(h=>(Object.assign(Object.create(null),{[h=Symbol.iterator]:(s=>(i,c,d,t)=>(i=0,t={[h]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))({v:[1,2,3,void 0],t:-1,d:3})})))()"`; exports[`null-constructor > serialize > supports self-recursion 1`] = `"(h=>(h=Object.create(null),h.b=h.a=h,h))()"`; exports[`null-constructor > serializeAsync > supports Object.create(null) 1`] = `"Promise.resolve(Object.assign(Object.create(null),{hello:\\"world\\"}))"`; -exports[`null-constructor > serializeAsync > supports Symbol.iterator 1`] = `"Promise.resolve(Object.assign(Object.create(null),{[Symbol.iterator]:()=>[1,2,3].values()}))"`; +exports[`null-constructor > serializeAsync > supports Symbol.asyncIterator 1`] = `"(h=>(Object.assign(Object.create(null),{[h=Symbol.asyncIterator]:(s=>(i,t)=>(i=0,t={[h]:()=>t,next:()=>Promise.resolve().then((c,d)=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}})}))({v:[1,2,3,void 0],t:-1,d:3})})))()"`; + +exports[`null-constructor > serializeAsync > supports Symbol.iterator 1`] = `"(h=>(Promise.resolve(Object.assign(Object.create(null),{[h=Symbol.iterator]:(s=>(i,c,d,t)=>(i=0,t={[h]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))({v:[1,2,3,void 0],t:-1,d:3})}))))()"`; exports[`null-constructor > serializeAsync > supports self-recursion 1`] = `"(h=>(h=Object.assign(Object.create(null),{a:Promise.resolve().then(()=>h),b:Promise.resolve().then(()=>h)})))()"`; +exports[`null-constructor > toCrossJSON > supports Object.create(null) 1`] = `"{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":0}"`; + +exports[`null-constructor > toCrossJSON > supports Symbol.iterator 1`] = `"{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0}"`; + +exports[`null-constructor > toCrossJSON > supports self-recursion 1`] = `"{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":4,\\"i\\":0},{\\"t\\":4,\\"i\\":0}],\\"s\\":2},\\"o\\":0}"`; + +exports[`null-constructor > toCrossJSONAsync > supports Object.create(null) 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":11,\\"i\\":1,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":0}}"`; + +exports[`null-constructor > toCrossJSONAsync > supports Symbol.asyncIterator 1`] = `"{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0}"`; + +exports[`null-constructor > toCrossJSONAsync > supports Symbol.iterator 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":11,\\"i\\":1,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0}}"`; + +exports[`null-constructor > toCrossJSONAsync > supports self-recursion 1`] = `"{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}},{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"s\\":2},\\"o\\":0}"`; + +exports[`null-constructor > toCrossJSONStream > supports Object.create(null) 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`null-constructor > toCrossJSONStream > supports Object.create(null) 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":11,\\"i\\":1,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":0}}"`; + +exports[`null-constructor > toCrossJSONStream > supports Symbol.asyncIterator 1`] = `"{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":31,\\"i\\":3}]}],\\"s\\":1},\\"o\\":0}"`; + +exports[`null-constructor > toCrossJSONStream > supports Symbol.asyncIterator 2`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":4,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":1}],\\"o\\":0}}"`; + +exports[`null-constructor > toCrossJSONStream > supports Symbol.asyncIterator 3`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":5,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":2}],\\"o\\":0}}"`; + +exports[`null-constructor > toCrossJSONStream > supports Symbol.asyncIterator 4`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":6,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}}"`; + +exports[`null-constructor > toCrossJSONStream > supports Symbol.asyncIterator 5`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":7,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":2},{\\"t\\":2,\\"s\\":1}],\\"o\\":0}}"`; + +exports[`null-constructor > toCrossJSONStream > supports Symbol.asyncIterator 6`] = `"{\\"t\\":33,\\"i\\":3}"`; + +exports[`null-constructor > toCrossJSONStream > supports Symbol.iterator 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`null-constructor > toCrossJSONStream > supports Symbol.iterator 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":11,\\"i\\":1,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0}}"`; + +exports[`null-constructor > toCrossJSONStream > supports self-recursion 1`] = `"{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":28,\\"i\\":1},{\\"t\\":28,\\"i\\":2}],\\"s\\":2},\\"o\\":0}"`; + +exports[`null-constructor > toCrossJSONStream > supports self-recursion 2`] = `"{\\"t\\":29,\\"i\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}"`; + +exports[`null-constructor > toCrossJSONStream > supports self-recursion 3`] = `"{\\"t\\":29,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":0}}"`; + exports[`null-constructor > toJSON > supports Object.create(null) 1`] = `"{\\"t\\":{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":0},\\"f\\":16383,\\"m\\":[]}"`; -exports[`null-constructor > toJSON > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[0],\\"v\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}],\\"s\\":1},\\"o\\":0},\\"f\\":16383,\\"m\\":[]}"`; +exports[`null-constructor > toJSON > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0},\\"f\\":16383,\\"m\\":[1]}"`; exports[`null-constructor > toJSON > supports self-recursion 1`] = `"{\\"t\\":{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":4,\\"i\\":0},{\\"t\\":4,\\"i\\":0}],\\"s\\":2},\\"o\\":0},\\"f\\":16383,\\"m\\":[0]}"`; -exports[`null-constructor > toJSONAsync > supports Object.create(null) 1`] = `"{\\"t\\":{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":0},\\"f\\":16383,\\"m\\":[]}"`; +exports[`null-constructor > toJSONAsync > supports Object.create(null) 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":11,\\"i\\":1,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":0}},\\"f\\":16383,\\"m\\":[]}"`; + +exports[`null-constructor > toJSONAsync > supports Symbol.asyncIterator 1`] = `"{\\"t\\":{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0},\\"f\\":16383,\\"m\\":[1]}"`; -exports[`null-constructor > toJSONAsync > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":11,\\"i\\":1,\\"p\\":{\\"k\\":[0],\\"v\\":[{\\"t\\":9,\\"i\\":2,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}],\\"s\\":1},\\"o\\":0}},\\"f\\":16383,\\"m\\":[]}"`; +exports[`null-constructor > toJSONAsync > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":11,\\"i\\":1,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0}},\\"f\\":16383,\\"m\\":[2]}"`; exports[`null-constructor > toJSONAsync > supports self-recursion 1`] = `"{\\"t\\":{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}},{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"s\\":2},\\"o\\":0},\\"f\\":16383,\\"m\\":[0]}"`; diff --git a/packages/seroval/test/__snapshots__/number.test.ts.snap b/packages/seroval/test/__snapshots__/number.test.ts.snap index 6c57479c..2c80c176 100644 --- a/packages/seroval/test/__snapshots__/number.test.ts.snap +++ b/packages/seroval/test/__snapshots__/number.test.ts.snap @@ -40,6 +40,46 @@ exports[`number > crossSerializeStream > supports numbers 1`] = `"$R[0]=_$.P()"` exports[`number > crossSerializeStream > supports numbers 2`] = `"_$.Ps($R[0],3735928559)"`; +exports[`number > toCrossJSON > supports numbers 1`] = `"{\\"t\\":0,\\"s\\":3735928559}"`; + +exports[`number > toCrossJSON > supports numbers 2`] = `"{\\"t\\":2,\\"s\\":7}"`; + +exports[`number > toCrossJSON > supports numbers 3`] = `"{\\"t\\":2,\\"s\\":5}"`; + +exports[`number > toCrossJSON > supports numbers 4`] = `"{\\"t\\":2,\\"s\\":6}"`; + +exports[`number > toCrossJSON > supports numbers 5`] = `"{\\"t\\":2,\\"s\\":4}"`; + +exports[`number > toCrossJSONAsync > supports numbers 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":0,\\"s\\":3735928559}}"`; + +exports[`number > toCrossJSONAsync > supports numbers 2`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":2,\\"s\\":7}}"`; + +exports[`number > toCrossJSONAsync > supports numbers 3`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":2,\\"s\\":5}}"`; + +exports[`number > toCrossJSONAsync > supports numbers 4`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":2,\\"s\\":6}}"`; + +exports[`number > toCrossJSONAsync > supports numbers 5`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":2,\\"s\\":4}}"`; + +exports[`number > toCrossJSONStream > supports -0 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`number > toCrossJSONStream > supports -0 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":4}}"`; + +exports[`number > toCrossJSONStream > supports -Infinity 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`number > toCrossJSONStream > supports -Infinity 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":6}}"`; + +exports[`number > toCrossJSONStream > supports Infinity 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`number > toCrossJSONStream > supports Infinity 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":5}}"`; + +exports[`number > toCrossJSONStream > supports NaN 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`number > toCrossJSONStream > supports NaN 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":2,\\"s\\":7}}"`; + +exports[`number > toCrossJSONStream > supports numbers 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`number > toCrossJSONStream > supports numbers 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":0,\\"s\\":3735928559}}"`; + exports[`number > toJSON > supports numbers 1`] = `"{\\"t\\":{\\"t\\":0,\\"s\\":3735928559},\\"f\\":16383,\\"m\\":[]}"`; exports[`number > toJSON > supports numbers 2`] = `"{\\"t\\":{\\"t\\":2,\\"s\\":7},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/object.test.ts.snap b/packages/seroval/test/__snapshots__/object.test.ts.snap index 93974ceb..7e7c357f 100644 --- a/packages/seroval/test/__snapshots__/object.test.ts.snap +++ b/packages/seroval/test/__snapshots__/object.test.ts.snap @@ -6,82 +6,150 @@ exports[`objects > compat#toJSON > should use manual assignment instead of Objec exports[`objects > compat#toJSON > should use manual assignment instead of Object.assign 2`] = `"({hello:\\"world\\"})"`; -exports[`objects > crossSerialize > scoped > supports Objects 1`] = `"($R=>($R[0]={hello:\\"world\\"}))($R[\\"example\\"])"`; +exports[`objects > crossSerialize > scoped > supports Objects 1`] = `"($R=>$R[0]={hello:\\"world\\"})($R[\\"example\\"])"`; -exports[`objects > crossSerialize > scoped > supports Symbol.iterator 1`] = `"($R=>($R[0]={[Symbol.iterator]:()=>$R[1]=[1,2,3].values()}))($R[\\"example\\"])"`; +exports[`objects > crossSerialize > scoped > supports Symbol.iterator 1`] = `"($R=>$R[0]={[$R[1]=Symbol.iterator]:($R[2]=s=>(i,c,d,t)=>(i=0,t={[$R[1]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})})($R[\\"example\\"])"`; -exports[`objects > crossSerialize > scoped > supports self-recursion 1`] = `"($R=>($R[0]={},$R[0].b=$R[0].a=$R[0],$R[0]))($R[\\"example\\"])"`; +exports[`objects > crossSerialize > scoped > supports self-recursion 1`] = `"($R=>$R[0]={},$R[0].b=$R[0].a=$R[0],$R[0])($R[\\"example\\"])"`; -exports[`objects > crossSerialize > supports Objects 1`] = `"$R[0]={hello:\\"world\\"}"`; +exports[`objects > crossSerialize > supports Objects 1`] = `"($R[0]={hello:\\"world\\"},Object.freeze($R[0]),$R[0])"`; -exports[`objects > crossSerialize > supports Symbol.iterator 1`] = `"$R[0]={[Symbol.iterator]:()=>$R[1]=[1,2,3].values()}"`; +exports[`objects > crossSerialize > supports Symbol.iterator 1`] = `"$R[0]={[$R[1]=Symbol.iterator]:($R[2]=s=>(i,c,d,t)=>(i=0,t={[$R[1]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})}"`; exports[`objects > crossSerialize > supports self-recursion 1`] = `"($R[0]={},$R[0].b=$R[0].a=$R[0],$R[0])"`; -exports[`objects > crossSerializeAsync > scoped > supports Objects 1`] = `"($R=>($R[0]=Promise.resolve($R[1]={hello:\\"world\\"})))($R[\\"example\\"])"`; +exports[`objects > crossSerializeAsync > scoped > supports Objects 1`] = `"($R=>$R[0]=Promise.resolve($R[1]={hello:\\"world\\"}))($R[\\"example\\"])"`; -exports[`objects > crossSerializeAsync > scoped > supports Symbol.iterator 1`] = `"($R=>($R[0]=Promise.resolve($R[1]={[Symbol.iterator]:()=>$R[2]=[1,2,3].values()})))($R[\\"example\\"])"`; +exports[`objects > crossSerializeAsync > scoped > supports Symbol.asyncIterator 1`] = `"($R=>$R[0]={[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})})($R[\\"example\\"])"`; -exports[`objects > crossSerializeAsync > scoped > supports self-recursion 1`] = `"($R=>($R[0]={a:$R[1]=Promise.resolve().then(()=>$R[0]),b:$R[2]=Promise.resolve().then(()=>$R[0])}))($R[\\"example\\"])"`; +exports[`objects > crossSerializeAsync > scoped > supports Symbol.iterator 1`] = `"($R=>$R[0]=Promise.resolve($R[1]={[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}))($R[\\"example\\"])"`; + +exports[`objects > crossSerializeAsync > scoped > supports self-recursion 1`] = `"($R=>$R[0]={a:$R[1]=Promise.resolve().then(()=>$R[0]),b:$R[2]=Promise.resolve().then(()=>$R[0])})($R[\\"example\\"])"`; exports[`objects > crossSerializeAsync > supports Objects 1`] = `"$R[0]=Promise.resolve($R[1]={hello:\\"world\\"})"`; -exports[`objects > crossSerializeAsync > supports Symbol.iterator 1`] = `"$R[0]=Promise.resolve($R[1]={[Symbol.iterator]:()=>$R[2]=[1,2,3].values()})"`; +exports[`objects > crossSerializeAsync > supports Symbol.asyncIterator 1`] = `"$R[0]={[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})}"`; + +exports[`objects > crossSerializeAsync > supports Symbol.iterator 1`] = `"$R[0]=Promise.resolve($R[1]={[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})})"`; exports[`objects > crossSerializeAsync > supports self-recursion 1`] = `"$R[0]={a:$R[1]=Promise.resolve().then(()=>$R[0]),b:$R[2]=Promise.resolve().then(()=>$R[0])}"`; -exports[`objects > crossSerializeStream > scoped > supports Objects 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`objects > crossSerializeStream > scoped > supports Objects 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; + +exports[`objects > crossSerializeStream > scoped > supports Objects 2`] = `"($R=>_$.Ps($R[0],$R[1]={hello:\\"world\\"}))($R[\\"example\\"])"`; + +exports[`objects > crossSerializeStream > scoped > supports Symbol.asyncIterator 1`] = `"($R=>$R[0]={[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]=_$.S())})($R[\\"example\\"])"`; + +exports[`objects > crossSerializeStream > scoped > supports Symbol.asyncIterator 2`] = `"($R=>_$.Se($R[3],$R[4]=[0,1]))($R[\\"example\\"])"`; -exports[`objects > crossSerializeStream > scoped > supports Objects 2`] = `"($R=>(_$.Ps($R[0],$R[1]={hello:\\"world\\"})))($R[\\"example\\"])"`; +exports[`objects > crossSerializeStream > scoped > supports Symbol.asyncIterator 3`] = `"($R=>_$.Se($R[3],$R[5]=[0,2]))($R[\\"example\\"])"`; -exports[`objects > crossSerializeStream > scoped > supports Symbol.iterator 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`objects > crossSerializeStream > scoped > supports Symbol.asyncIterator 4`] = `"($R=>_$.Se($R[3],$R[6]=[0,3]))($R[\\"example\\"])"`; -exports[`objects > crossSerializeStream > scoped > supports Symbol.iterator 2`] = `"($R=>(_$.Ps($R[0],$R[1]={[Symbol.iterator]:()=>$R[2]=[1,2,3].values()})))($R[\\"example\\"])"`; +exports[`objects > crossSerializeStream > scoped > supports Symbol.asyncIterator 5`] = `"($R=>_$.Se($R[3],$R[7]=[2,void 0]))($R[\\"example\\"])"`; -exports[`objects > crossSerializeStream > scoped > supports self-recursion 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`objects > crossSerializeStream > scoped > supports Symbol.asyncIterator 6`] = `"($R=>_$.Sc($R[3]))($R[\\"example\\"])"`; -exports[`objects > crossSerializeStream > scoped > supports self-recursion 2`] = `"($R=>(_$.Ps($R[0],$R[1]={a:$R[2]=_$.P(),b:$R[3]=_$.P()})))($R[\\"example\\"])"`; +exports[`objects > crossSerializeStream > scoped > supports Symbol.iterator 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`objects > crossSerializeStream > scoped > supports self-recursion 3`] = `"($R=>(_$.Ps($R[2],$R[1])))($R[\\"example\\"])"`; +exports[`objects > crossSerializeStream > scoped > supports Symbol.iterator 2`] = `"($R=>_$.Ps($R[0],$R[1]={[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}))($R[\\"example\\"])"`; -exports[`objects > crossSerializeStream > scoped > supports self-recursion 4`] = `"($R=>(_$.Ps($R[3],$R[1])))($R[\\"example\\"])"`; +exports[`objects > crossSerializeStream > scoped > supports self-recursion 1`] = `"($R=>$R[0]={a:$R[1]=_$.P(),b:$R[2]=_$.P()})($R[\\"example\\"])"`; + +exports[`objects > crossSerializeStream > scoped > supports self-recursion 2`] = `"($R=>_$.Ps($R[1],$R[0]))($R[\\"example\\"])"`; + +exports[`objects > crossSerializeStream > scoped > supports self-recursion 3`] = `"($R=>_$.Ps($R[2],$R[0]))($R[\\"example\\"])"`; exports[`objects > crossSerializeStream > supports Objects 1`] = `"$R[0]=_$.P()"`; exports[`objects > crossSerializeStream > supports Objects 2`] = `"_$.Ps($R[0],$R[1]={hello:\\"world\\"})"`; -exports[`objects > crossSerializeStream > supports Symbol.iterator 1`] = `"$R[0]=_$.P()"`; +exports[`objects > crossSerializeStream > supports Symbol.asyncIterator 1`] = `"$R[0]={[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]=_$.S())}"`; + +exports[`objects > crossSerializeStream > supports Symbol.asyncIterator 2`] = `"_$.Se($R[3],$R[4]=[0,1])"`; -exports[`objects > crossSerializeStream > supports Symbol.iterator 2`] = `"_$.Ps($R[0],$R[1]={[Symbol.iterator]:()=>$R[2]=[1,2,3].values()})"`; +exports[`objects > crossSerializeStream > supports Symbol.asyncIterator 3`] = `"_$.Se($R[3],$R[5]=[0,2])"`; -exports[`objects > crossSerializeStream > supports self-recursion 1`] = `"$R[0]=_$.P()"`; +exports[`objects > crossSerializeStream > supports Symbol.asyncIterator 4`] = `"_$.Se($R[3],$R[6]=[0,3])"`; -exports[`objects > crossSerializeStream > supports self-recursion 2`] = `"_$.Ps($R[0],$R[1]={a:$R[2]=_$.P(),b:$R[3]=_$.P()})"`; +exports[`objects > crossSerializeStream > supports Symbol.asyncIterator 5`] = `"_$.Se($R[3],$R[7]=[2,void 0])"`; -exports[`objects > crossSerializeStream > supports self-recursion 3`] = `"_$.Ps($R[2],$R[1])"`; +exports[`objects > crossSerializeStream > supports Symbol.asyncIterator 6`] = `"_$.Sc($R[3])"`; -exports[`objects > crossSerializeStream > supports self-recursion 4`] = `"_$.Ps($R[3],$R[1])"`; +exports[`objects > crossSerializeStream > supports Symbol.iterator 1`] = `"$R[0]=_$.P()"`; + +exports[`objects > crossSerializeStream > supports Symbol.iterator 2`] = `"_$.Ps($R[0],$R[1]={[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})})"`; + +exports[`objects > crossSerializeStream > supports self-recursion 1`] = `"$R[0]={a:$R[1]=_$.P(),b:$R[2]=_$.P()}"`; + +exports[`objects > crossSerializeStream > supports self-recursion 2`] = `"_$.Ps($R[1],$R[0])"`; + +exports[`objects > crossSerializeStream > supports self-recursion 3`] = `"_$.Ps($R[2],$R[0])"`; exports[`objects > serialize > supports Objects 1`] = `"({hello:\\"world\\"})"`; -exports[`objects > serialize > supports Symbol.iterator 1`] = `"({[Symbol.iterator]:()=>[1,2,3].values()})"`; +exports[`objects > serialize > supports Symbol.iterator 1`] = `"(h=>({[h=Symbol.iterator]:(s=>(i,c,d,t)=>(i=0,t={[h]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))({v:[1,2,3,void 0],t:-1,d:3})}))()"`; exports[`objects > serialize > supports self-recursion 1`] = `"(h=>(h={},h.b=h.a=h,h))()"`; exports[`objects > serializeAsync > supports Objects 1`] = `"Promise.resolve({hello:\\"world\\"})"`; -exports[`objects > serializeAsync > supports Symbol.iterator 1`] = `"Promise.resolve({[Symbol.iterator]:()=>[1,2,3].values()})"`; +exports[`objects > serializeAsync > supports Symbol.asyncIterator 1`] = `"(h=>({[h=Symbol.asyncIterator]:(s=>(i,t)=>(i=0,t={[h]:()=>t,next:()=>Promise.resolve().then((c,d)=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}})}))({v:[1,2,3,void 0],t:-1,d:3})}))()"`; + +exports[`objects > serializeAsync > supports Symbol.iterator 1`] = `"(h=>(Promise.resolve({[h=Symbol.iterator]:(s=>(i,c,d,t)=>(i=0,t={[h]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))({v:[1,2,3,void 0],t:-1,d:3})})))()"`; exports[`objects > serializeAsync > supports self-recursion 1`] = `"(h=>(h={a:Promise.resolve().then(()=>h),b:Promise.resolve().then(()=>h)}))()"`; +exports[`objects > toCrossJSON > supports Objects 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":0}"`; + +exports[`objects > toCrossJSON > supports Symbol.iterator 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0}"`; + +exports[`objects > toCrossJSON > supports self-recursion 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":4,\\"i\\":0},{\\"t\\":4,\\"i\\":0}],\\"s\\":2},\\"o\\":0}"`; + +exports[`objects > toCrossJSONAsync > supports Objects 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":0}}"`; + +exports[`objects > toCrossJSONAsync > supports Symbol.asyncIterator 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0}"`; + +exports[`objects > toCrossJSONAsync > supports Symbol.iterator 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0}}"`; + +exports[`objects > toCrossJSONAsync > supports self-recursion 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}},{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"s\\":2},\\"o\\":0}"`; + +exports[`objects > toCrossJSONStream > supports Objects 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`objects > toCrossJSONStream > supports Objects 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":0}}"`; + +exports[`objects > toCrossJSONStream > supports Symbol.asyncIterator 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":31,\\"i\\":3}]}],\\"s\\":1},\\"o\\":0}"`; + +exports[`objects > toCrossJSONStream > supports Symbol.asyncIterator 2`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":4,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":1}],\\"o\\":0}}"`; + +exports[`objects > toCrossJSONStream > supports Symbol.asyncIterator 3`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":5,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":2}],\\"o\\":0}}"`; + +exports[`objects > toCrossJSONStream > supports Symbol.asyncIterator 4`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":6,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}}"`; + +exports[`objects > toCrossJSONStream > supports Symbol.asyncIterator 5`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":7,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":2},{\\"t\\":2,\\"s\\":1}],\\"o\\":0}}"`; + +exports[`objects > toCrossJSONStream > supports Symbol.asyncIterator 6`] = `"{\\"t\\":33,\\"i\\":3}"`; + +exports[`objects > toCrossJSONStream > supports Symbol.iterator 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`objects > toCrossJSONStream > supports Symbol.iterator 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0}}"`; + +exports[`objects > toCrossJSONStream > supports self-recursion 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":28,\\"i\\":1},{\\"t\\":28,\\"i\\":2}],\\"s\\":2},\\"o\\":0}"`; + +exports[`objects > toCrossJSONStream > supports self-recursion 2`] = `"{\\"t\\":29,\\"i\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}"`; + +exports[`objects > toCrossJSONStream > supports self-recursion 3`] = `"{\\"t\\":29,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":0}}"`; + exports[`objects > toJSON > supports Objects 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":0},\\"f\\":16383,\\"m\\":[]}"`; -exports[`objects > toJSON > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[0],\\"v\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}],\\"s\\":1},\\"o\\":0},\\"f\\":16383,\\"m\\":[]}"`; +exports[`objects > toJSON > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0},\\"f\\":16383,\\"m\\":[1]}"`; exports[`objects > toJSON > supports self-recursion 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":4,\\"i\\":0},{\\"t\\":4,\\"i\\":0}],\\"s\\":2},\\"o\\":0},\\"f\\":16383,\\"m\\":[0]}"`; -exports[`objects > toJSONAsync > supports Objects 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":0},\\"f\\":16383,\\"m\\":[]}"`; +exports[`objects > toJSONAsync > supports Objects 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":0}},\\"f\\":16383,\\"m\\":[]}"`; + +exports[`objects > toJSONAsync > supports Symbol.asyncIterator 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0},\\"f\\":16383,\\"m\\":[1]}"`; -exports[`objects > toJSONAsync > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[0],\\"v\\":[{\\"t\\":9,\\"i\\":2,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}],\\"s\\":1},\\"o\\":0}},\\"f\\":16383,\\"m\\":[]}"`; +exports[`objects > toJSONAsync > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":0}},\\"f\\":16383,\\"m\\":[2]}"`; exports[`objects > toJSONAsync > supports self-recursion 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}},{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"s\\":2},\\"o\\":0},\\"f\\":16383,\\"m\\":[0]}"`; diff --git a/packages/seroval/test/__snapshots__/plugin.test.ts.snap b/packages/seroval/test/__snapshots__/plugin.test.ts.snap index 9fae2401..d49576c0 100644 --- a/packages/seroval/test/__snapshots__/plugin.test.ts.snap +++ b/packages/seroval/test/__snapshots__/plugin.test.ts.snap @@ -1,21 +1,27 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Plugin > crossSerialize > scoped > supports Plugin 1`] = `"($R=>(Buffer.from(\\"SGVsbG8sIFdvcmxkIQ==\\", \\"base64\\")))($R[\\"example\\"])"`; +exports[`Plugin > crossSerialize > scoped > supports Plugin 1`] = `"($R=>$R[0]=Buffer.from(\\"SGVsbG8sIFdvcmxkIQ==\\", \\"base64\\"))($R[\\"example\\"])"`; -exports[`Plugin > crossSerialize > supports Plugin 1`] = `"Buffer.from(\\"SGVsbG8sIFdvcmxkIQ==\\", \\"base64\\")"`; +exports[`Plugin > crossSerialize > supports Plugin 1`] = `"$R[0]=Buffer.from(\\"SGVsbG8sIFdvcmxkIQ==\\", \\"base64\\")"`; -exports[`Plugin > crossSerializeAsync > scoped > supports Plugin 1`] = `"($R=>($R[0]=Promise.resolve(Buffer.from(\\"SGVsbG8sIFdvcmxkIQ==\\", \\"base64\\"))))($R[\\"example\\"])"`; +exports[`Plugin > crossSerializeAsync > scoped > supports Plugin 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=Buffer.from(\\"SGVsbG8sIFdvcmxkIQ==\\", \\"base64\\")))($R[\\"example\\"])"`; -exports[`Plugin > crossSerializeAsync > supports Plugin 1`] = `"$R[0]=Promise.resolve(Buffer.from(\\"SGVsbG8sIFdvcmxkIQ==\\", \\"base64\\"))"`; +exports[`Plugin > crossSerializeAsync > supports Plugin 1`] = `"$R[0]=Promise.resolve($R[1]=Buffer.from(\\"SGVsbG8sIFdvcmxkIQ==\\", \\"base64\\"))"`; -exports[`Plugin > crossSerializeStream > scoped > supports Plugin 1`] = `"($R=>($R[0]=Object.assign(Object.create(null),{0:72,1:101,2:108,3:108,4:111,5:44,6:32,7:87,8:111,9:114,10:108,11:100,12:33,[Symbol.iterator]:()=>$R[1]=[72,101,108,108,111,44,32,87,111,114,108,100,33].values()})))($R[\\"example\\"])"`; +exports[`Plugin > crossSerializeStream > scoped > supports Plugin 1`] = `"($R=>$R[0]=Buffer.from(\\"SGVsbG8sIFdvcmxkIQ==\\", \\"base64\\"))($R[\\"example\\"])"`; -exports[`Plugin > crossSerializeStream > supports Plugin 1`] = `"$R[0]=Object.assign(Object.create(null),{0:72,1:101,2:108,3:108,4:111,5:44,6:32,7:87,8:111,9:114,10:108,11:100,12:33,[Symbol.iterator]:()=>$R[1]=[72,101,108,108,111,44,32,87,111,114,108,100,33].values()})"`; +exports[`Plugin > crossSerializeStream > supports Plugin 1`] = `"$R[0]=Buffer.from(\\"SGVsbG8sIFdvcmxkIQ==\\", \\"base64\\")"`; exports[`Plugin > serialize > supports Plugin 1`] = `"Buffer.from(\\"SGVsbG8sIFdvcmxkIQ==\\", \\"base64\\")"`; exports[`Plugin > serializeAsync > supports Plugin 1`] = `"Promise.resolve(Buffer.from(\\"SGVsbG8sIFdvcmxkIQ==\\", \\"base64\\"))"`; -exports[`Plugin > serializeAsync > supports Plugin 2`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":40,\\"i\\":1,\\"s\\":{\\"t\\":1,\\"s\\":\\"SGVsbG8sIFdvcmxkIQ==\\"},\\"c\\":\\"Buffer\\"}},\\"f\\":16383,\\"m\\":[]}"`; +exports[`Plugin > toCrossJSON > supports Plugin 1`] = `"{\\"t\\":40,\\"i\\":0,\\"s\\":{\\"t\\":1,\\"s\\":\\"SGVsbG8sIFdvcmxkIQ==\\"},\\"c\\":\\"Buffer\\"}"`; + +exports[`Plugin > toCrossJSONAsync > supports Plugin 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":40,\\"i\\":1,\\"s\\":{\\"t\\":1,\\"s\\":\\"SGVsbG8sIFdvcmxkIQ==\\"},\\"c\\":\\"Buffer\\"}}"`; + +exports[`Plugin > toCrossJSONStream > supports Plugin 1`] = `"{\\"t\\":40,\\"i\\":0,\\"s\\":{\\"t\\":1,\\"s\\":\\"SGVsbG8sIFdvcmxkIQ==\\"},\\"c\\":\\"Buffer\\"}"`; exports[`Plugin > toJSON > supports Plugin 1`] = `"{\\"t\\":{\\"t\\":40,\\"i\\":0,\\"s\\":{\\"t\\":1,\\"s\\":\\"SGVsbG8sIFdvcmxkIQ==\\"},\\"c\\":\\"Buffer\\"},\\"f\\":16383,\\"m\\":[]}"`; + +exports[`Plugin > toJSONAsync > supports Plugin 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":40,\\"i\\":1,\\"s\\":{\\"t\\":1,\\"s\\":\\"SGVsbG8sIFdvcmxkIQ==\\"},\\"c\\":\\"Buffer\\"}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/promise.test.ts.snap b/packages/seroval/test/__snapshots__/promise.test.ts.snap index d2226fa4..3bbf8e42 100644 --- a/packages/seroval/test/__snapshots__/promise.test.ts.snap +++ b/packages/seroval/test/__snapshots__/promise.test.ts.snap @@ -2,8 +2,8 @@ exports[`Promise > compat > should throw an error for unsupported target 1`] = `"Unsupported type \\"[object Promise]\\""`; -exports[`Promise > compat > should use function expression instead of arrow functions 1`] = `"(function(h){return h={self:Promise.resolve().then(function(){return h})}})()"`; +exports[`Promise > compat > should use function expression instead of arrow functions 1`] = `"(function(h){return (h={self:Promise.resolve().then(function(){return h})})})()"`; -exports[`Promise > compat > should use function expression instead of arrow functions 2`] = `"(function(h){return h={self:Promise.reject().catch(function(){throw h})}})()"`; +exports[`Promise > compat > should use function expression instead of arrow functions 2`] = `"(function(h){return (h={self:Promise.reject().catch(function(){throw h})})})()"`; exports[`Promise > compat#toJSON > should throw an error for unsupported target 1`] = `"Unsupported type \\"[object Promise]\\""`; diff --git a/packages/seroval/test/__snapshots__/reference.test.ts.snap b/packages/seroval/test/__snapshots__/reference.test.ts.snap index 651b2a46..3ea70d29 100644 --- a/packages/seroval/test/__snapshots__/reference.test.ts.snap +++ b/packages/seroval/test/__snapshots__/reference.test.ts.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Reference > crossSerialize > crossSerialize > supports Reference 1`] = `"($R=>($R[0]=__SEROVAL_REFS__.get(\\"example\\")))($R[\\"example\\"])"`; +exports[`Reference > crossSerialize > crossSerialize > supports Reference 1`] = `"($R=>$R[0]=__SEROVAL_REFS__.get(\\"example\\"))($R[\\"example\\"])"`; exports[`Reference > crossSerialize > supports Reference 1`] = `"$R[0]=__SEROVAL_REFS__.get(\\"example\\")"`; -exports[`Reference > crossSerializeAsync > scoped > supports Reference 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=__SEROVAL_REFS__.get(\\"example\\"))))($R[\\"example\\"])"`; +exports[`Reference > crossSerializeAsync > scoped > supports Reference 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=__SEROVAL_REFS__.get(\\"example\\")))($R[\\"example\\"])"`; exports[`Reference > crossSerializeAsync > supports Reference 1`] = `"$R[0]=Promise.resolve($R[1]=__SEROVAL_REFS__.get(\\"example\\"))"`; -exports[`Reference > crossSerializeStream > scoped > supports Reference 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`Reference > crossSerializeStream > scoped > supports Reference 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`Reference > crossSerializeStream > scoped > supports Reference 2`] = `"($R=>(_$.Ps($R[0],$R[1]=__SEROVAL_REFS__.get(\\"example\\"))))($R[\\"example\\"])"`; +exports[`Reference > crossSerializeStream > scoped > supports Reference 2`] = `"($R=>_$.Ps($R[0],$R[1]=__SEROVAL_REFS__.get(\\"example\\")))($R[\\"example\\"])"`; exports[`Reference > crossSerializeStream > supports Reference 1`] = `"$R[0]=_$.P()"`; @@ -20,6 +20,14 @@ exports[`Reference > serialize > supports Reference 1`] = `"__SEROVAL_REFS__.get exports[`Reference > serializeAsync > supports Reference 1`] = `"Promise.resolve(__SEROVAL_REFS__.get(\\"example\\"))"`; +exports[`Reference > toCrossJSON > supports Reference 1`] = `"{\\"t\\":20,\\"i\\":0,\\"s\\":\\"example\\"}"`; + +exports[`Reference > toCrossJSONAsync > supports Reference 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":20,\\"i\\":1,\\"s\\":\\"example\\"}}"`; + +exports[`Reference > toCrossJSONStream > supports Reference 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`Reference > toCrossJSONStream > supports Reference 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":20,\\"i\\":1,\\"s\\":\\"example\\"}}"`; + exports[`Reference > toJSON > supports Reference 1`] = `"{\\"t\\":{\\"t\\":20,\\"i\\":0,\\"s\\":\\"example\\"},\\"f\\":16383,\\"m\\":[]}"`; exports[`Reference > toJSONAsync > supports Reference 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":20,\\"i\\":1,\\"s\\":\\"example\\"}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/regexp.test.ts.snap b/packages/seroval/test/__snapshots__/regexp.test.ts.snap index 85ca4758..78ed5573 100644 --- a/packages/seroval/test/__snapshots__/regexp.test.ts.snap +++ b/packages/seroval/test/__snapshots__/regexp.test.ts.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`RegExp > crossSerialize > scoped > supports RegExp 1`] = `"($R=>($R[0]=/[a-z0-9]+/i))($R[\\"example\\"])"`; +exports[`RegExp > crossSerialize > scoped > supports RegExp 1`] = `"($R=>$R[0]=/[a-z0-9]+/i)($R[\\"example\\"])"`; exports[`RegExp > crossSerialize > supports RegExp 1`] = `"$R[0]=/[a-z0-9]+/i"`; -exports[`RegExp > crossSerializeAsync > scoped > supports RegExp 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=/[a-z0-9]+/i)))($R[\\"example\\"])"`; +exports[`RegExp > crossSerializeAsync > scoped > supports RegExp 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=/[a-z0-9]+/i))($R[\\"example\\"])"`; exports[`RegExp > crossSerializeAsync > supports RegExp 1`] = `"$R[0]=Promise.resolve($R[1]=/[a-z0-9]+/i)"`; -exports[`RegExp > crossSerializeStream > scoped > supports RegExp 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`RegExp > crossSerializeStream > scoped > supports RegExp 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`RegExp > crossSerializeStream > scoped > supports RegExp 2`] = `"($R=>(_$.Ps($R[0],$R[1]=/[a-z0-9]+/i)))($R[\\"example\\"])"`; +exports[`RegExp > crossSerializeStream > scoped > supports RegExp 2`] = `"($R=>_$.Ps($R[0],$R[1]=/[a-z0-9]+/i))($R[\\"example\\"])"`; exports[`RegExp > crossSerializeStream > supports RegExp 1`] = `"$R[0]=_$.P()"`; @@ -20,6 +20,14 @@ exports[`RegExp > serialize > supports RegExp 1`] = `"/[a-z0-9]+/i"`; exports[`RegExp > serializeAsync > supports RegExp 1`] = `"Promise.resolve(/[a-z0-9]+/i)"`; +exports[`RegExp > toCrossJSON > supports RegExp 1`] = `"{\\"t\\":6,\\"i\\":0,\\"c\\":\\"[a-z0-9]+\\",\\"m\\":\\"i\\"}"`; + +exports[`RegExp > toCrossJSONAsync > supports RegExp 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":6,\\"i\\":1,\\"c\\":\\"[a-z0-9]+\\",\\"m\\":\\"i\\"}}"`; + +exports[`RegExp > toCrossJSONStream > supports RegExp 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`RegExp > toCrossJSONStream > supports RegExp 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":6,\\"i\\":1,\\"c\\":\\"[a-z0-9]+\\",\\"m\\":\\"i\\"}}"`; + exports[`RegExp > toJSON > supports RegExp 1`] = `"{\\"t\\":{\\"t\\":6,\\"i\\":0,\\"c\\":\\"[a-z0-9]+\\",\\"m\\":\\"i\\"},\\"f\\":16383,\\"m\\":[]}"`; exports[`RegExp > toJSONAsync > supports RegExp 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":6,\\"i\\":1,\\"c\\":\\"[a-z0-9]+\\",\\"m\\":\\"i\\"}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/sealed-object.test.ts.snap b/packages/seroval/test/__snapshots__/sealed-object.test.ts.snap index f2aaceab..0dda1782 100644 --- a/packages/seroval/test/__snapshots__/sealed-object.test.ts.snap +++ b/packages/seroval/test/__snapshots__/sealed-object.test.ts.snap @@ -1,81 +1,149 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`sealed object > crossSerialize > scoped > supports Objects 1`] = `"($R=>($R[0]={hello:\\"world\\"},Object.seal($R[0]),$R[0]))($R[\\"example\\"])"`; +exports[`sealed object > crossSerialize > scoped > supports Objects 1`] = `"($R=>$R[0]={hello:\\"world\\"},Object.seal($R[0]),$R[0])($R[\\"example\\"])"`; -exports[`sealed object > crossSerialize > scoped > supports Symbol.iterator 1`] = `"($R=>($R[0]={[Symbol.iterator]:()=>$R[1]=[1,2,3].values()},Object.seal($R[0]),$R[0]))($R[\\"example\\"])"`; +exports[`sealed object > crossSerialize > scoped > supports Symbol.iterator 1`] = `"($R=>$R[0]={[$R[1]=Symbol.iterator]:($R[2]=s=>(i,c,d,t)=>(i=0,t={[$R[1]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})},Object.seal($R[0]),$R[0])($R[\\"example\\"])"`; -exports[`sealed object > crossSerialize > scoped > supports self-recursion 1`] = `"($R=>($R[0]={},$R[0].b=$R[0].a=$R[0],Object.seal($R[0]),$R[0]))($R[\\"example\\"])"`; +exports[`sealed object > crossSerialize > scoped > supports self-recursion 1`] = `"($R=>$R[0]={},$R[0].b=$R[0].a=$R[0],Object.seal($R[0]),$R[0])($R[\\"example\\"])"`; exports[`sealed object > crossSerialize > supports Objects 1`] = `"($R[0]={hello:\\"world\\"},Object.seal($R[0]),$R[0])"`; -exports[`sealed object > crossSerialize > supports Symbol.iterator 1`] = `"($R[0]={[Symbol.iterator]:()=>$R[1]=[1,2,3].values()},Object.seal($R[0]),$R[0])"`; +exports[`sealed object > crossSerialize > supports Symbol.iterator 1`] = `"($R[0]={[$R[1]=Symbol.iterator]:($R[2]=s=>(i,c,d,t)=>(i=0,t={[$R[1]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})},Object.seal($R[0]),$R[0])"`; exports[`sealed object > crossSerialize > supports self-recursion 1`] = `"($R[0]={},$R[0].b=$R[0].a=$R[0],Object.seal($R[0]),$R[0])"`; -exports[`sealed object > crossSerializeAsync > scoped > supports Objects 1`] = `"($R=>($R[0]=Promise.resolve($R[1]={hello:\\"world\\"}),Object.seal($R[1]),$R[0]))($R[\\"example\\"])"`; +exports[`sealed object > crossSerializeAsync > scoped > supports Objects 1`] = `"($R=>$R[0]=Promise.resolve($R[1]={hello:\\"world\\"}),Object.seal($R[1]),$R[0])($R[\\"example\\"])"`; -exports[`sealed object > crossSerializeAsync > scoped > supports Symbol.iterator 1`] = `"($R=>($R[0]=Promise.resolve($R[1]={[Symbol.iterator]:()=>$R[2]=[1,2,3].values()}),Object.seal($R[1]),$R[0]))($R[\\"example\\"])"`; +exports[`sealed object > crossSerializeAsync > scoped > supports Symbol.asyncIterator 1`] = `"($R=>$R[0]={[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})},Object.seal($R[0]),$R[0])($R[\\"example\\"])"`; -exports[`sealed object > crossSerializeAsync > scoped > supports self-recursion 1`] = `"($R=>($R[0]={a:$R[1]=Promise.resolve().then(()=>$R[0]),b:$R[2]=Promise.resolve().then(()=>$R[0])},Object.seal($R[0]),$R[0]))($R[\\"example\\"])"`; +exports[`sealed object > crossSerializeAsync > scoped > supports Symbol.iterator 1`] = `"($R=>$R[0]=Promise.resolve($R[1]={[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}),Object.seal($R[1]),$R[0])($R[\\"example\\"])"`; + +exports[`sealed object > crossSerializeAsync > scoped > supports self-recursion 1`] = `"($R=>$R[0]={a:$R[1]=Promise.resolve().then(()=>$R[0]),b:$R[2]=Promise.resolve().then(()=>$R[0])},Object.seal($R[0]),$R[0])($R[\\"example\\"])"`; exports[`sealed object > crossSerializeAsync > supports Objects 1`] = `"($R[0]=Promise.resolve($R[1]={hello:\\"world\\"}),Object.seal($R[1]),$R[0])"`; -exports[`sealed object > crossSerializeAsync > supports Symbol.iterator 1`] = `"($R[0]=Promise.resolve($R[1]={[Symbol.iterator]:()=>$R[2]=[1,2,3].values()}),Object.seal($R[1]),$R[0])"`; +exports[`sealed object > crossSerializeAsync > supports Symbol.asyncIterator 1`] = `"($R[0]={[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]={v:$R[4]=[1,2,3,void 0],t:-1,d:3})},Object.seal($R[0]),$R[0])"`; + +exports[`sealed object > crossSerializeAsync > supports Symbol.iterator 1`] = `"($R[0]=Promise.resolve($R[1]={[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}),Object.seal($R[1]),$R[0])"`; exports[`sealed object > crossSerializeAsync > supports self-recursion 1`] = `"($R[0]={a:$R[1]=Promise.resolve().then(()=>$R[0]),b:$R[2]=Promise.resolve().then(()=>$R[0])},Object.seal($R[0]),$R[0])"`; -exports[`sealed object > crossSerializeStream > scoped > supports Objects 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`sealed object > crossSerializeStream > scoped > supports Objects 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; + +exports[`sealed object > crossSerializeStream > scoped > supports Objects 2`] = `"($R=>_$.Ps($R[0],$R[1]={hello:\\"world\\"}),Object.seal($R[1]),$R[0])($R[\\"example\\"])"`; + +exports[`sealed object > crossSerializeStream > scoped > supports Symbol.asyncIterator 1`] = `"($R=>$R[0]={[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]=_$.S())},Object.seal($R[0]),$R[0])($R[\\"example\\"])"`; + +exports[`sealed object > crossSerializeStream > scoped > supports Symbol.asyncIterator 2`] = `"($R=>_$.Se($R[3],$R[4]=[0,1]))($R[\\"example\\"])"`; -exports[`sealed object > crossSerializeStream > scoped > supports Objects 2`] = `"($R=>(_$.Ps($R[0],$R[1]={hello:\\"world\\"}),Object.seal($R[1]),$R[0]))($R[\\"example\\"])"`; +exports[`sealed object > crossSerializeStream > scoped > supports Symbol.asyncIterator 3`] = `"($R=>_$.Se($R[3],$R[5]=[0,2]))($R[\\"example\\"])"`; -exports[`sealed object > crossSerializeStream > scoped > supports Symbol.iterator 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`sealed object > crossSerializeStream > scoped > supports Symbol.asyncIterator 4`] = `"($R=>_$.Se($R[3],$R[6]=[0,3]))($R[\\"example\\"])"`; -exports[`sealed object > crossSerializeStream > scoped > supports Symbol.iterator 2`] = `"($R=>(_$.Ps($R[0],$R[1]={[Symbol.iterator]:()=>$R[2]=[1,2,3].values()}),Object.seal($R[1]),$R[0]))($R[\\"example\\"])"`; +exports[`sealed object > crossSerializeStream > scoped > supports Symbol.asyncIterator 5`] = `"($R=>_$.Se($R[3],$R[7]=[2,void 0]))($R[\\"example\\"])"`; -exports[`sealed object > crossSerializeStream > scoped > supports self-recursion 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`sealed object > crossSerializeStream > scoped > supports Symbol.asyncIterator 6`] = `"($R=>_$.Sc($R[3]))($R[\\"example\\"])"`; -exports[`sealed object > crossSerializeStream > scoped > supports self-recursion 2`] = `"($R=>(_$.Ps($R[0],$R[1]={a:$R[2]=_$.P(),b:$R[3]=_$.P()}),Object.seal($R[1]),$R[0]))($R[\\"example\\"])"`; +exports[`sealed object > crossSerializeStream > scoped > supports Symbol.iterator 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`sealed object > crossSerializeStream > scoped > supports self-recursion 3`] = `"($R=>(_$.Ps($R[2],$R[1])))($R[\\"example\\"])"`; +exports[`sealed object > crossSerializeStream > scoped > supports Symbol.iterator 2`] = `"($R=>_$.Ps($R[0],$R[1]={[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}),Object.seal($R[1]),$R[0])($R[\\"example\\"])"`; -exports[`sealed object > crossSerializeStream > scoped > supports self-recursion 4`] = `"($R=>(_$.Ps($R[3],$R[1])))($R[\\"example\\"])"`; +exports[`sealed object > crossSerializeStream > scoped > supports self-recursion 1`] = `"($R=>$R[0]={a:$R[1]=_$.P(),b:$R[2]=_$.P()},Object.seal($R[0]),$R[0])($R[\\"example\\"])"`; + +exports[`sealed object > crossSerializeStream > scoped > supports self-recursion 2`] = `"($R=>_$.Ps($R[1],$R[0]))($R[\\"example\\"])"`; + +exports[`sealed object > crossSerializeStream > scoped > supports self-recursion 3`] = `"($R=>_$.Ps($R[2],$R[0]))($R[\\"example\\"])"`; exports[`sealed object > crossSerializeStream > supports Objects 1`] = `"$R[0]=_$.P()"`; exports[`sealed object > crossSerializeStream > supports Objects 2`] = `"(_$.Ps($R[0],$R[1]={hello:\\"world\\"}),Object.seal($R[1]),$R[0])"`; -exports[`sealed object > crossSerializeStream > supports Symbol.iterator 1`] = `"$R[0]=_$.P()"`; +exports[`sealed object > crossSerializeStream > supports Symbol.asyncIterator 1`] = `"($R[0]={[$R[1]=Symbol.asyncIterator]:($R[2]=s=>(b,t)=>(b=s.tee(),s=b[0],b=b[1].getReader(),t={[$R[1]]:()=>t,next:()=>b.read().then(d=>{if(d.done)return{done:!0,value:void 0};d=d.value;if(d[0]===1)throw d[1];return{done:d[0]===2,value:d[1]}})}))($R[3]=_$.S())},Object.seal($R[0]),$R[0])"`; + +exports[`sealed object > crossSerializeStream > supports Symbol.asyncIterator 2`] = `"_$.Se($R[3],$R[4]=[0,1])"`; -exports[`sealed object > crossSerializeStream > supports Symbol.iterator 2`] = `"(_$.Ps($R[0],$R[1]={[Symbol.iterator]:()=>$R[2]=[1,2,3].values()}),Object.seal($R[1]),$R[0])"`; +exports[`sealed object > crossSerializeStream > supports Symbol.asyncIterator 3`] = `"_$.Se($R[3],$R[5]=[0,2])"`; -exports[`sealed object > crossSerializeStream > supports self-recursion 1`] = `"$R[0]=_$.P()"`; +exports[`sealed object > crossSerializeStream > supports Symbol.asyncIterator 4`] = `"_$.Se($R[3],$R[6]=[0,3])"`; -exports[`sealed object > crossSerializeStream > supports self-recursion 2`] = `"(_$.Ps($R[0],$R[1]={a:$R[2]=_$.P(),b:$R[3]=_$.P()}),Object.seal($R[1]),$R[0])"`; +exports[`sealed object > crossSerializeStream > supports Symbol.asyncIterator 5`] = `"_$.Se($R[3],$R[7]=[2,void 0])"`; -exports[`sealed object > crossSerializeStream > supports self-recursion 3`] = `"_$.Ps($R[2],$R[1])"`; +exports[`sealed object > crossSerializeStream > supports Symbol.asyncIterator 6`] = `"_$.Sc($R[3])"`; -exports[`sealed object > crossSerializeStream > supports self-recursion 4`] = `"_$.Ps($R[3],$R[1])"`; +exports[`sealed object > crossSerializeStream > supports Symbol.iterator 1`] = `"$R[0]=_$.P()"`; + +exports[`sealed object > crossSerializeStream > supports Symbol.iterator 2`] = `"(_$.Ps($R[0],$R[1]={[$R[2]=Symbol.iterator]:($R[3]=s=>(i,c,d,t)=>(i=0,t={[$R[2]]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))($R[4]={v:$R[5]=[1,2,3,void 0],t:-1,d:3})}),Object.seal($R[1]),$R[0])"`; + +exports[`sealed object > crossSerializeStream > supports self-recursion 1`] = `"($R[0]={a:$R[1]=_$.P(),b:$R[2]=_$.P()},Object.seal($R[0]),$R[0])"`; + +exports[`sealed object > crossSerializeStream > supports self-recursion 2`] = `"_$.Ps($R[1],$R[0])"`; + +exports[`sealed object > crossSerializeStream > supports self-recursion 3`] = `"_$.Ps($R[2],$R[0])"`; exports[`sealed object > serialize > supports Objects 1`] = `"(h=>(h={hello:\\"world\\"},Object.seal(h),h))()"`; -exports[`sealed object > serialize > supports Symbol.iterator 1`] = `"(h=>(h={[Symbol.iterator]:()=>[1,2,3].values()},Object.seal(h),h))()"`; +exports[`sealed object > serialize > supports Symbol.iterator 1`] = `"((h,j)=>(h={[j=Symbol.iterator]:(s=>(i,c,d,t)=>(i=0,t={[j]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))({v:[1,2,3,void 0],t:-1,d:3})},Object.seal(h),h))()"`; exports[`sealed object > serialize > supports self-recursion 1`] = `"(h=>(h={},h.b=h.a=h,Object.seal(h),h))()"`; exports[`sealed object > serializeAsync > supports Objects 1`] = `"((h,j)=>(j=Promise.resolve(h={hello:\\"world\\"}),Object.seal(h),j))()"`; -exports[`sealed object > serializeAsync > supports Symbol.iterator 1`] = `"((h,j)=>(j=Promise.resolve(h={[Symbol.iterator]:()=>[1,2,3].values()}),Object.seal(h),j))()"`; +exports[`sealed object > serializeAsync > supports Symbol.asyncIterator 1`] = `"((h,j)=>(h={[j=Symbol.asyncIterator]:(s=>(i,t)=>(i=0,t={[j]:()=>t,next:()=>Promise.resolve().then((c,d)=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}})}))({v:[1,2,3,void 0],t:-1,d:3})},Object.seal(h),h))()"`; + +exports[`sealed object > serializeAsync > supports Symbol.iterator 1`] = `"((h,j,k)=>(k=Promise.resolve(h={[j=Symbol.iterator]:(s=>(i,c,d,t)=>(i=0,t={[j]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))({v:[1,2,3,void 0],t:-1,d:3})}),Object.seal(h),k))()"`; exports[`sealed object > serializeAsync > supports self-recursion 1`] = `"(h=>(h={a:Promise.resolve().then(()=>h),b:Promise.resolve().then(()=>h)},Object.seal(h),h))()"`; +exports[`sealed object > toCrossJSON > supports Objects 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":2}"`; + +exports[`sealed object > toCrossJSON > supports Symbol.iterator 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":2}"`; + +exports[`sealed object > toCrossJSON > supports self-recursion 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":4,\\"i\\":0},{\\"t\\":4,\\"i\\":0}],\\"s\\":2},\\"o\\":2}"`; + +exports[`sealed object > toCrossJSONAsync > supports Objects 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":2}}"`; + +exports[`sealed object > toCrossJSONAsync > supports Symbol.asyncIterator 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":2}"`; + +exports[`sealed object > toCrossJSONAsync > supports Symbol.iterator 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":2}}"`; + +exports[`sealed object > toCrossJSONAsync > supports self-recursion 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}},{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"s\\":2},\\"o\\":2}"`; + +exports[`sealed object > toCrossJSONStream > supports Objects 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`sealed object > toCrossJSONStream > supports Objects 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":2}}"`; + +exports[`sealed object > toCrossJSONStream > supports Symbol.asyncIterator 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":31,\\"i\\":3}]}],\\"s\\":1},\\"o\\":2}"`; + +exports[`sealed object > toCrossJSONStream > supports Symbol.asyncIterator 2`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":4,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":1}],\\"o\\":0}}"`; + +exports[`sealed object > toCrossJSONStream > supports Symbol.asyncIterator 3`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":5,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":2}],\\"o\\":0}}"`; + +exports[`sealed object > toCrossJSONStream > supports Symbol.asyncIterator 4`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":6,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}}"`; + +exports[`sealed object > toCrossJSONStream > supports Symbol.asyncIterator 5`] = `"{\\"t\\":32,\\"i\\":3,\\"f\\":{\\"t\\":9,\\"i\\":7,\\"l\\":2,\\"a\\":[{\\"t\\":0,\\"s\\":2},{\\"t\\":2,\\"s\\":1}],\\"o\\":0}}"`; + +exports[`sealed object > toCrossJSONStream > supports Symbol.asyncIterator 6`] = `"{\\"t\\":33,\\"i\\":3}"`; + +exports[`sealed object > toCrossJSONStream > supports Symbol.iterator 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`sealed object > toCrossJSONStream > supports Symbol.iterator 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":2}}"`; + +exports[`sealed object > toCrossJSONStream > supports self-recursion 1`] = `"{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":28,\\"i\\":1},{\\"t\\":28,\\"i\\":2}],\\"s\\":2},\\"o\\":2}"`; + +exports[`sealed object > toCrossJSONStream > supports self-recursion 2`] = `"{\\"t\\":29,\\"i\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}"`; + +exports[`sealed object > toCrossJSONStream > supports self-recursion 3`] = `"{\\"t\\":29,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":0}}"`; + exports[`sealed object > toJSON > supports Objects 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":2},\\"f\\":16383,\\"m\\":[]}"`; -exports[`sealed object > toJSON > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[0],\\"v\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}],\\"s\\":1},\\"o\\":2},\\"f\\":16383,\\"m\\":[]}"`; +exports[`sealed object > toJSON > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":2},\\"f\\":16383,\\"m\\":[1]}"`; exports[`sealed object > toJSON > supports self-recursion 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":4,\\"i\\":0},{\\"t\\":4,\\"i\\":0}],\\"s\\":2},\\"o\\":2},\\"f\\":16383,\\"m\\":[0]}"`; exports[`sealed object > toJSONAsync > supports Objects 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"hello\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"}],\\"s\\":1},\\"o\\":2}},\\"f\\":16383,\\"m\\":[]}"`; -exports[`sealed object > toJSONAsync > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[0],\\"v\\":[{\\"t\\":9,\\"i\\":2,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}],\\"s\\":1},\\"o\\":2}},\\"f\\":16383,\\"m\\":[]}"`; +exports[`sealed object > toJSONAsync > supports Symbol.asyncIterator 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":0}],\\"v\\":[{\\"t\\":45,\\"a\\":[{\\"t\\":44,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":2},\\"f\\":16383,\\"m\\":[1]}"`; + +exports[`sealed object > toJSONAsync > supports Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":2,\\"s\\":3}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":3,\\"f\\":{\\"t\\":4,\\"i\\":2}},{\\"t\\":10,\\"i\\":4,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":5,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}],\\"s\\":1},\\"o\\":2}},\\"f\\":16383,\\"m\\":[2]}"`; exports[`sealed object > toJSONAsync > supports self-recursion 1`] = `"{\\"t\\":{\\"t\\":10,\\"i\\":0,\\"p\\":{\\"k\\":[\\"a\\",\\"b\\"],\\"v\\":[{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}},{\\"t\\":12,\\"i\\":2,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}],\\"s\\":2},\\"o\\":2},\\"f\\":16383,\\"m\\":[0]}"`; diff --git a/packages/seroval/test/__snapshots__/set.test.ts.snap b/packages/seroval/test/__snapshots__/set.test.ts.snap index 029e1dfe..c2b7a976 100644 --- a/packages/seroval/test/__snapshots__/set.test.ts.snap +++ b/packages/seroval/test/__snapshots__/set.test.ts.snap @@ -1,36 +1,36 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Set > compat > should fallback to Symbol.iterator 1`] = `"Object.assign(Object.create(null),{[Symbol.iterator]:()=>[1,2,3].values()})"`; +exports[`Set > compat > should fallback to Symbol.iterator 1`] = `"(h=>(Object.assign(Object.create(null),{[h=Symbol.iterator]:(s=>(i,c,d,t)=>(i=0,t={[h]:()=>t,next:()=>{if(i>s.d)return{done:!0,value:void 0};c=i++,d=s.v[c];if(c===s.t)throw d;return{done:c===s.d,value:d}}}))({v:[1,2,3,void 0],t:-1,d:3}),[Symbol.toStringTag]:\\"Set\\"})))()"`; exports[`Set > compat > should throw an error for unsupported target 1`] = `"Unsupported type \\"[object Set]\\""`; -exports[`Set > compat#toJSON > should fallback to Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[0],\\"v\\":[{\\"t\\":9,\\"i\\":1,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}],\\"o\\":0}],\\"s\\":1},\\"o\\":0},\\"f\\":15871,\\"m\\":[]}"`; +exports[`Set > compat#toJSON > should fallback to Symbol.iterator 1`] = `"{\\"t\\":{\\"t\\":11,\\"i\\":0,\\"p\\":{\\"k\\":[{\\"t\\":17,\\"i\\":1,\\"s\\":3},{\\"t\\":17,\\"i\\":5,\\"s\\":11}],\\"v\\":[{\\"t\\":43,\\"a\\":[{\\"t\\":42,\\"i\\":2,\\"f\\":{\\"t\\":4,\\"i\\":1}},{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":4,\\"l\\":4,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]},{\\"t\\":1,\\"s\\":\\"Set\\"}],\\"s\\":2},\\"o\\":0},\\"f\\":15871,\\"m\\":[1]}"`; exports[`Set > compat#toJSON > should throw an error for unsupported target 1`] = `"Unsupported type \\"[object Set]\\""`; -exports[`Set > crossSerialize > scoped > supports Set 1`] = `"($R=>($R[0]=new Set([1,2,3])))($R[\\"example\\"])"`; +exports[`Set > crossSerialize > scoped > supports Set 1`] = `"($R=>$R[0]=new Set([1,2,3]))($R[\\"example\\"])"`; -exports[`Set > crossSerialize > scoped > supports self-recursion 1`] = `"($R=>($R[0]=new Set,$R[0].add($R[0]),$R[0]))($R[\\"example\\"])"`; +exports[`Set > crossSerialize > scoped > supports self-recursion 1`] = `"($R=>$R[0]=new Set,$R[0].add($R[0]),$R[0])($R[\\"example\\"])"`; exports[`Set > crossSerialize > supports Set 1`] = `"$R[0]=new Set([1,2,3])"`; exports[`Set > crossSerialize > supports self-recursion 1`] = `"($R[0]=new Set,$R[0].add($R[0]),$R[0])"`; -exports[`Set > crossSerializeAsync > scoped > supports Set 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=new Set([1,2,3]))))($R[\\"example\\"])"`; +exports[`Set > crossSerializeAsync > scoped > supports Set 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=new Set([1,2,3])))($R[\\"example\\"])"`; -exports[`Set > crossSerializeAsync > scoped > supports self-recursion 1`] = `"($R=>($R[0]=new Set([$R[1]=Promise.resolve().then(()=>$R[0])])))($R[\\"example\\"])"`; +exports[`Set > crossSerializeAsync > scoped > supports self-recursion 1`] = `"($R=>$R[0]=new Set([$R[1]=Promise.resolve().then(()=>$R[0])]))($R[\\"example\\"])"`; exports[`Set > crossSerializeAsync > supports Set 1`] = `"$R[0]=Promise.resolve($R[1]=new Set([1,2,3]))"`; exports[`Set > crossSerializeAsync > supports self-recursion 1`] = `"$R[0]=new Set([$R[1]=Promise.resolve().then(()=>$R[0])])"`; -exports[`Set > crossSerializeStream > scoped > supports Set 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`Set > crossSerializeStream > scoped > supports Set 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`Set > crossSerializeStream > scoped > supports Set 2`] = `"($R=>(_$.Ps($R[0],$R[1]=new Set([1,2,3]))))($R[\\"example\\"])"`; +exports[`Set > crossSerializeStream > scoped > supports Set 2`] = `"($R=>_$.Ps($R[0],$R[1]=new Set([1,2,3])))($R[\\"example\\"])"`; -exports[`Set > crossSerializeStream > scoped > supports self-recursion 1`] = `"($R=>($R[0]=new Set([$R[1]=_$.P()])))($R[\\"example\\"])"`; +exports[`Set > crossSerializeStream > scoped > supports self-recursion 1`] = `"($R=>$R[0]=new Set([$R[1]=_$.P()]))($R[\\"example\\"])"`; -exports[`Set > crossSerializeStream > scoped > supports self-recursion 2`] = `"($R=>(_$.Ps($R[1],$R[0])))($R[\\"example\\"])"`; +exports[`Set > crossSerializeStream > scoped > supports self-recursion 2`] = `"($R=>_$.Ps($R[1],$R[0]))($R[\\"example\\"])"`; exports[`Set > crossSerializeStream > supports Set 1`] = `"$R[0]=_$.P()"`; @@ -48,6 +48,14 @@ exports[`Set > serializeAsync > supports Set 1`] = `"Promise.resolve(new Set([1, exports[`Set > serializeAsync > supports self-recursion 1`] = `"(h=>(h=new Set([Promise.resolve().then(()=>h)])))()"`; +exports[`Set > toCrossJSON > supports Set 1`] = `"{\\"t\\":7,\\"i\\":0,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}]}"`; + +exports[`Set > toCrossJSON > supports self-recursion 1`] = `"{\\"t\\":7,\\"i\\":0,\\"l\\":1,\\"a\\":[{\\"t\\":4,\\"i\\":0}]}"`; + +exports[`Set > toCrossJSONAsync > supports Set 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":7,\\"i\\":1,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}]}}"`; + +exports[`Set > toCrossJSONAsync > supports self-recursion 1`] = `"{\\"t\\":7,\\"i\\":0,\\"l\\":1,\\"a\\":[{\\"t\\":12,\\"i\\":1,\\"s\\":1,\\"f\\":{\\"t\\":4,\\"i\\":0}}]}"`; + exports[`Set > toJSON > supports Set 1`] = `"{\\"t\\":{\\"t\\":7,\\"i\\":0,\\"l\\":3,\\"a\\":[{\\"t\\":0,\\"s\\":1},{\\"t\\":0,\\"s\\":2},{\\"t\\":0,\\"s\\":3}]},\\"f\\":16383,\\"m\\":[]}"`; exports[`Set > toJSON > supports self-recursion 1`] = `"{\\"t\\":{\\"t\\":7,\\"i\\":0,\\"l\\":1,\\"a\\":[{\\"t\\":4,\\"i\\":0}]},\\"f\\":16383,\\"m\\":[0]}"`; diff --git a/packages/seroval/test/__snapshots__/sparse-array.test.ts.snap b/packages/seroval/test/__snapshots__/sparse-array.test.ts.snap index 0ef23626..f8981059 100644 --- a/packages/seroval/test/__snapshots__/sparse-array.test.ts.snap +++ b/packages/seroval/test/__snapshots__/sparse-array.test.ts.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`sparse arrays > crossSerialize > scoped > supports sparse arrays 1`] = `"($R=>($R[0]=[,,,,,,,,,,]))($R[\\"example\\"])"`; +exports[`sparse arrays > crossSerialize > scoped > supports sparse arrays 1`] = `"($R=>$R[0]=[,,,,,,,,,,])($R[\\"example\\"])"`; exports[`sparse arrays > crossSerialize > supports sparse arrays 1`] = `"$R[0]=[,,,,,,,,,,]"`; -exports[`sparse arrays > crossSerializeAsync > scoped > supports sparse arrays 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=[,,,,,,,,,,])))($R[\\"example\\"])"`; +exports[`sparse arrays > crossSerializeAsync > scoped > supports sparse arrays 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=[,,,,,,,,,,]))($R[\\"example\\"])"`; exports[`sparse arrays > crossSerializeAsync > supports sparse arrays 1`] = `"$R[0]=Promise.resolve($R[1]=[,,,,,,,,,,])"`; -exports[`sparse arrays > crossSerializeStream > scoped > supports sparse arrays 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`sparse arrays > crossSerializeStream > scoped > supports sparse arrays 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`sparse arrays > crossSerializeStream > scoped > supports sparse arrays 2`] = `"($R=>(_$.Ps($R[0],$R[1]=[,,,,,,,,,,])))($R[\\"example\\"])"`; +exports[`sparse arrays > crossSerializeStream > scoped > supports sparse arrays 2`] = `"($R=>_$.Ps($R[0],$R[1]=[,,,,,,,,,,]))($R[\\"example\\"])"`; exports[`sparse arrays > crossSerializeStream > supports sparse arrays 1`] = `"$R[0]=_$.P()"`; @@ -20,6 +20,14 @@ exports[`sparse arrays > serialize > supports sparse arrays 1`] = `"[,,,,,,,,,,] exports[`sparse arrays > serializeAsync > supports sparse arrays 1`] = `"Promise.resolve([,,,,,,,,,,])"`; +exports[`sparse arrays > toCrossJSON > supports sparse arrays 1`] = `"{\\"t\\":9,\\"i\\":0,\\"l\\":10,\\"a\\":[],\\"o\\":0}"`; + +exports[`sparse arrays > toCrossJSONAsync > supports sparse arrays 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":9,\\"i\\":1,\\"l\\":10,\\"a\\":[],\\"o\\":0}}"`; + +exports[`sparse arrays > toCrossJSONStream > supports sparse arrays 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`sparse arrays > toCrossJSONStream > supports sparse arrays 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":9,\\"i\\":1,\\"l\\":10,\\"a\\":[],\\"o\\":0}}"`; + exports[`sparse arrays > toJSON > supports sparse arrays 1`] = `"{\\"t\\":{\\"t\\":9,\\"i\\":0,\\"l\\":10,\\"a\\":[],\\"o\\":0},\\"f\\":16383,\\"m\\":[]}"`; exports[`sparse arrays > toJSONAsync > supports sparse arrays 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":9,\\"i\\":1,\\"l\\":10,\\"a\\":[],\\"o\\":0}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/string.test.ts.snap b/packages/seroval/test/__snapshots__/string.test.ts.snap index b9d81b0a..cacea9d1 100644 --- a/packages/seroval/test/__snapshots__/string.test.ts.snap +++ b/packages/seroval/test/__snapshots__/string.test.ts.snap @@ -24,6 +24,22 @@ exports[`string > serializeAsync > supports strings 1`] = `"Promise.resolve(\\"\ exports[`string > serializeAsync > supports strings 2`] = `"Promise.resolve(\\"\\\\x3Cscript>\\\\x3C/script>\\")"`; +exports[`string > toCrossJSON > supports strings 1`] = `"{\\"t\\":1,\\"s\\":\\"\\\\\\\\\\\\\\"hello\\\\\\\\\\\\\\"\\"}"`; + +exports[`string > toCrossJSON > supports strings 2`] = `"{\\"t\\":1,\\"s\\":\\"\\\\\\\\x3Cscript>\\\\\\\\x3C/script>\\"}"`; + +exports[`string > toCrossJSONAsync > supports strings 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\\\\\\\"hello\\\\\\\\\\\\\\"\\"}}"`; + +exports[`string > toCrossJSONAsync > supports strings 2`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\x3Cscript>\\\\\\\\x3C/script>\\"}}"`; + +exports[`string > toCrossJSONStream > supports sanitized strings 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`string > toCrossJSONStream > supports sanitized strings 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\x3Cscript>\\\\\\\\x3C/script>\\"}}"`; + +exports[`string > toCrossJSONStream > supports strings 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`string > toCrossJSONStream > supports strings 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\\\\\\\"hello\\\\\\\\\\\\\\"\\"}}"`; + exports[`string > toJSON > supports strings 1`] = `"{\\"t\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\\\\\\\"hello\\\\\\\\\\\\\\"\\"},\\"f\\":16383,\\"m\\":[]}"`; exports[`string > toJSON > supports strings 2`] = `"{\\"t\\":{\\"t\\":1,\\"s\\":\\"\\\\\\\\x3Cscript>\\\\\\\\x3C/script>\\"},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/typed-array.test.ts.snap b/packages/seroval/test/__snapshots__/typed-array.test.ts.snap index 316a1200..a2121cf9 100644 --- a/packages/seroval/test/__snapshots__/typed-array.test.ts.snap +++ b/packages/seroval/test/__snapshots__/typed-array.test.ts.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`typed arrays > crossSerialize > scoped > supports typed arrays 1`] = `"($R=>($R[0]=new Uint32Array($R[1]=new Uint8Array([255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]).buffer,0,4)))($R[\\"example\\"])"`; +exports[`typed arrays > crossSerialize > scoped > supports typed arrays 1`] = `"($R=>$R[0]=new Uint32Array($R[1]=new Uint8Array([255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]).buffer,0,4))($R[\\"example\\"])"`; exports[`typed arrays > crossSerialize > supports typed arrays 1`] = `"$R[0]=new Uint32Array($R[1]=new Uint8Array([255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]).buffer,0,4)"`; -exports[`typed arrays > crossSerializeAsync > scoped > supports typed arrays 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=new Uint32Array($R[2]=new Uint8Array([255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]).buffer,0,4))))($R[\\"example\\"])"`; +exports[`typed arrays > crossSerializeAsync > scoped > supports typed arrays 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=new Uint32Array($R[2]=new Uint8Array([255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]).buffer,0,4)))($R[\\"example\\"])"`; exports[`typed arrays > crossSerializeAsync > supports typed arrays 1`] = `"$R[0]=Promise.resolve($R[1]=new Uint32Array($R[2]=new Uint8Array([255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]).buffer,0,4))"`; -exports[`typed arrays > crossSerializeStream > scoped > supports typed arrays 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`typed arrays > crossSerializeStream > scoped > supports typed arrays 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`typed arrays > crossSerializeStream > scoped > supports typed arrays 2`] = `"($R=>(_$.Ps($R[0],$R[1]=new Uint32Array($R[2]=new Uint8Array([255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]).buffer,0,4))))($R[\\"example\\"])"`; +exports[`typed arrays > crossSerializeStream > scoped > supports typed arrays 2`] = `"($R=>_$.Ps($R[0],$R[1]=new Uint32Array($R[2]=new Uint8Array([255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]).buffer,0,4)))($R[\\"example\\"])"`; exports[`typed arrays > crossSerializeStream > supports typed arrays 1`] = `"$R[0]=_$.P()"`; @@ -20,6 +20,14 @@ exports[`typed arrays > serialize > supports typed arrays 1`] = `"new Uint32Arra exports[`typed arrays > serializeAsync > supports typed arrays 1`] = `"Promise.resolve(new Uint32Array(new Uint8Array([255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]).buffer,0,4))"`; +exports[`typed arrays > toCrossJSON > supports typed arrays 1`] = `"{\\"t\\":15,\\"i\\":0,\\"l\\":4,\\"c\\":\\"Uint32Array\\",\\"f\\":{\\"t\\":21,\\"i\\":1,\\"s\\":[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]},\\"b\\":0}"`; + +exports[`typed arrays > toCrossJSONAsync > supports typed arrays 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":15,\\"i\\":1,\\"l\\":4,\\"c\\":\\"Uint32Array\\",\\"f\\":{\\"t\\":21,\\"i\\":2,\\"s\\":[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]},\\"b\\":0}}"`; + +exports[`typed arrays > toCrossJSONStream > supports typed arrays 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`typed arrays > toCrossJSONStream > supports typed arrays 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":15,\\"i\\":1,\\"l\\":4,\\"c\\":\\"Uint32Array\\",\\"f\\":{\\"t\\":21,\\"i\\":2,\\"s\\":[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]},\\"b\\":0}}"`; + exports[`typed arrays > toJSON > supports typed arrays 1`] = `"{\\"t\\":{\\"t\\":15,\\"i\\":0,\\"l\\":4,\\"c\\":\\"Uint32Array\\",\\"f\\":{\\"t\\":21,\\"i\\":1,\\"s\\":[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]},\\"b\\":0},\\"f\\":16383,\\"m\\":[]}"`; exports[`typed arrays > toJSONAsync > supports typed arrays 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":15,\\"i\\":1,\\"l\\":4,\\"c\\":\\"Uint32Array\\",\\"f\\":{\\"t\\":21,\\"i\\":2,\\"s\\":[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]},\\"b\\":0}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/__snapshots__/wk-symbols.test.ts.snap b/packages/seroval/test/__snapshots__/wk-symbols.test.ts.snap index 6ab822b9..62ac7ec8 100644 --- a/packages/seroval/test/__snapshots__/wk-symbols.test.ts.snap +++ b/packages/seroval/test/__snapshots__/wk-symbols.test.ts.snap @@ -1,30 +1,30 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 1`] = `"($R=>($R[0]=Symbol.asyncIterator))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 1`] = `"($R=>$R[0]=Symbol.asyncIterator)($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 2`] = `"($R=>($R[0]=Symbol.hasInstance))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 2`] = `"($R=>$R[0]=Symbol.hasInstance)($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 3`] = `"($R=>($R[0]=Symbol.isConcatSpreadable))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 3`] = `"($R=>$R[0]=Symbol.isConcatSpreadable)($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 4`] = `"($R=>($R[0]=Symbol.iterator))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 4`] = `"($R=>$R[0]=Symbol.iterator)($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 5`] = `"($R=>($R[0]=Symbol.match))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 5`] = `"($R=>$R[0]=Symbol.match)($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 6`] = `"($R=>($R[0]=Symbol.matchAll))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 6`] = `"($R=>$R[0]=Symbol.matchAll)($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 7`] = `"($R=>($R[0]=Symbol.replace))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 7`] = `"($R=>$R[0]=Symbol.replace)($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 8`] = `"($R=>($R[0]=Symbol.search))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 8`] = `"($R=>$R[0]=Symbol.search)($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 9`] = `"($R=>($R[0]=Symbol.species))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 9`] = `"($R=>$R[0]=Symbol.species)($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 10`] = `"($R=>($R[0]=Symbol.split))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 10`] = `"($R=>$R[0]=Symbol.split)($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 11`] = `"($R=>($R[0]=Symbol.toPrimitive))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 11`] = `"($R=>$R[0]=Symbol.toPrimitive)($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 12`] = `"($R=>($R[0]=Symbol.toStringTag))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 12`] = `"($R=>$R[0]=Symbol.toStringTag)($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 13`] = `"($R=>($R[0]=Symbol.unscopables))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerialize > scoped > supports well-known symbols 13`] = `"($R=>$R[0]=Symbol.unscopables)($R[\\"example\\"])"`; exports[`well-known symbols > crossSerialize > supports well-known symbols 1`] = `"$R[0]=Symbol.asyncIterator"`; @@ -52,31 +52,31 @@ exports[`well-known symbols > crossSerialize > supports well-known symbols 12`] exports[`well-known symbols > crossSerialize > supports well-known symbols 13`] = `"$R[0]=Symbol.unscopables"`; -exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=Symbol.asyncIterator)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=Symbol.asyncIterator))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 2`] = `"($R=>($R[0]=Promise.resolve($R[1]=Symbol.hasInstance)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 2`] = `"($R=>$R[0]=Promise.resolve($R[1]=Symbol.hasInstance))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 3`] = `"($R=>($R[0]=Promise.resolve($R[1]=Symbol.isConcatSpreadable)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 3`] = `"($R=>$R[0]=Promise.resolve($R[1]=Symbol.isConcatSpreadable))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 4`] = `"($R=>($R[0]=Promise.resolve($R[1]=Symbol.iterator)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 4`] = `"($R=>$R[0]=Promise.resolve($R[1]=Symbol.iterator))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 5`] = `"($R=>($R[0]=Promise.resolve($R[1]=Symbol.match)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 5`] = `"($R=>$R[0]=Promise.resolve($R[1]=Symbol.match))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 6`] = `"($R=>($R[0]=Promise.resolve($R[1]=Symbol.matchAll)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 6`] = `"($R=>$R[0]=Promise.resolve($R[1]=Symbol.matchAll))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 7`] = `"($R=>($R[0]=Promise.resolve($R[1]=Symbol.replace)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 7`] = `"($R=>$R[0]=Promise.resolve($R[1]=Symbol.replace))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 8`] = `"($R=>($R[0]=Promise.resolve($R[1]=Symbol.search)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 8`] = `"($R=>$R[0]=Promise.resolve($R[1]=Symbol.search))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 9`] = `"($R=>($R[0]=Promise.resolve($R[1]=Symbol.species)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 9`] = `"($R=>$R[0]=Promise.resolve($R[1]=Symbol.species))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 10`] = `"($R=>($R[0]=Promise.resolve($R[1]=Symbol.split)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 10`] = `"($R=>$R[0]=Promise.resolve($R[1]=Symbol.split))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 11`] = `"($R=>($R[0]=Promise.resolve($R[1]=Symbol.toPrimitive)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 11`] = `"($R=>$R[0]=Promise.resolve($R[1]=Symbol.toPrimitive))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 12`] = `"($R=>($R[0]=Promise.resolve($R[1]=Symbol.toStringTag)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 12`] = `"($R=>$R[0]=Promise.resolve($R[1]=Symbol.toStringTag))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 13`] = `"($R=>($R[0]=Promise.resolve($R[1]=Symbol.unscopables)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeAsync > scoped > supports well-known symbols 13`] = `"($R=>$R[0]=Promise.resolve($R[1]=Symbol.unscopables))($R[\\"example\\"])"`; exports[`well-known symbols > crossSerializeAsync > supports well-known symbols 1`] = `"$R[0]=Promise.resolve($R[1]=Symbol.asyncIterator)"`; @@ -104,57 +104,57 @@ exports[`well-known symbols > crossSerializeAsync > supports well-known symbols exports[`well-known symbols > crossSerializeAsync > supports well-known symbols 13`] = `"$R[0]=Promise.resolve($R[1]=Symbol.unscopables)"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.asyncIterator 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.asyncIterator 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.asyncIterator 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Symbol.asyncIterator)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.asyncIterator 2`] = `"($R=>_$.Ps($R[0],$R[1]=Symbol.asyncIterator))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.hasInstance 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.hasInstance 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.hasInstance 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Symbol.hasInstance)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.hasInstance 2`] = `"($R=>_$.Ps($R[0],$R[1]=Symbol.hasInstance))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.isConcatSpreadable 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.isConcatSpreadable 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.isConcatSpreadable 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Symbol.isConcatSpreadable)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.isConcatSpreadable 2`] = `"($R=>_$.Ps($R[0],$R[1]=Symbol.isConcatSpreadable))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.iterator 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.iterator 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.iterator 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Symbol.iterator)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.iterator 2`] = `"($R=>_$.Ps($R[0],$R[1]=Symbol.iterator))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.match 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.match 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.match 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Symbol.match)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.match 2`] = `"($R=>_$.Ps($R[0],$R[1]=Symbol.match))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.matchAll 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.matchAll 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.matchAll 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Symbol.matchAll)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.matchAll 2`] = `"($R=>_$.Ps($R[0],$R[1]=Symbol.matchAll))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.replace 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.replace 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.replace 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Symbol.replace)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.replace 2`] = `"($R=>_$.Ps($R[0],$R[1]=Symbol.replace))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.search 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.search 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.search 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Symbol.search)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.search 2`] = `"($R=>_$.Ps($R[0],$R[1]=Symbol.search))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.species 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.species 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.species 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Symbol.species)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.species 2`] = `"($R=>_$.Ps($R[0],$R[1]=Symbol.species))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.split 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.split 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.split 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Symbol.split)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.split 2`] = `"($R=>_$.Ps($R[0],$R[1]=Symbol.split))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.toPrimitive 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.toPrimitive 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.toPrimitive 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Symbol.toPrimitive)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.toPrimitive 2`] = `"($R=>_$.Ps($R[0],$R[1]=Symbol.toPrimitive))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.toStringTag 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.toStringTag 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.toStringTag 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Symbol.toStringTag)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.toStringTag 2`] = `"($R=>_$.Ps($R[0],$R[1]=Symbol.toStringTag))($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.unscopables 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.unscopables 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.unscopables 2`] = `"($R=>(_$.Ps($R[0],$R[1]=Symbol.unscopables)))($R[\\"example\\"])"`; +exports[`well-known symbols > crossSerializeStream > scoped > supports Symbol.unscopables 2`] = `"($R=>_$.Ps($R[0],$R[1]=Symbol.unscopables))($R[\\"example\\"])"`; exports[`well-known symbols > crossSerializeStream > supports Symbol.asyncIterator 1`] = `"$R[0]=_$.P()"`; @@ -260,6 +260,110 @@ exports[`well-known symbols > serializeAsync > supports well-known symbols 12`] exports[`well-known symbols > serializeAsync > supports well-known symbols 13`] = `"Promise.resolve(Symbol.unscopables)"`; +exports[`well-known symbols > toCrossJSON > supports well-known symbols 1`] = `"{\\"t\\":17,\\"i\\":0,\\"s\\":0}"`; + +exports[`well-known symbols > toCrossJSON > supports well-known symbols 2`] = `"{\\"t\\":17,\\"i\\":0,\\"s\\":1}"`; + +exports[`well-known symbols > toCrossJSON > supports well-known symbols 3`] = `"{\\"t\\":17,\\"i\\":0,\\"s\\":2}"`; + +exports[`well-known symbols > toCrossJSON > supports well-known symbols 4`] = `"{\\"t\\":17,\\"i\\":0,\\"s\\":3}"`; + +exports[`well-known symbols > toCrossJSON > supports well-known symbols 5`] = `"{\\"t\\":17,\\"i\\":0,\\"s\\":4}"`; + +exports[`well-known symbols > toCrossJSON > supports well-known symbols 6`] = `"{\\"t\\":17,\\"i\\":0,\\"s\\":5}"`; + +exports[`well-known symbols > toCrossJSON > supports well-known symbols 7`] = `"{\\"t\\":17,\\"i\\":0,\\"s\\":6}"`; + +exports[`well-known symbols > toCrossJSON > supports well-known symbols 8`] = `"{\\"t\\":17,\\"i\\":0,\\"s\\":7}"`; + +exports[`well-known symbols > toCrossJSON > supports well-known symbols 9`] = `"{\\"t\\":17,\\"i\\":0,\\"s\\":8}"`; + +exports[`well-known symbols > toCrossJSON > supports well-known symbols 10`] = `"{\\"t\\":17,\\"i\\":0,\\"s\\":9}"`; + +exports[`well-known symbols > toCrossJSON > supports well-known symbols 11`] = `"{\\"t\\":17,\\"i\\":0,\\"s\\":10}"`; + +exports[`well-known symbols > toCrossJSON > supports well-known symbols 12`] = `"{\\"t\\":17,\\"i\\":0,\\"s\\":11}"`; + +exports[`well-known symbols > toCrossJSON > supports well-known symbols 13`] = `"{\\"t\\":17,\\"i\\":0,\\"s\\":12}"`; + +exports[`well-known symbols > toCrossJSONAsync > supports well-known symbols 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":0}}"`; + +exports[`well-known symbols > toCrossJSONAsync > supports well-known symbols 2`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":1}}"`; + +exports[`well-known symbols > toCrossJSONAsync > supports well-known symbols 3`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":2}}"`; + +exports[`well-known symbols > toCrossJSONAsync > supports well-known symbols 4`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":3}}"`; + +exports[`well-known symbols > toCrossJSONAsync > supports well-known symbols 5`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":4}}"`; + +exports[`well-known symbols > toCrossJSONAsync > supports well-known symbols 6`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":5}}"`; + +exports[`well-known symbols > toCrossJSONAsync > supports well-known symbols 7`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":6}}"`; + +exports[`well-known symbols > toCrossJSONAsync > supports well-known symbols 8`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":7}}"`; + +exports[`well-known symbols > toCrossJSONAsync > supports well-known symbols 9`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":8}}"`; + +exports[`well-known symbols > toCrossJSONAsync > supports well-known symbols 10`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":9}}"`; + +exports[`well-known symbols > toCrossJSONAsync > supports well-known symbols 11`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":10}}"`; + +exports[`well-known symbols > toCrossJSONAsync > supports well-known symbols 12`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":11}}"`; + +exports[`well-known symbols > toCrossJSONAsync > supports well-known symbols 13`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":12}}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.asyncIterator 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.asyncIterator 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":0}}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.hasInstance 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.hasInstance 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":1}}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.isConcatSpreadable 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.isConcatSpreadable 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":2}}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.iterator 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.iterator 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":3}}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.match 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.match 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":4}}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.matchAll 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.matchAll 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":5}}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.replace 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.replace 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":6}}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.search 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.search 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":7}}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.species 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.species 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":8}}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.split 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.split 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":9}}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.toPrimitive 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.toPrimitive 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":10}}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.toStringTag 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.toStringTag 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":11}}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.unscopables 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`well-known symbols > toCrossJSONStream > supports Symbol.unscopables 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":17,\\"i\\":1,\\"s\\":12}}"`; + exports[`well-known symbols > toJSON > supports well-known symbols 1`] = `"{\\"t\\":{\\"t\\":17,\\"i\\":0,\\"s\\":0},\\"f\\":16383,\\"m\\":[]}"`; exports[`well-known symbols > toJSON > supports well-known symbols 2`] = `"{\\"t\\":{\\"t\\":17,\\"i\\":0,\\"s\\":1},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/array.test.ts b/packages/seroval/test/array.test.ts index a4842962..f4174660 100644 --- a/packages/seroval/test/array.test.ts +++ b/packages/seroval/test/array.test.ts @@ -9,41 +9,50 @@ import { crossSerialize, crossSerializeAsync, crossSerializeStream, + toCrossJSONStream, + toCrossJSONAsync, + fromCrossJSON, + toCrossJSON, } from '../src'; +const EXAMPLE = [1, 2, 3]; + +const RECURSIVE_EXAMPLE: unknown[] = []; +RECURSIVE_EXAMPLE[0] = RECURSIVE_EXAMPLE; +RECURSIVE_EXAMPLE[1] = RECURSIVE_EXAMPLE; + +const ASYNC_RECURSIVE_EXAMPLE: Promise[] = []; +ASYNC_RECURSIVE_EXAMPLE[0] = Promise.resolve(ASYNC_RECURSIVE_EXAMPLE); +ASYNC_RECURSIVE_EXAMPLE[1] = Promise.resolve(ASYNC_RECURSIVE_EXAMPLE); + describe('arrays', () => { describe('serialize', () => { it('supports Arrays', () => { - const example = [1, 2, 3]; - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back).toBeInstanceOf(Array); - expect(back[0]).toBe(example[0]); - expect(back[1]).toBe(example[1]); - expect(back[2]).toBe(example[2]); + expect(back[0]).toBe(EXAMPLE[0]); + expect(back[1]).toBe(EXAMPLE[1]); + expect(back[2]).toBe(EXAMPLE[2]); }); it('supports self recursion', () => { - const example: unknown[] = []; - example[0] = example; - example[1] = example; - const result = serialize(example); + const result = serialize(RECURSIVE_EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back[0]).toBe(back); expect(back[1]).toBe(back); }); }); describe('serializeAsync', () => { it('supports Arrays', async () => { - const example = [1, 2, 3]; - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(Array); - expect(back[0]).toBe(example[0]); - expect(back[1]).toBe(example[1]); - expect(back[2]).toBe(example[2]); + expect(back[0]).toBe(EXAMPLE[0]); + expect(back[1]).toBe(EXAMPLE[1]); + expect(back[2]).toBe(EXAMPLE[2]); }); it('supports self recursion', async () => { const example: Promise[] = []; @@ -58,156 +67,208 @@ describe('arrays', () => { }); describe('toJSON', () => { it('supports Arrays', () => { - const example = [1, 2, 3]; - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(Array); - expect(back[0]).toBe(example[0]); - expect(back[1]).toBe(example[1]); - expect(back[2]).toBe(example[2]); + expect(back[0]).toBe(EXAMPLE[0]); + expect(back[1]).toBe(EXAMPLE[1]); + expect(back[2]).toBe(EXAMPLE[2]); }); it('supports self recursion', () => { - const example: unknown[] = []; - example[0] = example; - example[1] = example; - const result = toJSON(example); + const result = toJSON(RECURSIVE_EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back[0]).toBe(back); expect(back[1]).toBe(back); }); }); describe('toJSONAsync', () => { it('supports Arrays', async () => { - const example = [1, 2, 3]; - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = await fromJSON>(result); expect(back).toBeInstanceOf(Array); - expect(back[0]).toBe(example[0]); - expect(back[1]).toBe(example[1]); - expect(back[2]).toBe(example[2]); + expect(back[0]).toBe(EXAMPLE[0]); + expect(back[1]).toBe(EXAMPLE[1]); + expect(back[2]).toBe(EXAMPLE[2]); }); it('supports self recursion', async () => { - const example: Promise[] = []; - example[0] = Promise.resolve(example); - example[1] = Promise.resolve(example); - const result = await toJSONAsync(example); + const result = await toJSONAsync(ASYNC_RECURSIVE_EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(await back[0]).toBe(back); expect(await back[1]).toBe(back); }); }); describe('crossSerialize', () => { it('supports Arrays', () => { - const example = [1, 2, 3]; - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); it('supports self recursion', () => { - const example: unknown[] = []; - example[0] = example; - example[1] = example; - const result = crossSerialize(example); + const result = crossSerialize(RECURSIVE_EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Arrays', () => { - const example = [1, 2, 3]; - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports self recursion', () => { - const example: unknown[] = []; - example[0] = example; - example[1] = example; - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(RECURSIVE_EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports Arrays', async () => { - const example = [1, 2, 3]; - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); it('supports self recursion', async () => { - const example: Promise[] = []; - example[0] = Promise.resolve(example); - example[1] = Promise.resolve(example); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(ASYNC_RECURSIVE_EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Arrays', async () => { - const example = [1, 2, 3]; - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports self recursion', async () => { - const example: Promise[] = []; - example[0] = Promise.resolve(example); - example[1] = Promise.resolve(example); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync(ASYNC_RECURSIVE_EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports Arrays', async () => new Promise((done) => { - const example = [1, 2, 3]; - crossSerializeStream(Promise.resolve(example), { + it('supports Arrays', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self recursion', async () => new Promise((done) => { - const example: Promise[] = []; - example[0] = Promise.resolve(example); - example[1] = Promise.resolve(example); - crossSerializeStream(example, { + it('supports self recursion', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_RECURSIVE_EXAMPLE, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Arrays', async () => new Promise((done) => { - const example = [1, 2, 3]; - crossSerializeStream(Promise.resolve(example), { + it('supports Arrays', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self recursion', async () => new Promise((done) => { - const example: Promise[] = []; - example[0] = Promise.resolve(example); - example[1] = Promise.resolve(example); - crossSerializeStream(example, { + it('supports self recursion', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_RECURSIVE_EXAMPLE, { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Arrays', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Array); + expect(back[0]).toBe(EXAMPLE[0]); + expect(back[1]).toBe(EXAMPLE[1]); + expect(back[2]).toBe(EXAMPLE[2]); + }); + it('supports self recursion', () => { + const result = toCrossJSON(RECURSIVE_EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back[0]).toBe(back); + expect(back[1]).toBe(back); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Arrays', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Array); + expect(back[0]).toBe(EXAMPLE[0]); + expect(back[1]).toBe(EXAMPLE[1]); + expect(back[2]).toBe(EXAMPLE[2]); + }); + it('supports self recursion', async () => { + const result = await toCrossJSONAsync(ASYNC_RECURSIVE_EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(await back[0]).toBe(back); + expect(await back[1]).toBe(back); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Arrays', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports self recursion', async () => new Promise((resolve, reject) => { + toCrossJSONStream(ASYNC_RECURSIVE_EXAMPLE, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/async-iterable.test.ts b/packages/seroval/test/async-iterable.test.ts new file mode 100644 index 00000000..c3fb4234 --- /dev/null +++ b/packages/seroval/test/async-iterable.test.ts @@ -0,0 +1,142 @@ +import { describe, it, expect } from 'vitest'; +import { + compileJSON, + crossSerializeAsync, + crossSerializeStream, + deserialize, + Feature, + fromCrossJSON, + fromJSON, + serializeAsync, + toCrossJSONAsync, + toCrossJSONStream, + toJSONAsync, +} from '../src'; + +const EXAMPLE = { + title: 'Hello World', + async* [Symbol.asyncIterator](): AsyncIterator { + await Promise.resolve(); + yield 1; + yield 2; + yield 3; + }, +}; + +describe('AsyncIterable', () => { + describe('serializeAsync', () => { + it('supports AsyncIterables', async () => { + const result = await serializeAsync(EXAMPLE); + expect(result).toMatchSnapshot(); + const back = deserialize(result); + expect(back.title).toBe(EXAMPLE.title); + expect(Symbol.asyncIterator in back).toBe(true); + const iterator = back[Symbol.asyncIterator](); + expect((await iterator.next()).value).toBe(1); + expect((await iterator.next()).value).toBe(2); + expect((await iterator.next()).value).toBe(3); + }); + }); + describe('toJSONAsync', () => { + it('supports AsyncIterables', async () => { + const result = await toJSONAsync(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromJSON(result); + expect(back.title).toBe(EXAMPLE.title); + expect(Symbol.asyncIterator in back).toBe(true); + const iterator = back[Symbol.asyncIterator](); + expect((await iterator.next()).value).toBe(1); + expect((await iterator.next()).value).toBe(2); + expect((await iterator.next()).value).toBe(3); + }); + }); + describe('crossSerializeAsync', () => { + it('supports AsyncIterables', async () => { + const result = await crossSerializeAsync(EXAMPLE); + expect(result).toMatchSnapshot(); + }); + describe('scoped', () => { + it('supports AsyncIterables', async () => { + const result = await crossSerializeAsync(EXAMPLE, { scopeId: 'example' }); + expect(result).toMatchSnapshot(); + }); + }); + }); + describe('crossSerializeStream', () => { + it('supports AsyncIterables', async () => new Promise((resolve, reject) => { + crossSerializeStream(EXAMPLE, { + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + describe('scoped', () => { + it('supports AsyncIterables', async () => new Promise((resolve, reject) => { + crossSerializeStream(EXAMPLE, { + scopeId: 'example', + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports AsyncIterables', async () => { + const result = await toCrossJSONAsync(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back.title).toBe(EXAMPLE.title); + expect(Symbol.asyncIterator in back).toBe(true); + const iterator = back[Symbol.asyncIterator](); + expect((await iterator.next()).value).toBe(1); + expect((await iterator.next()).value).toBe(2); + expect((await iterator.next()).value).toBe(3); + }); + }); + describe('toCrossJSONStream', () => { + it('supports AsyncIterables', async () => new Promise((resolve, reject) => { + toCrossJSONStream(EXAMPLE, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); + describe('compat', () => { + it('should use function expressions instead of arrow functions.', async () => { + expect(await serializeAsync(EXAMPLE, { + disabledFeatures: Feature.ArrowFunction, + })).toMatchSnapshot(); + }); + }); + describe('compat#toJSONAsync', () => { + it('should use function expression instead of arrow functions.', async () => { + const result = await toJSONAsync(EXAMPLE, { + disabledFeatures: Feature.ArrowFunction, + }); + expect(JSON.stringify(result)).toMatchSnapshot(); + expect(compileJSON(result)).toMatchSnapshot(); + }); + }); +}); diff --git a/packages/seroval/test/bigint.test.ts b/packages/seroval/test/bigint.test.ts index 1778bc90..eac3edb4 100644 --- a/packages/seroval/test/bigint.test.ts +++ b/packages/seroval/test/bigint.test.ts @@ -10,65 +10,102 @@ import { crossSerialize, crossSerializeAsync, crossSerializeStream, + toCrossJSONAsync, + toCrossJSON, + fromCrossJSON, + toCrossJSONStream, } from '../src'; +const EXAMPLE = 9007199254740991n; + describe('bigint', () => { describe('serialize', () => { it('supports bigint', () => { - expect(serialize(9007199254740991n)).toMatchSnapshot(); - expect(deserialize(serialize(9007199254740991n))).toBe(9007199254740991n); + expect(serialize(EXAMPLE)).toMatchSnapshot(); + expect(deserialize(serialize(EXAMPLE))).toBe(EXAMPLE); }); }); describe('serializeAsync', () => { it('supports bigint', async () => { - expect(await serializeAsync(Promise.resolve(9007199254740991n))).toMatchSnapshot(); + expect(await serializeAsync(Promise.resolve(EXAMPLE))).toMatchSnapshot(); }); }); describe('toJSON', () => { it('supports bigint', () => { - expect(JSON.stringify(toJSON(9007199254740991n))).toMatchSnapshot(); - expect(fromJSON(toJSON(9007199254740991n))).toBe(9007199254740991n); + expect(JSON.stringify(toJSON(EXAMPLE))).toMatchSnapshot(); + expect(fromJSON(toJSON(EXAMPLE))).toBe(EXAMPLE); }); }); describe('toJSONAsync', () => { it('supports bigint', async () => { expect( - JSON.stringify(await toJSONAsync(Promise.resolve(9007199254740991n))), + JSON.stringify(await toJSONAsync(Promise.resolve(EXAMPLE))), ).toMatchSnapshot(); }); }); describe('crossSerialize', () => { it('supports bigint', () => { - expect(crossSerialize(9007199254740991n)).toMatchSnapshot(); + expect(crossSerialize(EXAMPLE)).toMatchSnapshot(); }); }); describe('crossSerializeAsync', () => { it('supports bigint', async () => { - expect(await crossSerializeAsync(Promise.resolve(9007199254740991n))).toMatchSnapshot(); + expect(await crossSerializeAsync(Promise.resolve(EXAMPLE))).toMatchSnapshot(); }); }); describe('crossSerializeStream', () => { - it('supports bigint', async () => new Promise((done) => { - crossSerializeStream(Promise.resolve(9007199254740991n), { + it('supports bigint', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); + describe('toCrossJSON', () => { + it('supports bigint', () => { + expect(JSON.stringify(toCrossJSON(EXAMPLE))).toMatchSnapshot(); + expect(fromCrossJSON(toCrossJSON(EXAMPLE), { refs: new Map() })).toBe(EXAMPLE); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports bigint', async () => { + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(EXAMPLE))), + ).toMatchSnapshot(); + }); + }); + describe('toCrossJSONStream', () => { + it('supports bigint', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); describe('compat', () => { it('should throw an error for unsupported target', () => { - expect(() => serialize(9007199254740991n, { + expect(() => serialize(EXAMPLE, { disabledFeatures: Feature.BigInt, })).toThrowErrorMatchingSnapshot(); }); }); describe('compat#toJSON', () => { it('should throw an error for unsupported target', () => { - expect(() => toJSON(9007199254740991n, { + expect(() => toJSON(EXAMPLE, { disabledFeatures: Feature.BigInt, })).toThrowErrorMatchingSnapshot(); }); diff --git a/packages/seroval/test/boolean.test.ts b/packages/seroval/test/boolean.test.ts index 0ff4e774..4ce2cbef 100644 --- a/packages/seroval/test/boolean.test.ts +++ b/packages/seroval/test/boolean.test.ts @@ -5,6 +5,9 @@ import { crossSerializeStream, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; @@ -28,7 +31,7 @@ describe('boolean', () => { expect(JSON.stringify(toJSON(false))).toMatchSnapshot(); }); }); - describe('serializeAsync', () => { + describe('toJSONAsync', () => { it('supports boolean', async () => { expect( JSON.stringify(await toJSONAsync(Promise.resolve(true))), @@ -50,24 +53,74 @@ describe('boolean', () => { expect(await crossSerializeAsync(Promise.resolve(false))).toMatchSnapshot(); }); }); - describe('crossSerializeAsync', () => { - it('supports true value', async () => new Promise((done) => { + describe('crossSerializeStream', () => { + it('supports true value', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(true), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports false value', async () => new Promise((done) => { + it('supports false value', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(false), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); + describe('toCrossJSON', () => { + it('supports boolean', () => { + expect(JSON.stringify(toCrossJSON(true))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(false))).toMatchSnapshot(); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports boolean', async () => { + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(true))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(false))), + ).toMatchSnapshot(); + }); + }); + describe('toCrossJSONStream', () => { + it('supports true value', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(true), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports false value', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(false), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); }, }); })); diff --git a/packages/seroval/test/boxed-bigint.test.ts b/packages/seroval/test/boxed-bigint.test.ts index 2892983f..342999d7 100644 --- a/packages/seroval/test/boxed-bigint.test.ts +++ b/packages/seroval/test/boxed-bigint.test.ts @@ -10,93 +10,137 @@ import { crossSerialize, crossSerializeAsync, crossSerializeStream, + toCrossJSON, + fromCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, } from '../src'; +const EXAMPLE = 9007199254740991n; + describe('boxed bigint', () => { describe('serialize', () => { it('supports boxed bigint', () => { - expect(serialize(Object(9007199254740991n))).toMatchSnapshot(); - expect(deserialize(serialize(Object(9007199254740991n))).valueOf()) - .toBe(9007199254740991n); + expect(serialize(Object(EXAMPLE))).toMatchSnapshot(); + expect(deserialize(serialize(Object(EXAMPLE))).valueOf()) + .toBe(EXAMPLE); }); }); describe('serializeAsync', () => { it('supports boxed bigint', async () => { - expect(await serializeAsync(Promise.resolve(Object(9007199254740991n)))).toMatchSnapshot(); + expect(await serializeAsync(Promise.resolve(Object(EXAMPLE)))).toMatchSnapshot(); }); }); describe('toJSON', () => { it('supports boxed bigint', () => { - expect(JSON.stringify(toJSON(Object(9007199254740991n)))).toMatchSnapshot(); - expect(fromJSON(toJSON(Object(9007199254740991n))).valueOf()).toBe(9007199254740991n); + expect(JSON.stringify(toJSON(Object(EXAMPLE)))).toMatchSnapshot(); + expect(fromJSON(toJSON(Object(EXAMPLE))).valueOf()).toBe(EXAMPLE); }); }); describe('toJSONAsync', () => { it('supports boxed bigint', async () => { expect( - JSON.stringify(await toJSONAsync(Promise.resolve(Object(9007199254740991n)))), + JSON.stringify(await toJSONAsync(Promise.resolve(Object(EXAMPLE)))), ).toMatchSnapshot(); }); }); describe('crossSerialize', () => { it('supports boxed bigint', () => { - expect(crossSerialize(Object(9007199254740991n))).toMatchSnapshot(); + expect(crossSerialize(Object(EXAMPLE))).toMatchSnapshot(); }); describe('scoped', () => { it('supports boxed bigint', () => { - expect(crossSerialize(Object(9007199254740991n), { scopeId: 'example' })).toMatchSnapshot(); + expect(crossSerialize(Object(EXAMPLE), { scopeId: 'example' })).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports boxed bigint', async () => { expect( - await crossSerializeAsync(Promise.resolve(Object(9007199254740991n))), + await crossSerializeAsync(Promise.resolve(Object(EXAMPLE))), ).toMatchSnapshot(); }); describe('scoped', () => { it('supports boxed bigint', async () => { expect( - await crossSerializeAsync(Promise.resolve(Object(9007199254740991n)), { scopeId: 'example' }), + await crossSerializeAsync(Promise.resolve(Object(EXAMPLE)), { scopeId: 'example' }), ).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports boxed bigint', async () => new Promise((done) => { - crossSerializeStream(Promise.resolve(Object(9007199254740991n)), { + it('supports boxed bigint', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(Object(EXAMPLE)), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports boxed bigint', async () => new Promise((done) => { - crossSerializeStream(Promise.resolve(Object(9007199254740991n)), { + it('supports boxed bigint', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(Object(EXAMPLE)), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports boxed bigint', () => { + expect(JSON.stringify(toCrossJSON(Object(EXAMPLE)))).toMatchSnapshot(); + expect( + fromCrossJSON(toCrossJSON(Object(EXAMPLE)), { + refs: new Map(), + }).valueOf(), + ).toBe(EXAMPLE); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports boxed bigint', async () => { + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Object(EXAMPLE)))), + ).toMatchSnapshot(); + }); + }); + describe('toCrossJSONStream', () => { + it('supports boxed bigint', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Object(EXAMPLE)), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); describe('compat', () => { it('should throw an error for unsupported target', () => { - expect(() => serialize(Object(9007199254740991n), { + expect(() => serialize(Object(EXAMPLE), { disabledFeatures: Feature.BigInt, })).toThrowErrorMatchingSnapshot(); }); }); describe('compat#toJSON', () => { it('should throw an error for unsupported target', () => { - expect(() => toJSON(Object(9007199254740991n), { + expect(() => toJSON(Object(EXAMPLE), { disabledFeatures: Feature.BigInt, })).toThrowErrorMatchingSnapshot(); }); diff --git a/packages/seroval/test/boxed-boolean.test.ts b/packages/seroval/test/boxed-boolean.test.ts index 910f2ad0..2faec212 100644 --- a/packages/seroval/test/boxed-boolean.test.ts +++ b/packages/seroval/test/boxed-boolean.test.ts @@ -5,6 +5,11 @@ import { crossSerializeStream, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, + toJSON, + toJSONAsync, } from '../src'; describe('boxed boolean', () => { @@ -20,6 +25,22 @@ describe('boxed boolean', () => { expect(await serializeAsync(Object(false))).toBe('Object(!1)'); }); }); + describe('toJSON', () => { + it('supports boolean', () => { + expect(JSON.stringify(toJSON(Object(true)))).toMatchSnapshot(); + expect(JSON.stringify(toJSON(Object(false)))).toMatchSnapshot(); + }); + }); + describe('toJSONAsync', () => { + it('supports boolean', async () => { + expect( + JSON.stringify(await toJSONAsync(Promise.resolve(Object(true)))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toJSONAsync(Promise.resolve(Object(false)))), + ).toMatchSnapshot(); + }); + }); describe('crossSerialize', () => { it('supports boolean', () => { expect(crossSerialize(Object(true))).toMatchSnapshot(); @@ -45,47 +66,103 @@ describe('boxed boolean', () => { }); }); describe('crossSerializeStream', () => { - it('supports boxed true', async () => new Promise((done) => { + it('supports boxed true', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Object(true)), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports boxed false', async () => new Promise((done) => { + it('supports boxed false', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Object(false)), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); + describe('scoped', () => { + it('supports boxed true', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(Object(true)), { + scopeId: 'example', + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports boxed false', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(Object(false)), { + scopeId: 'example', + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); - describe('scoped', () => { - it('supports boxed true', async () => new Promise((done) => { - crossSerializeStream(Promise.resolve(Object(true)), { - scopeId: 'example', - onSerialize(data) { - expect(data).toMatchSnapshot(); + describe('toCrossJSON', () => { + it('supports boolean', () => { + expect(JSON.stringify(toCrossJSON(Object(true)))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Object(false)))).toMatchSnapshot(); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports boolean', async () => { + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Object(true)))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Object(false)))), + ).toMatchSnapshot(); + }); + }); + describe('toCrossJSONStream', () => { + it('supports boxed true', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Object(true)), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports boxed false', async () => new Promise((done) => { - crossSerializeStream(Promise.resolve(Object(false)), { - scopeId: 'example', - onSerialize(data) { - expect(data).toMatchSnapshot(); + it('supports boxed false', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Object(false)), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); diff --git a/packages/seroval/test/boxed-number.test.ts b/packages/seroval/test/boxed-number.test.ts index 8a50b49f..23b5af27 100644 --- a/packages/seroval/test/boxed-number.test.ts +++ b/packages/seroval/test/boxed-number.test.ts @@ -5,6 +5,9 @@ import { crossSerializeStream, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; @@ -102,112 +105,239 @@ describe('boxed number', () => { }); describe('crossSerializeStream', () => { - it('supports boxed numbers', async () => new Promise((done) => { + it('supports boxed numbers', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Object(0xDEADBEEF)), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports boxed NaN', async () => new Promise((done) => { + it('supports boxed NaN', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Object(NaN)), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports boxed Infinity', async () => new Promise((done) => { + it('supports boxed Infinity', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Object(Infinity)), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports boxed -Infinity', async () => new Promise((done) => { + it('supports boxed -Infinity', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Object(-Infinity)), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports boxed -0', async () => new Promise((done) => { + it('supports boxed -0', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Object(-0)), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports boxed numbers', async () => new Promise((done) => { + it('supports boxed numbers', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Object(0xDEADBEEF)), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports boxed NaN', async () => new Promise((done) => { + it('supports boxed NaN', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Object(NaN)), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports boxed Infinity', async () => new Promise((done) => { + it('supports boxed Infinity', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Object(Infinity)), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports boxed -Infinity', async () => new Promise((done) => { + it('supports boxed -Infinity', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Object(-Infinity)), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports boxed -0', async () => new Promise((done) => { + it('supports boxed -0', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Object(-0)), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports boxed numbers', () => { + const value = 0xDEADBEEF; + expect(JSON.stringify(toCrossJSON(Object(value)))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Object(NaN)))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Object(Infinity)))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Object(-Infinity)))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Object(-0)))).toMatchSnapshot(); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports boxed numbers', async () => { + const value = 0xDEADBEEF; + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Object(value)))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Object(NaN)))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Object(Infinity)))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Object(-Infinity)))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Object(-0)))), + ).toMatchSnapshot(); + }); + }); + describe('toCrossJSONStream', () => { + it('supports boxed numbers', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Object(0xDEADBEEF)), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports boxed NaN', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Object(NaN)), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports boxed Infinity', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Object(Infinity)), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports boxed -Infinity', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Object(-Infinity)), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports boxed -0', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Object(-0)), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/boxed-string.test.ts b/packages/seroval/test/boxed-string.test.ts index 1346820f..b9c08406 100644 --- a/packages/seroval/test/boxed-string.test.ts +++ b/packages/seroval/test/boxed-string.test.ts @@ -4,114 +4,183 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; +const QUOTED = '"hello"'; +const HTML = ''; + describe('boxed string', () => { describe('serialize', () => { it('supports boxed strings', () => { - expect(serialize(Object('"hello"'))).toMatchSnapshot(); - expect(serialize(Object(''))).toMatchSnapshot(); - expect(deserialize(serialize(Object('"hello"'))).valueOf()).toBe('"hello"'); - expect(deserialize(serialize(Object(''))).valueOf()).toBe(''); + expect(serialize(Object(QUOTED))).toMatchSnapshot(); + expect(serialize(Object(HTML))).toMatchSnapshot(); + expect(deserialize(serialize(Object(QUOTED))).valueOf()).toBe(QUOTED); + expect(deserialize(serialize(Object(HTML))).valueOf()).toBe(HTML); }); }); describe('serializeAsync', () => { it('supports boxed strings', async () => { - expect(await serializeAsync(Promise.resolve(Object('"hello"')))).toMatchSnapshot(); - expect(await serializeAsync(Promise.resolve(Object('')))).toMatchSnapshot(); + expect(await serializeAsync(Promise.resolve(Object(QUOTED)))).toMatchSnapshot(); + expect(await serializeAsync(Promise.resolve(Object(HTML)))).toMatchSnapshot(); }); }); describe('toJSON', () => { it('supports boxed strings', () => { - expect(JSON.stringify(toJSON(Object('"hello"')))).toMatchSnapshot(); - expect(JSON.stringify(toJSON(Object('')))).toMatchSnapshot(); - expect(fromJSON(toJSON(Object('"hello"'))).valueOf()).toBe('"hello"'); - expect(fromJSON(toJSON(Object(''))).valueOf()).toBe(''); + expect(JSON.stringify(toJSON(Object(QUOTED)))).toMatchSnapshot(); + expect(JSON.stringify(toJSON(Object(HTML)))).toMatchSnapshot(); + expect(fromJSON(toJSON(Object(QUOTED))).valueOf()).toBe(QUOTED); + expect(fromJSON(toJSON(Object(HTML))).valueOf()).toBe(HTML); }); }); describe('toJSONAsync', () => { it('supports boxed strings', async () => { expect( - JSON.stringify(await toJSONAsync(Promise.resolve(Object('"hello"')))), + JSON.stringify(await toJSONAsync(Promise.resolve(Object(QUOTED)))), ).toMatchSnapshot(); expect( - JSON.stringify(await toJSONAsync(Promise.resolve(Object('')))), + JSON.stringify(await toJSONAsync(Promise.resolve(Object(HTML)))), ).toMatchSnapshot(); }); }); describe('crossSerialize', () => { it('supports boxed strings', () => { - expect(crossSerialize(Object('"hello"'))).toMatchSnapshot(); - expect(crossSerialize(Object(''))).toMatchSnapshot(); + expect(crossSerialize(Object(QUOTED))).toMatchSnapshot(); + expect(crossSerialize(Object(HTML))).toMatchSnapshot(); }); describe('scoped', () => { it('supports boxed strings', () => { - expect(crossSerialize(Object('"hello"'), { scopeId: 'example' })).toMatchSnapshot(); - expect(crossSerialize(Object(''), { scopeId: 'example' })).toMatchSnapshot(); + expect(crossSerialize(Object(QUOTED), { scopeId: 'example' })).toMatchSnapshot(); + expect(crossSerialize(Object(HTML), { scopeId: 'example' })).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports boxed strings', async () => { - expect(await crossSerializeAsync(Promise.resolve(Object('"hello"')))).toMatchSnapshot(); - expect(await crossSerializeAsync(Promise.resolve(Object('')))).toMatchSnapshot(); + expect(await crossSerializeAsync(Promise.resolve(Object(QUOTED)))).toMatchSnapshot(); + expect(await crossSerializeAsync(Promise.resolve(Object(HTML)))).toMatchSnapshot(); }); describe('scoped', () => { it('supports boxed strings', async () => { - expect(await crossSerializeAsync(Promise.resolve(Object('"hello"')), { scopeId: 'example' })).toMatchSnapshot(); - expect(await crossSerializeAsync(Promise.resolve(Object('')), { scopeId: 'example' })).toMatchSnapshot(); + expect(await crossSerializeAsync(Promise.resolve(Object(QUOTED)), { scopeId: 'example' })).toMatchSnapshot(); + expect(await crossSerializeAsync(Promise.resolve(Object(HTML)), { scopeId: 'example' })).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports boxed strings', async () => new Promise((done) => { - crossSerializeStream(Promise.resolve(Object('"hello"')), { + it('supports boxed strings', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(Object(QUOTED)), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports boxed sanitized strings', async () => new Promise((done) => { - crossSerializeStream(Promise.resolve(Object('')), { + it('supports boxed sanitized strings', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(Object(HTML)), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports boxed strings', async () => new Promise((done) => { - crossSerializeStream(Promise.resolve(Object('"hello"')), { + it('supports boxed strings', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(Object(QUOTED)), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports boxed sanitized strings', async () => new Promise((done) => { - crossSerializeStream(Promise.resolve(Object('')), { + it('supports boxed sanitized strings', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(Object(HTML)), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports boxed strings', () => { + expect(JSON.stringify(toCrossJSON(Object(QUOTED)))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Object(HTML)))).toMatchSnapshot(); + expect( + fromCrossJSON(toCrossJSON(Object(QUOTED)), { refs: new Map() }).valueOf(), + ).toBe(QUOTED); + expect( + fromCrossJSON(toCrossJSON(Object(HTML)), { refs: new Map() }).valueOf(), + ).toBe(HTML); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports boxed strings', async () => { + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Object(QUOTED)))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Object(HTML)))), + ).toMatchSnapshot(); + }); + }); + describe('toCrossJSONStream', () => { + it('supports boxed strings', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Object(QUOTED)), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports boxed sanitized strings', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Object(HTML)), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/data-view.test.ts b/packages/seroval/test/data-view.test.ts index cf238c09..9c06a9c3 100644 --- a/packages/seroval/test/data-view.test.ts +++ b/packages/seroval/test/data-view.test.ts @@ -9,122 +9,143 @@ import { crossSerialize, crossSerializeAsync, crossSerializeStream, + toCrossJSON, + toCrossJSONAsync, + fromCrossJSON, + toCrossJSONStream, } from '../src'; +const BUFFER = new ArrayBuffer(16); +const EXAMPLE = new DataView(BUFFER, 0); +EXAMPLE.setInt16(1, 42); + describe('DataView', () => { describe('serialize', () => { it('supports DataView', () => { - const buffer = new ArrayBuffer(16); - const example = new DataView(buffer, 0); - example.setInt16(1, 42); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back).toBeInstanceOf(DataView); - expect(back.getInt16(1)).toBe(example.getInt16(1)); + expect(back.getInt16(1)).toBe(EXAMPLE.getInt16(1)); }); }); describe('serializeAsync', () => { it('supports DataView', async () => { - const buffer = new ArrayBuffer(16); - const example = new DataView(buffer, 0); - example.setInt16(1, 42); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(DataView); - expect(back.getInt16(1)).toBe(example.getInt16(1)); + expect(back.getInt16(1)).toBe(EXAMPLE.getInt16(1)); }); }); describe('toJSON', () => { it('supports DataView', () => { - const buffer = new ArrayBuffer(16); - const example = new DataView(buffer, 0); - example.setInt16(1, 42); - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(DataView); - expect(back.getInt16(1)).toBe(example.getInt16(1)); + expect(back.getInt16(1)).toBe(EXAMPLE.getInt16(1)); }); }); describe('toJSONAsync', () => { it('supports DataView', async () => { - const buffer = new ArrayBuffer(16); - const example = new DataView(buffer, 0); - example.setInt16(1, 42); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = await fromJSON>(result); expect(back).toBeInstanceOf(DataView); - expect(back.getInt16(1)).toBe(example.getInt16(1)); + expect(back.getInt16(1)).toBe(EXAMPLE.getInt16(1)); }); }); describe('crossSerialize', () => { it('supports DataView', () => { - const buffer = new ArrayBuffer(16); - const example = new DataView(buffer, 0); - example.setInt16(1, 42); - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports DataView', () => { - const buffer = new ArrayBuffer(16); - const example = new DataView(buffer, 0); - example.setInt16(1, 42); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports DataView', async () => { - const buffer = new ArrayBuffer(16); - const example = new DataView(buffer, 0); - example.setInt16(1, 42); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports DataView', async () => { - const buffer = new ArrayBuffer(16); - const example = new DataView(buffer, 0); - example.setInt16(1, 42); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports DataView', async () => new Promise((done) => { - const buffer = new ArrayBuffer(16); - const example = new DataView(buffer, 0); - example.setInt16(1, 42); - crossSerializeStream(Promise.resolve(example), { + it('supports DataView', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports DataView', async () => new Promise((done) => { - const buffer = new ArrayBuffer(16); - const example = new DataView(buffer, 0); - example.setInt16(1, 42); - crossSerializeStream(Promise.resolve(example), { + it('supports DataView', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports DataView', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(DataView); + expect(back.getInt16(1)).toBe(EXAMPLE.getInt16(1)); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports DataView', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(DataView); + expect(back.getInt16(1)).toBe(EXAMPLE.getInt16(1)); + }); + }); + describe('toCrossJSONStream', () => { + it('supports DataView', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/date.test.ts b/packages/seroval/test/date.test.ts index d96bd87e..cefbb1bf 100644 --- a/packages/seroval/test/date.test.ts +++ b/packages/seroval/test/date.test.ts @@ -9,103 +9,142 @@ import { crossSerialize, crossSerializeAsync, crossSerializeStream, + toCrossJSON, + toCrossJSONAsync, + fromCrossJSON, + toCrossJSONStream, } from '../src'; +const EXAMPLE = new Date('2023-03-14T11:16:24.879Z'); + describe('Date', () => { describe('serialize', () => { it('supports Date', () => { - const example = new Date('2023-03-14T11:16:24.879Z'); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back).toBeInstanceOf(Date); - expect(back.toISOString()).toBe(example.toISOString()); + expect(back.toISOString()).toBe(EXAMPLE.toISOString()); }); }); describe('serializeAsync', () => { it('supports Date', async () => { - const example = new Date('2023-03-14T11:16:24.879Z'); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(Date); - expect(back.toISOString()).toBe(example.toISOString()); + expect(back.toISOString()).toBe(EXAMPLE.toISOString()); }); }); describe('toJSON', () => { it('supports Date', () => { - const example = new Date('2023-03-14T11:16:24.879Z'); - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(Date); - expect(back.toISOString()).toBe(example.toISOString()); + expect(back.toISOString()).toBe(EXAMPLE.toISOString()); }); }); describe('toJSONAsync', () => { it('supports Date', async () => { - const example = new Date('2023-03-14T11:16:24.879Z'); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = await fromJSON>(result); expect(back).toBeInstanceOf(Date); - expect(back.toISOString()).toBe(example.toISOString()); + expect(back.toISOString()).toBe(EXAMPLE.toISOString()); }); }); describe('crossSerialize', () => { it('supports Date', () => { - const example = new Date('2023-03-14T11:16:24.879Z'); - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Date', () => { - const example = new Date('2023-03-14T11:16:24.879Z'); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports Date', async () => { - const example = new Date('2023-03-14T11:16:24.879Z'); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Date', async () => { - const example = new Date('2023-03-14T11:16:24.879Z'); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports Date', async () => new Promise((done) => { - const example = new Date('2023-03-14T11:16:24.879Z'); - crossSerializeStream(Promise.resolve(example), { + it('supports Date', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Date', async () => new Promise((done) => { - const example = new Date('2023-03-14T11:16:24.879Z'); - crossSerializeStream(Promise.resolve(example), { + it('supports Date', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Date', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Date); + expect(back.toISOString()).toBe(EXAMPLE.toISOString()); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Date', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Date); + expect(back.toISOString()).toBe(EXAMPLE.toISOString()); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Date', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/error.test.ts b/packages/seroval/test/error.test.ts index 96f39d88..c46a4779 100644 --- a/packages/seroval/test/error.test.ts +++ b/packages/seroval/test/error.test.ts @@ -5,6 +5,9 @@ import { crossSerializeStream, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; @@ -178,7 +181,7 @@ describe('Error', () => { }); describe('crossSerializeStream', () => { - it('supports Error.prototype.name', async () => new Promise((done) => { + it('supports Error.prototype.name', async () => new Promise((resolve, reject) => { const a = new Error('A'); a.name = 'ExampleError'; a.stack = ''; @@ -187,11 +190,14 @@ describe('Error', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Error.prototype.cause', async () => new Promise((done) => { + it('supports Error.prototype.cause', async () => new Promise((resolve, reject) => { const a = new Error('A'); const b = new Error('B', { cause: Promise.resolve(a) }); a.stack = ''; @@ -201,11 +207,14 @@ describe('Error', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports other Error classes', async () => new Promise((done) => { + it('supports other Error classes', async () => new Promise((resolve, reject) => { const a = new ReferenceError('A'); a.stack = ''; crossSerializeStream(Promise.resolve(a), { @@ -213,13 +222,16 @@ describe('Error', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Error.prototype.name', async () => new Promise((done) => { + it('supports Error.prototype.name', async () => new Promise((resolve, reject) => { const a = new Error('A'); a.name = 'ExampleError'; a.stack = ''; @@ -229,11 +241,14 @@ describe('Error', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Error.prototype.cause', async () => new Promise((done) => { + it('supports Error.prototype.cause', async () => new Promise((resolve, reject) => { const a = new Error('A'); const b = new Error('B', { cause: Promise.resolve(a) }); a.stack = ''; @@ -244,11 +259,14 @@ describe('Error', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports other Error classes', async () => new Promise((done) => { + it('supports other Error classes', async () => new Promise((resolve, reject) => { const a = new ReferenceError('A'); a.stack = ''; crossSerializeStream(Promise.resolve(a), { @@ -257,10 +275,110 @@ describe('Error', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Error.prototype.name', () => { + const a = new Error('A'); + a.name = 'ExampleError'; + a.stack = ''; + expect(JSON.stringify(toCrossJSON(a))).toMatchSnapshot(); + }); + it('supports Error.prototype.cause', () => { + const a = new Error('A'); + const b = new Error('B', { cause: a }); + a.stack = ''; + b.stack = ''; + expect(JSON.stringify(toCrossJSON(b))).toMatchSnapshot(); + }); + it('supports other Error classes', () => { + const a = new ReferenceError('A'); + a.stack = ''; + expect(JSON.stringify(toCrossJSON(a))).toMatchSnapshot(); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Error.prototype.name', async () => { + const a = new Error('A'); + a.name = 'ExampleError'; + a.stack = ''; + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(a))), + ).toMatchSnapshot(); + }); + it('supports Error.prototype.cause', async () => { + const a = new Error('A'); + const b = new Error('B', { cause: Promise.resolve(a) }); + a.stack = ''; + b.stack = ''; + expect( + JSON.stringify(await toCrossJSONAsync(b)), + ).toMatchSnapshot(); + }); + it('supports other Error classes', async () => { + const a = new ReferenceError('A'); + a.stack = ''; + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(a))), + ).toMatchSnapshot(); + }); + }); + + describe('toCrossJSONStream', () => { + it('supports Error.prototype.name', async () => new Promise((resolve, reject) => { + const a = new Error('A'); + a.name = 'ExampleError'; + a.stack = ''; + toCrossJSONStream(Promise.resolve(a), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Error.prototype.cause', async () => new Promise((resolve, reject) => { + const a = new Error('A'); + const b = new Error('B', { cause: Promise.resolve(a) }); + a.stack = ''; + b.stack = ''; + toCrossJSONStream(Promise.resolve(b), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports other Error classes', async () => new Promise((resolve, reject) => { + const a = new ReferenceError('A'); + a.stack = ''; + toCrossJSONStream(Promise.resolve(a), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/frozen-object.test.ts b/packages/seroval/test/frozen-object.test.ts index fff2c3d8..1b5be57d 100644 --- a/packages/seroval/test/frozen-object.test.ts +++ b/packages/seroval/test/frozen-object.test.ts @@ -4,49 +4,68 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; +const EXAMPLE = Object.freeze({ hello: 'world' }); + +const RECURSIVE = {} as Record; +RECURSIVE.a = RECURSIVE; +RECURSIVE.b = RECURSIVE; +Object.freeze(RECURSIVE); + +const ITERABLE = Object.freeze({ + * [Symbol.iterator]() { + yield 1; + yield 2; + yield 3; + }, +}); + +const ASYNC_RECURSIVE = {} as Record>; +ASYNC_RECURSIVE.a = Promise.resolve(ASYNC_RECURSIVE); +ASYNC_RECURSIVE.b = Promise.resolve(ASYNC_RECURSIVE); +Object.freeze(ASYNC_RECURSIVE); + +const ASYNC_ITERABLE = Object.freeze({ + async* [Symbol.asyncIterator]() { + await Promise.resolve(); + yield 1; + yield 2; + yield 3; + }, +}); + describe('frozen object', () => { describe('serialize', () => { it('supports Objects', () => { - const example = ({ hello: 'world' }) as { hello: string }; - Object.freeze(example); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(Object.isFrozen(back)).toBe(true); expect(back.constructor).toBe(Object); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', () => { - const example = {} as Record; - example.a = example; - example.b = example; - Object.freeze(example); - const result = serialize(example); + const result = serialize(RECURSIVE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(Object.isFrozen(back)).toBe(true); expect(back.a).toBe(back); expect(back.b).toBe(back); }); it('supports Symbol.iterator', () => { - const example = ({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - Object.freeze(example); - const result = serialize(example); + const result = serialize(ITERABLE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(Object.isFrozen(back)).toBe(true); expect(back.constructor).toBe(Object); expect([...back]).toMatchObject([1, 2, 3]); @@ -54,76 +73,59 @@ describe('frozen object', () => { }); describe('serializeAsync', () => { it('supports Objects', async () => { - const example = Promise.resolve(Object.freeze({ hello: 'world' }) as { hello: string }); - const result = await serializeAsync(example); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>>(result); + const back = await deserialize>(result); expect(Object.isFrozen(back)).toBe(true); expect(back.constructor).toBe(Object); - expect(back.hello).toBe((await example).hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', async () => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - Object.freeze(example); - const result = await serializeAsync(example); + const result = await serializeAsync(ASYNC_RECURSIVE); expect(result).toMatchSnapshot(); - const back = deserialize>>(result); + const back = deserialize(result); expect(Object.isFrozen(back)).toBe(true); expect(await back.a).toBe(back); expect(await back.b).toBe(back); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(Object.freeze({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await serializeAsync(example); + const result = await serializeAsync(Promise.resolve(ITERABLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>>(result); + const back = await deserialize>(result); expect(Object.isFrozen(back)).toBe(true); expect(back.constructor).toBe(Object); expect([...back]).toMatchObject([1, 2, 3]); }); + it('supports Symbol.asyncIterator', async () => { + const result = await serializeAsync(ASYNC_ITERABLE); + expect(result).toMatchSnapshot(); + const back = deserialize(result); + expect(Object.isFrozen(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect(Symbol.asyncIterator in back).toBe(true); + }); }); describe('toJSON', () => { it('supports Objects', () => { - const example = Object.freeze({ hello: 'world' }) as { hello: string }; - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(Object.isFrozen(back)).toBe(true); expect(back.constructor).toBe(Object); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', () => { - const example = {} as Record; - example.a = example; - example.b = example; - Object.freeze(example); - const result = toJSON(example); + const result = toJSON(RECURSIVE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(Object.isFrozen(back)).toBe(true); expect(back.a).toBe(back); expect(back.b).toBe(back); }); it('supports Symbol.iterator', () => { - const example = ({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - Object.freeze(example); - const result = toJSON(example); + const result = toJSON(ITERABLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(Object.isFrozen(back)).toBe(true); expect(back.constructor).toBe(Object); expect([...back]).toMatchObject([1, 2, 3]); @@ -131,41 +133,37 @@ describe('frozen object', () => { }); describe('toJSONAsync', () => { it('supports Objects', async () => { - const example = Promise.resolve(Object.freeze({ hello: 'world' }) as { hello: string }); - const result = await toJSONAsync(example); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>>(result); + const back = await fromJSON>(result); expect(Object.isFrozen(back)).toBe(true); expect(back.constructor).toBe(Object); - expect(back.hello).toBe((await example).hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', async () => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - Object.freeze(example); - const result = await toJSONAsync(example); + const result = await toJSONAsync(ASYNC_RECURSIVE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>>(result); + const back = fromJSON(result); expect(Object.isFrozen(back)).toBe(true); expect(await back.a).toBe(back); expect(await back.b).toBe(back); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(Object.freeze({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await toJSONAsync(example); + const result = await toJSONAsync(Promise.resolve(ITERABLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>>(result); + const back = await fromJSON>(result); expect(Object.isFrozen(back)).toBe(true); expect(back.constructor).toBe(Object); expect([...back]).toMatchObject([1, 2, 3]); }); + it('supports Symbol.asyncIterator', async () => { + const result = await toJSONAsync(ASYNC_ITERABLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromJSON(result); + expect(Object.isFrozen(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect(Symbol.asyncIterator in back).toBe(true); + }); }); describe('crossSerialize', () => { it('supports Objects', () => { @@ -175,195 +173,308 @@ describe('frozen object', () => { expect(result).toMatchSnapshot(); }); it('supports self-recursion', () => { - const example = {} as Record; - example.a = example; - example.b = example; - Object.freeze(example); - const result = crossSerialize(example); + const result = crossSerialize(RECURSIVE); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', () => { - const example = ({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - Object.freeze(example); - const result = crossSerialize(example); + const result = crossSerialize(ITERABLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Objects', () => { - const example = ({ hello: 'world' }) as { hello: string }; - Object.freeze(example); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports self-recursion', () => { - const example = {} as Record; - example.a = example; - example.b = example; - Object.freeze(example); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(RECURSIVE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', () => { - const example = ({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - Object.freeze(example); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(ITERABLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports Objects', async () => { - const example = Promise.resolve(Object.freeze({ hello: 'world' }) as { hello: string }); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); it('supports self-recursion', async () => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - Object.freeze(example); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(ASYNC_RECURSIVE); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(Object.freeze({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(Promise.resolve(ITERABLE)); + expect(result).toMatchSnapshot(); + }); + it('supports Symbol.asyncIterator', async () => { + const result = await crossSerializeAsync(ASYNC_ITERABLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Objects', async () => { - const example = Promise.resolve(Object.freeze({ hello: 'world' }) as { hello: string }); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync( + Promise.resolve(EXAMPLE), + { scopeId: 'example' }, + ); expect(result).toMatchSnapshot(); }); it('supports self-recursion', async () => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - Object.freeze(example); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync(ASYNC_RECURSIVE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(Object.freeze({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync( + Promise.resolve(ITERABLE), + { scopeId: 'example' }, + ); + expect(result).toMatchSnapshot(); + }); + it('supports Symbol.asyncIterator', async () => { + const result = await crossSerializeAsync(ASYNC_ITERABLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports Objects', async () => new Promise((done) => { - const example = Promise.resolve(Object.freeze({ hello: 'world' }) as { hello: string }); - crossSerializeStream(example, { + it('supports Objects', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self-recursion', async () => new Promise((done) => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - Object.freeze(example); - crossSerializeStream(Promise.resolve(example), { + it('supports self-recursion', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_RECURSIVE, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.iterator', async () => new Promise((done) => { - const example = Promise.resolve(Object.freeze({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(ITERABLE), { + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); }, - }) as Iterable); - crossSerializeStream(example, { + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_ITERABLE, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Objects', async () => new Promise((done) => { - const example = Promise.resolve(Object.freeze({ hello: 'world' }) as { hello: string }); - crossSerializeStream(example, { + it('supports Objects', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self-recursion', async () => new Promise((done) => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - Object.freeze(example); - crossSerializeStream(Promise.resolve(example), { + it('supports self-recursion', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_RECURSIVE, { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.iterator', async () => new Promise((done) => { - const example = Promise.resolve(Object.freeze({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(ITERABLE), { + scopeId: 'example', + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); }, - }) as Iterable); - crossSerializeStream(example, { + }); + })); + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_ITERABLE, { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Objects', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(Object.isFrozen(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect(back.hello).toBe(EXAMPLE.hello); + }); + it('supports self-recursion', () => { + const result = toCrossJSON(RECURSIVE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(Object.isFrozen(back)).toBe(true); + expect(back.a).toBe(back); + expect(back.b).toBe(back); + }); + it('supports Symbol.iterator', () => { + const result = toCrossJSON(ITERABLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(Object.isFrozen(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect([...back]).toMatchObject([1, 2, 3]); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Objects', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(Object.isFrozen(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect(back.hello).toBe(EXAMPLE.hello); + }); + it('supports self-recursion', async () => { + const result = await toCrossJSONAsync(ASYNC_RECURSIVE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(Object.isFrozen(back)).toBe(true); + expect(await back.a).toBe(back); + expect(await back.b).toBe(back); + }); + it('supports Symbol.iterator', async () => { + const result = await toCrossJSONAsync(Promise.resolve(ITERABLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(Object.isFrozen(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect([...back]).toMatchObject([1, 2, 3]); + }); + it('supports Symbol.asyncIterator', async () => { + const result = await toCrossJSONAsync(ASYNC_ITERABLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(Object.isFrozen(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect(Symbol.asyncIterator in back).toBe(true); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Objects', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports self-recursion', async () => new Promise((resolve, reject) => { + toCrossJSONStream(ASYNC_RECURSIVE, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(ITERABLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { + toCrossJSONStream(ASYNC_ITERABLE, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/iterable.test.ts b/packages/seroval/test/iterable.test.ts index e38cc653..b02b1475 100644 --- a/packages/seroval/test/iterable.test.ts +++ b/packages/seroval/test/iterable.test.ts @@ -6,29 +6,34 @@ import { crossSerializeStream, deserialize, Feature, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; +const EXAMPLE = { + title: 'Hello World', + * [Symbol.iterator](): Generator { + yield 1; + yield 2; + yield 3; + }, +}; + describe('Iterable', () => { describe('serialize', () => { it('supports Iterables', () => { - const example = { - title: 'Hello World', - * [Symbol.iterator](): unknown { - yield 1; - yield 2; - yield 3; - }, - }; - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize & { title: string }>(result); - expect(back.title).toBe(example.title); - expect(Symbol.iterator in back).toBeTruthy(); + const back = deserialize(result); + expect(back.title).toBe(EXAMPLE.title); + expect(Symbol.iterator in back).toBe(true); const iterator = back[Symbol.iterator](); expect(iterator.next().value).toBe(1); expect(iterator.next().value).toBe(2); @@ -37,19 +42,11 @@ describe('Iterable', () => { }); describe('serializeAsync', () => { it('supports Iterables', async () => { - const example = Promise.resolve({ - title: 'Hello World', - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }); - const result = await serializeAsync(example); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize(result); - expect(back.title).toBe((await example).title); - expect(Symbol.iterator in back).toBeTruthy(); + const back = await deserialize>(result); + expect(back.title).toBe(EXAMPLE.title); + expect(Symbol.iterator in back).toBe(true); const iterator = back[Symbol.iterator](); expect(iterator.next().value).toBe(1); expect(iterator.next().value).toBe(2); @@ -58,19 +55,11 @@ describe('Iterable', () => { }); describe('toJSON', () => { it('supports Iterables', () => { - const example = { - title: 'Hello World', - * [Symbol.iterator](): unknown { - yield 1; - yield 2; - yield 3; - }, - }; - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON & { title: string }>(result); - expect(back.title).toBe(example.title); - expect(Symbol.iterator in back).toBeTruthy(); + const back = fromJSON(result); + expect(back.title).toBe(EXAMPLE.title); + expect(Symbol.iterator in back).toBe(true); const iterator = back[Symbol.iterator](); expect(iterator.next().value).toBe(1); expect(iterator.next().value).toBe(2); @@ -79,19 +68,11 @@ describe('Iterable', () => { }); describe('toJSONAsync', () => { it('supports Iterables', async () => { - const example = Promise.resolve({ - title: 'Hello World', - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }); - const result = await toJSONAsync(example); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON(result); - expect(back.title).toBe((await example).title); - expect(Symbol.iterator in back).toBeTruthy(); + const back = await fromJSON>(result); + expect(back.title).toBe(EXAMPLE.title); + expect(Symbol.iterator in back).toBe(true); const iterator = back[Symbol.iterator](); expect(iterator.next().value).toBe(1); expect(iterator.next().value).toBe(2); @@ -100,169 +81,121 @@ describe('Iterable', () => { }); describe('crossSerialize', () => { it('supports Iterables', () => { - const example = { - title: 'Hello World', - * [Symbol.iterator](): unknown { - yield 1; - yield 2; - yield 3; - }, - }; - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Iterables', () => { - const example = { - title: 'Hello World', - * [Symbol.iterator](): unknown { - yield 1; - yield 2; - yield 3; - }, - }; - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports Iterables', async () => { - const example = Promise.resolve({ - title: 'Hello World', - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Iterables', async () => { - const example = Promise.resolve({ - title: 'Hello World', - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync( + Promise.resolve(EXAMPLE), + { scopeId: 'example' }, + ); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports Iterables', async () => new Promise((done) => { - const example = Promise.resolve({ - title: 'Hello World', - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }); - crossSerializeStream(example, { + it('supports Iterables', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Iterables', async () => new Promise((done) => { - const example = Promise.resolve({ - title: 'Hello World', - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }); - crossSerializeStream(example, { + it('supports Iterables', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); describe('compat', () => { - it('should use Symbol.iterator instead of Array.values.', () => { - const example = { - * [Symbol.iterator](): unknown { - yield example; - }, - }; - expect(serialize(example, { - disabledFeatures: Feature.ArrayPrototypeValues, - })).toMatchSnapshot(); - }); - it('should use method shorthand instead of arrow functions.', () => { - const example = { - * [Symbol.iterator](): unknown { - yield example; - }, - }; - expect(serialize(example, { + it('should use function expression instead of arrow functions.', () => { + expect(serialize(EXAMPLE, { disabledFeatures: Feature.ArrowFunction, })).toMatchSnapshot(); }); - it('should use functions instead of method shorthand.', () => { - const example = { - * [Symbol.iterator](): unknown { - yield example; - }, - }; - expect(serialize(example, { - disabledFeatures: Feature.MethodShorthand | Feature.ArrowFunction, - })).toMatchSnapshot(); - }); }); describe('compat#toJSON', () => { - it('should use Symbol.iterator instead of Array.values.', () => { - const example = { - * [Symbol.iterator](): unknown { - yield example; - }, - }; - const result = toJSON(example, { - disabledFeatures: Feature.ArrayPrototypeValues, + it('should use function expression instead of arrow functions.', () => { + const result = toJSON(EXAMPLE, { + disabledFeatures: Feature.ArrowFunction, }); expect(JSON.stringify(result)).toMatchSnapshot(); expect(compileJSON(result)).toMatchSnapshot(); }); - it('should use method shorthand instead of arrow functions.', () => { - const example = { - * [Symbol.iterator](): unknown { - yield example; - }, - }; - const result = toJSON(example, { - disabledFeatures: Feature.ArrowFunction, + }); + describe('toCrossJSON', () => { + it('supports Iterables', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), }); + expect(back.title).toBe(EXAMPLE.title); + expect(Symbol.iterator in back).toBe(true); + const iterator = back[Symbol.iterator](); + expect(iterator.next().value).toBe(1); + expect(iterator.next().value).toBe(2); + expect(iterator.next().value).toBe(3); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Iterables', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - expect(compileJSON(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(back.title).toBe(EXAMPLE.title); + expect(Symbol.iterator in back).toBe(true); + const iterator = back[Symbol.iterator](); + expect(iterator.next().value).toBe(1); + expect(iterator.next().value).toBe(2); + expect(iterator.next().value).toBe(3); }); - it('should use functions instead of method shorthand.', () => { - const example = { - * [Symbol.iterator](): unknown { - yield example; + }); + describe('toCrossJSONStream', () => { + it('supports Iterables', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); }, - }; - const result = toJSON(example, { - disabledFeatures: Feature.MethodShorthand | Feature.ArrowFunction, }); - expect(JSON.stringify(result)).toMatchSnapshot(); - expect(compileJSON(result)).toMatchSnapshot(); - }); + })); }); }); diff --git a/packages/seroval/test/map.test.ts b/packages/seroval/test/map.test.ts index e5c67c4c..d27609d4 100644 --- a/packages/seroval/test/map.test.ts +++ b/packages/seroval/test/map.test.ts @@ -6,50 +6,55 @@ import { crossSerializeStream, deserialize, Feature, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; +const EXAMPLE = new Map([[1, 2], [3, 4]]); +const RECURSIVE = new Map(); +RECURSIVE.set(RECURSIVE, RECURSIVE); + +const ASYNC_RECURSIVE = new Map, Promise>(); +ASYNC_RECURSIVE.set(Promise.resolve(ASYNC_RECURSIVE), Promise.resolve(ASYNC_RECURSIVE)); + describe('Map', () => { describe('serialize', () => { it('supports Map', () => { - const example = new Map([[1, 2], [3, 4]]); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(back).toBeInstanceOf(Map); - expect(back.get(1)).toBe(example.get(1)); - expect(back.get(3)).toBe(example.get(3)); + expect(back.get(1)).toBe(EXAMPLE.get(1)); + expect(back.get(3)).toBe(EXAMPLE.get(3)); }); it('supports self-recursion', () => { - const example: Map = new Map(); - example.set(example, example); - const result = serialize(example); + const result = serialize(RECURSIVE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(back.has(back)).toBe(true); expect(back.get(back)).toBe(back); }); }); describe('serializeAsync', () => { it('supports Map', async () => { - const example = new Map([[1, 2], [3, 4]]); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(Map); - expect(back.get(1)).toBe(example.get(1)); - expect(back.get(3)).toBe(example.get(3)); + expect(back.get(1)).toBe(EXAMPLE.get(1)); + expect(back.get(3)).toBe(EXAMPLE.get(3)); }); it('supports self-recursion', async () => { - const example: Map, Promise> = new Map(); - example.set(Promise.resolve(example), Promise.resolve(example)); - const result = await serializeAsync(example); + const result = await serializeAsync(ASYNC_RECURSIVE); expect(result).toMatchSnapshot(); - const back = deserialize, Promise>>(result); + const back = deserialize(result); for (const [key, value] of back) { expect(await key).toBe(back); expect(await value).toBe(back); @@ -58,40 +63,34 @@ describe('Map', () => { }); describe('toJSON', () => { it('supports Map', () => { - const example = new Map([[1, 2], [3, 4]]); - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(Map); - expect(back.get(1)).toBe(example.get(1)); - expect(back.get(3)).toBe(example.get(3)); + expect(back.get(1)).toBe(EXAMPLE.get(1)); + expect(back.get(3)).toBe(EXAMPLE.get(3)); }); it('supports self-recursion', () => { - const example: Map = new Map(); - example.set(example, example); - const result = toJSON(example); + const result = toJSON(RECURSIVE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(back.has(back)).toBe(true); expect(back.get(back)).toBe(back); }); }); describe('toJSONAsync', () => { it('supports Map', async () => { - const example = new Map([[1, 2], [3, 4]]); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>>(result); + const back = await fromJSON>(result); expect(back).toBeInstanceOf(Map); - expect(back.get(1)).toBe(example.get(1)); - expect(back.get(3)).toBe(example.get(3)); + expect(back.get(1)).toBe(EXAMPLE.get(1)); + expect(back.get(3)).toBe(EXAMPLE.get(3)); }); it('supports self-recursion', async () => { - const example: Map, Promise> = new Map(); - example.set(Promise.resolve(example), Promise.resolve(example)); - const result = await toJSONAsync(example); + const result = await toJSONAsync(ASYNC_RECURSIVE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON, Promise>>(result); + const back = fromJSON(result); for (const [key, value] of back) { expect(await key).toBe(back); expect(await value).toBe(back); @@ -100,128 +99,197 @@ describe('Map', () => { }); describe('crossSerialize', () => { it('supports Map', () => { - const example = new Map([[1, 2], [3, 4]]); - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); it('supports self-recursion', () => { - const example: Map = new Map(); - example.set(example, example); - const result = crossSerialize(example); + const result = crossSerialize(RECURSIVE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Map', () => { - const example = new Map([[1, 2], [3, 4]]); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports self-recursion', () => { - const example: Map = new Map(); - example.set(example, example); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(RECURSIVE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports Map', async () => { - const example = new Map([[1, 2], [3, 4]]); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); it('supports self-recursion', async () => { - const example: Map, Promise> = new Map(); - example.set(Promise.resolve(example), Promise.resolve(example)); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(ASYNC_RECURSIVE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Map', async () => { - const example = new Map([[1, 2], [3, 4]]); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync( + Promise.resolve(EXAMPLE), + { scopeId: 'example' }, + ); expect(result).toMatchSnapshot(); }); it('supports self-recursion', async () => { - const example: Map, Promise> = new Map(); - example.set(Promise.resolve(example), Promise.resolve(example)); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync(ASYNC_RECURSIVE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports Map', async () => new Promise((done) => { - const example = new Map([[1, 2], [3, 4]]); - crossSerializeStream(Promise.resolve(example), { + it('supports Map', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self-recursion', async () => new Promise((done) => { - const example: Map, Promise> = new Map(); - example.set(Promise.resolve(example), Promise.resolve(example)); - crossSerializeStream(example, { + it('supports self-recursion', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_RECURSIVE, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Map', async () => new Promise((done) => { - const example = new Map([[1, 2], [3, 4]]); - crossSerializeStream(Promise.resolve(example), { + it('supports Map', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self-recursion', async () => new Promise((done) => { - const example: Map, Promise> = new Map(); - example.set(Promise.resolve(example), Promise.resolve(example)); - crossSerializeStream(example, { + it('supports self-recursion', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_RECURSIVE, { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Map', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Map); + expect(back.get(1)).toBe(EXAMPLE.get(1)); + expect(back.get(3)).toBe(EXAMPLE.get(3)); + }); + it('supports self-recursion', () => { + const result = toCrossJSON(RECURSIVE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back.has(back)).toBe(true); + expect(back.get(back)).toBe(back); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Map', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Map); + expect(back.get(1)).toBe(EXAMPLE.get(1)); + expect(back.get(3)).toBe(EXAMPLE.get(3)); + }); + it('supports self-recursion', async () => { + const result = await toCrossJSONAsync(ASYNC_RECURSIVE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + for (const [key, value] of back) { + expect(await key).toBe(back); + expect(await value).toBe(back); + } + }); + }); + describe('crossSerializeStream', () => { + it('supports Map', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports self-recursion', async () => new Promise((resolve, reject) => { + toCrossJSONStream(ASYNC_RECURSIVE, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); describe('compat', () => { it('should fallback to Symbol.iterator', () => { - expect(serialize(new Map(), { + expect(serialize(EXAMPLE, { disabledFeatures: Feature.Map, })).toMatchSnapshot(); }); it('should throw an error for unsupported target', () => { - expect(() => serialize(new Map(), { + expect(() => serialize(EXAMPLE, { disabledFeatures: Feature.Map | Feature.Symbol, })).toThrowErrorMatchingSnapshot(); }); }); describe('compat#toJSON', () => { it('should fallback to Symbol.iterator', () => { - expect(JSON.stringify(toJSON(new Map(), { + expect(JSON.stringify(toJSON(EXAMPLE, { disabledFeatures: Feature.Map, }))).toMatchSnapshot(); }); it('should throw an error for unsupported target', () => { - expect(() => toJSON(new Map(), { + expect(() => toJSON(EXAMPLE, { disabledFeatures: Feature.Map | Feature.Symbol, })).toThrowErrorMatchingSnapshot(); }); diff --git a/packages/seroval/test/mutual-cycle.test.ts b/packages/seroval/test/mutual-cycle.test.ts index 77e4460a..36c299db 100644 --- a/packages/seroval/test/mutual-cycle.test.ts +++ b/packages/seroval/test/mutual-cycle.test.ts @@ -9,6 +9,10 @@ import { crossSerialize, crossSerializeAsync, crossSerializeStream, + toCrossJSON, + toCrossJSONAsync, + fromCrossJSON, + toCrossJSONStream, } from '../src'; describe('mutual cyclic references', () => { @@ -18,10 +22,10 @@ describe('mutual cyclic references', () => { const b: unknown[] = []; a[0] = b; b[0] = a; - const example = [a, b]; + const example = [a, b] as const; const result = serialize(example); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back[0]).toBe(back[1][0]); expect(back[1]).toBe(back[0][0]); }); @@ -30,10 +34,10 @@ describe('mutual cyclic references', () => { const b: Record = {}; a[0] = b; b[0] = a; - const example = [a, b]; + const example = [a, b] as const; const result = serialize(example); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back[0]).toBe(back[1][0]); expect(back[1]).toBe(back[0][0]); }); @@ -42,10 +46,10 @@ describe('mutual cyclic references', () => { const b: Record = {}; a[0] = b; b[0] = a; - const example = [a, b]; + const example = [a, b] as const; const result = serialize(example); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back[0]).toBe(back[1][0]); expect(back[1]).toBe(back[0][0]); }); @@ -56,10 +60,10 @@ describe('mutual cyclic references', () => { const b: Promise[] = []; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; const result = await serializeAsync(example); expect(result).toMatchSnapshot(); - const back = deserialize[][]>(result); + const back = deserialize(result); expect(back[0]).toStrictEqual(await back[1][0]); expect(back[1]).toStrictEqual(await back[0][0]); }); @@ -68,10 +72,10 @@ describe('mutual cyclic references', () => { const b: Record> = {}; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; const result = await serializeAsync(example); expect(result).toMatchSnapshot(); - const back = deserialize[][]>(result); + const back = deserialize(result); expect(back[0]).toStrictEqual(await back[1][0]); expect(back[1]).toStrictEqual(await back[0][0]); }); @@ -80,10 +84,10 @@ describe('mutual cyclic references', () => { const b: Record> = {}; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; const result = await serializeAsync(example); expect(result).toMatchSnapshot(); - const back = deserialize[][]>(result); + const back = deserialize(result); expect(back[0]).toStrictEqual(await back[1][0]); expect(back[1]).toStrictEqual(await back[0][0]); }); @@ -94,10 +98,10 @@ describe('mutual cyclic references', () => { const b: unknown[] = []; a[0] = b; b[0] = a; - const example = [a, b]; + const example = [a, b] as const; const result = toJSON(example); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back[0]).toBe(back[1][0]); expect(back[1]).toBe(back[0][0]); }); @@ -106,10 +110,10 @@ describe('mutual cyclic references', () => { const b: Record = {}; a[0] = b; b[0] = a; - const example = [a, b]; + const example = [a, b] as const; const result = toJSON(example); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back[0]).toBe(back[1][0]); expect(back[1]).toBe(back[0][0]); }); @@ -118,10 +122,10 @@ describe('mutual cyclic references', () => { const b: Record = {}; a[0] = b; b[0] = a; - const example = [a, b]; + const example = [a, b] as const; const result = toJSON(example); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back[0]).toBe(back[1][0]); expect(back[1]).toBe(back[0][0]); }); @@ -132,10 +136,10 @@ describe('mutual cyclic references', () => { const b: Promise[] = []; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; const result = await toJSONAsync(example); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON[][]>(result); + const back = fromJSON(result); expect(back[0]).toStrictEqual(await back[1][0]); expect(back[1]).toStrictEqual(await back[0][0]); }); @@ -144,10 +148,10 @@ describe('mutual cyclic references', () => { const b: Record> = {}; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; const result = await toJSONAsync(example); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON[][]>(result); + const back = fromJSON(result); expect(back[0]).toStrictEqual(await back[1][0]); expect(back[1]).toStrictEqual(await back[0][0]); }); @@ -156,10 +160,10 @@ describe('mutual cyclic references', () => { const b: Record> = {}; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; const result = await toJSONAsync(example); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON[][]>(result); + const back = fromJSON(result); expect(back[0]).toStrictEqual(await back[1][0]); expect(back[1]).toStrictEqual(await back[0][0]); }); @@ -170,7 +174,7 @@ describe('mutual cyclic references', () => { const b: unknown[] = []; a[0] = b; b[0] = a; - const example = [a, b]; + const example = [a, b] as const; const result = crossSerialize(example); expect(result).toMatchSnapshot(); }); @@ -179,7 +183,7 @@ describe('mutual cyclic references', () => { const b: Record = {}; a[0] = b; b[0] = a; - const example = [a, b]; + const example = [a, b] as const; const result = crossSerialize(example); expect(result).toMatchSnapshot(); }); @@ -188,7 +192,7 @@ describe('mutual cyclic references', () => { const b: Record = {}; a[0] = b; b[0] = a; - const example = [a, b]; + const example = [a, b] as const; const result = crossSerialize(example); expect(result).toMatchSnapshot(); }); @@ -198,7 +202,7 @@ describe('mutual cyclic references', () => { const b: unknown[] = []; a[0] = b; b[0] = a; - const example = [a, b]; + const example = [a, b] as const; const result = crossSerialize(example, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); @@ -207,7 +211,7 @@ describe('mutual cyclic references', () => { const b: Record = {}; a[0] = b; b[0] = a; - const example = [a, b]; + const example = [a, b] as const; const result = crossSerialize(example, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); @@ -216,7 +220,7 @@ describe('mutual cyclic references', () => { const b: Record = {}; a[0] = b; b[0] = a; - const example = [a, b]; + const example = [a, b] as const; const result = crossSerialize(example, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); @@ -228,7 +232,7 @@ describe('mutual cyclic references', () => { const b: Promise[] = []; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; const result = await crossSerializeAsync(example); expect(result).toMatchSnapshot(); }); @@ -237,7 +241,7 @@ describe('mutual cyclic references', () => { const b: Record> = {}; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; const result = await crossSerializeAsync(example); expect(result).toMatchSnapshot(); }); @@ -246,7 +250,7 @@ describe('mutual cyclic references', () => { const b: Record> = {}; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; const result = await crossSerializeAsync(example); expect(result).toMatchSnapshot(); }); @@ -256,7 +260,7 @@ describe('mutual cyclic references', () => { const b: Promise[] = []; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; const result = await crossSerializeAsync(example, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); @@ -265,7 +269,7 @@ describe('mutual cyclic references', () => { const b: Record> = {}; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; const result = await crossSerializeAsync(example, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); @@ -274,107 +278,269 @@ describe('mutual cyclic references', () => { const b: Record> = {}; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; const result = await crossSerializeAsync(example, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports Arrays and Arrays', async () => new Promise((done) => { + it('supports Arrays and Arrays', async () => new Promise((resolve, reject) => { const a: Promise[] = []; const b: Promise[] = []; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; crossSerializeStream(example, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Arrays and Objects', async () => new Promise((done) => { + it('supports Arrays and Objects', async () => new Promise((resolve, reject) => { const a: Promise[] = []; const b: Record> = {}; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; crossSerializeStream(example, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Objects and Objects', async () => new Promise((done) => { + it('supports Objects and Objects', async () => new Promise((resolve, reject) => { const a: Record> = {}; const b: Record> = {}; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; crossSerializeStream(example, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Arrays and Arrays', async () => new Promise((done) => { + it('supports Arrays and Arrays', async () => new Promise((resolve, reject) => { const a: Promise[] = []; const b: Promise[] = []; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; crossSerializeStream(example, { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Arrays and Objects', async () => new Promise((done) => { + it('supports Arrays and Objects', async () => new Promise((resolve, reject) => { const a: Promise[] = []; const b: Record> = {}; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; crossSerializeStream(example, { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Objects and Objects', async () => new Promise((done) => { + it('supports Objects and Objects', async () => new Promise((resolve, reject) => { const a: Record> = {}; const b: Record> = {}; a[0] = Promise.resolve(b); b[0] = Promise.resolve(a); - const example = [a, b]; + const example = [a, b] as const; crossSerializeStream(example, { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Arrays and Arrays', () => { + const a: unknown[] = []; + const b: unknown[] = []; + a[0] = b; + b[0] = a; + const example = [a, b] as const; + const result = toCrossJSON(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back[0]).toBe(back[1][0]); + expect(back[1]).toBe(back[0][0]); + }); + it('supports Arrays and Objects', () => { + const a: unknown[] = []; + const b: Record = {}; + a[0] = b; + b[0] = a; + const example = [a, b] as const; + const result = toCrossJSON(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back[0]).toBe(back[1][0]); + expect(back[1]).toBe(back[0][0]); + }); + it('supports Objects and Objects', () => { + const a: Record = {}; + const b: Record = {}; + a[0] = b; + b[0] = a; + const example = [a, b] as const; + const result = toCrossJSON(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back[0]).toBe(back[1][0]); + expect(back[1]).toBe(back[0][0]); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Arrays and Arrays', async () => { + const a: Promise[] = []; + const b: Promise[] = []; + a[0] = Promise.resolve(b); + b[0] = Promise.resolve(a); + const example = [a, b] as const; + const result = await toCrossJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back[0]).toStrictEqual(await back[1][0]); + expect(back[1]).toStrictEqual(await back[0][0]); + }); + it('supports Arrays and Objects', async () => { + const a: Promise[] = []; + const b: Record> = {}; + a[0] = Promise.resolve(b); + b[0] = Promise.resolve(a); + const example = [a, b] as const; + const result = await toCrossJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back[0]).toStrictEqual(await back[1][0]); + expect(back[1]).toStrictEqual(await back[0][0]); + }); + it('supports Objects and Objects', async () => { + const a: Record> = {}; + const b: Record> = {}; + a[0] = Promise.resolve(b); + b[0] = Promise.resolve(a); + const example = [a, b] as const; + const result = await toCrossJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back[0]).toStrictEqual(await back[1][0]); + expect(back[1]).toStrictEqual(await back[0][0]); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Arrays and Arrays', async () => new Promise((resolve, reject) => { + const a: Promise[] = []; + const b: Promise[] = []; + a[0] = Promise.resolve(b); + b[0] = Promise.resolve(a); + const example = [a, b] as const; + toCrossJSONStream(example, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Arrays and Objects', async () => new Promise((resolve, reject) => { + const a: Promise[] = []; + const b: Record> = {}; + a[0] = Promise.resolve(b); + b[0] = Promise.resolve(a); + const example = [a, b] as const; + toCrossJSONStream(example, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Objects and Objects', async () => new Promise((resolve, reject) => { + const a: Record> = {}; + const b: Record> = {}; + a[0] = Promise.resolve(b); + b[0] = Promise.resolve(a); + const example = [a, b] as const; + toCrossJSONStream(example, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/null-constructor.test.ts b/packages/seroval/test/null-constructor.test.ts index 8a51aa98..7026484f 100644 --- a/packages/seroval/test/null-constructor.test.ts +++ b/packages/seroval/test/null-constructor.test.ts @@ -1,367 +1,487 @@ import { describe, it, expect } from 'vitest'; import { + Feature, compileJSON, crossSerialize, crossSerializeAsync, crossSerializeStream, deserialize, - Feature, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; +const EXAMPLE = Object.assign(Object.create(null), { hello: 'world' }) as { hello: string }; + +const RECURSIVE = Object.create(null) as Record; +RECURSIVE.a = RECURSIVE; +RECURSIVE.b = RECURSIVE; + +const ITERABLE = Object.assign(Object.create(null), { + * [Symbol.iterator]() { + yield 1; + yield 2; + yield 3; + }, +}) as Iterable; + +const ASYNC_RECURSIVE = Object.create(null) as Record>; +ASYNC_RECURSIVE.a = Promise.resolve(ASYNC_RECURSIVE); +ASYNC_RECURSIVE.b = Promise.resolve(ASYNC_RECURSIVE); + +const ASYNC_ITERABLE = Object.assign(Object.create(null), { + async* [Symbol.asyncIterator]() { + await Promise.resolve(); + yield 1; + yield 2; + yield 3; + }, +}) as AsyncIterable; + describe('null-constructor', () => { describe('serialize', () => { it('supports Object.create(null)', () => { - const example = Object.assign(Object.create(null), { hello: 'world' }) as { hello: string }; - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(back.constructor).toBeUndefined(); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', () => { - const example = Object.create(null) as Record; - example.a = example; - example.b = example; - const result = serialize(example); + const result = serialize(RECURSIVE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(back.a).toBe(back); expect(back.b).toBe(back); }); it('supports Symbol.iterator', () => { - const example = Object.assign(Object.create(null), { - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - const result = serialize(example); + const result = serialize(ITERABLE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(back.constructor).toBeUndefined(); expect([...back]).toMatchObject([1, 2, 3]); }); }); describe('serializeAsync', () => { it('supports Object.create(null)', async () => { - const example = Promise.resolve(Object.assign(Object.create(null), { hello: 'world' }) as { hello: string }); - const result = await serializeAsync(example); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>>(result); + const back = await deserialize>(result); expect(back.constructor).toBeUndefined(); - expect(back.hello).toBe((await example).hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', async () => { - const example = Object.create(null) as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - const result = await serializeAsync(example); + const result = await serializeAsync(ASYNC_RECURSIVE); expect(result).toMatchSnapshot(); - const back = deserialize>>(result); + const back = deserialize(result); expect(await back.a).toBe(back); expect(await back.b).toBe(back); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(Object.assign(Object.create(null), { - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await serializeAsync(example); + const result = await serializeAsync(Promise.resolve(ITERABLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>>(result); + const back = await deserialize>(result); expect(back.constructor).toBeUndefined(); expect([...back]).toMatchObject([1, 2, 3]); }); + it('supports Symbol.asyncIterator', async () => { + const result = await serializeAsync(ASYNC_ITERABLE); + expect(result).toMatchSnapshot(); + const back = deserialize(result); + expect(back.constructor).toBeUndefined(); + expect(Symbol.asyncIterator in back).toBe(true); + }); }); describe('toJSON', () => { it('supports Object.create(null)', () => { - const example = Object.assign(Object.create(null), { hello: 'world' }) as { hello: string }; - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(back.constructor).toBeUndefined(); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', () => { - const example = Object.create(null) as Record; - example.a = example; - example.b = example; - const result = toJSON(example); + const result = toJSON(RECURSIVE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(back.a).toBe(back); expect(back.b).toBe(back); }); it('supports Symbol.iterator', () => { - const example = Object.assign(Object.create(null), { - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - const result = toJSON(example); + const result = toJSON(ITERABLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(back.constructor).toBeUndefined(); expect([...back]).toMatchObject([1, 2, 3]); }); }); describe('toJSONAsync', () => { it('supports Object.create(null)', async () => { - const example = Object.assign(Object.create(null), { hello: 'world' }) as { hello: string }; - const result = await toJSONAsync(example); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>>(result); + const back = await fromJSON>(result); expect(back.constructor).toBeUndefined(); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', async () => { - const example = Object.create(null) as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - const result = await toJSONAsync(example); + const result = await toJSONAsync(ASYNC_RECURSIVE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>>(result); + const back = fromJSON(result); expect(await back.a).toBe(back); expect(await back.b).toBe(back); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(Object.assign(Object.create(null), { - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await toJSONAsync(example); + const result = await toJSONAsync(Promise.resolve(ITERABLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>>(result); + const back = await fromJSON>(result); expect(back.constructor).toBeUndefined(); expect([...back]).toMatchObject([1, 2, 3]); }); + it('supports Symbol.asyncIterator', async () => { + const result = await toJSONAsync(ASYNC_ITERABLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromJSON(result); + expect(back.constructor).toBeUndefined(); + expect(Symbol.asyncIterator in back).toBe(true); + }); }); describe('crossSerialize', () => { - it('supports Objects', () => { - const example = Object.assign(Object.create(null), { hello: 'world' }) as { hello: string }; + it('supports Object.create(null)', () => { + const example = ({ hello: 'world' }) as { hello: string }; + Object.freeze(example); const result = crossSerialize(example); expect(result).toMatchSnapshot(); }); it('supports self-recursion', () => { - const example = Object.create(null) as Record; - example.a = example; - example.b = example; - const result = crossSerialize(example); + const result = crossSerialize(RECURSIVE); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', () => { - const example = Object.assign(Object.create(null), { - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - const result = crossSerialize(example); + const result = crossSerialize(ITERABLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { - it('supports Objects', () => { - const example = Object.assign(Object.create(null), { hello: 'world' }) as { hello: string }; - const result = crossSerialize(example, { scopeId: 'example' }); + it('supports Object.create(null)', () => { + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports self-recursion', () => { - const example = Object.create(null) as Record; - example.a = example; - example.b = example; - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(RECURSIVE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', () => { - const example = Object.assign(Object.create(null), { - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(ITERABLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { - it('supports Objects', async () => { - const example = Promise.resolve(Object.assign(Object.create(null), { hello: 'world' }) as { hello: string }); - const result = await crossSerializeAsync(example); + it('supports Object.create(null)', async () => { + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); it('supports self-recursion', async () => { - const example = Object.create(null) as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(ASYNC_RECURSIVE); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(Object.assign(Object.create(null), { - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(Promise.resolve(ITERABLE)); + expect(result).toMatchSnapshot(); + }); + it('supports Symbol.asyncIterator', async () => { + const result = await crossSerializeAsync(ASYNC_ITERABLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { - it('supports Objects', async () => { - const example = Promise.resolve(Object.assign(Object.create(null), { hello: 'world' }) as { hello: string }); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + it('supports Object.create(null)', async () => { + const result = await crossSerializeAsync( + Promise.resolve(EXAMPLE), + { scopeId: 'example' }, + ); expect(result).toMatchSnapshot(); }); it('supports self-recursion', async () => { - const example = Object.create(null) as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync(ASYNC_RECURSIVE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(Object.assign(Object.create(null), { - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync( + Promise.resolve(ITERABLE), + { scopeId: 'example' }, + ); + expect(result).toMatchSnapshot(); + }); + it('supports Symbol.asyncIterator', async () => { + const result = await crossSerializeAsync(ASYNC_ITERABLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports Objects', async () => new Promise((done) => { - const example = Promise.resolve(Object.assign(Object.create(null), { hello: 'world' }) as { hello: string }); - crossSerializeStream(example, { + it('supports Object.create(null)', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self-recursion', async () => new Promise((done) => { - const example = Object.create(null) as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - crossSerializeStream(Promise.resolve(example), { + it('supports self-recursion', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_RECURSIVE, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.iterator', async () => new Promise((done) => { - const example = Promise.resolve(Object.assign(Object.create(null), { - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(ITERABLE), { + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); }, - }) as Iterable); - crossSerializeStream(example, { + }); + })); + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_ITERABLE, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Objects', async () => new Promise((done) => { - const example = Promise.resolve(Object.assign(Object.create(null), { hello: 'world' }) as { hello: string }); - crossSerializeStream(example, { + it('supports Object.create(null)', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self-recursion', async () => new Promise((done) => { - const example = Object.create(null) as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - crossSerializeStream(Promise.resolve(example), { + it('supports self-recursion', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_RECURSIVE, { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.iterator', async () => new Promise((done) => { - const example = Promise.resolve(Object.assign(Object.create(null), { - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(ITERABLE), { + scopeId: 'example', + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); }, - }) as Iterable); - crossSerializeStream(example, { + }); + })); + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_ITERABLE, { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Object.create(null)', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + + expect(back.constructor).toBeUndefined(); + expect(back.hello).toBe(EXAMPLE.hello); + }); + it('supports self-recursion', () => { + const result = toCrossJSON(RECURSIVE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + + expect(back.a).toBe(back); + expect(back.b).toBe(back); + }); + it('supports Symbol.iterator', () => { + const result = toCrossJSON(ITERABLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + + expect(back.constructor).toBeUndefined(); + expect([...back]).toMatchObject([1, 2, 3]); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Object.create(null)', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + + expect(back.constructor).toBeUndefined(); + expect(back.hello).toBe(EXAMPLE.hello); + }); + it('supports self-recursion', async () => { + const result = await toCrossJSONAsync(ASYNC_RECURSIVE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + + expect(await back.a).toBe(back); + expect(await back.b).toBe(back); + }); + it('supports Symbol.iterator', async () => { + const result = await toCrossJSONAsync(Promise.resolve(ITERABLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(back.constructor).toBeUndefined(); + expect([...back]).toMatchObject([1, 2, 3]); + }); + it('supports Symbol.asyncIterator', async () => { + const result = await toCrossJSONAsync(ASYNC_ITERABLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back.constructor).toBeUndefined(); + expect(Symbol.asyncIterator in back).toBe(true); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Object.create(null)', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports self-recursion', async () => new Promise((resolve, reject) => { + toCrossJSONStream(ASYNC_RECURSIVE, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(ITERABLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { + toCrossJSONStream(ASYNC_ITERABLE, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); describe('compat', () => { it('should use manual assignment instead of Object.assign', () => { - const example = Object.assign(Object.create(null), { hello: 'world' }) as { hello: string }; - const result = serialize(example, { + const result = serialize(EXAMPLE, { disabledFeatures: Feature.ObjectAssign, }); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(back.constructor).toBeUndefined(); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); }); describe('compat#toJSON', () => { it('should use manual assignment instead of Object.assign', () => { - const example = Object.assign(Object.create(null), { hello: 'world' }) as { hello: string }; - const result = toJSON(example, { + const result = toJSON(EXAMPLE, { disabledFeatures: Feature.ObjectAssign, }); expect(JSON.stringify(result)).toMatchSnapshot(); expect(compileJSON(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(back.constructor).toBeUndefined(); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); }); }); diff --git a/packages/seroval/test/number.test.ts b/packages/seroval/test/number.test.ts index 9a1710ba..e5795eb0 100644 --- a/packages/seroval/test/number.test.ts +++ b/packages/seroval/test/number.test.ts @@ -5,6 +5,9 @@ import { crossSerializeStream, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; @@ -82,53 +85,165 @@ describe('number', () => { }); describe('crossSerializeStream', () => { - it('supports numbers', async () => new Promise((done) => { + it('supports numbers', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(0xDEADBEEF), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports NaN', async () => new Promise((done) => { + it('supports NaN', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(NaN), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Infinity', async () => new Promise((done) => { + it('supports Infinity', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Infinity), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports -Infinity', async () => new Promise((done) => { + it('supports -Infinity', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(-Infinity), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports -0', async () => new Promise((done) => { + it('supports -0', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(-0), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); + describe('toCrossJSON', () => { + it('supports numbers', () => { + const value = 0xDEADBEEF; + expect(JSON.stringify(toCrossJSON(value))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(NaN))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Infinity))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(-Infinity))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(-0))).toMatchSnapshot(); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports numbers', async () => { + const value = 0xDEADBEEF; + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(value))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(NaN))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Infinity))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(-Infinity))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(-0))), + ).toMatchSnapshot(); + }); + }); + describe('toCrossJSONStream', () => { + it('supports numbers', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(0xDEADBEEF), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports NaN', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(NaN), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Infinity', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Infinity), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports -Infinity', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(-Infinity), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports -0', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(-0), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); }, }); })); diff --git a/packages/seroval/test/object.test.ts b/packages/seroval/test/object.test.ts index a7bdf674..aadd9214 100644 --- a/packages/seroval/test/object.test.ts +++ b/packages/seroval/test/object.test.ts @@ -1,367 +1,487 @@ import { describe, it, expect } from 'vitest'; import { + Feature, compileJSON, crossSerialize, crossSerializeAsync, crossSerializeStream, deserialize, - Feature, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; +const EXAMPLE = { hello: 'world' }; + +const RECURSIVE = {} as Record; +RECURSIVE.a = RECURSIVE; +RECURSIVE.b = RECURSIVE; + +const ITERABLE = { + * [Symbol.iterator](): Generator { + yield 1; + yield 2; + yield 3; + }, +}; + +const ASYNC_RECURSIVE = {} as Record>; +ASYNC_RECURSIVE.a = Promise.resolve(ASYNC_RECURSIVE); +ASYNC_RECURSIVE.b = Promise.resolve(ASYNC_RECURSIVE); + +const ASYNC_ITERABLE = { + async* [Symbol.asyncIterator](): AsyncGenerator { + await Promise.resolve(); + yield 1; + yield 2; + yield 3; + }, +}; + describe('objects', () => { describe('serialize', () => { it('supports Objects', () => { - const example = ({ hello: 'world' }) as { hello: string }; - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(back.constructor).toBe(Object); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', () => { - const example = {} as Record; - example.a = example; - example.b = example; - const result = serialize(example); + const result = serialize(RECURSIVE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(back.a).toBe(back); expect(back.b).toBe(back); }); it('supports Symbol.iterator', () => { - const example = ({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - const result = serialize(example); + const result = serialize(ITERABLE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(back.constructor).toBe(Object); expect([...back]).toMatchObject([1, 2, 3]); }); }); describe('serializeAsync', () => { it('supports Objects', async () => { - const example = Promise.resolve(({ hello: 'world' }) as { hello: string }); - const result = await serializeAsync(example); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>>(result); + const back = await deserialize>(result); expect(back.constructor).toBe(Object); - expect(back.hello).toBe((await example).hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', async () => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - const result = await serializeAsync(example); + const result = await serializeAsync(ASYNC_RECURSIVE); expect(result).toMatchSnapshot(); - const back = deserialize>>(result); + const back = deserialize(result); expect(await back.a).toBe(back); expect(await back.b).toBe(back); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await serializeAsync(example); + const result = await serializeAsync(Promise.resolve(ITERABLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>>(result); + const back = await deserialize>(result); expect(back.constructor).toBe(Object); expect([...back]).toMatchObject([1, 2, 3]); }); + it('supports Symbol.asyncIterator', async () => { + const result = await serializeAsync(ASYNC_ITERABLE); + expect(result).toMatchSnapshot(); + const back = deserialize(result); + expect(back.constructor).toBe(Object); + expect(Symbol.asyncIterator in back).toBe(true); + }); }); describe('toJSON', () => { it('supports Objects', () => { - const example = ({ hello: 'world' }) as { hello: string }; - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(back.constructor).toBe(Object); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', () => { - const example = {} as Record; - example.a = example; - example.b = example; - const result = toJSON(example); + const result = toJSON(RECURSIVE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(back.a).toBe(back); expect(back.b).toBe(back); }); it('supports Symbol.iterator', () => { - const example = ({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - const result = toJSON(example); + const result = toJSON(ITERABLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(back.constructor).toBe(Object); expect([...back]).toMatchObject([1, 2, 3]); }); }); describe('toJSONAsync', () => { it('supports Objects', async () => { - const example = ({ hello: 'world' }) as { hello: string }; - const result = await toJSONAsync(example); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>>(result); + const back = await fromJSON>(result); expect(back.constructor).toBe(Object); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', async () => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - const result = await toJSONAsync(example); + const result = await toJSONAsync(ASYNC_RECURSIVE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>>(result); + const back = fromJSON(result); expect(await back.a).toBe(back); expect(await back.b).toBe(back); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await toJSONAsync(example); + const result = await toJSONAsync(Promise.resolve(ITERABLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>>(result); + const back = await fromJSON>(result); expect(back.constructor).toBe(Object); expect([...back]).toMatchObject([1, 2, 3]); }); + it('supports Symbol.asyncIterator', async () => { + const result = await toJSONAsync(ASYNC_ITERABLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromJSON(result); + expect(back.constructor).toBe(Object); + expect(Symbol.asyncIterator in back).toBe(true); + }); }); describe('crossSerialize', () => { it('supports Objects', () => { const example = ({ hello: 'world' }) as { hello: string }; + Object.freeze(example); const result = crossSerialize(example); expect(result).toMatchSnapshot(); }); it('supports self-recursion', () => { - const example = {} as Record; - example.a = example; - example.b = example; - const result = crossSerialize(example); + const result = crossSerialize(RECURSIVE); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', () => { - const example = ({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - const result = crossSerialize(example); + const result = crossSerialize(ITERABLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Objects', () => { - const example = ({ hello: 'world' }) as { hello: string }; - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports self-recursion', () => { - const example = {} as Record; - example.a = example; - example.b = example; - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(RECURSIVE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', () => { - const example = ({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(ITERABLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports Objects', async () => { - const example = Promise.resolve({ hello: 'world' } as { hello: string }); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); it('supports self-recursion', async () => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(ASYNC_RECURSIVE); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - } as Iterable); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(Promise.resolve(ITERABLE)); + expect(result).toMatchSnapshot(); + }); + it('supports Symbol.asyncIterator', async () => { + const result = await crossSerializeAsync(ASYNC_ITERABLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Objects', async () => { - const example = Promise.resolve({ hello: 'world' } as { hello: string }); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync( + Promise.resolve(EXAMPLE), + { scopeId: 'example' }, + ); expect(result).toMatchSnapshot(); }); it('supports self-recursion', async () => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync(ASYNC_RECURSIVE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - } as Iterable); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync( + Promise.resolve(ITERABLE), + { scopeId: 'example' }, + ); + expect(result).toMatchSnapshot(); + }); + it('supports Symbol.asyncIterator', async () => { + const result = await crossSerializeAsync(ASYNC_ITERABLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports Objects', async () => new Promise((done) => { - const example = Promise.resolve({ hello: 'world' } as { hello: string }); - crossSerializeStream(example, { + it('supports Objects', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self-recursion', async () => new Promise((done) => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - crossSerializeStream(Promise.resolve(example), { + it('supports self-recursion', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_RECURSIVE, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.iterator', async () => new Promise((done) => { - const example = Promise.resolve({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(ITERABLE), { + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); }, - } as Iterable); - crossSerializeStream(example, { + }); + })); + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_ITERABLE, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Objects', async () => new Promise((done) => { - const example = Promise.resolve({ hello: 'world' } as { hello: string }); - crossSerializeStream(example, { + it('supports Objects', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self-recursion', async () => new Promise((done) => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - crossSerializeStream(Promise.resolve(example), { + it('supports self-recursion', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_RECURSIVE, { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.iterator', async () => new Promise((done) => { - const example = Promise.resolve({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(ITERABLE), { + scopeId: 'example', + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); }, - } as Iterable); - crossSerializeStream(example, { + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_ITERABLE, { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Objects', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + + expect(back.constructor).toBe(Object); + expect(back.hello).toBe(EXAMPLE.hello); + }); + it('supports self-recursion', () => { + const result = toCrossJSON(RECURSIVE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + + expect(back.a).toBe(back); + expect(back.b).toBe(back); + }); + it('supports Symbol.iterator', () => { + const result = toCrossJSON(ITERABLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + + expect(back.constructor).toBe(Object); + expect([...back]).toMatchObject([1, 2, 3]); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Objects', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + + expect(back.constructor).toBe(Object); + expect(back.hello).toBe(EXAMPLE.hello); + }); + it('supports self-recursion', async () => { + const result = await toCrossJSONAsync(ASYNC_RECURSIVE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + + expect(await back.a).toBe(back); + expect(await back.b).toBe(back); + }); + it('supports Symbol.iterator', async () => { + const result = await toCrossJSONAsync(Promise.resolve(ITERABLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(back.constructor).toBe(Object); + expect([...back]).toMatchObject([1, 2, 3]); + }); + it('supports Symbol.asyncIterator', async () => { + const result = await toCrossJSONAsync(ASYNC_ITERABLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back.constructor).toBe(Object); + expect(Symbol.asyncIterator in back).toBe(true); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Objects', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports self-recursion', async () => new Promise((resolve, reject) => { + toCrossJSONStream(ASYNC_RECURSIVE, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(ITERABLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { + toCrossJSONStream(ASYNC_ITERABLE, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); describe('compat', () => { it('should use manual assignment instead of Object.assign', () => { - const example = ({ hello: 'world' }) as { hello: string }; - const result = serialize(example, { + const result = serialize(EXAMPLE, { disabledFeatures: Feature.ObjectAssign, }); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(back.constructor).toBe(Object); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); }); describe('compat#toJSON', () => { it('should use manual assignment instead of Object.assign', () => { - const example = ({ hello: 'world' }) as { hello: string }; - const result = toJSON(example, { + const result = toJSON(EXAMPLE, { disabledFeatures: Feature.ObjectAssign, }); expect(JSON.stringify(result)).toMatchSnapshot(); expect(compileJSON(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(back.constructor).toBe(Object); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); }); }); diff --git a/packages/seroval/test/plugin.test.ts b/packages/seroval/test/plugin.test.ts index 2924c460..84166880 100644 --- a/packages/seroval/test/plugin.test.ts +++ b/packages/seroval/test/plugin.test.ts @@ -11,6 +11,10 @@ import { serializeAsync, crossSerializeAsync, crossSerializeStream, + toCrossJSON, + fromCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, } from '../src'; const BufferPlugin = createPlugin({ @@ -45,9 +49,8 @@ describe('Plugin', () => { const result = serialize(EXAMPLE, { plugins: [BufferPlugin], }); - expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back).toBeInstanceOf(Buffer); expect(back.toString('utf-8')).toBe(EXAMPLE.toString('utf-8')); }); @@ -57,9 +60,8 @@ describe('Plugin', () => { const result = await serializeAsync(Promise.resolve(EXAMPLE), { plugins: [BufferPlugin], }); - expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(Buffer); expect(back.toString('utf-8')).toBe(EXAMPLE.toString('utf-8')); }); @@ -71,21 +73,20 @@ describe('Plugin', () => { }); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result, { + const back = fromJSON(result, { plugins: [BufferPlugin], }); expect(back).toBeInstanceOf(Buffer); expect(back.toString('utf-8')).toBe(EXAMPLE.toString('utf-8')); }); }); - describe('serializeAsync', () => { + describe('toJSONAsync', () => { it('supports Plugin', async () => { const result = await toJSONAsync(Promise.resolve(EXAMPLE), { plugins: [BufferPlugin], }); - expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result, { + const back = await fromJSON>(result, { plugins: [BufferPlugin], }); expect(back).toBeInstanceOf(Buffer); @@ -97,7 +98,6 @@ describe('Plugin', () => { const result = crossSerialize(EXAMPLE, { plugins: [BufferPlugin], }); - expect(result).toMatchSnapshot(); }); describe('scoped', () => { @@ -106,7 +106,6 @@ describe('Plugin', () => { scopeId: 'example', plugins: [BufferPlugin], }); - expect(result).toMatchSnapshot(); }); }); @@ -116,7 +115,6 @@ describe('Plugin', () => { const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { plugins: [BufferPlugin], }); - expect(result).toMatchSnapshot(); }); describe('scoped', () => { @@ -125,27 +123,28 @@ describe('Plugin', () => { scopeId: 'example', plugins: [BufferPlugin], }); - expect(result).toMatchSnapshot(); }); }); }); - describe('crossSerializeStream', () => { - it('supports Plugin', async () => new Promise((done) => { + it('supports Plugin', async () => new Promise((resolve, reject) => { crossSerializeStream(EXAMPLE, { plugins: [BufferPlugin], onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Plugin', async () => new Promise((done) => { + it('supports Plugin', async () => new Promise((resolve, reject) => { crossSerializeStream(EXAMPLE, { scopeId: 'example', plugins: [BufferPlugin], @@ -153,10 +152,58 @@ describe('Plugin', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Plugin', () => { + const result = toCrossJSON(EXAMPLE, { + plugins: [BufferPlugin], + }); + + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + plugins: [BufferPlugin], + refs: new Map(), + }); + expect(back).toBeInstanceOf(Buffer); + expect(back.toString('utf-8')).toBe(EXAMPLE.toString('utf-8')); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Plugin', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE), { + plugins: [BufferPlugin], + }); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + plugins: [BufferPlugin], + refs: new Map(), + }); + expect(back).toBeInstanceOf(Buffer); + expect(back.toString('utf-8')).toBe(EXAMPLE.toString('utf-8')); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Plugin', async () => new Promise((resolve, reject) => { + toCrossJSONStream(EXAMPLE, { + plugins: [BufferPlugin], + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/reference.test.ts b/packages/seroval/test/reference.test.ts index ea527b9e..186d6179 100644 --- a/packages/seroval/test/reference.test.ts +++ b/packages/seroval/test/reference.test.ts @@ -5,103 +5,140 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; +const EXAMPLE = createReference('example', () => 'Hello World'); + describe('Reference', () => { describe('serialize', () => { it('supports Reference', () => { - const example = createReference('example', () => 'Hello World'); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); - expect(back).toBe(example); + const back = deserialize(result); + expect(back).toBe(EXAMPLE); }); }); describe('serializeAsync', () => { it('supports Reference', async () => { - const example = createReference('example', () => 'Hello World'); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); - expect(back).toBe(example); + const back = await deserialize>(result); + expect(back).toBe(EXAMPLE); }); }); describe('toJSON', () => { it('supports Reference', () => { - const example = createReference('example', () => 'Hello World'); - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); - expect(back).toBe(example); + const back = fromJSON(result); + expect(back).toBe(EXAMPLE); }); }); describe('toJSONAsync', () => { it('supports Reference', async () => { - const example = createReference('example', () => 'Hello World'); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); - expect(back).toBe(example); + const back = await fromJSON>(result); + expect(back).toBe(EXAMPLE); }); }); describe('crossSerialize', () => { it('supports Reference', () => { - const example = createReference('example', () => 'Hello World'); - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('crossSerialize', () => { it('supports Reference', () => { - const example = createReference('example', () => 'Hello World'); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports Reference', async () => { - const example = createReference('example', () => 'Hello World'); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Reference', async () => { - const example = createReference('example', () => 'Hello World'); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports Reference', async () => new Promise((done) => { - const example = createReference('example', () => 'Hello World'); - crossSerializeStream(Promise.resolve(example), { + it('supports Reference', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Reference', async () => new Promise((done) => { - const example = createReference('example', () => 'Hello World'); - crossSerializeStream(Promise.resolve(example), { + it('supports Reference', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Reference', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBe(EXAMPLE); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Reference', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(back).toBe(EXAMPLE); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Reference', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/regexp.test.ts b/packages/seroval/test/regexp.test.ts index 277e5c53..d343bd51 100644 --- a/packages/seroval/test/regexp.test.ts +++ b/packages/seroval/test/regexp.test.ts @@ -4,107 +4,146 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; +const EXAMPLE = /[a-z0-9]+/i; + describe('RegExp', () => { describe('serialize', () => { it('supports RegExp', () => { - const example = /[a-z0-9]+/i; - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back).toBeInstanceOf(RegExp); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('serializeAsync', () => { it('supports RegExp', async () => { - const example = /[a-z0-9]+/i; - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(RegExp); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('toJSON', () => { it('supports RegExp', () => { - const example = /[a-z0-9]+/i; - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(RegExp); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('toJSONAsync', () => { it('supports RegExp', async () => { - const example = /[a-z0-9]+/i; - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = await fromJSON>(result); expect(back).toBeInstanceOf(RegExp); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('crossSerialize', () => { it('supports RegExp', () => { - const example = /[a-z0-9]+/i; - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports RegExp', () => { - const example = /[a-z0-9]+/i; - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports RegExp', async () => { - const example = /[a-z0-9]+/i; - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports RegExp', async () => { - const example = /[a-z0-9]+/i; - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports RegExp', async () => new Promise((done) => { - const example = /[a-z0-9]+/i; - crossSerializeStream(Promise.resolve(example), { + it('supports RegExp', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports RegExp', async () => new Promise((done) => { - const example = /[a-z0-9]+/i; - crossSerializeStream(Promise.resolve(example), { + it('supports RegExp', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports RegExp', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(RegExp); + expect(String(back)).toBe(String(EXAMPLE)); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports RegExp', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(RegExp); + expect(String(back)).toBe(String(EXAMPLE)); + }); + }); + describe('toCrossJSONStream', () => { + it('supports RegExp', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/sealed-object.test.ts b/packages/seroval/test/sealed-object.test.ts index 3f29b9cc..659be7c4 100644 --- a/packages/seroval/test/sealed-object.test.ts +++ b/packages/seroval/test/sealed-object.test.ts @@ -4,49 +4,68 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; +const EXAMPLE = Object.seal({ hello: 'world' }); + +const RECURSIVE = {} as Record; +RECURSIVE.a = RECURSIVE; +RECURSIVE.b = RECURSIVE; +Object.seal(RECURSIVE); + +const ITERABLE = Object.seal({ + * [Symbol.iterator]() { + yield 1; + yield 2; + yield 3; + }, +}); + +const ASYNC_RECURSIVE = {} as Record>; +ASYNC_RECURSIVE.a = Promise.resolve(ASYNC_RECURSIVE); +ASYNC_RECURSIVE.b = Promise.resolve(ASYNC_RECURSIVE); +Object.seal(ASYNC_RECURSIVE); + +const ASYNC_ITERABLE = Object.seal({ + async* [Symbol.asyncIterator]() { + await Promise.resolve(); + yield 1; + yield 2; + yield 3; + }, +}); + describe('sealed object', () => { describe('serialize', () => { it('supports Objects', () => { - const example = ({ hello: 'world' }) as { hello: string }; - Object.seal(example); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(Object.isSealed(back)).toBe(true); expect(back.constructor).toBe(Object); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', () => { - const example = {} as Record; - example.a = example; - example.b = example; - Object.seal(example); - const result = serialize(example); + const result = serialize(RECURSIVE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(Object.isSealed(back)).toBe(true); expect(back.a).toBe(back); expect(back.b).toBe(back); }); it('supports Symbol.iterator', () => { - const example = ({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - Object.seal(example); - const result = serialize(example); + const result = serialize(ITERABLE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(Object.isSealed(back)).toBe(true); expect(back.constructor).toBe(Object); expect([...back]).toMatchObject([1, 2, 3]); @@ -54,76 +73,59 @@ describe('sealed object', () => { }); describe('serializeAsync', () => { it('supports Objects', async () => { - const example = Promise.resolve(Object.seal({ hello: 'world' }) as { hello: string }); - const result = await serializeAsync(example); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>>(result); + const back = await deserialize>(result); expect(Object.isSealed(back)).toBe(true); expect(back.constructor).toBe(Object); - expect(back.hello).toBe((await example).hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', async () => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - Object.seal(example); - const result = await serializeAsync(example); + const result = await serializeAsync(ASYNC_RECURSIVE); expect(result).toMatchSnapshot(); - const back = deserialize>>(result); + const back = deserialize(result); expect(Object.isSealed(back)).toBe(true); expect(await back.a).toBe(back); expect(await back.b).toBe(back); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(Object.seal({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await serializeAsync(example); + const result = await serializeAsync(Promise.resolve(ITERABLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>>(result); + const back = await deserialize>(result); expect(Object.isSealed(back)).toBe(true); expect(back.constructor).toBe(Object); expect([...back]).toMatchObject([1, 2, 3]); }); + it('supports Symbol.asyncIterator', async () => { + const result = await serializeAsync(ASYNC_ITERABLE); + expect(result).toMatchSnapshot(); + const back = deserialize(result); + expect(Object.isSealed(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect(Symbol.asyncIterator in back).toBe(true); + }); }); describe('toJSON', () => { it('supports Objects', () => { - const example = Object.seal({ hello: 'world' }) as { hello: string }; - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(Object.isSealed(back)).toBe(true); expect(back.constructor).toBe(Object); - expect(back.hello).toBe(example.hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', () => { - const example = {} as Record; - example.a = example; - example.b = example; - Object.seal(example); - const result = toJSON(example); + const result = toJSON(RECURSIVE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(Object.isSealed(back)).toBe(true); expect(back.a).toBe(back); expect(back.b).toBe(back); }); it('supports Symbol.iterator', () => { - const example = ({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - Object.seal(example); - const result = toJSON(example); + const result = toJSON(ITERABLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(Object.isSealed(back)).toBe(true); expect(back.constructor).toBe(Object); expect([...back]).toMatchObject([1, 2, 3]); @@ -131,41 +133,37 @@ describe('sealed object', () => { }); describe('toJSONAsync', () => { it('supports Objects', async () => { - const example = Promise.resolve(Object.seal({ hello: 'world' }) as { hello: string }); - const result = await toJSONAsync(example); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>>(result); + const back = await fromJSON>(result); expect(Object.isSealed(back)).toBe(true); expect(back.constructor).toBe(Object); - expect(back.hello).toBe((await example).hello); + expect(back.hello).toBe(EXAMPLE.hello); }); it('supports self-recursion', async () => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - Object.seal(example); - const result = await toJSONAsync(example); + const result = await toJSONAsync(ASYNC_RECURSIVE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>>(result); + const back = fromJSON(result); expect(Object.isSealed(back)).toBe(true); expect(await back.a).toBe(back); expect(await back.b).toBe(back); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(Object.seal({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await toJSONAsync(example); + const result = await toJSONAsync(Promise.resolve(ITERABLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>>(result); + const back = await fromJSON>(result); expect(Object.isSealed(back)).toBe(true); expect(back.constructor).toBe(Object); expect([...back]).toMatchObject([1, 2, 3]); }); + it('supports Symbol.asyncIterator', async () => { + const result = await toJSONAsync(ASYNC_ITERABLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromJSON(result); + expect(Object.isSealed(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect(Symbol.asyncIterator in back).toBe(true); + }); }); describe('crossSerialize', () => { it('supports Objects', () => { @@ -175,195 +173,308 @@ describe('sealed object', () => { expect(result).toMatchSnapshot(); }); it('supports self-recursion', () => { - const example = {} as Record; - example.a = example; - example.b = example; - Object.seal(example); - const result = crossSerialize(example); + const result = crossSerialize(RECURSIVE); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', () => { - const example = ({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - Object.seal(example); - const result = crossSerialize(example); + const result = crossSerialize(ITERABLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Objects', () => { - const example = ({ hello: 'world' }) as { hello: string }; - Object.seal(example); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports self-recursion', () => { - const example = {} as Record; - example.a = example; - example.b = example; - Object.seal(example); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(RECURSIVE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', () => { - const example = ({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable; - Object.seal(example); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(ITERABLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports Objects', async () => { - const example = Promise.resolve(Object.seal({ hello: 'world' }) as { hello: string }); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); it('supports self-recursion', async () => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - Object.seal(example); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(ASYNC_RECURSIVE); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(Object.seal({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await crossSerializeAsync(example); + const result = await crossSerializeAsync(Promise.resolve(ITERABLE)); + expect(result).toMatchSnapshot(); + }); + it('supports Symbol.asyncIterator', async () => { + const result = await crossSerializeAsync(ASYNC_ITERABLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Objects', async () => { - const example = Promise.resolve(Object.seal({ hello: 'world' }) as { hello: string }); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync( + Promise.resolve(EXAMPLE), + { scopeId: 'example' }, + ); expect(result).toMatchSnapshot(); }); it('supports self-recursion', async () => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - Object.seal(example); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync(ASYNC_RECURSIVE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports Symbol.iterator', async () => { - const example = Promise.resolve(Object.seal({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; - }, - }) as Iterable); - const result = await crossSerializeAsync(example, { scopeId: 'example' }); + const result = await crossSerializeAsync( + Promise.resolve(ITERABLE), + { scopeId: 'example' }, + ); + expect(result).toMatchSnapshot(); + }); + it('supports Symbol.asyncIterator', async () => { + const result = await crossSerializeAsync(ASYNC_ITERABLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports Objects', async () => new Promise((done) => { - const example = Promise.resolve(Object.seal({ hello: 'world' }) as { hello: string }); - crossSerializeStream(example, { + it('supports Objects', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self-recursion', async () => new Promise((done) => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - Object.seal(example); - crossSerializeStream(Promise.resolve(example), { + it('supports self-recursion', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_RECURSIVE, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.iterator', async () => new Promise((done) => { - const example = Promise.resolve(Object.seal({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(ITERABLE), { + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); }, - }) as Iterable); - crossSerializeStream(example, { + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_ITERABLE, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Objects', async () => new Promise((done) => { - const example = Promise.resolve(Object.seal({ hello: 'world' }) as { hello: string }); - crossSerializeStream(example, { + it('supports Objects', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self-recursion', async () => new Promise((done) => { - const example = {} as Record>; - example.a = Promise.resolve(example); - example.b = Promise.resolve(example); - Object.seal(example); - crossSerializeStream(Promise.resolve(example), { + it('supports self-recursion', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_RECURSIVE, { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.iterator', async () => new Promise((done) => { - const example = Promise.resolve(Object.seal({ - * [Symbol.iterator]() { - yield 1; - yield 2; - yield 3; + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(ITERABLE), { + scopeId: 'example', + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); }, - }) as Iterable); - crossSerializeStream(example, { + }); + })); + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { + crossSerializeStream(ASYNC_ITERABLE, { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Objects', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(Object.isSealed(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect(back.hello).toBe(EXAMPLE.hello); + }); + it('supports self-recursion', () => { + const result = toCrossJSON(RECURSIVE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(Object.isSealed(back)).toBe(true); + expect(back.a).toBe(back); + expect(back.b).toBe(back); + }); + it('supports Symbol.iterator', () => { + const result = toCrossJSON(ITERABLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(Object.isSealed(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect([...back]).toMatchObject([1, 2, 3]); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Objects', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(Object.isSealed(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect(back.hello).toBe(EXAMPLE.hello); + }); + it('supports self-recursion', async () => { + const result = await toCrossJSONAsync(ASYNC_RECURSIVE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(Object.isSealed(back)).toBe(true); + expect(await back.a).toBe(back); + expect(await back.b).toBe(back); + }); + it('supports Symbol.iterator', async () => { + const result = await toCrossJSONAsync(Promise.resolve(ITERABLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(Object.isSealed(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect([...back]).toMatchObject([1, 2, 3]); + }); + it('supports Symbol.asyncIterator', async () => { + const result = await toCrossJSONAsync(ASYNC_ITERABLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(Object.isSealed(back)).toBe(true); + expect(back.constructor).toBe(Object); + expect(Symbol.asyncIterator in back).toBe(true); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Objects', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports self-recursion', async () => new Promise((resolve, reject) => { + toCrossJSONStream(ASYNC_RECURSIVE, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(ITERABLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { + toCrossJSONStream(ASYNC_ITERABLE, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/set.test.ts b/packages/seroval/test/set.test.ts index 7fb9b1fe..9cc7dd1b 100644 --- a/packages/seroval/test/set.test.ts +++ b/packages/seroval/test/set.test.ts @@ -6,44 +6,48 @@ import { crossSerializeStream, deserialize, Feature, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, toJSON, toJSONAsync, } from '../src'; +const EXAMPLE = new Set([1, 2, 3]); + +const RECURSIVE = new Set(); +RECURSIVE.add(RECURSIVE); + describe('Set', () => { describe('serialize', () => { it('supports Set', () => { - const example = new Set([1, 2, 3]); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(back).toBeInstanceOf(Set); - expect(back.has(1)).toBe(example.has(1)); - expect(back.has(2)).toBe(example.has(2)); - expect(back.has(3)).toBe(example.has(3)); + expect(back.has(1)).toBe(EXAMPLE.has(1)); + expect(back.has(2)).toBe(EXAMPLE.has(2)); + expect(back.has(3)).toBe(EXAMPLE.has(3)); }); it('supports self-recursion', () => { - const example: Set = new Set(); - example.add(example); - const result = serialize(example); + const result = serialize(RECURSIVE); expect(result).toMatchSnapshot(); - const back = deserialize>(result); + const back = deserialize(result); expect(back.has(back)).toBe(true); }); }); describe('serializeAsync', () => { it('supports Set', async () => { - const example = new Set([1, 2, 3]); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(Set); - expect(back.has(1)).toBe(example.has(1)); - expect(back.has(2)).toBe(example.has(2)); - expect(back.has(3)).toBe(example.has(3)); + expect(back.has(1)).toBe(EXAMPLE.has(1)); + expect(back.has(2)).toBe(EXAMPLE.has(2)); + expect(back.has(3)).toBe(EXAMPLE.has(3)); }); it('supports self-recursion', async () => { const example: Set> = new Set(); @@ -58,34 +62,30 @@ describe('Set', () => { }); describe('toJSON', () => { it('supports Set', () => { - const example = new Set([1, 2, 3]); - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(Set); - expect(back.has(1)).toBe(example.has(1)); - expect(back.has(2)).toBe(example.has(2)); - expect(back.has(3)).toBe(example.has(3)); + expect(back.has(1)).toBe(EXAMPLE.has(1)); + expect(back.has(2)).toBe(EXAMPLE.has(2)); + expect(back.has(3)).toBe(EXAMPLE.has(3)); }); it('supports self-recursion', () => { - const example: Set = new Set(); - example.add(example); - const result = toJSON(example); + const result = toJSON(RECURSIVE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON>(result); + const back = fromJSON(result); expect(back.has(back)).toBe(true); }); }); describe('toJSONAsync', () => { it('supports Set', async () => { - const example = new Set([1, 2, 3]); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>>(result); + const back = await fromJSON>(result); expect(back).toBeInstanceOf(Set); - expect(back.has(1)).toBe(example.has(1)); - expect(back.has(2)).toBe(example.has(2)); - expect(back.has(3)).toBe(example.has(3)); + expect(back.has(1)).toBe(EXAMPLE.has(1)); + expect(back.has(2)).toBe(EXAMPLE.has(2)); + expect(back.has(3)).toBe(EXAMPLE.has(3)); }); it('supports self-recursion', async () => { const example: Set> = new Set(); @@ -100,34 +100,27 @@ describe('Set', () => { }); describe('crossSerialize', () => { it('supports Set', () => { - const example = new Set([1, 2, 3]); - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); it('supports self-recursion', () => { - const example: Set = new Set(); - example.add(example); - const result = crossSerialize(example); + const result = crossSerialize(RECURSIVE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Set', () => { - const example = new Set([1, 2, 3]); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports self-recursion', () => { - const example: Set = new Set(); - example.add(example); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(RECURSIVE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports Set', async () => { - const example = new Set([1, 2, 3]); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); it('supports self-recursion', async () => { @@ -138,8 +131,7 @@ describe('Set', () => { }); describe('scoped', () => { it('supports Set', async () => { - const example = new Set([1, 2, 3]); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); it('supports self-recursion', async () => { @@ -151,18 +143,20 @@ describe('Set', () => { }); }); describe('crossSerializeStream', () => { - it('supports Set', async () => new Promise((done) => { - const example = new Set([1, 2, 3]); - crossSerializeStream(Promise.resolve(example), { + it('supports Set', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self-recursion', async () => new Promise((done) => { + it('supports self-recursion', async () => new Promise((resolve, reject) => { const example: Set> = new Set(); example.add(Promise.resolve(example)); crossSerializeStream(example, { @@ -170,24 +164,29 @@ describe('Set', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Set', async () => new Promise((done) => { - const example = new Set([1, 2, 3]); - crossSerializeStream(Promise.resolve(example), { + it('supports Set', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports self-recursion', async () => new Promise((done) => { + it('supports self-recursion', async () => new Promise((resolve, reject) => { const example: Set> = new Set(); example.add(Promise.resolve(example)); crossSerializeStream(example, { @@ -196,32 +195,81 @@ describe('Set', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Set', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Set); + expect(back.has(1)).toBe(EXAMPLE.has(1)); + expect(back.has(2)).toBe(EXAMPLE.has(2)); + expect(back.has(3)).toBe(EXAMPLE.has(3)); + }); + it('supports self-recursion', () => { + const result = toCrossJSON(RECURSIVE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back.has(back)).toBe(true); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Set', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Set); + expect(back.has(1)).toBe(EXAMPLE.has(1)); + expect(back.has(2)).toBe(EXAMPLE.has(2)); + expect(back.has(3)).toBe(EXAMPLE.has(3)); + }); + it('supports self-recursion', async () => { + const example: Set> = new Set(); + example.add(Promise.resolve(example)); + const result = await toCrossJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON>>(result, { + refs: new Map(), + }); + for (const key of back) { + expect(await key).toBe(back); + } + }); + }); describe('compat', () => { it('should fallback to Symbol.iterator', () => { - expect(serialize(new Set([1, 2, 3]), { + expect(serialize(EXAMPLE, { disabledFeatures: Feature.Set, })).toMatchSnapshot(); }); it('should throw an error for unsupported target', () => { - expect(() => serialize(new Set([1, 2, 3]), { + expect(() => serialize(EXAMPLE, { disabledFeatures: Feature.Set | Feature.Symbol, })).toThrowErrorMatchingSnapshot(); }); }); describe('compat#toJSON', () => { it('should fallback to Symbol.iterator', () => { - expect(JSON.stringify(toJSON(new Set([1, 2, 3]), { + expect(JSON.stringify(toJSON(EXAMPLE, { disabledFeatures: Feature.Set, }))).toMatchSnapshot(); }); it('should throw an error for unsupported target', () => { - expect(() => toJSON(new Set([1, 2, 3]), { + expect(() => toJSON(EXAMPLE, { disabledFeatures: Feature.Set | Feature.Symbol, })).toThrowErrorMatchingSnapshot(); }); diff --git a/packages/seroval/test/sparse-array.test.ts b/packages/seroval/test/sparse-array.test.ts index 107acbaa..02d9b889 100644 --- a/packages/seroval/test/sparse-array.test.ts +++ b/packages/seroval/test/sparse-array.test.ts @@ -9,106 +9,147 @@ import { crossSerialize, crossSerializeAsync, crossSerializeStream, + toCrossJSON, + fromCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, } from '../src'; +const EXAMPLE = new Array(10); + describe('sparse arrays', () => { describe('serialize', () => { it('supports sparse arrays', () => { - const example = new Array(10); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(0 in back).toBeFalsy(); expect(back[0]).toBe(undefined); - expect(back.length).toBe(example.length); + expect(back.length).toBe(EXAMPLE.length); }); }); describe('serializeAsync', () => { it('supports sparse arrays', async () => { - const example = new Array(10); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = await deserialize>(result); expect(0 in back).toBeFalsy(); expect(back[0]).toBe(undefined); - expect(back.length).toBe(example.length); + expect(back.length).toBe(EXAMPLE.length); }); }); describe('toJSON', () => { it('supports sparse arrays', () => { - const example = new Array(10); - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(0 in back).toBeFalsy(); expect(back[0]).toBe(undefined); - expect(back.length).toBe(example.length); + expect(back.length).toBe(EXAMPLE.length); }); }); describe('toJSONAsync', () => { it('supports sparse arrays', async () => { - const example = new Array(10); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = await fromJSON>(result); expect(0 in back).toBeFalsy(); expect(back[0]).toBe(undefined); - expect(back.length).toBe(example.length); + expect(back.length).toBe(EXAMPLE.length); }); }); describe('crossSerialize', () => { it('supports sparse arrays', () => { - const example = new Array(10); - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports sparse arrays', () => { - const example = new Array(10); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports sparse arrays', async () => { - const example = new Array(10); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports sparse arrays', async () => { - const example = new Array(10); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports sparse arrays', async () => new Promise((done) => { - const example = new Array(10); - crossSerializeStream(Promise.resolve(example), { + it('supports sparse arrays', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports sparse arrays', async () => new Promise((done) => { - const example = new Array(10); - crossSerializeStream(Promise.resolve(example), { + it('supports sparse arrays', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports sparse arrays', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(0 in back).toBeFalsy(); + expect(back[0]).toBe(undefined); + expect(back.length).toBe(EXAMPLE.length); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports sparse arrays', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(0 in back).toBeFalsy(); + expect(back[0]).toBe(undefined); + expect(back.length).toBe(EXAMPLE.length); + }); + }); + describe('toCrossJSONStream', () => { + it('supports sparse arrays', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/string.test.ts b/packages/seroval/test/string.test.ts index bb3b43c1..d581928d 100644 --- a/packages/seroval/test/string.test.ts +++ b/packages/seroval/test/string.test.ts @@ -4,76 +4,139 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; +const QUOTED = '"hello"'; +const HTML = ''; + describe('string', () => { describe('serialize', () => { it('supports strings', () => { - expect(serialize('"hello"')).toMatchSnapshot(); - expect(serialize('')).toMatchSnapshot(); - expect(deserialize(serialize('"hello"'))).toBe('"hello"'); - expect(deserialize(serialize(''))).toBe(''); + expect(serialize(QUOTED)).toMatchSnapshot(); + expect(serialize(HTML)).toMatchSnapshot(); + expect(deserialize(serialize(QUOTED))).toBe(QUOTED); + expect(deserialize(serialize(HTML))).toBe(HTML); }); }); describe('serializeAsync', () => { it('supports strings', async () => { - expect(await serializeAsync(Promise.resolve('"hello"'))).toMatchSnapshot(); - expect(await serializeAsync(Promise.resolve(''))).toMatchSnapshot(); + expect(await serializeAsync(Promise.resolve(QUOTED))).toMatchSnapshot(); + expect(await serializeAsync(Promise.resolve(HTML))).toMatchSnapshot(); }); }); describe('toJSON', () => { it('supports strings', () => { - expect(JSON.stringify(toJSON('"hello"'))).toMatchSnapshot(); - expect(JSON.stringify(toJSON(''))).toMatchSnapshot(); - expect(fromJSON(toJSON('"hello"'))).toBe('"hello"'); - expect(fromJSON(toJSON(''))).toBe(''); + expect(JSON.stringify(toJSON(QUOTED))).toMatchSnapshot(); + expect(JSON.stringify(toJSON(HTML))).toMatchSnapshot(); + expect(fromJSON(toJSON(QUOTED))).toBe(QUOTED); + expect(fromJSON(toJSON(HTML))).toBe(HTML); }); }); describe('toJSONAsync', () => { it('supports strings', async () => { expect( - JSON.stringify(await toJSONAsync(Promise.resolve('"hello"'))), + JSON.stringify(await toJSONAsync(Promise.resolve(QUOTED))), ).toMatchSnapshot(); expect( - JSON.stringify(await toJSONAsync(Promise.resolve(''))), + JSON.stringify(await toJSONAsync(Promise.resolve(HTML))), ).toMatchSnapshot(); }); }); describe('crossSerialize', () => { it('supports strings', () => { - expect(crossSerialize('"hello"')).toMatchSnapshot(); - expect(crossSerialize('')).toMatchSnapshot(); + expect(crossSerialize(QUOTED)).toMatchSnapshot(); + expect(crossSerialize(HTML)).toMatchSnapshot(); }); }); describe('crossSerializeAsync', () => { it('supports strings', async () => { - expect(await crossSerializeAsync(Promise.resolve('"hello"'))).toMatchSnapshot(); - expect(await crossSerializeAsync(Promise.resolve(''))).toMatchSnapshot(); + expect(await crossSerializeAsync(Promise.resolve(QUOTED))).toMatchSnapshot(); + expect(await crossSerializeAsync(Promise.resolve(HTML))).toMatchSnapshot(); }); }); describe('crossSerializeStream', () => { - it('supports strings', async () => new Promise((done) => { - crossSerializeStream(Promise.resolve('"hello"'), { + it('supports strings', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(QUOTED), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports sanitized strings', async () => new Promise((done) => { - crossSerializeStream(Promise.resolve(''), { + it('supports sanitized strings', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(HTML), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); + describe('toCrossJSON', () => { + it('supports strings', () => { + expect(JSON.stringify(toCrossJSON(QUOTED))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(HTML))).toMatchSnapshot(); + expect( + fromCrossJSON(toCrossJSON(QUOTED), { refs: new Map() }), + ).toBe(QUOTED); + expect( + fromCrossJSON(toCrossJSON(HTML), { refs: new Map() }), + ).toBe(HTML); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports strings', async () => { + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(QUOTED))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(HTML))), + ).toMatchSnapshot(); + }); + }); + describe('toCrossJSONStream', () => { + it('supports strings', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(QUOTED), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports sanitized strings', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(HTML), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); }, }); })); diff --git a/packages/seroval/test/typed-array.test.ts b/packages/seroval/test/typed-array.test.ts index 17ae6fb3..5d3cd302 100644 --- a/packages/seroval/test/typed-array.test.ts +++ b/packages/seroval/test/typed-array.test.ts @@ -9,164 +9,164 @@ import { crossSerialize, crossSerializeAsync, crossSerializeStream, + toCrossJSON, + fromCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, } from '../src'; +const EXAMPLE = new Uint32Array([ + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, +]); + describe('typed arrays', () => { describe('serialize', () => { it('supports typed arrays', () => { - const example = new Uint32Array([ - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - ]); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back).toBeInstanceOf(Uint32Array); - expect(back[0]).toBe(example[0]); - expect(back[1]).toBe(example[1]); - expect(back[2]).toBe(example[2]); - expect(back[3]).toBe(example[3]); + expect(back[0]).toBe(EXAMPLE[0]); + expect(back[1]).toBe(EXAMPLE[1]); + expect(back[2]).toBe(EXAMPLE[2]); + expect(back[3]).toBe(EXAMPLE[3]); }); }); describe('serializeAsync', () => { it('supports typed arrays', async () => { - const example = new Uint32Array([ - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - ]); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(Uint32Array); - expect(back[0]).toBe(example[0]); - expect(back[1]).toBe(example[1]); - expect(back[2]).toBe(example[2]); - expect(back[3]).toBe(example[3]); + expect(back[0]).toBe(EXAMPLE[0]); + expect(back[1]).toBe(EXAMPLE[1]); + expect(back[2]).toBe(EXAMPLE[2]); + expect(back[3]).toBe(EXAMPLE[3]); }); }); describe('toJSON', () => { it('supports typed arrays', () => { - const example = new Uint32Array([ - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - ]); - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(Uint32Array); - expect(back[0]).toBe(example[0]); - expect(back[1]).toBe(example[1]); - expect(back[2]).toBe(example[2]); - expect(back[3]).toBe(example[3]); + expect(back[0]).toBe(EXAMPLE[0]); + expect(back[1]).toBe(EXAMPLE[1]); + expect(back[2]).toBe(EXAMPLE[2]); + expect(back[3]).toBe(EXAMPLE[3]); }); }); describe('toJSONAsync', () => { it('supports typed arrays', async () => { - const example = new Uint32Array([ - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - ]); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = await fromJSON>(result); expect(back).toBeInstanceOf(Uint32Array); - expect(back[0]).toBe(example[0]); - expect(back[1]).toBe(example[1]); - expect(back[2]).toBe(example[2]); - expect(back[3]).toBe(example[3]); + expect(back[0]).toBe(EXAMPLE[0]); + expect(back[1]).toBe(EXAMPLE[1]); + expect(back[2]).toBe(EXAMPLE[2]); + expect(back[3]).toBe(EXAMPLE[3]); }); }); describe('crossSerialize', () => { it('supports typed arrays', () => { - const example = new Uint32Array([ - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - ]); - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports typed arrays', () => { - const example = new Uint32Array([ - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - ]); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports typed arrays', async () => { - const example = new Uint32Array([ - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - ]); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports typed arrays', async () => { - const example = new Uint32Array([ - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - ]); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports typed arrays', async () => new Promise((done) => { - const example = new Uint32Array([ - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - ]); - crossSerializeStream(Promise.resolve(example), { + it('supports typed arrays', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports typed arrays', async () => new Promise((done) => { - const example = new Uint32Array([ - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - ]); - crossSerializeStream(Promise.resolve(example), { + it('supports typed arrays', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports typed arrays', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Uint32Array); + expect(back[0]).toBe(EXAMPLE[0]); + expect(back[1]).toBe(EXAMPLE[1]); + expect(back[2]).toBe(EXAMPLE[2]); + expect(back[3]).toBe(EXAMPLE[3]); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports typed arrays', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Uint32Array); + expect(back[0]).toBe(EXAMPLE[0]); + expect(back[1]).toBe(EXAMPLE[1]); + expect(back[2]).toBe(EXAMPLE[2]); + expect(back[3]).toBe(EXAMPLE[3]); + }); + }); + describe('toCrossJSONStream', () => { + it('supports typed arrays', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/web-api/__snapshots__/blob.test.ts.snap b/packages/seroval/test/web-api/__snapshots__/blob.test.ts.snap index 16f04e2a..3bdc07cc 100644 --- a/packages/seroval/test/web-api/__snapshots__/blob.test.ts.snap +++ b/packages/seroval/test/web-api/__snapshots__/blob.test.ts.snap @@ -1,9 +1,11 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Blob > crossSerializeAsync > scoped > supports Blob 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=new Blob([$R[2]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],{type:\\"text/plain\\"}))))($R[\\"example\\"])"`; +exports[`Blob > crossSerializeAsync > scoped > supports Blob 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=new Blob([$R[2]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],{type:\\"text/plain\\"})))($R[\\"example\\"])"`; -exports[`Blob > crossSerializeAsync > supports Blob 1`] = `"$R[0]=Promise.resolve($R[1]=new Blob([$R[2]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],{type:\\"text/plain\\"}))"`; +exports[`Blob > crossSerializeAsync > supports Blob 1`] = `"$R[0]=new Blob([$R[1]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],{type:\\"text/plain\\"})"`; -exports[`Blob > serializeAsync > supports Blob 1`] = `"Promise.resolve(new Blob([new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],{type:\\"text/plain\\"}))"`; +exports[`Blob > serializeAsync > supports Blob 1`] = `"new Blob([new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],{type:\\"text/plain\\"})"`; -exports[`Blob > toJSONAsync > supports Blob 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":23,\\"i\\":1,\\"c\\":\\"text/plain\\",\\"f\\":{\\"t\\":21,\\"i\\":2,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100]}}},\\"f\\":16383,\\"m\\":[]}"`; +exports[`Blob > toCrossJSONAsync > supports Blob 1`] = `"{\\"t\\":23,\\"i\\":0,\\"c\\":\\"text/plain\\",\\"f\\":{\\"t\\":21,\\"i\\":1,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100]}}"`; + +exports[`Blob > toJSONAsync > supports Blob 1`] = `"{\\"t\\":{\\"t\\":23,\\"i\\":0,\\"c\\":\\"text/plain\\",\\"f\\":{\\"t\\":21,\\"i\\":1,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100]}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/web-api/__snapshots__/custom-event.test.ts.snap b/packages/seroval/test/web-api/__snapshots__/custom-event.test.ts.snap index d489c954..fe6c5447 100644 --- a/packages/seroval/test/web-api/__snapshots__/custom-event.test.ts.snap +++ b/packages/seroval/test/web-api/__snapshots__/custom-event.test.ts.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`CustomEvent > crossSerialize > scoped > supports CustomEvent 1`] = `"($R=>($R[0]=new CustomEvent(\\"example\\",$R[1]={detail:$R[2]={},bubbles:!1,cancelable:!1,composed:!1}),$R[2].self=$R[2],$R[0]))($R[\\"example\\"])"`; +exports[`CustomEvent > crossSerialize > scoped > supports CustomEvent 1`] = `"($R=>$R[0]=new CustomEvent(\\"example\\",$R[1]={detail:$R[2]={},bubbles:!1,cancelable:!1,composed:!1}),$R[2].self=$R[2],$R[0])($R[\\"example\\"])"`; exports[`CustomEvent > crossSerialize > supports CustomEvent 1`] = `"($R[0]=new CustomEvent(\\"example\\",$R[1]={detail:$R[2]={},bubbles:!1,cancelable:!1,composed:!1}),$R[2].self=$R[2],$R[0])"`; -exports[`CustomEvent > crossSerializeAsync > scoped > supports CustomEvent 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=new CustomEvent(\\"example\\",$R[2]={detail:$R[3]={},bubbles:!1,cancelable:!1,composed:!1})),$R[3].self=$R[3],$R[0]))($R[\\"example\\"])"`; +exports[`CustomEvent > crossSerializeAsync > scoped > supports CustomEvent 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=new CustomEvent(\\"example\\",$R[2]={detail:$R[3]={},bubbles:!1,cancelable:!1,composed:!1})),$R[3].self=$R[3],$R[0])($R[\\"example\\"])"`; exports[`CustomEvent > crossSerializeAsync > supports CustomEvent 1`] = `"($R[0]=Promise.resolve($R[1]=new CustomEvent(\\"example\\",$R[2]={detail:$R[3]={},bubbles:!1,cancelable:!1,composed:!1})),$R[3].self=$R[3],$R[0])"`; -exports[`CustomEvent > crossSerializeStream > scoped > supports CustomEvent 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`CustomEvent > crossSerializeStream > scoped > supports CustomEvent 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`CustomEvent > crossSerializeStream > scoped > supports CustomEvent 2`] = `"($R=>(_$.Ps($R[0],$R[1]=new CustomEvent(\\"example\\",$R[2]={detail:$R[3]={},bubbles:!1,cancelable:!1,composed:!1})),$R[3].self=$R[3],$R[0]))($R[\\"example\\"])"`; +exports[`CustomEvent > crossSerializeStream > scoped > supports CustomEvent 2`] = `"($R=>_$.Ps($R[0],$R[1]=new CustomEvent(\\"example\\",$R[2]={detail:$R[3]={},bubbles:!1,cancelable:!1,composed:!1})),$R[3].self=$R[3],$R[0])($R[\\"example\\"])"`; exports[`CustomEvent > crossSerializeStream > supports CustomEvent 1`] = `"$R[0]=_$.P()"`; @@ -20,6 +20,14 @@ exports[`CustomEvent > serialize > supports CustomEvent 1`] = `"((h,j)=>(j=new C exports[`CustomEvent > serializeAsync > supports CustomEvent 1`] = `"((h,j)=>(j=Promise.resolve(new CustomEvent(\\"example\\",{detail:h={},bubbles:!1,cancelable:!1,composed:!1})),h.self=h,j))()"`; +exports[`CustomEvent > toCrossJSON > supports CustomEvent 1`] = `"{\\"t\\":38,\\"i\\":0,\\"s\\":\\"example\\",\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"detail\\",\\"bubbles\\",\\"cancelable\\",\\"composed\\"],\\"v\\":[{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"self\\"],\\"v\\":[{\\"t\\":4,\\"i\\":2}],\\"s\\":1},\\"o\\":0},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3}],\\"s\\":4},\\"o\\":0}}"`; + +exports[`CustomEvent > toCrossJSONAsync > supports CustomEvent 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":38,\\"i\\":1,\\"s\\":\\"example\\",\\"f\\":{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"detail\\",\\"bubbles\\",\\"cancelable\\",\\"composed\\"],\\"v\\":[{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"self\\"],\\"v\\":[{\\"t\\":4,\\"i\\":3}],\\"s\\":1},\\"o\\":0},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3}],\\"s\\":4},\\"o\\":0}}}"`; + +exports[`CustomEvent > toCrossJSONStream > supports CustomEvent 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`CustomEvent > toCrossJSONStream > supports CustomEvent 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":38,\\"i\\":1,\\"s\\":\\"example\\",\\"f\\":{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"detail\\",\\"bubbles\\",\\"cancelable\\",\\"composed\\"],\\"v\\":[{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"self\\"],\\"v\\":[{\\"t\\":4,\\"i\\":3}],\\"s\\":1},\\"o\\":0},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3}],\\"s\\":4},\\"o\\":0}}}"`; + exports[`CustomEvent > toJSON > supports CustomEvent 1`] = `"{\\"t\\":{\\"t\\":38,\\"i\\":0,\\"s\\":\\"example\\",\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"detail\\",\\"bubbles\\",\\"cancelable\\",\\"composed\\"],\\"v\\":[{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"self\\"],\\"v\\":[{\\"t\\":4,\\"i\\":2}],\\"s\\":1},\\"o\\":0},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3}],\\"s\\":4},\\"o\\":0}},\\"f\\":16383,\\"m\\":[2]}"`; exports[`CustomEvent > toJSONAsync > supports CustomEvent 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":38,\\"i\\":1,\\"s\\":\\"example\\",\\"f\\":{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"detail\\",\\"bubbles\\",\\"cancelable\\",\\"composed\\"],\\"v\\":[{\\"t\\":10,\\"i\\":3,\\"p\\":{\\"k\\":[\\"self\\"],\\"v\\":[{\\"t\\":4,\\"i\\":3}],\\"s\\":1},\\"o\\":0},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3}],\\"s\\":4},\\"o\\":0}}},\\"f\\":16383,\\"m\\":[3]}"`; diff --git a/packages/seroval/test/web-api/__snapshots__/dom-exception.test.ts.snap b/packages/seroval/test/web-api/__snapshots__/dom-exception.test.ts.snap index 47e43503..3f8b61a3 100644 --- a/packages/seroval/test/web-api/__snapshots__/dom-exception.test.ts.snap +++ b/packages/seroval/test/web-api/__snapshots__/dom-exception.test.ts.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`DOMException > crossSerialize > scoped > supports DOMException 1`] = `"($R=>($R[0]=new DOMException(\\"This is an example message.\\",\\"Example\\")))($R[\\"example\\"])"`; +exports[`DOMException > crossSerialize > scoped > supports DOMException 1`] = `"($R=>$R[0]=new DOMException(\\"This is an example message.\\",\\"Example\\"))($R[\\"example\\"])"`; exports[`DOMException > crossSerialize > supports DOMException 1`] = `"$R[0]=new DOMException(\\"This is an example message.\\",\\"Example\\")"`; -exports[`DOMException > crossSerializeAsync > scoped > supports DOMException 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=new DOMException(\\"This is an example message.\\",\\"Example\\"))))($R[\\"example\\"])"`; +exports[`DOMException > crossSerializeAsync > scoped > supports DOMException 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=new DOMException(\\"This is an example message.\\",\\"Example\\")))($R[\\"example\\"])"`; exports[`DOMException > crossSerializeAsync > supports DOMException 1`] = `"$R[0]=Promise.resolve($R[1]=new DOMException(\\"This is an example message.\\",\\"Example\\"))"`; -exports[`DOMException > crossSerializeStream > scoped > supports DOMException 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`DOMException > crossSerializeStream > scoped > supports DOMException 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`DOMException > crossSerializeStream > scoped > supports DOMException 2`] = `"($R=>(_$.Ps($R[0],$R[1]=new DOMException(\\"This is an example message.\\",\\"Example\\"))))($R[\\"example\\"])"`; +exports[`DOMException > crossSerializeStream > scoped > supports DOMException 2`] = `"($R=>_$.Ps($R[0],$R[1]=new DOMException(\\"This is an example message.\\",\\"Example\\")))($R[\\"example\\"])"`; exports[`DOMException > crossSerializeStream > supports DOMException 1`] = `"$R[0]=_$.P()"`; @@ -20,6 +20,14 @@ exports[`DOMException > serialize > supports DOMException 1`] = `"new DOMExcepti exports[`DOMException > serializeAsync > supports DOMException 1`] = `"Promise.resolve(new DOMException(\\"This is an example message.\\",\\"Example\\"))"`; +exports[`DOMException > toCrossJSON > supports DOMException 1`] = `"{\\"t\\":39,\\"i\\":0,\\"s\\":\\"This is an example message.\\",\\"c\\":\\"Example\\"}"`; + +exports[`DOMException > toCrossJSONAsync > supports DOMException 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":39,\\"i\\":1,\\"s\\":\\"This is an example message.\\",\\"c\\":\\"Example\\"}}"`; + +exports[`DOMException > toCrossJSONStream > supports DOMException 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`DOMException > toCrossJSONStream > supports DOMException 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":39,\\"i\\":1,\\"s\\":\\"This is an example message.\\",\\"c\\":\\"Example\\"}}"`; + exports[`DOMException > toJSON > supports DOMException 1`] = `"{\\"t\\":{\\"t\\":39,\\"i\\":0,\\"s\\":\\"This is an example message.\\",\\"c\\":\\"Example\\"},\\"f\\":16383,\\"m\\":[]}"`; exports[`DOMException > toJSONAsync > supports DOMException 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":39,\\"i\\":1,\\"s\\":\\"This is an example message.\\",\\"c\\":\\"Example\\"}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/web-api/__snapshots__/event.test.ts.snap b/packages/seroval/test/web-api/__snapshots__/event.test.ts.snap index 1aae1165..40c4f8bc 100644 --- a/packages/seroval/test/web-api/__snapshots__/event.test.ts.snap +++ b/packages/seroval/test/web-api/__snapshots__/event.test.ts.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Event > crossSerialize > scoped > supports Event 1`] = `"($R=>($R[0]=new Event(\\"example\\",$R[1]={bubbles:!1,cancelable:!1,composed:!1})))($R[\\"example\\"])"`; +exports[`Event > crossSerialize > scoped > supports Event 1`] = `"($R=>$R[0]=new Event(\\"example\\",$R[1]={bubbles:!1,cancelable:!1,composed:!1}))($R[\\"example\\"])"`; exports[`Event > crossSerialize > supports Event 1`] = `"$R[0]=new Event(\\"example\\",$R[1]={bubbles:!1,cancelable:!1,composed:!1})"`; -exports[`Event > crossSerializeAsync > scoped > supports Event 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=new Event(\\"example\\",$R[2]={bubbles:!1,cancelable:!1,composed:!1}))))($R[\\"example\\"])"`; +exports[`Event > crossSerializeAsync > scoped > supports Event 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=new Event(\\"example\\",$R[2]={bubbles:!1,cancelable:!1,composed:!1})))($R[\\"example\\"])"`; exports[`Event > crossSerializeAsync > supports Event 1`] = `"$R[0]=Promise.resolve($R[1]=new Event(\\"example\\",$R[2]={bubbles:!1,cancelable:!1,composed:!1}))"`; -exports[`Event > crossSerializeStream > scoped > supports Event 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`Event > crossSerializeStream > scoped > supports Event 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`Event > crossSerializeStream > scoped > supports Event 2`] = `"($R=>(_$.Ps($R[0],$R[1]=new Event(\\"example\\",$R[2]={bubbles:!1,cancelable:!1,composed:!1}))))($R[\\"example\\"])"`; +exports[`Event > crossSerializeStream > scoped > supports Event 2`] = `"($R=>_$.Ps($R[0],$R[1]=new Event(\\"example\\",$R[2]={bubbles:!1,cancelable:!1,composed:!1})))($R[\\"example\\"])"`; exports[`Event > crossSerializeStream > supports Event 1`] = `"$R[0]=_$.P()"`; @@ -20,6 +20,14 @@ exports[`Event > serialize > supports Event 1`] = `"new Event(\\"example\\",{bub exports[`Event > serializeAsync > supports Event 1`] = `"Promise.resolve(new Event(\\"example\\",{bubbles:!1,cancelable:!1,composed:!1}))"`; +exports[`Event > toCrossJSON > supports Event 1`] = `"{\\"t\\":37,\\"i\\":0,\\"s\\":\\"example\\",\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"bubbles\\",\\"cancelable\\",\\"composed\\"],\\"v\\":[{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3}],\\"s\\":3},\\"o\\":0}}"`; + +exports[`Event > toCrossJSONAsync > supports Event 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":37,\\"i\\":1,\\"s\\":\\"example\\",\\"f\\":{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"bubbles\\",\\"cancelable\\",\\"composed\\"],\\"v\\":[{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3}],\\"s\\":3},\\"o\\":0}}}"`; + +exports[`Event > toCrossJSONStream > supports Event 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`Event > toCrossJSONStream > supports Event 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":37,\\"i\\":1,\\"s\\":\\"example\\",\\"f\\":{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"bubbles\\",\\"cancelable\\",\\"composed\\"],\\"v\\":[{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3}],\\"s\\":3},\\"o\\":0}}}"`; + exports[`Event > toJSON > supports Event 1`] = `"{\\"t\\":{\\"t\\":37,\\"i\\":0,\\"s\\":\\"example\\",\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"bubbles\\",\\"cancelable\\",\\"composed\\"],\\"v\\":[{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3}],\\"s\\":3},\\"o\\":0}},\\"f\\":16383,\\"m\\":[]}"`; exports[`Event > toJSONAsync > supports Event 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":37,\\"i\\":1,\\"s\\":\\"example\\",\\"f\\":{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"bubbles\\",\\"cancelable\\",\\"composed\\"],\\"v\\":[{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3},{\\"t\\":2,\\"s\\":3}],\\"s\\":3},\\"o\\":0}}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/web-api/__snapshots__/file.test.ts.snap b/packages/seroval/test/web-api/__snapshots__/file.test.ts.snap index 5ae680d8..cf4946a2 100644 --- a/packages/seroval/test/web-api/__snapshots__/file.test.ts.snap +++ b/packages/seroval/test/web-api/__snapshots__/file.test.ts.snap @@ -1,9 +1,11 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`File > crossSerializeAsync > scoped > supports File 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=new File([$R[2]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],\\"hello.txt\\",{type:\\"text/plain\\",lastModified:1681027542680}))))($R[\\"example\\"])"`; +exports[`File > crossSerializeAsync > scoped > supports File 1`] = `"($R=>$R[0]=new File([$R[1]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],\\"hello.txt\\",{type:\\"text/plain\\",lastModified:1681027542680}))($R[\\"example\\"])"`; -exports[`File > crossSerializeAsync > supports File 1`] = `"$R[0]=Promise.resolve($R[1]=new File([$R[2]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],\\"hello.txt\\",{type:\\"text/plain\\",lastModified:1681027542680}))"`; +exports[`File > crossSerializeAsync > supports File 1`] = `"$R[0]=new File([$R[1]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],\\"hello.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})"`; -exports[`File > serializeAsync > supports File 1`] = `"Promise.resolve(new File([new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],\\"hello.txt\\",{type:\\"text/plain\\",lastModified:1681027542680}))"`; +exports[`File > serializeAsync > supports File 1`] = `"new File([new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],\\"hello.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})"`; -exports[`File > toJSONAsync > supports File 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":24,\\"i\\":1,\\"c\\":\\"text/plain\\",\\"m\\":\\"hello.txt\\",\\"f\\":{\\"t\\":21,\\"i\\":2,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100]},\\"b\\":1681027542680}},\\"f\\":16383,\\"m\\":[]}"`; +exports[`File > toCrossJSONAsync > supports File 1`] = `"{\\"t\\":24,\\"i\\":0,\\"c\\":\\"text/plain\\",\\"m\\":\\"hello.txt\\",\\"f\\":{\\"t\\":21,\\"i\\":1,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100]},\\"b\\":1681027542680}"`; + +exports[`File > toJSONAsync > supports File 1`] = `"{\\"t\\":{\\"t\\":24,\\"i\\":0,\\"c\\":\\"text/plain\\",\\"m\\":\\"hello.txt\\",\\"f\\":{\\"t\\":21,\\"i\\":1,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100]},\\"b\\":1681027542680},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/web-api/__snapshots__/form-data.test.ts.snap b/packages/seroval/test/web-api/__snapshots__/form-data.test.ts.snap index e5a2f210..08697eab 100644 --- a/packages/seroval/test/web-api/__snapshots__/form-data.test.ts.snap +++ b/packages/seroval/test/web-api/__snapshots__/form-data.test.ts.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`FormData > crossSerialize > scoped > supports FormData 1`] = `"($R=>(($R[0]=new FormData(),$R[0].append(\\"hello\\",\\"world\\"),$R[0].append(\\"foo\\",\\"bar\\"),$R[0])))($R[\\"example\\"])"`; +exports[`FormData > crossSerialize > scoped > supports FormData 1`] = `"($R=>($R[0]=new FormData(),$R[0].append(\\"hello\\",\\"world\\"),$R[0].append(\\"foo\\",\\"bar\\"),$R[0]))($R[\\"example\\"])"`; exports[`FormData > crossSerialize > supports FormData 1`] = `"($R[0]=new FormData(),$R[0].append(\\"hello\\",\\"world\\"),$R[0].append(\\"foo\\",\\"bar\\"),$R[0])"`; -exports[`FormData > crossSerializeAsync > scoped > supports FormData 1`] = `"($R=>($R[0]=Promise.resolve(($R[1]=new FormData(),$R[1].append(\\"hello-world\\",$R[2]=new File([$R[3]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],\\"hello.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})),$R[1].append(\\"foo-bar\\",$R[4]=new File([$R[5]=new Uint8Array([70,111,111,32,66,97,114]).buffer],\\"foo-bar.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})),$R[1]))))($R[\\"example\\"])"`; +exports[`FormData > crossSerializeAsync > scoped > supports FormData 1`] = `"($R=>($R[0]=new FormData(),$R[0].append(\\"hello-world\\",$R[1]=new File([$R[2]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],\\"hello.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})),$R[0].append(\\"foo-bar\\",$R[3]=new File([$R[4]=new Uint8Array([70,111,111,32,66,97,114]).buffer],\\"foo-bar.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})),$R[0]))($R[\\"example\\"])"`; -exports[`FormData > crossSerializeAsync > supports FormData 1`] = `"$R[0]=Promise.resolve(($R[1]=new FormData(),$R[1].append(\\"hello-world\\",$R[2]=new File([$R[3]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],\\"hello.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})),$R[1].append(\\"foo-bar\\",$R[4]=new File([$R[5]=new Uint8Array([70,111,111,32,66,97,114]).buffer],\\"foo-bar.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})),$R[1]))"`; +exports[`FormData > crossSerializeAsync > supports FormData 1`] = `"($R[0]=new FormData(),$R[0].append(\\"hello-world\\",$R[1]=new File([$R[2]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],\\"hello.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})),$R[0].append(\\"foo-bar\\",$R[3]=new File([$R[4]=new Uint8Array([70,111,111,32,66,97,114]).buffer],\\"foo-bar.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})),$R[0])"`; -exports[`FormData > crossSerializeStream > scoped > supports FormData 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`FormData > crossSerializeStream > scoped > supports FormData 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`FormData > crossSerializeStream > scoped > supports FormData 2`] = `"($R=>(_$.Ps($R[0],($R[1]=new FormData(),$R[1].append(\\"hello\\",\\"world\\"),$R[1].append(\\"foo\\",\\"bar\\"),$R[1]))))($R[\\"example\\"])"`; +exports[`FormData > crossSerializeStream > scoped > supports FormData 2`] = `"($R=>_$.Ps($R[0],($R[1]=new FormData(),$R[1].append(\\"hello\\",\\"world\\"),$R[1].append(\\"foo\\",\\"bar\\"),$R[1])))($R[\\"example\\"])"`; exports[`FormData > crossSerializeStream > supports FormData 1`] = `"$R[0]=_$.P()"`; @@ -18,8 +18,16 @@ exports[`FormData > crossSerializeStream > supports FormData 2`] = `"_$.Ps($R[0] exports[`FormData > serialize > supports FormData 1`] = `"(h=>((h=new FormData(),h.append(\\"hello\\",\\"world\\"),h.append(\\"foo\\",\\"bar\\"),h)))()"`; -exports[`FormData > serializeAsync > supports FormData 1`] = `"(h=>(Promise.resolve((h=new FormData(),h.append(\\"hello-world\\",new File([new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],\\"hello.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})),h.append(\\"foo-bar\\",new File([new Uint8Array([70,111,111,32,66,97,114]).buffer],\\"foo-bar.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})),h))))()"`; +exports[`FormData > serializeAsync > supports FormData 1`] = `"(h=>((h=new FormData(),h.append(\\"hello-world\\",new File([new Uint8Array([72,101,108,108,111,32,87,111,114,108,100]).buffer],\\"hello.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})),h.append(\\"foo-bar\\",new File([new Uint8Array([70,111,111,32,66,97,114]).buffer],\\"foo-bar.txt\\",{type:\\"text/plain\\",lastModified:1681027542680})),h)))()"`; + +exports[`FormData > toCrossJSON > supports FormData 1`] = `"{\\"t\\":26,\\"i\\":0,\\"e\\":{\\"k\\":[\\"hello\\",\\"foo\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"},{\\"t\\":1,\\"s\\":\\"bar\\"}],\\"s\\":2}}"`; + +exports[`FormData > toCrossJSONAsync > supports FormData 1`] = `"{\\"t\\":26,\\"i\\":0,\\"e\\":{\\"k\\":[\\"hello-world\\",\\"foo-bar\\"],\\"v\\":[{\\"t\\":24,\\"i\\":1,\\"c\\":\\"text/plain\\",\\"m\\":\\"hello.txt\\",\\"f\\":{\\"t\\":21,\\"i\\":2,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100]},\\"b\\":1681027542680},{\\"t\\":24,\\"i\\":3,\\"c\\":\\"text/plain\\",\\"m\\":\\"foo-bar.txt\\",\\"f\\":{\\"t\\":21,\\"i\\":4,\\"s\\":[70,111,111,32,66,97,114]},\\"b\\":1681027542680}],\\"s\\":2}}"`; + +exports[`FormData > toCrossJSONStream > supports FormData 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`FormData > toCrossJSONStream > supports FormData 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":26,\\"i\\":1,\\"e\\":{\\"k\\":[\\"hello\\",\\"foo\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"},{\\"t\\":1,\\"s\\":\\"bar\\"}],\\"s\\":2}}}"`; exports[`FormData > toJSON > supports FormData 1`] = `"{\\"t\\":{\\"t\\":26,\\"i\\":0,\\"e\\":{\\"k\\":[\\"hello\\",\\"foo\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"world\\"},{\\"t\\":1,\\"s\\":\\"bar\\"}],\\"s\\":2}},\\"f\\":16383,\\"m\\":[]}"`; -exports[`FormData > toJSONAsync > supports FormData 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":26,\\"i\\":1,\\"e\\":{\\"k\\":[\\"example\\",\\"foo-bar\\"],\\"v\\":[{\\"t\\":24,\\"i\\":2,\\"c\\":\\"text/plain\\",\\"m\\":\\"hello.txt\\",\\"f\\":{\\"t\\":21,\\"i\\":3,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100]},\\"b\\":1681027542680},{\\"t\\":24,\\"i\\":4,\\"c\\":\\"text/plain\\",\\"m\\":\\"foo-bar.txt\\",\\"f\\":{\\"t\\":21,\\"i\\":5,\\"s\\":[70,111,111,32,66,97,114]},\\"b\\":1681027542680}],\\"s\\":2}}},\\"f\\":16383,\\"m\\":[]}"`; +exports[`FormData > toJSONAsync > supports FormData 1`] = `"{\\"t\\":{\\"t\\":26,\\"i\\":0,\\"e\\":{\\"k\\":[\\"hello-world\\",\\"foo-bar\\"],\\"v\\":[{\\"t\\":24,\\"i\\":1,\\"c\\":\\"text/plain\\",\\"m\\":\\"hello.txt\\",\\"f\\":{\\"t\\":21,\\"i\\":2,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100]},\\"b\\":1681027542680},{\\"t\\":24,\\"i\\":3,\\"c\\":\\"text/plain\\",\\"m\\":\\"foo-bar.txt\\",\\"f\\":{\\"t\\":21,\\"i\\":4,\\"s\\":[70,111,111,32,66,97,114]},\\"b\\":1681027542680}],\\"s\\":2}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/web-api/__snapshots__/headers.test.ts.snap b/packages/seroval/test/web-api/__snapshots__/headers.test.ts.snap index 4ae1ed7d..d2d66cd0 100644 --- a/packages/seroval/test/web-api/__snapshots__/headers.test.ts.snap +++ b/packages/seroval/test/web-api/__snapshots__/headers.test.ts.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Headers > crossSerialize > scoped > supports Headers 1`] = `"($R=>($R[0]=new Headers({\\"content-encoding\\":\\"gzip\\",\\"content-type\\":\\"text/plain\\"})))($R[\\"example\\"])"`; +exports[`Headers > crossSerialize > scoped > supports Headers 1`] = `"($R=>$R[0]=new Headers({\\"content-encoding\\":\\"gzip\\",\\"content-type\\":\\"text/plain\\"}))($R[\\"example\\"])"`; exports[`Headers > crossSerialize > supports Headers 1`] = `"$R[0]=new Headers({\\"content-encoding\\":\\"gzip\\",\\"content-type\\":\\"text/plain\\"})"`; -exports[`Headers > crossSerializeAsync > scoped > supports Headers 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=new Headers({\\"content-encoding\\":\\"gzip\\",\\"content-type\\":\\"text/plain\\"}))))($R[\\"example\\"])"`; +exports[`Headers > crossSerializeAsync > scoped > supports Headers 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=new Headers({\\"content-encoding\\":\\"gzip\\",\\"content-type\\":\\"text/plain\\"})))($R[\\"example\\"])"`; exports[`Headers > crossSerializeAsync > supports Headers 1`] = `"$R[0]=Promise.resolve($R[1]=new Headers({\\"content-encoding\\":\\"gzip\\",\\"content-type\\":\\"text/plain\\"}))"`; -exports[`Headers > crossSerializeStream > scoped > supports Headers 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`Headers > crossSerializeStream > scoped > supports Headers 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`Headers > crossSerializeStream > scoped > supports Headers 2`] = `"($R=>(_$.Ps($R[0],$R[1]=new Headers({\\"content-encoding\\":\\"gzip\\",\\"content-type\\":\\"text/plain\\"}))))($R[\\"example\\"])"`; +exports[`Headers > crossSerializeStream > scoped > supports Headers 2`] = `"($R=>_$.Ps($R[0],$R[1]=new Headers({\\"content-encoding\\":\\"gzip\\",\\"content-type\\":\\"text/plain\\"})))($R[\\"example\\"])"`; exports[`Headers > crossSerializeStream > supports Headers 1`] = `"$R[0]=_$.P()"`; @@ -20,6 +20,14 @@ exports[`Headers > serialize > supports Headers 1`] = `"new Headers({\\"content- exports[`Headers > serializeAsync > supports Headers 1`] = `"Promise.resolve(new Headers({\\"content-encoding\\":\\"gzip\\",\\"content-type\\":\\"text/plain\\"}))"`; +exports[`Headers > toCrossJSON > supports Headers 1`] = `"{\\"t\\":25,\\"i\\":0,\\"e\\":{\\"k\\":[\\"content-encoding\\",\\"content-type\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"gzip\\"},{\\"t\\":1,\\"s\\":\\"text/plain\\"}],\\"s\\":2}}"`; + +exports[`Headers > toCrossJSONAsync > supports Headers 1`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":25,\\"i\\":1,\\"e\\":{\\"k\\":[\\"content-encoding\\",\\"content-type\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"gzip\\"},{\\"t\\":1,\\"s\\":\\"text/plain\\"}],\\"s\\":2}}}"`; + +exports[`Headers > toCrossJSONStream > supports Headers 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`Headers > toCrossJSONStream > supports Headers 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":25,\\"i\\":1,\\"e\\":{\\"k\\":[\\"content-encoding\\",\\"content-type\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"gzip\\"},{\\"t\\":1,\\"s\\":\\"text/plain\\"}],\\"s\\":2}}}"`; + exports[`Headers > toJSON > supports Headers 1`] = `"{\\"t\\":{\\"t\\":25,\\"i\\":0,\\"e\\":{\\"k\\":[\\"content-encoding\\",\\"content-type\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"gzip\\"},{\\"t\\":1,\\"s\\":\\"text/plain\\"}],\\"s\\":2}},\\"f\\":16383,\\"m\\":[]}"`; exports[`Headers > toJSONAsync > supports Headers 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":25,\\"i\\":1,\\"e\\":{\\"k\\":[\\"content-encoding\\",\\"content-type\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"gzip\\"},{\\"t\\":1,\\"s\\":\\"text/plain\\"}],\\"s\\":2}}},\\"f\\":16383,\\"m\\":[]}"`; diff --git a/packages/seroval/test/web-api/__snapshots__/readable-stream.test.ts.snap b/packages/seroval/test/web-api/__snapshots__/readable-stream.test.ts.snap index 19f2f6af..1f74f37b 100644 --- a/packages/seroval/test/web-api/__snapshots__/readable-stream.test.ts.snap +++ b/packages/seroval/test/web-api/__snapshots__/readable-stream.test.ts.snap @@ -1,29 +1,69 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream 1`] = `"($R=>($R[0]=_$.S()))($R[\\"example\\"])"`; +exports[`ReadableStream > crossSerializeAsync > scoped > supports ReadableStream 1`] = `"($R=>$R[0]=($R[1]=s=>new ReadableStream({start:c=>Promise.resolve().then((i,v)=>{for(i=0;i crossSerializeStream > scoped > supports ReadableStream 2`] = `"($R=>(_$.Se($R[0],0,\\"foo\\")))($R[\\"example\\"])"`; +exports[`ReadableStream > crossSerializeAsync > scoped > supports ReadableStream errors 1`] = `"($R=>$R[0]=($R[1]=s=>new ReadableStream({start:c=>Promise.resolve().then((i,v)=>{for(i=0;i crossSerializeStream > scoped > supports ReadableStream 3`] = `"($R=>(_$.Se($R[0],0,\\"bar\\")))($R[\\"example\\"])"`; +exports[`ReadableStream > crossSerializeAsync > supports ReadableStream 1`] = `"$R[0]=($R[1]=s=>new ReadableStream({start:c=>Promise.resolve().then((i,v)=>{for(i=0;i crossSerializeStream > scoped > supports ReadableStream 4`] = `"($R=>(_$.Se($R[0],0,\\"baz\\")))($R[\\"example\\"])"`; +exports[`ReadableStream > crossSerializeAsync > supports ReadableStream errors 1`] = `"$R[0]=($R[1]=s=>new ReadableStream({start:c=>Promise.resolve().then((i,v)=>{for(i=0;i crossSerializeStream > scoped > supports ReadableStream 5`] = `"($R=>(_$.Se($R[0],2)))($R[\\"example\\"])"`; +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream 1`] = `"($R=>$R[0]=_$.S())($R[\\"example\\"])"`; -exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream errors 1`] = `"($R=>($R[0]=_$.S()))($R[\\"example\\"])"`; +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream 2`] = `"($R=>_$.Se($R[0],\\"foo\\"))($R[\\"example\\"])"`; -exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream errors 2`] = `"($R=>(_$.Se($R[0],1,$R[1]=Object.assign(new Error(\\"Oops!\\"),{stack:\\"\\"}))))($R[\\"example\\"])"`; +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream 3`] = `"($R=>_$.Se($R[0],\\"bar\\"))($R[\\"example\\"])"`; + +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream 4`] = `"($R=>_$.Se($R[0],\\"baz\\"))($R[\\"example\\"])"`; + +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream 5`] = `"($R=>_$.Sc($R[0]))($R[\\"example\\"])"`; + +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream errors 1`] = `"($R=>$R[0]=_$.S())($R[\\"example\\"])"`; + +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream errors 2`] = `"($R=>_$.St($R[0],$R[1]=Object.assign(new Error(\\"Oops!\\"),{stack:\\"\\"})))($R[\\"example\\"])"`; exports[`ReadableStream > crossSerializeStream > supports ReadableStream 1`] = `"$R[0]=_$.S()"`; -exports[`ReadableStream > crossSerializeStream > supports ReadableStream 2`] = `"_$.Se($R[0],0,\\"foo\\")"`; +exports[`ReadableStream > crossSerializeStream > supports ReadableStream 2`] = `"_$.Se($R[0],\\"foo\\")"`; -exports[`ReadableStream > crossSerializeStream > supports ReadableStream 3`] = `"_$.Se($R[0],0,\\"bar\\")"`; +exports[`ReadableStream > crossSerializeStream > supports ReadableStream 3`] = `"_$.Se($R[0],\\"bar\\")"`; -exports[`ReadableStream > crossSerializeStream > supports ReadableStream 4`] = `"_$.Se($R[0],0,\\"baz\\")"`; +exports[`ReadableStream > crossSerializeStream > supports ReadableStream 4`] = `"_$.Se($R[0],\\"baz\\")"`; -exports[`ReadableStream > crossSerializeStream > supports ReadableStream 5`] = `"_$.Se($R[0],2)"`; +exports[`ReadableStream > crossSerializeStream > supports ReadableStream 5`] = `"_$.Sc($R[0])"`; exports[`ReadableStream > crossSerializeStream > supports ReadableStream errors 1`] = `"$R[0]=_$.S()"`; -exports[`ReadableStream > crossSerializeStream > supports ReadableStream errors 2`] = `"_$.Se($R[0],1,$R[1]=Object.assign(new Error(\\"Oops!\\"),{stack:\\"\\"}))"`; +exports[`ReadableStream > crossSerializeStream > supports ReadableStream errors 2`] = `"_$.St($R[0],$R[1]=Object.assign(new Error(\\"Oops!\\"),{stack:\\"\\"}))"`; + +exports[`ReadableStream > serializeAsync > supports ReadableStream 1`] = `"(s=>new ReadableStream({start:c=>Promise.resolve().then((i,v)=>{for(i=0;i serializeAsync > supports ReadableStream errors 1`] = `"(s=>new ReadableStream({start:c=>Promise.resolve().then((i,v)=>{for(i=0;i serializeAsync > supports ReadableStream errors 2`] = `"Oops!"`; + +exports[`ReadableStream > toCrossJSONAsync > supports ReadableStream 1`] = `"{\\"t\\":46,\\"i\\":0,\\"a\\":[{\\"t\\":47,\\"i\\":1},{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":3,\\"l\\":4,\\"a\\":[{\\"t\\":1,\\"s\\":\\"foo\\"},{\\"t\\":1,\\"s\\":\\"bar\\"},{\\"t\\":1,\\"s\\":\\"baz\\"},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]}"`; + +exports[`ReadableStream > toCrossJSONAsync > supports ReadableStream errors 1`] = `"{\\"t\\":46,\\"i\\":0,\\"a\\":[{\\"t\\":47,\\"i\\":1},{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":3,\\"l\\":1,\\"a\\":[{\\"t\\":13,\\"i\\":4,\\"s\\":0,\\"m\\":\\"Oops!\\",\\"p\\":{\\"k\\":[\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":1}}],\\"o\\":0},{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":0}],\\"s\\":3},\\"o\\":0}]}"`; + +exports[`ReadableStream > toCrossJSONAsync > supports ReadableStream errors 2`] = `"Oops!"`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream 1`] = `"{\\"t\\":31,\\"i\\":0}"`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream 2`] = `"{\\"t\\":32,\\"i\\":0,\\"f\\":{\\"t\\":1,\\"s\\":\\"foo\\"}}"`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream 3`] = `"{\\"t\\":32,\\"i\\":0,\\"f\\":{\\"t\\":1,\\"s\\":\\"bar\\"}}"`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream 4`] = `"{\\"t\\":32,\\"i\\":0,\\"f\\":{\\"t\\":1,\\"s\\":\\"baz\\"}}"`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream 5`] = `"{\\"t\\":33,\\"i\\":0}"`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream errors 1`] = `"{\\"t\\":31,\\"i\\":0}"`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream errors 2`] = `"{\\"t\\":34,\\"i\\":0,\\"f\\":{\\"t\\":13,\\"i\\":1,\\"s\\":0,\\"m\\":\\"Oops!\\",\\"p\\":{\\"k\\":[\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":1}}}"`; + +exports[`ReadableStream > toJSONAsync > supports ReadableStream 1`] = `"{\\"t\\":{\\"t\\":46,\\"i\\":0,\\"a\\":[{\\"t\\":47,\\"i\\":1},{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":3,\\"l\\":4,\\"a\\":[{\\"t\\":1,\\"s\\":\\"foo\\"},{\\"t\\":1,\\"s\\":\\"bar\\"},{\\"t\\":1,\\"s\\":\\"baz\\"},{\\"t\\":2,\\"s\\":1}],\\"o\\":0},{\\"t\\":0,\\"s\\":-1},{\\"t\\":0,\\"s\\":3}],\\"s\\":3},\\"o\\":0}]},\\"f\\":16383,\\"m\\":[]}"`; + +exports[`ReadableStream > toJSONAsync > supports ReadableStream errors 1`] = `"{\\"t\\":{\\"t\\":46,\\"i\\":0,\\"a\\":[{\\"t\\":47,\\"i\\":1},{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"v\\",\\"t\\",\\"d\\"],\\"v\\":[{\\"t\\":9,\\"i\\":3,\\"l\\":1,\\"a\\":[{\\"t\\":13,\\"i\\":4,\\"s\\":0,\\"m\\":\\"Oops!\\",\\"p\\":{\\"k\\":[\\"stack\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":1}}],\\"o\\":0},{\\"t\\":0,\\"s\\":0},{\\"t\\":0,\\"s\\":0}],\\"s\\":3},\\"o\\":0}]},\\"f\\":16383,\\"m\\":[]}"`; + +exports[`ReadableStream > toJSONAsync > supports ReadableStream errors 2`] = `"Oops!"`; diff --git a/packages/seroval/test/web-api/__snapshots__/request.test.ts.snap b/packages/seroval/test/web-api/__snapshots__/request.test.ts.snap index 24b84c66..6a1366cf 100644 --- a/packages/seroval/test/web-api/__snapshots__/request.test.ts.snap +++ b/packages/seroval/test/web-api/__snapshots__/request.test.ts.snap @@ -1,21 +1,29 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Request > crossSerializeAsync > scoped > supports Blob 1`] = `"($R=>($R[0]=new Request(\\"http://localhost:3000/\\",$R[1]={body:$R[2]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,cache:\\"default\\",credentials:\\"same-origin\\",headers:$R[3]=new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),integrity:\\"\\",keepalive:!1,method:\\"POST\\",mode:\\"cors\\",redirect:\\"follow\\",referrer:\\"about:client\\",referrerPolicy:\\"\\"})))($R[\\"example\\"])"`; +exports[`Request > crossSerializeAsync > scoped > supports Blob 1`] = `"($R=>$R[0]=new Request(\\"http://localhost:3000/\\",$R[1]={body:$R[2]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,cache:\\"default\\",credentials:\\"same-origin\\",headers:$R[3]=new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),integrity:\\"\\",keepalive:!1,method:\\"POST\\",mode:\\"cors\\",redirect:\\"follow\\",referrer:\\"about:client\\",referrerPolicy:\\"\\"}))($R[\\"example\\"])"`; exports[`Request > crossSerializeAsync > supports Blob 1`] = `"$R[0]=new Request(\\"http://localhost:3000/\\",$R[1]={body:$R[2]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,cache:\\"default\\",credentials:\\"same-origin\\",headers:$R[3]=new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),integrity:\\"\\",keepalive:!1,method:\\"POST\\",mode:\\"cors\\",redirect:\\"follow\\",referrer:\\"about:client\\",referrerPolicy:\\"\\"})"`; -exports[`Request > crossSerializeStream > scoped > supports Request 1`] = `"($R=>($R[0]=new Request(\\"http://localhost:3000/\\",$R[1]={body:$R[2]=_$.S(),cache:\\"default\\",credentials:\\"same-origin\\",headers:$R[3]=new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),integrity:\\"\\",keepalive:!1,method:\\"POST\\",mode:\\"cors\\",redirect:\\"follow\\",referrer:\\"about:client\\",referrerPolicy:\\"\\"})))($R[\\"example\\"])"`; +exports[`Request > crossSerializeStream > scoped > supports Request 1`] = `"($R=>$R[0]=new Request(\\"http://localhost:3000/\\",$R[1]={body:$R[2]=_$.S(),cache:\\"default\\",credentials:\\"same-origin\\",headers:$R[3]=new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),integrity:\\"\\",keepalive:!1,method:\\"POST\\",mode:\\"cors\\",redirect:\\"follow\\",referrer:\\"about:client\\",referrerPolicy:\\"\\"}))($R[\\"example\\"])"`; -exports[`Request > crossSerializeStream > scoped > supports Request 2`] = `"($R=>(_$.Se($R[2],0,$R[4]=new Uint8Array($R[5]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,0,12))))($R[\\"example\\"])"`; +exports[`Request > crossSerializeStream > scoped > supports Request 2`] = `"($R=>_$.Se($R[2],$R[4]=new Uint8Array($R[5]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,0,12)))($R[\\"example\\"])"`; -exports[`Request > crossSerializeStream > scoped > supports Request 3`] = `"($R=>(_$.Se($R[2],2)))($R[\\"example\\"])"`; +exports[`Request > crossSerializeStream > scoped > supports Request 3`] = `"($R=>_$.Sc($R[2]))($R[\\"example\\"])"`; exports[`Request > crossSerializeStream > supports Request 1`] = `"$R[0]=new Request(\\"http://localhost:3000/\\",$R[1]={body:$R[2]=_$.S(),cache:\\"default\\",credentials:\\"same-origin\\",headers:$R[3]=new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),integrity:\\"\\",keepalive:!1,method:\\"POST\\",mode:\\"cors\\",redirect:\\"follow\\",referrer:\\"about:client\\",referrerPolicy:\\"\\"})"`; -exports[`Request > crossSerializeStream > supports Request 2`] = `"_$.Se($R[2],0,$R[4]=new Uint8Array($R[5]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,0,12))"`; +exports[`Request > crossSerializeStream > supports Request 2`] = `"_$.Se($R[2],$R[4]=new Uint8Array($R[5]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,0,12))"`; -exports[`Request > crossSerializeStream > supports Request 3`] = `"_$.Se($R[2],2)"`; +exports[`Request > crossSerializeStream > supports Request 3`] = `"_$.Sc($R[2])"`; exports[`Request > serializeAsync > supports Request 1`] = `"new Request(\\"http://localhost:3000/\\",{body:new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,cache:\\"default\\",credentials:\\"same-origin\\",headers:new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),integrity:\\"\\",keepalive:!1,method:\\"POST\\",mode:\\"cors\\",redirect:\\"follow\\",referrer:\\"about:client\\",referrerPolicy:\\"\\"})"`; +exports[`Request > toCrossJSONStream > supports Request 1`] = `"{\\"t\\":35,\\"i\\":0,\\"s\\":\\"http://localhost:3000/\\",\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"body\\",\\"cache\\",\\"credentials\\",\\"headers\\",\\"integrity\\",\\"keepalive\\",\\"method\\",\\"mode\\",\\"redirect\\",\\"referrer\\",\\"referrerPolicy\\"],\\"v\\":[{\\"t\\":31,\\"i\\":2},{\\"t\\":1,\\"s\\":\\"default\\"},{\\"t\\":1,\\"s\\":\\"same-origin\\"},{\\"t\\":25,\\"i\\":3,\\"e\\":{\\"k\\":[\\"content-type\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"text/plain;charset=UTF-8\\"}],\\"s\\":1}},{\\"t\\":1,\\"s\\":\\"\\"},{\\"t\\":2,\\"s\\":3},{\\"t\\":1,\\"s\\":\\"POST\\"},{\\"t\\":1,\\"s\\":\\"cors\\"},{\\"t\\":1,\\"s\\":\\"follow\\"},{\\"t\\":1,\\"s\\":\\"about:client\\"},{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":11},\\"o\\":0}}"`; + +exports[`Request > toCrossJSONStream > supports Request 2`] = `"{\\"t\\":32,\\"i\\":2,\\"f\\":{\\"t\\":15,\\"i\\":4,\\"l\\":12,\\"c\\":\\"Uint8Array\\",\\"f\\":{\\"t\\":21,\\"i\\":5,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100,33]},\\"b\\":0}}"`; + +exports[`Request > toCrossJSONStream > supports Request 3`] = `"{\\"t\\":33,\\"i\\":2}"`; + exports[`Request > toJSONAsync > supports Request 1`] = `"{\\"t\\":{\\"t\\":35,\\"i\\":0,\\"s\\":\\"http://localhost:3000/\\",\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"body\\",\\"cache\\",\\"credentials\\",\\"headers\\",\\"integrity\\",\\"keepalive\\",\\"method\\",\\"mode\\",\\"redirect\\",\\"referrer\\",\\"referrerPolicy\\"],\\"v\\":[{\\"t\\":21,\\"i\\":2,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100,33]},{\\"t\\":1,\\"s\\":\\"default\\"},{\\"t\\":1,\\"s\\":\\"same-origin\\"},{\\"t\\":25,\\"i\\":3,\\"e\\":{\\"k\\":[\\"content-type\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"text/plain;charset=UTF-8\\"}],\\"s\\":1}},{\\"t\\":1,\\"s\\":\\"\\"},{\\"t\\":2,\\"s\\":3},{\\"t\\":1,\\"s\\":\\"POST\\"},{\\"t\\":1,\\"s\\":\\"cors\\"},{\\"t\\":1,\\"s\\":\\"follow\\"},{\\"t\\":1,\\"s\\":\\"about:client\\"},{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":11},\\"o\\":0}},\\"f\\":16383,\\"m\\":[]}"`; + +exports[`Request > toJSONAsync > supports Request 2`] = `"{\\"t\\":35,\\"i\\":0,\\"s\\":\\"http://localhost:3000/\\",\\"f\\":{\\"t\\":10,\\"i\\":1,\\"p\\":{\\"k\\":[\\"body\\",\\"cache\\",\\"credentials\\",\\"headers\\",\\"integrity\\",\\"keepalive\\",\\"method\\",\\"mode\\",\\"redirect\\",\\"referrer\\",\\"referrerPolicy\\"],\\"v\\":[{\\"t\\":21,\\"i\\":2,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100,33]},{\\"t\\":1,\\"s\\":\\"default\\"},{\\"t\\":1,\\"s\\":\\"same-origin\\"},{\\"t\\":25,\\"i\\":3,\\"e\\":{\\"k\\":[\\"content-type\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"text/plain;charset=UTF-8\\"}],\\"s\\":1}},{\\"t\\":1,\\"s\\":\\"\\"},{\\"t\\":2,\\"s\\":3},{\\"t\\":1,\\"s\\":\\"POST\\"},{\\"t\\":1,\\"s\\":\\"cors\\"},{\\"t\\":1,\\"s\\":\\"follow\\"},{\\"t\\":1,\\"s\\":\\"about:client\\"},{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":11},\\"o\\":0}}"`; diff --git a/packages/seroval/test/web-api/__snapshots__/response.test.ts.snap b/packages/seroval/test/web-api/__snapshots__/response.test.ts.snap index 79600a67..bf081b31 100644 --- a/packages/seroval/test/web-api/__snapshots__/response.test.ts.snap +++ b/packages/seroval/test/web-api/__snapshots__/response.test.ts.snap @@ -1,21 +1,29 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Response > crossSerializeAsync > scoped > supports Blob 1`] = `"($R=>($R[0]=new Response($R[1]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,$R[2]={headers:$R[3]=new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),status:200,statusText:\\"\\"})))($R[\\"example\\"])"`; +exports[`Response > crossSerializeAsync > scoped > supports Blob 1`] = `"($R=>$R[0]=new Response($R[1]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,$R[2]={headers:$R[3]=new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),status:200,statusText:\\"\\"}))($R[\\"example\\"])"`; exports[`Response > crossSerializeAsync > supports Blob 1`] = `"$R[0]=new Response($R[1]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,$R[2]={headers:$R[3]=new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),status:200,statusText:\\"\\"})"`; -exports[`Response > crossSerializeStream > scoped > supports Response 1`] = `"($R=>($R[0]=new Response($R[1]=_$.S(),$R[2]={headers:$R[3]=new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),status:200,statusText:\\"\\"})))($R[\\"example\\"])"`; +exports[`Response > crossSerializeStream > scoped > supports Response 1`] = `"($R=>$R[0]=new Response($R[1]=_$.S(),$R[2]={headers:$R[3]=new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),status:200,statusText:\\"\\"}))($R[\\"example\\"])"`; -exports[`Response > crossSerializeStream > scoped > supports Response 2`] = `"($R=>(_$.Se($R[1],0,$R[4]=new Uint8Array($R[5]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,0,12))))($R[\\"example\\"])"`; +exports[`Response > crossSerializeStream > scoped > supports Response 2`] = `"($R=>_$.Se($R[1],$R[4]=new Uint8Array($R[5]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,0,12)))($R[\\"example\\"])"`; -exports[`Response > crossSerializeStream > scoped > supports Response 3`] = `"($R=>(_$.Se($R[1],2)))($R[\\"example\\"])"`; +exports[`Response > crossSerializeStream > scoped > supports Response 3`] = `"($R=>_$.Sc($R[1]))($R[\\"example\\"])"`; exports[`Response > crossSerializeStream > supports Response 1`] = `"$R[0]=new Response($R[1]=_$.S(),$R[2]={headers:$R[3]=new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),status:200,statusText:\\"\\"})"`; -exports[`Response > crossSerializeStream > supports Response 2`] = `"_$.Se($R[1],0,$R[4]=new Uint8Array($R[5]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,0,12))"`; +exports[`Response > crossSerializeStream > supports Response 2`] = `"_$.Se($R[1],$R[4]=new Uint8Array($R[5]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,0,12))"`; -exports[`Response > crossSerializeStream > supports Response 3`] = `"_$.Se($R[1],2)"`; +exports[`Response > crossSerializeStream > supports Response 3`] = `"_$.Sc($R[1])"`; exports[`Response > serializeAsync > supports Response 1`] = `"new Response(new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,{headers:new Headers({\\"content-type\\":\\"text/plain;charset=UTF-8\\"}),status:200,statusText:\\"\\"})"`; +exports[`Response > toCrossJSONStream > supports Response 1`] = `"{\\"t\\":36,\\"i\\":0,\\"a\\":[{\\"t\\":31,\\"i\\":1},{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"headers\\",\\"status\\",\\"statusText\\"],\\"v\\":[{\\"t\\":25,\\"i\\":3,\\"e\\":{\\"k\\":[\\"content-type\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"text/plain;charset=UTF-8\\"}],\\"s\\":1}},{\\"t\\":0,\\"s\\":200},{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":3},\\"o\\":0}]}"`; + +exports[`Response > toCrossJSONStream > supports Response 2`] = `"{\\"t\\":32,\\"i\\":1,\\"f\\":{\\"t\\":15,\\"i\\":4,\\"l\\":12,\\"c\\":\\"Uint8Array\\",\\"f\\":{\\"t\\":21,\\"i\\":5,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100,33]},\\"b\\":0}}"`; + +exports[`Response > toCrossJSONStream > supports Response 3`] = `"{\\"t\\":33,\\"i\\":1}"`; + exports[`Response > toJSONAsync > supports Response 1`] = `"{\\"t\\":{\\"t\\":36,\\"i\\":0,\\"a\\":[{\\"t\\":21,\\"i\\":1,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100,33]},{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"headers\\",\\"status\\",\\"statusText\\"],\\"v\\":[{\\"t\\":25,\\"i\\":3,\\"e\\":{\\"k\\":[\\"content-type\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"text/plain;charset=UTF-8\\"}],\\"s\\":1}},{\\"t\\":0,\\"s\\":200},{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":3},\\"o\\":0}]},\\"f\\":16383,\\"m\\":[]}"`; + +exports[`Response > toJSONAsync > supports Response 2`] = `"{\\"t\\":36,\\"i\\":0,\\"a\\":[{\\"t\\":21,\\"i\\":1,\\"s\\":[72,101,108,108,111,32,87,111,114,108,100,33]},{\\"t\\":10,\\"i\\":2,\\"p\\":{\\"k\\":[\\"headers\\",\\"status\\",\\"statusText\\"],\\"v\\":[{\\"t\\":25,\\"i\\":3,\\"e\\":{\\"k\\":[\\"content-type\\"],\\"v\\":[{\\"t\\":1,\\"s\\":\\"text/plain;charset=UTF-8\\"}],\\"s\\":1}},{\\"t\\":0,\\"s\\":200},{\\"t\\":1,\\"s\\":\\"\\"}],\\"s\\":3},\\"o\\":0}]}"`; diff --git a/packages/seroval/test/web-api/__snapshots__/url-search-params.test.ts.snap b/packages/seroval/test/web-api/__snapshots__/url-search-params.test.ts.snap index 817e1370..e3e91837 100644 --- a/packages/seroval/test/web-api/__snapshots__/url-search-params.test.ts.snap +++ b/packages/seroval/test/web-api/__snapshots__/url-search-params.test.ts.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`URLSearchParams > crossSerialize > scoped > supports URLSearchParams 1`] = `"($R=>($R[0]=new URLSearchParams(\\"hello=world&foo=bar\\")))($R[\\"example\\"])"`; +exports[`URLSearchParams > crossSerialize > scoped > supports URLSearchParams 1`] = `"($R=>$R[0]=new URLSearchParams(\\"hello=world&foo=bar\\"))($R[\\"example\\"])"`; exports[`URLSearchParams > crossSerialize > supports URLSearchParams 1`] = `"$R[0]=new URLSearchParams(\\"hello=world&foo=bar\\")"`; -exports[`URLSearchParams > crossSerializeAsync > scoped > supports URLSearchParams 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=new URLSearchParams(\\"hello=world&foo=bar\\"))))($R[\\"example\\"])"`; +exports[`URLSearchParams > crossSerializeAsync > scoped > supports URLSearchParams 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=new URLSearchParams(\\"hello=world&foo=bar\\")))($R[\\"example\\"])"`; exports[`URLSearchParams > crossSerializeAsync > supports URLSearchParams 1`] = `"$R[0]=Promise.resolve($R[1]=new URLSearchParams(\\"hello=world&foo=bar\\"))"`; -exports[`URLSearchParams > crossSerializeStream > scoped > supports URLSearchParams 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`URLSearchParams > crossSerializeStream > scoped > supports URLSearchParams 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`URLSearchParams > crossSerializeStream > scoped > supports URLSearchParams 2`] = `"($R=>(_$.Ps($R[0],$R[1]=new URLSearchParams(\\"hello=world&foo=bar\\"))))($R[\\"example\\"])"`; +exports[`URLSearchParams > crossSerializeStream > scoped > supports URLSearchParams 2`] = `"($R=>_$.Ps($R[0],$R[1]=new URLSearchParams(\\"hello=world&foo=bar\\")))($R[\\"example\\"])"`; exports[`URLSearchParams > crossSerializeStream > supports URLSearchParams 1`] = `"$R[0]=_$.P()"`; @@ -20,6 +20,14 @@ exports[`URLSearchParams > serialize > supports URLSearchParams 1`] = `"new URLS exports[`URLSearchParams > serializeAsync > supports URLSearchParams 1`] = `"Promise.resolve(new URLSearchParams(\\"hello=world&foo=bar\\"))"`; +exports[`URLSearchParams > toCrossJSONStream > supports URLSearchParams 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`URLSearchParams > toCrossJSONStream > supports URLSearchParams 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":19,\\"i\\":1,\\"s\\":\\"hello=world&foo=bar\\"}}"`; + exports[`URLSearchParams > toJSON > supports URLSearchParams 1`] = `"{\\"t\\":{\\"t\\":19,\\"i\\":0,\\"s\\":\\"hello=world&foo=bar\\"},\\"f\\":16383,\\"m\\":[]}"`; +exports[`URLSearchParams > toJSON > supports URLSearchParams 2`] = `"{\\"t\\":19,\\"i\\":0,\\"s\\":\\"hello=world&foo=bar\\"}"`; + exports[`URLSearchParams > toJSONAsync > supports URLSearchParams 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":19,\\"i\\":1,\\"s\\":\\"hello=world&foo=bar\\"}},\\"f\\":16383,\\"m\\":[]}"`; + +exports[`URLSearchParams > toJSONAsync > supports URLSearchParams 2`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":19,\\"i\\":1,\\"s\\":\\"hello=world&foo=bar\\"}}"`; diff --git a/packages/seroval/test/web-api/__snapshots__/url.test.ts.snap b/packages/seroval/test/web-api/__snapshots__/url.test.ts.snap index 6a350cb2..f8147f3a 100644 --- a/packages/seroval/test/web-api/__snapshots__/url.test.ts.snap +++ b/packages/seroval/test/web-api/__snapshots__/url.test.ts.snap @@ -1,16 +1,16 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`URL > crossSerialize > scoped > supports URL 1`] = `"($R=>($R[0]=new URL(\\"https://github.com/lxsmnsyc/seroval?hello=world\\")))($R[\\"example\\"])"`; +exports[`URL > crossSerialize > scoped > supports URL 1`] = `"($R=>$R[0]=new URL(\\"https://github.com/lxsmnsyc/seroval?hello=world\\"))($R[\\"example\\"])"`; exports[`URL > crossSerialize > supports URL 1`] = `"$R[0]=new URL(\\"https://github.com/lxsmnsyc/seroval?hello=world\\")"`; -exports[`URL > crossSerializeAsync > scoped > supports URL 1`] = `"($R=>($R[0]=Promise.resolve($R[1]=new URL(\\"https://github.com/lxsmnsyc/seroval?hello=world\\"))))($R[\\"example\\"])"`; +exports[`URL > crossSerializeAsync > scoped > supports URL 1`] = `"($R=>$R[0]=Promise.resolve($R[1]=new URL(\\"https://github.com/lxsmnsyc/seroval?hello=world\\")))($R[\\"example\\"])"`; exports[`URL > crossSerializeAsync > supports URL 1`] = `"$R[0]=Promise.resolve($R[1]=new URL(\\"https://github.com/lxsmnsyc/seroval?hello=world\\"))"`; -exports[`URL > crossSerializeStream > scoped > supports URL 1`] = `"($R=>($R[0]=_$.P()))($R[\\"example\\"])"`; +exports[`URL > crossSerializeStream > scoped > supports URL 1`] = `"($R=>$R[0]=_$.P())($R[\\"example\\"])"`; -exports[`URL > crossSerializeStream > scoped > supports URL 2`] = `"($R=>(_$.Ps($R[0],$R[1]=new URL(\\"https://github.com/lxsmnsyc/seroval?hello=world\\"))))($R[\\"example\\"])"`; +exports[`URL > crossSerializeStream > scoped > supports URL 2`] = `"($R=>_$.Ps($R[0],$R[1]=new URL(\\"https://github.com/lxsmnsyc/seroval?hello=world\\")))($R[\\"example\\"])"`; exports[`URL > crossSerializeStream > supports URL 1`] = `"$R[0]=_$.P()"`; @@ -20,6 +20,14 @@ exports[`URL > serialize > supports URL 1`] = `"new URL(\\"https://github.com/lx exports[`URL > serializeAsync > supports URL 1`] = `"Promise.resolve(new URL(\\"https://github.com/lxsmnsyc/seroval?hello=world\\"))"`; +exports[`URL > toCrossJSONStream > supports URL 1`] = `"{\\"t\\":28,\\"i\\":0}"`; + +exports[`URL > toCrossJSONStream > supports URL 2`] = `"{\\"t\\":29,\\"i\\":0,\\"f\\":{\\"t\\":18,\\"i\\":1,\\"s\\":\\"https://github.com/lxsmnsyc/seroval?hello=world\\"}}"`; + exports[`URL > toJSON > supports URL 1`] = `"{\\"t\\":{\\"t\\":18,\\"i\\":0,\\"s\\":\\"https://github.com/lxsmnsyc/seroval?hello=world\\"},\\"f\\":16383,\\"m\\":[]}"`; +exports[`URL > toJSON > supports URL 2`] = `"{\\"t\\":18,\\"i\\":0,\\"s\\":\\"https://github.com/lxsmnsyc/seroval?hello=world\\"}"`; + exports[`URL > toJSONAsync > supports URL 1`] = `"{\\"t\\":{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":18,\\"i\\":1,\\"s\\":\\"https://github.com/lxsmnsyc/seroval?hello=world\\"}},\\"f\\":16383,\\"m\\":[]}"`; + +exports[`URL > toJSONAsync > supports URL 2`] = `"{\\"t\\":12,\\"i\\":0,\\"s\\":1,\\"f\\":{\\"t\\":18,\\"i\\":1,\\"s\\":\\"https://github.com/lxsmnsyc/seroval?hello=world\\"}}"`; diff --git a/packages/seroval/test/web-api/blob.test.ts b/packages/seroval/test/web-api/blob.test.ts index aad0ade3..df2ea5a0 100644 --- a/packages/seroval/test/web-api/blob.test.ts +++ b/packages/seroval/test/web-api/blob.test.ts @@ -2,54 +2,59 @@ import { describe, it, expect } from 'vitest'; import { crossSerializeAsync, deserialize, + fromCrossJSON, fromJSON, serializeAsync, + toCrossJSONAsync, toJSONAsync, } from '../../src'; +const EXAMPLE = new Blob(['Hello World'], { + type: 'text/plain', +}); describe('Blob', () => { describe('serializeAsync', () => { it('supports Blob', async () => { - const example = new Blob(['Hello World'], { - type: 'text/plain', - }); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(EXAMPLE); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = deserialize(result); expect(back).toBeInstanceOf(Blob); - expect(await back.text()).toBe(await example.text()); - expect(back.type).toBe(example.type); + expect(await back.text()).toBe(await EXAMPLE.text()); + expect(back.type).toBe(EXAMPLE.type); }); }); describe('toJSONAsync', () => { it('supports Blob', async () => { - const example = new Blob(['Hello World'], { - type: 'text/plain', - }); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(Blob); - expect(await back.text()).toBe(await example.text()); - expect(back.type).toBe(example.type); + expect(await back.text()).toBe(await EXAMPLE.text()); + expect(back.type).toBe(EXAMPLE.type); }); }); describe('crossSerializeAsync', () => { it('supports Blob', async () => { - const example = new Blob(['Hello World'], { - type: 'text/plain', - }); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Blob', async () => { - const example = new Blob(['Hello World'], { - type: 'text/plain', - }); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); + describe('toCrossJSONAsync', () => { + it('supports Blob', async () => { + const result = await toCrossJSONAsync(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Blob); + expect(await back.text()).toBe(await EXAMPLE.text()); + expect(back.type).toBe(EXAMPLE.type); + }); + }); }); diff --git a/packages/seroval/test/web-api/custom-event.test.ts b/packages/seroval/test/web-api/custom-event.test.ts index 90eeec3b..d7a8f3af 100644 --- a/packages/seroval/test/web-api/custom-event.test.ts +++ b/packages/seroval/test/web-api/custom-event.test.ts @@ -4,9 +4,13 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../../src'; @@ -15,97 +19,131 @@ const EXAMPLE_EVENT_TYPE = 'example'; const EXAMPLE_DETAIL: Record = {}; EXAMPLE_DETAIL.self = EXAMPLE_DETAIL; const EXAMPLE_OPTIONS: CustomEventInit = { detail: EXAMPLE_DETAIL }; +const EXAMPLE = new CustomEvent(EXAMPLE_EVENT_TYPE, EXAMPLE_OPTIONS); describe('CustomEvent', () => { describe('serialize', () => { it('supports CustomEvent', () => { - const example = new CustomEvent(EXAMPLE_EVENT_TYPE, EXAMPLE_OPTIONS); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back).toBeInstanceOf(CustomEvent); }); }); describe('serializeAsync', () => { it('supports CustomEvent', async () => { - const example = new CustomEvent(EXAMPLE_EVENT_TYPE, EXAMPLE_OPTIONS); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(CustomEvent); }); }); describe('toJSON', () => { it('supports CustomEvent', () => { - const example = new CustomEvent(EXAMPLE_EVENT_TYPE, EXAMPLE_OPTIONS); - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(CustomEvent); }); }); describe('toJSONAsync', () => { it('supports CustomEvent', async () => { - const example = new CustomEvent(EXAMPLE_EVENT_TYPE, EXAMPLE_OPTIONS); - const result = await toJSONAsync(Promise.resolve(example)); + const example = Promise.resolve(EXAMPLE); + const result = await toJSONAsync(example); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = await fromJSON(result); expect(back).toBeInstanceOf(CustomEvent); }); }); describe('crossSerialize', () => { it('supports CustomEvent', () => { - const example = new CustomEvent(EXAMPLE_EVENT_TYPE, EXAMPLE_OPTIONS); - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports CustomEvent', () => { - const example = new CustomEvent(EXAMPLE_EVENT_TYPE, EXAMPLE_OPTIONS); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports CustomEvent', async () => { - const example = new CustomEvent(EXAMPLE_EVENT_TYPE, EXAMPLE_OPTIONS); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports CustomEvent', async () => { - const example = new CustomEvent(EXAMPLE_EVENT_TYPE, EXAMPLE_OPTIONS); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports CustomEvent', async () => new Promise((done) => { - const example = new CustomEvent(EXAMPLE_EVENT_TYPE, EXAMPLE_OPTIONS); - crossSerializeStream(Promise.resolve(example), { + it('supports CustomEvent', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports CustomEvent', async () => new Promise((done) => { - const example = new CustomEvent(EXAMPLE_EVENT_TYPE, EXAMPLE_OPTIONS); - crossSerializeStream(Promise.resolve(example), { + it('supports CustomEvent', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports CustomEvent', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(CustomEvent); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports CustomEvent', async () => { + const example = Promise.resolve(EXAMPLE); + const result = await toCrossJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(CustomEvent); + }); + }); + describe('toCrossJSONStream', () => { + it('supports CustomEvent', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/web-api/dom-exception.test.ts b/packages/seroval/test/web-api/dom-exception.test.ts index 7c0492bf..d19ac921 100644 --- a/packages/seroval/test/web-api/dom-exception.test.ts +++ b/packages/seroval/test/web-api/dom-exception.test.ts @@ -4,114 +4,151 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../../src'; const EXAMPLE_MESSAGE = 'This is an example message.'; const EXAMPLE_NAME = 'Example'; +const EXAMPLE = new DOMException(EXAMPLE_MESSAGE, EXAMPLE_NAME); describe('DOMException', () => { describe('serialize', () => { it('supports DOMException', () => { - const example = new DOMException(EXAMPLE_MESSAGE, EXAMPLE_NAME); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back).toBeInstanceOf(DOMException); - expect(back.message).toBe(example.message); - expect(back.name).toBe(example.name); + expect(back.message).toBe(EXAMPLE.message); + expect(back.name).toBe(EXAMPLE.name); }); }); describe('serializeAsync', () => { it('supports DOMException', async () => { - const example = new DOMException(EXAMPLE_MESSAGE, EXAMPLE_NAME); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(DOMException); - expect(back.message).toBe(example.message); - expect(back.name).toBe(example.name); + expect(back.message).toBe(EXAMPLE.message); + expect(back.name).toBe(EXAMPLE.name); }); }); describe('toJSON', () => { it('supports DOMException', () => { - const example = new DOMException(EXAMPLE_MESSAGE, EXAMPLE_NAME); - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(DOMException); - expect(back.message).toBe(example.message); - expect(back.name).toBe(example.name); + expect(back.message).toBe(EXAMPLE.message); + expect(back.name).toBe(EXAMPLE.name); }); }); describe('toJSONAsync', () => { it('supports DOMException', async () => { - const example = new DOMException(EXAMPLE_MESSAGE, EXAMPLE_NAME); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = await fromJSON>(result); expect(back).toBeInstanceOf(DOMException); - expect(back.message).toBe(example.message); - expect(back.name).toBe(example.name); + expect(back.message).toBe(EXAMPLE.message); + expect(back.name).toBe(EXAMPLE.name); }); }); describe('crossSerialize', () => { it('supports DOMException', () => { - const example = new DOMException(EXAMPLE_MESSAGE, EXAMPLE_NAME); - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports DOMException', () => { - const example = new DOMException(EXAMPLE_MESSAGE, EXAMPLE_NAME); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports DOMException', async () => { - const example = new DOMException(EXAMPLE_MESSAGE, EXAMPLE_NAME); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports DOMException', async () => { - const example = new DOMException(EXAMPLE_MESSAGE, EXAMPLE_NAME); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports DOMException', async () => new Promise((done) => { - const example = new DOMException(EXAMPLE_MESSAGE, EXAMPLE_NAME); - crossSerializeStream(Promise.resolve(example), { + it('supports DOMException', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports DOMException', async () => new Promise((done) => { - const example = new DOMException(EXAMPLE_MESSAGE, EXAMPLE_NAME); - crossSerializeStream(Promise.resolve(example), { + it('supports DOMException', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports DOMException', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(DOMException); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports DOMException', async () => { + const example = Promise.resolve(EXAMPLE); + const result = await toCrossJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(DOMException); + }); + }); + describe('toCrossJSONStream', () => { + it('supports DOMException', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/web-api/event.test.ts b/packages/seroval/test/web-api/event.test.ts index dad536e6..e2144a57 100644 --- a/packages/seroval/test/web-api/event.test.ts +++ b/packages/seroval/test/web-api/event.test.ts @@ -4,105 +4,142 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../../src'; const EXAMPLE_EVENT_TYPE = 'example'; +const EXAMPLE = new Event(EXAMPLE_EVENT_TYPE); describe('Event', () => { describe('serialize', () => { it('supports Event', () => { - const example = new Event(EXAMPLE_EVENT_TYPE); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back).toBeInstanceOf(Event); }); }); describe('serializeAsync', () => { it('supports Event', async () => { - const example = new Event(EXAMPLE_EVENT_TYPE); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(Event); }); }); describe('toJSON', () => { it('supports Event', () => { - const example = new Event(EXAMPLE_EVENT_TYPE); - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(Event); }); }); describe('toJSONAsync', () => { it('supports Event', async () => { - const example = new Event(EXAMPLE_EVENT_TYPE); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = await fromJSON>(result); expect(back).toBeInstanceOf(Event); }); }); describe('crossSerialize', () => { it('supports Event', () => { - const example = new Event(EXAMPLE_EVENT_TYPE); - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Event', () => { - const example = new Event(EXAMPLE_EVENT_TYPE); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports Event', async () => { - const example = new Event(EXAMPLE_EVENT_TYPE); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Event', async () => { - const example = new Event(EXAMPLE_EVENT_TYPE); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports Event', async () => new Promise((done) => { - const example = new Event(EXAMPLE_EVENT_TYPE); - crossSerializeStream(Promise.resolve(example), { + it('supports Event', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Event', async () => new Promise((done) => { - const example = new Event(EXAMPLE_EVENT_TYPE); - crossSerializeStream(Promise.resolve(example), { + it('supports Event', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Event', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Event); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Event', async () => { + const example = Promise.resolve(EXAMPLE); + const result = await toCrossJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Event); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Event', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/web-api/file.test.ts b/packages/seroval/test/web-api/file.test.ts index 7c264004..7f321e0e 100644 --- a/packages/seroval/test/web-api/file.test.ts +++ b/packages/seroval/test/web-api/file.test.ts @@ -2,58 +2,61 @@ import { describe, it, expect } from 'vitest'; import { crossSerializeAsync, deserialize, + fromCrossJSON, fromJSON, serializeAsync, + toCrossJSONAsync, toJSONAsync, } from '../../src'; +const EXAMPLE = new File(['Hello World'], 'hello.txt', { + type: 'text/plain', + lastModified: 1681027542680, +}); + describe('File', () => { describe('serializeAsync', () => { it('supports File', async () => { - const example = new File(['Hello World'], 'hello.txt', { - type: 'text/plain', - lastModified: 1681027542680, - }); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(EXAMPLE); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = deserialize(result); expect(back).toBeInstanceOf(File); - expect(await back.text()).toBe(await example.text()); - expect(back.type).toBe(example.type); + expect(await back.text()).toBe(await EXAMPLE.text()); + expect(back.type).toBe(EXAMPLE.type); }); }); describe('toJSONAsync', () => { it('supports File', async () => { - const example = new File(['Hello World'], 'hello.txt', { - type: 'text/plain', - lastModified: 1681027542680, - }); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(File); - expect(await back.text()).toBe(await example.text()); - expect(back.type).toBe(example.type); + expect(await back.text()).toBe(await EXAMPLE.text()); + expect(back.type).toBe(EXAMPLE.type); }); }); describe('crossSerializeAsync', () => { it('supports File', async () => { - const example = new File(['Hello World'], 'hello.txt', { - type: 'text/plain', - lastModified: 1681027542680, - }); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports File', async () => { - const example = new File(['Hello World'], 'hello.txt', { - type: 'text/plain', - lastModified: 1681027542680, - }); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); + describe('toCrossJSONAsync', () => { + it('supports File', async () => { + const result = await toCrossJSONAsync(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(File); + expect(await back.text()).toBe(await EXAMPLE.text()); + expect(back.type).toBe(EXAMPLE.type); + }); + }); }); diff --git a/packages/seroval/test/web-api/form-data.test.ts b/packages/seroval/test/web-api/form-data.test.ts index c6b10628..0db31c1f 100644 --- a/packages/seroval/test/web-api/form-data.test.ts +++ b/packages/seroval/test/web-api/form-data.test.ts @@ -4,148 +4,152 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../../src'; +const SYNC_EXAMPLE = new FormData(); +SYNC_EXAMPLE.set('hello', 'world'); +SYNC_EXAMPLE.set('foo', 'bar'); + +const ASYNC_EXAMPLE = new FormData(); +ASYNC_EXAMPLE.set('hello-world', new File(['Hello World'], 'hello.txt', { + type: 'text/plain', + lastModified: 1681027542680, +})); +ASYNC_EXAMPLE.set('foo-bar', new File(['Foo Bar'], 'foo-bar.txt', { + type: 'text/plain', + lastModified: 1681027542680, +})); + describe('FormData', () => { describe('serialize', () => { it('supports FormData', () => { - const example = new FormData(); - example.set('hello', 'world'); - example.set('foo', 'bar'); - const result = serialize(example); + const result = serialize(SYNC_EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back).toBeInstanceOf(FormData); }); }); describe('serializeAsync', () => { it('supports FormData', async () => { - const example = new FormData(); - example.set('hello-world', new File(['Hello World'], 'hello.txt', { - type: 'text/plain', - lastModified: 1681027542680, - })); - example.set('foo-bar', new File(['Foo Bar'], 'foo-bar.txt', { - type: 'text/plain', - lastModified: 1681027542680, - })); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(ASYNC_EXAMPLE); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = deserialize(result); expect(back).toBeInstanceOf(FormData); }); }); describe('toJSON', () => { it('supports FormData', () => { - const example = new FormData(); - example.set('hello', 'world'); - example.set('foo', 'bar'); - const result = toJSON(example); + const result = toJSON(SYNC_EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(FormData); }); }); describe('toJSONAsync', () => { it('supports FormData', async () => { - const example = new FormData(); - example.set('example', new File(['Hello World'], 'hello.txt', { - type: 'text/plain', - lastModified: 1681027542680, - })); - example.set('foo-bar', new File(['Foo Bar'], 'foo-bar.txt', { - type: 'text/plain', - lastModified: 1681027542680, - })); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(ASYNC_EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(FormData); - expect(String(back)).toBe(String(example)); }); }); describe('crossSerialize', () => { it('supports FormData', () => { - const example = new FormData(); - example.set('hello', 'world'); - example.set('foo', 'bar'); - const result = crossSerialize(example); + const result = crossSerialize(SYNC_EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports FormData', () => { - const example = new FormData(); - example.set('hello', 'world'); - example.set('foo', 'bar'); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(SYNC_EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports FormData', async () => { - const example = new FormData(); - example.set('hello-world', new File(['Hello World'], 'hello.txt', { - type: 'text/plain', - lastModified: 1681027542680, - })); - example.set('foo-bar', new File(['Foo Bar'], 'foo-bar.txt', { - type: 'text/plain', - lastModified: 1681027542680, - })); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(ASYNC_EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports FormData', async () => { - const example = new FormData(); - example.set('hello-world', new File(['Hello World'], 'hello.txt', { - type: 'text/plain', - lastModified: 1681027542680, - })); - example.set('foo-bar', new File(['Foo Bar'], 'foo-bar.txt', { - type: 'text/plain', - lastModified: 1681027542680, - })); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(ASYNC_EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports FormData', async () => new Promise((done) => { - const example = new FormData(); - example.set('hello', 'world'); - example.set('foo', 'bar'); - crossSerializeStream(Promise.resolve(example), { + it('supports FormData', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(SYNC_EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports FormData', async () => new Promise((done) => { - const example = new FormData(); - example.set('hello', 'world'); - example.set('foo', 'bar'); - crossSerializeStream(Promise.resolve(example), { + it('supports FormData', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(SYNC_EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports FormData', () => { + const result = toCrossJSON(SYNC_EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(FormData); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports FormData', async () => { + const result = await toCrossJSONAsync(ASYNC_EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(FormData); + }); + }); + describe('toCrossJSONStream', () => { + it('supports FormData', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(SYNC_EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/web-api/headers.test.ts b/packages/seroval/test/web-api/headers.test.ts index c3ea0727..3c4939f5 100644 --- a/packages/seroval/test/web-api/headers.test.ts +++ b/packages/seroval/test/web-api/headers.test.ts @@ -4,137 +4,148 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../../src'; +const EXAMPLE = new Headers([ + ['Content-Type', 'text/plain'], + ['Content-Encoding', 'gzip'], +]); + describe('Headers', () => { describe('serialize', () => { it('supports Headers', () => { - const example = new Headers([ - ['Content-Type', 'text/plain'], - ['Content-Encoding', 'gzip'], - ]); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back).toBeInstanceOf(Headers); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('serializeAsync', () => { it('supports Headers', async () => { - const example = new Headers([ - ['Content-Type', 'text/plain'], - ['Content-Encoding', 'gzip'], - ]); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(Headers); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('toJSON', () => { it('supports Headers', () => { - const example = new Headers([ - ['Content-Type', 'text/plain'], - ['Content-Encoding', 'gzip'], - ]); - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); const back = fromJSON(result); expect(back).toBeInstanceOf(Headers); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('toJSONAsync', () => { it('supports Headers', async () => { - const example = new Headers([ - ['Content-Type', 'text/plain'], - ['Content-Encoding', 'gzip'], - ]); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = await fromJSON>(result); expect(back).toBeInstanceOf(Headers); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('crossSerialize', () => { it('supports Headers', () => { - const example = new Headers([ - ['Content-Type', 'text/plain'], - ['Content-Encoding', 'gzip'], - ]); - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Headers', () => { - const example = new Headers([ - ['Content-Type', 'text/plain'], - ['Content-Encoding', 'gzip'], - ]); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports Headers', async () => { - const example = new Headers([ - ['Content-Type', 'text/plain'], - ['Content-Encoding', 'gzip'], - ]); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports Headers', async () => { - const example = new Headers([ - ['Content-Type', 'text/plain'], - ['Content-Encoding', 'gzip'], - ]); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports Headers', async () => new Promise((done) => { - const example = new Headers([ - ['Content-Type', 'text/plain'], - ['Content-Encoding', 'gzip'], - ]); - crossSerializeStream(Promise.resolve(example), { + it('supports Headers', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Headers', async () => new Promise((done) => { - const example = new Headers([ - ['Content-Type', 'text/plain'], - ['Content-Encoding', 'gzip'], - ]); - crossSerializeStream(Promise.resolve(example), { + it('supports Headers', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports Headers', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Headers); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports Headers', async () => { + const example = Promise.resolve(EXAMPLE); + const result = await toCrossJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Headers); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Headers', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/web-api/readable-stream.test.ts b/packages/seroval/test/web-api/readable-stream.test.ts index 69ac8ce7..6e754a4e 100644 --- a/packages/seroval/test/web-api/readable-stream.test.ts +++ b/packages/seroval/test/web-api/readable-stream.test.ts @@ -1,11 +1,165 @@ import { describe, it, expect } from 'vitest'; import { + crossSerializeAsync, crossSerializeStream, + deserialize, + fromCrossJSON, + fromJSON, + serializeAsync, + toCrossJSONAsync, + toCrossJSONStream, + toJSONAsync, } from '../../src'; describe('ReadableStream', () => { + describe('serializeAsync', () => { + it('supports ReadableStream', async () => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + const result = await serializeAsync(example); + expect(result).toMatchSnapshot(); + const back = deserialize(result); + expect(back).toBeInstanceOf(ReadableStream); + const reader = back.getReader(); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'foo', + }); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'bar', + }); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'baz', + }); + expect(await reader.read()).toMatchObject({ + done: true, + value: undefined, + }); + }); + it('supports ReadableStream errors', async () => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + const result = await serializeAsync(example); + expect(result).toMatchSnapshot(); + const back = deserialize(result); + expect(back).toBeInstanceOf(ReadableStream); + const reader = back.getReader(); + await expect(async () => reader.read()).rejects.toThrowErrorMatchingSnapshot(); + }); + }); + describe('toJSONAsync', () => { + it('supports ReadableStream', async () => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + const result = await toJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromJSON(result); + expect(back).toBeInstanceOf(ReadableStream); + const reader = back.getReader(); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'foo', + }); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'bar', + }); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'baz', + }); + expect(await reader.read()).toMatchObject({ + done: true, + value: undefined, + }); + }); + it('supports ReadableStream errors', async () => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + const result = await toJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromJSON(result); + expect(back).toBeInstanceOf(ReadableStream); + const reader = back.getReader(); + await expect(async () => reader.read()).rejects.toThrowErrorMatchingSnapshot(); + }); + }); + describe('crossSerializeAsync', () => { + it('supports ReadableStream', async () => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + const result = await crossSerializeAsync(example); + expect(result).toMatchSnapshot(); + }); + it('supports ReadableStream errors', async () => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + const result = await crossSerializeAsync(example); + expect(result).toMatchSnapshot(); + }); + describe('scoped', () => { + it('supports ReadableStream', async () => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + const result = await crossSerializeAsync(example, { scopeId: 'example' }); + expect(result).toMatchSnapshot(); + }); + it('supports ReadableStream errors', async () => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + const result = await crossSerializeAsync(example, { scopeId: 'example' }); + expect(result).toMatchSnapshot(); + }); + }); + }); describe('crossSerializeStream', () => { - it('supports ReadableStream', async () => new Promise((done) => { + it('supports ReadableStream', async () => new Promise((resolve, reject) => { const example = new ReadableStream({ start(controller): void { controller.enqueue('foo'); @@ -19,11 +173,14 @@ describe('ReadableStream', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports ReadableStream errors', async () => new Promise((done) => { + it('supports ReadableStream errors', async () => new Promise((resolve, reject) => { const example = new ReadableStream({ start(controller): void { const error = new Error('Oops!'); @@ -36,12 +193,15 @@ describe('ReadableStream', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports ReadableStream', async () => new Promise((done) => { + it('supports ReadableStream', async () => new Promise((resolve, reject) => { const example = new ReadableStream({ start(controller): void { controller.enqueue('foo'); @@ -56,11 +216,14 @@ describe('ReadableStream', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports ReadableStream errors', async () => new Promise((done) => { + it('supports ReadableStream errors', async () => new Promise((resolve, reject) => { const example = new ReadableStream({ start(controller): void { const error = new Error('Oops!'); @@ -74,10 +237,108 @@ describe('ReadableStream', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSONAsync', () => { + it('supports ReadableStream', async () => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + const result = await toCrossJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(ReadableStream); + const reader = back.getReader(); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'foo', + }); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'bar', + }); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'baz', + }); + expect(await reader.read()).toMatchObject({ + done: true, + value: undefined, + }); + }); + it('supports ReadableStream errors', async () => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + const result = await toCrossJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(ReadableStream); + const reader = back.getReader(); + await expect(async () => reader.read()).rejects.toThrowErrorMatchingSnapshot(); + }); + }); + describe('toCrossJSONStream', () => { + it('supports ReadableStream', async () => new Promise((resolve, reject) => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + toCrossJSONStream(example, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports ReadableStream errors', async () => new Promise((resolve, reject) => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + toCrossJSONStream(example, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/web-api/request.test.ts b/packages/seroval/test/web-api/request.test.ts index fe80e468..9e4ce824 100644 --- a/packages/seroval/test/web-api/request.test.ts +++ b/packages/seroval/test/web-api/request.test.ts @@ -3,8 +3,11 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serializeAsync, + toCrossJSONAsync, + toCrossJSONStream, toJSONAsync, } from '../../src'; @@ -20,7 +23,7 @@ describe('Request', () => { }); const result = await serializeAsync(example); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = deserialize(result); expect(back).toBeInstanceOf(Request); expect(await back.text()).toBe(await example.text()); expect(back.url).toBe(example.url); @@ -35,7 +38,7 @@ describe('Request', () => { }); const result = await toJSONAsync(example); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(Request); expect(await back.text()).toBe(await example.text()); expect(back.url).toBe(example.url); @@ -62,9 +65,8 @@ describe('Request', () => { }); }); }); - describe('crossSerializeStream', () => { - it('supports Request', async () => new Promise((done) => { + it('supports Request', async () => new Promise((resolve, reject) => { const example = new Request(EXAMPLE_URL, { method: 'POST', body: EXAMPLE_BODY, @@ -74,12 +76,15 @@ describe('Request', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Request', async () => new Promise((done) => { + it('supports Request', async () => new Promise((resolve, reject) => { const example = new Request(EXAMPLE_URL, { method: 'POST', body: EXAMPLE_BODY, @@ -90,10 +95,49 @@ describe('Request', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toJSONAsync', () => { + it('supports Request', async () => { + const example = new Request(EXAMPLE_URL, { + method: 'POST', + body: EXAMPLE_BODY, + }); + const result = await toCrossJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Request); + expect(await back.text()).toBe(await example.text()); + expect(back.url).toBe(example.url); + expect(back.method).toBe(example.method); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Request', async () => new Promise((resolve, reject) => { + const example = new Request(EXAMPLE_URL, { + method: 'POST', + body: EXAMPLE_BODY, + }); + toCrossJSONStream(example, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/web-api/response.test.ts b/packages/seroval/test/web-api/response.test.ts index 4e824db2..0cdcc7f4 100644 --- a/packages/seroval/test/web-api/response.test.ts +++ b/packages/seroval/test/web-api/response.test.ts @@ -3,8 +3,11 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serializeAsync, + toCrossJSONAsync, + toCrossJSONStream, toJSONAsync, } from '../../src'; @@ -16,7 +19,7 @@ describe('Response', () => { const example = new Response(EXAMPLE_BODY); const result = await serializeAsync(example); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = deserialize(result); expect(back).toBeInstanceOf(Response); expect(await back.text()).toBe(await example.text()); }); @@ -26,7 +29,7 @@ describe('Response', () => { const example = new Response(EXAMPLE_BODY); const result = await toJSONAsync(example); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(Response); expect(await back.text()).toBe(await example.text()); }); @@ -47,19 +50,22 @@ describe('Response', () => { }); describe('crossSerializeStream', () => { - it('supports Response', async () => new Promise((done) => { + it('supports Response', async () => new Promise((resolve, reject) => { const example = new Response(EXAMPLE_BODY); crossSerializeStream(example, { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Response', async () => new Promise((done) => { + it('supports Response', async () => new Promise((resolve, reject) => { const example = new Response(EXAMPLE_BODY); crossSerializeStream(example, { scopeId: 'example', @@ -67,10 +73,41 @@ describe('Response', () => { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toJSONAsync', () => { + it('supports Response', async () => { + const example = new Response(EXAMPLE_BODY); + const result = await toCrossJSONAsync(example); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(Response); + expect(await back.text()).toBe(await example.text()); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Response', async () => new Promise((resolve, reject) => { + const example = new Response(EXAMPLE_BODY); + toCrossJSONStream(example, { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/web-api/url-search-params.test.ts b/packages/seroval/test/web-api/url-search-params.test.ts index e721de50..c08de257 100644 --- a/packages/seroval/test/web-api/url-search-params.test.ts +++ b/packages/seroval/test/web-api/url-search-params.test.ts @@ -4,107 +4,146 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../../src'; +const EXAMPLE = new URLSearchParams('hello=world&foo=bar'); + describe('URLSearchParams', () => { describe('serialize', () => { it('supports URLSearchParams', () => { - const example = new URLSearchParams('hello=world&foo=bar'); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back).toBeInstanceOf(URLSearchParams); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('serializeAsync', () => { it('supports URLSearchParams', async () => { - const example = new URLSearchParams('hello=world&foo=bar'); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(URLSearchParams); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('toJSON', () => { it('supports URLSearchParams', () => { - const example = new URLSearchParams('hello=world&foo=bar'); - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(URLSearchParams); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('toJSONAsync', () => { it('supports URLSearchParams', async () => { - const example = new URLSearchParams('hello=world&foo=bar'); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = await fromJSON>(result); + const back = await fromJSON>(result); expect(back).toBeInstanceOf(URLSearchParams); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('crossSerialize', () => { it('supports URLSearchParams', () => { - const example = new URLSearchParams('hello=world&foo=bar'); - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports URLSearchParams', () => { - const example = new URLSearchParams('hello=world&foo=bar'); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports URLSearchParams', async () => { - const example = new URLSearchParams('hello=world&foo=bar'); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports URLSearchParams', async () => { - const example = new URLSearchParams('hello=world&foo=bar'); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports URLSearchParams', async () => new Promise((done) => { - const example = new URLSearchParams('hello=world&foo=bar'); - crossSerializeStream(Promise.resolve(example), { + it('supports URLSearchParams', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports URLSearchParams', async () => new Promise((done) => { - const example = new URLSearchParams('hello=world&foo=bar'); - crossSerializeStream(Promise.resolve(example), { + it('supports URLSearchParams', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toJSON', () => { + it('supports URLSearchParams', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(URLSearchParams); + expect(String(back)).toBe(String(EXAMPLE)); + }); + }); + describe('toJSONAsync', () => { + it('supports URLSearchParams', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(URLSearchParams); + expect(String(back)).toBe(String(EXAMPLE)); + }); + }); + describe('toCrossJSONStream', () => { + it('supports URLSearchParams', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/web-api/url.test.ts b/packages/seroval/test/web-api/url.test.ts index 1458b856..bcf70c16 100644 --- a/packages/seroval/test/web-api/url.test.ts +++ b/packages/seroval/test/web-api/url.test.ts @@ -4,107 +4,146 @@ import { crossSerializeAsync, crossSerializeStream, deserialize, + fromCrossJSON, fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../../src'; +const EXAMPLE = new URL('https://github.com/lxsmnsyc/seroval?hello=world'); + describe('URL', () => { describe('serialize', () => { it('supports URL', () => { - const example = new URL('https://github.com/lxsmnsyc/seroval?hello=world'); - const result = serialize(example); + const result = serialize(EXAMPLE); expect(result).toMatchSnapshot(); - const back = deserialize(result); + const back = deserialize(result); expect(back).toBeInstanceOf(URL); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('serializeAsync', () => { it('supports URL', async () => { - const example = new URL('https://github.com/lxsmnsyc/seroval?hello=world'); - const result = await serializeAsync(Promise.resolve(example)); + const result = await serializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); - const back = await deserialize>(result); + const back = await deserialize>(result); expect(back).toBeInstanceOf(URL); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('toJSON', () => { it('supports URL', () => { - const example = new URL('https://github.com/lxsmnsyc/seroval?hello=world'); - const result = toJSON(example); + const result = toJSON(EXAMPLE); expect(JSON.stringify(result)).toMatchSnapshot(); - const back = fromJSON(result); + const back = fromJSON(result); expect(back).toBeInstanceOf(URL); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('toJSONAsync', () => { it('supports URL', async () => { - const example = new URL('https://github.com/lxsmnsyc/seroval?hello=world'); - const result = await toJSONAsync(Promise.resolve(example)); + const result = await toJSONAsync(Promise.resolve(EXAMPLE)); expect(JSON.stringify(result)).toMatchSnapshot(); const back = await fromJSON>(result); expect(back).toBeInstanceOf(URL); - expect(String(back)).toBe(String(example)); + expect(String(back)).toBe(String(EXAMPLE)); }); }); describe('crossSerialize', () => { it('supports URL', () => { - const example = new URL('https://github.com/lxsmnsyc/seroval?hello=world'); - const result = crossSerialize(example); + const result = crossSerialize(EXAMPLE); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports URL', () => { - const example = new URL('https://github.com/lxsmnsyc/seroval?hello=world'); - const result = crossSerialize(example, { scopeId: 'example' }); + const result = crossSerialize(EXAMPLE, { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeAsync', () => { it('supports URL', async () => { - const example = new URL('https://github.com/lxsmnsyc/seroval?hello=world'); - const result = await crossSerializeAsync(Promise.resolve(example)); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE)); expect(result).toMatchSnapshot(); }); describe('scoped', () => { it('supports URL', async () => { - const example = new URL('https://github.com/lxsmnsyc/seroval?hello=world'); - const result = await crossSerializeAsync(Promise.resolve(example), { scopeId: 'example' }); + const result = await crossSerializeAsync(Promise.resolve(EXAMPLE), { scopeId: 'example' }); expect(result).toMatchSnapshot(); }); }); }); describe('crossSerializeStream', () => { - it('supports URL', async () => new Promise((done) => { - const example = new URL('https://github.com/lxsmnsyc/seroval?hello=world'); - crossSerializeStream(Promise.resolve(example), { + it('supports URL', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports URL', async () => new Promise((done) => { - const example = new URL('https://github.com/lxsmnsyc/seroval?hello=world'); - crossSerializeStream(Promise.resolve(example), { + it('supports URL', async () => new Promise((resolve, reject) => { + crossSerializeStream(Promise.resolve(EXAMPLE), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toJSON', () => { + it('supports URL', () => { + const result = toCrossJSON(EXAMPLE); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(URL); + expect(String(back)).toBe(String(EXAMPLE)); + }); + }); + describe('toJSONAsync', () => { + it('supports URL', async () => { + const result = await toCrossJSONAsync(Promise.resolve(EXAMPLE)); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = await fromCrossJSON>(result, { + refs: new Map(), + }); + expect(back).toBeInstanceOf(URL); + expect(String(back)).toBe(String(EXAMPLE)); + }); + }); + describe('toCrossJSONStream', () => { + it('supports URL', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(EXAMPLE), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test/wk-symbols.test.ts b/packages/seroval/test/wk-symbols.test.ts index e6791a55..238f662f 100644 --- a/packages/seroval/test/wk-symbols.test.ts +++ b/packages/seroval/test/wk-symbols.test.ts @@ -7,6 +7,9 @@ import { // fromJSON, serialize, serializeAsync, + toCrossJSON, + toCrossJSONAsync, + toCrossJSONStream, toJSON, toJSONAsync, } from '../src'; @@ -177,280 +180,589 @@ describe('well-known symbols', () => { }); }); describe('crossSerializeStream', () => { - it('supports Symbol.asyncIterator', async () => new Promise((done) => { + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.asyncIterator), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.hasInstance', async () => new Promise((done) => { + it('supports Symbol.hasInstance', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.hasInstance), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.isConcatSpreadable', async () => new Promise((done) => { + it('supports Symbol.isConcatSpreadable', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.isConcatSpreadable), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.iterator', async () => new Promise((done) => { + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.iterator), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.match', async () => new Promise((done) => { + it('supports Symbol.match', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.match), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.matchAll', async () => new Promise((done) => { + it('supports Symbol.matchAll', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.matchAll), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.replace', async () => new Promise((done) => { + it('supports Symbol.replace', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.replace), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.search', async () => new Promise((done) => { + it('supports Symbol.search', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.search), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.species', async () => new Promise((done) => { + it('supports Symbol.species', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.species), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.split', async () => new Promise((done) => { + it('supports Symbol.split', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.split), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.toPrimitive', async () => new Promise((done) => { + it('supports Symbol.toPrimitive', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.toPrimitive), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.toStringTag', async () => new Promise((done) => { + it('supports Symbol.toStringTag', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.toStringTag), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.unscopables', async () => new Promise((done) => { + it('supports Symbol.unscopables', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.unscopables), { onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); describe('scoped', () => { - it('supports Symbol.asyncIterator', async () => new Promise((done) => { + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.asyncIterator), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.hasInstance', async () => new Promise((done) => { + it('supports Symbol.hasInstance', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.hasInstance), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.isConcatSpreadable', async () => new Promise((done) => { + it('supports Symbol.isConcatSpreadable', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.isConcatSpreadable), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.iterator', async () => new Promise((done) => { + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.iterator), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.match', async () => new Promise((done) => { + it('supports Symbol.match', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.match), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.matchAll', async () => new Promise((done) => { + it('supports Symbol.matchAll', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.matchAll), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.replace', async () => new Promise((done) => { + it('supports Symbol.replace', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.replace), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.search', async () => new Promise((done) => { + it('supports Symbol.search', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.search), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.species', async () => new Promise((done) => { + it('supports Symbol.species', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.species), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.split', async () => new Promise((done) => { + it('supports Symbol.split', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.split), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.toPrimitive', async () => new Promise((done) => { + it('supports Symbol.toPrimitive', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.toPrimitive), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.toStringTag', async () => new Promise((done) => { + it('supports Symbol.toStringTag', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.toStringTag), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); - it('supports Symbol.unscopables', async () => new Promise((done) => { + it('supports Symbol.unscopables', async () => new Promise((resolve, reject) => { crossSerializeStream(Promise.resolve(Symbol.unscopables), { scopeId: 'example', onSerialize(data) { expect(data).toMatchSnapshot(); }, onDone() { - done(); + resolve(); + }, + onError(error) { + reject(error); }, }); })); }); }); + describe('toCrossJSON', () => { + it('supports well-known symbols', () => { + expect(JSON.stringify(toCrossJSON(Symbol.asyncIterator))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Symbol.hasInstance))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Symbol.isConcatSpreadable))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Symbol.iterator))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Symbol.match))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Symbol.matchAll))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Symbol.replace))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Symbol.search))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Symbol.species))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Symbol.split))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Symbol.toPrimitive))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Symbol.toStringTag))).toMatchSnapshot(); + expect(JSON.stringify(toCrossJSON(Symbol.unscopables))).toMatchSnapshot(); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports well-known symbols', async () => { + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Symbol.asyncIterator))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Symbol.hasInstance))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Symbol.isConcatSpreadable))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Symbol.iterator))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Symbol.match))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Symbol.matchAll))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Symbol.replace))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Symbol.search))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Symbol.species))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Symbol.split))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Symbol.toPrimitive))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Symbol.toStringTag))), + ).toMatchSnapshot(); + expect( + JSON.stringify(await toCrossJSONAsync(Promise.resolve(Symbol.unscopables))), + ).toMatchSnapshot(); + }); + }); + describe('toCrossJSONStream', () => { + it('supports Symbol.asyncIterator', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Symbol.asyncIterator), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.hasInstance', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Symbol.hasInstance), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.isConcatSpreadable', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Symbol.isConcatSpreadable), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.iterator', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Symbol.iterator), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.match', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Symbol.match), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.matchAll', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Symbol.matchAll), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.replace', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Symbol.replace), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.search', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Symbol.search), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.species', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Symbol.species), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.split', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Symbol.split), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.toPrimitive', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Symbol.toPrimitive), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.toStringTag', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Symbol.toStringTag), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports Symbol.unscopables', async () => new Promise((resolve, reject) => { + toCrossJSONStream(Promise.resolve(Symbol.unscopables), { + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); }); diff --git a/packages/seroval/test2.js b/packages/seroval/test2.js index 665407ff..b9d4d16d 100644 --- a/packages/seroval/test2.js +++ b/packages/seroval/test2.js @@ -1,17 +1,33 @@ -import { crossSerializeStream } from './dist/esm/development/index.mjs'; - -const source = new ReadableStream({ - start(controller) { - controller.enqueue('Hello'); - controller.enqueue('World'); - controller.close(); - } -}) - -crossSerializeStream(source, { - scopeId: 'example', - onSerialize(data) { - console.log([data]); - } -}); +import { serialize } from './dist/esm/development/index.mjs'; + +// const instance = new Serializer({ +// globalIdentifier: 'test', +// onData: console.log, +// }); + +// const example = { foo: 'bar' }; + +// function* hello() { +// yield example; +// } + +// instance.write('foo', hello()); +// instance.write('bar', hello()); + +const example = { + a: new Map(), + b: new Set(), +}; + +example.a.set(example.a, example.b); + +const example2 = { + foo: new Map(), + bar: new Set(), +}; + +example2.foo.set(example2.foo, example2.bar); +example2.heck = example; + +console.log(serialize(example2)); \ No newline at end of file diff --git a/packages/seroval/theory.js b/packages/seroval/theory.js new file mode 100644 index 00000000..241cecee --- /dev/null +++ b/packages/seroval/theory.js @@ -0,0 +1,20 @@ +import { Serializer } from "./dist/esm/development/index.mjs"; + +const sleep = (value, ms) => ( + new Promise((res) => setTimeout(res, ms, value)) +); + +async function * example() { + yield sleep('foo', 1000); + yield sleep('bar', 1000); + yield sleep('baz', 1000); +} + +const serializer = new Serializer({ + globalIdentifier: 'X', + onData(value) { + console.log(value); + }, +}); + +serializer.write('example', example()); \ No newline at end of file