seroval 0.4.0-alpha.3 → 0.4.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/development/index.cjs +241 -162
- package/dist/cjs/development/index.cjs.map +2 -2
- package/dist/cjs/production/index.cjs +2 -2
- package/dist/esm/development/index.mjs +241 -162
- package/dist/esm/development/index.mjs.map +2 -2
- package/dist/esm/production/index.mjs +2 -2
- package/dist/types/compat.d.ts +13 -12
- package/dist/types/index.d.ts +4 -0
- package/dist/types/tree.d.ts +39 -29
- package/dist/types/types.d.ts +2 -2
- package/package.json +2 -2
- package/src/checks.ts +1 -2
- package/src/compat.ts +28 -14
- package/src/index.ts +74 -19
- package/src/tree.ts +180 -138
- package/src/types.ts +3 -3
package/src/tree.ts
CHANGED
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
ErrorValue,
|
|
15
15
|
PrimitiveValue,
|
|
16
16
|
ServerValue,
|
|
17
|
-
TypedArrayValue,
|
|
18
17
|
} from './types';
|
|
19
18
|
import getIdentifier from './get-identifier';
|
|
20
19
|
import { Feature, parseTargets } from './compat';
|
|
@@ -45,20 +44,24 @@ export type Assignment =
|
|
|
45
44
|
| MapAssignment
|
|
46
45
|
| SetAssignment;
|
|
47
46
|
|
|
47
|
+
export interface ParserContext {
|
|
48
|
+
refs: Map<unknown, number>;
|
|
49
|
+
markedRefs: Set<number>;
|
|
50
|
+
features: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
48
53
|
export interface SerializationContext {
|
|
49
54
|
stack: number[];
|
|
50
|
-
// Value-to-ref map
|
|
51
|
-
refs: Map<unknown, number>;
|
|
52
55
|
// Map tree refs to actual refs
|
|
53
56
|
validRefs: Map<number, number>;
|
|
54
57
|
// Refs that are...referenced
|
|
55
|
-
markedRefs:
|
|
58
|
+
markedRefs: Set<number>;
|
|
56
59
|
// Variables
|
|
57
60
|
vars: string[];
|
|
58
61
|
// Array of assignments to be done (used for recursion)
|
|
59
62
|
assignments: Assignment[];
|
|
60
63
|
// Supported features
|
|
61
|
-
features:
|
|
64
|
+
features: number;
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
export interface Options {
|
|
@@ -69,17 +72,29 @@ const DEFAULT_OPTIONS: Options = {
|
|
|
69
72
|
target: 'es2023',
|
|
70
73
|
};
|
|
71
74
|
|
|
72
|
-
export function
|
|
75
|
+
export function createParserContext(options: Partial<Options> = {}): ParserContext {
|
|
73
76
|
// eslint-disable-next-line prefer-object-spread
|
|
74
77
|
const result = Object.assign({}, DEFAULT_OPTIONS, options || {});
|
|
75
78
|
return {
|
|
76
|
-
markedRefs:
|
|
77
|
-
stack: [],
|
|
79
|
+
markedRefs: new Set(),
|
|
78
80
|
refs: new Map(),
|
|
81
|
+
features: parseTargets(result.target),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface SerializationOptions {
|
|
86
|
+
markedRefs: number[] | Set<number>;
|
|
87
|
+
features: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function createSerializationContext(options: SerializationOptions): SerializationContext {
|
|
91
|
+
return {
|
|
92
|
+
stack: [],
|
|
79
93
|
vars: [],
|
|
80
94
|
assignments: [],
|
|
81
95
|
validRefs: new Map(),
|
|
82
|
-
features:
|
|
96
|
+
features: options.features,
|
|
97
|
+
markedRefs: new Set(options.markedRefs),
|
|
83
98
|
};
|
|
84
99
|
}
|
|
85
100
|
|
|
@@ -162,24 +177,8 @@ export function resolvePatches(ctx: SerializationContext) {
|
|
|
162
177
|
/**
|
|
163
178
|
* Increments the number of references the referenced value has
|
|
164
179
|
*/
|
|
165
|
-
function markRef(ctx: SerializationContext, current: number) {
|
|
166
|
-
ctx.markedRefs
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Creates a reference ID from the given values
|
|
171
|
-
*/
|
|
172
|
-
export function createRef(
|
|
173
|
-
ctx: SerializationContext,
|
|
174
|
-
index: unknown,
|
|
175
|
-
) {
|
|
176
|
-
const current = ctx.refs.get(index);
|
|
177
|
-
if (current != null) {
|
|
178
|
-
return current;
|
|
179
|
-
}
|
|
180
|
-
const id = ctx.refs.size;
|
|
181
|
-
ctx.refs.set(index, id);
|
|
182
|
-
return id;
|
|
180
|
+
function markRef(ctx: ParserContext | SerializationContext, current: number) {
|
|
181
|
+
ctx.markedRefs.add(current);
|
|
183
182
|
}
|
|
184
183
|
|
|
185
184
|
/**
|
|
@@ -225,12 +224,28 @@ function assignRef(
|
|
|
225
224
|
index: number,
|
|
226
225
|
value: string,
|
|
227
226
|
) {
|
|
228
|
-
if (ctx.markedRefs
|
|
227
|
+
if (ctx.markedRefs.has(index)) {
|
|
229
228
|
return `${getRefParam(ctx, index)}=${value}`;
|
|
230
229
|
}
|
|
231
230
|
return value;
|
|
232
231
|
}
|
|
233
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Creates a reference ID from the given values
|
|
235
|
+
*/
|
|
236
|
+
function createRef(
|
|
237
|
+
ctx: ParserContext,
|
|
238
|
+
index: unknown,
|
|
239
|
+
) {
|
|
240
|
+
const current = ctx.refs.get(index);
|
|
241
|
+
if (current != null) {
|
|
242
|
+
return current;
|
|
243
|
+
}
|
|
244
|
+
const id = ctx.refs.size;
|
|
245
|
+
ctx.refs.set(index, id);
|
|
246
|
+
return id;
|
|
247
|
+
}
|
|
248
|
+
|
|
234
249
|
function createAssignment(
|
|
235
250
|
ctx: SerializationContext,
|
|
236
251
|
source: string,
|
|
@@ -281,24 +296,16 @@ function createArrayAssign(
|
|
|
281
296
|
createAssignment(ctx, `${getRefParam(ctx, ref)}[${index}]`, value);
|
|
282
297
|
}
|
|
283
298
|
|
|
284
|
-
function
|
|
299
|
+
function createObjectAssign(
|
|
285
300
|
ctx: SerializationContext,
|
|
286
301
|
ref: number,
|
|
287
302
|
key: string,
|
|
288
303
|
value: string,
|
|
304
|
+
computed: boolean,
|
|
289
305
|
) {
|
|
290
306
|
markRef(ctx, ref);
|
|
291
|
-
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
function createObjectComputedAssign(
|
|
295
|
-
ctx: SerializationContext,
|
|
296
|
-
ref: number,
|
|
297
|
-
key: string,
|
|
298
|
-
value: string,
|
|
299
|
-
) {
|
|
300
|
-
markRef(ctx, ref);
|
|
301
|
-
createAssignment(ctx, `${getRefParam(ctx, ref)}[${key}]`, value);
|
|
307
|
+
const member = computed ? `[${key}]` : `.${key}`;
|
|
308
|
+
createAssignment(ctx, `${getRefParam(ctx, ref)}${member}`, value);
|
|
302
309
|
}
|
|
303
310
|
|
|
304
311
|
function getErrorConstructor(error: ErrorValue) {
|
|
@@ -360,6 +367,7 @@ function getIterableOptions(obj: Iterable<any>) {
|
|
|
360
367
|
|
|
361
368
|
const enum SerovalNodeType {
|
|
362
369
|
Primitive,
|
|
370
|
+
BigInt,
|
|
363
371
|
Reference,
|
|
364
372
|
Date,
|
|
365
373
|
RegExp,
|
|
@@ -373,16 +381,23 @@ const enum SerovalNodeType {
|
|
|
373
381
|
AggregateError,
|
|
374
382
|
Iterable,
|
|
375
383
|
TypedArray,
|
|
384
|
+
BigIntTypedArray,
|
|
376
385
|
}
|
|
377
386
|
|
|
378
387
|
type SerovalPrimitiveNode = [type: SerovalNodeType.Primitive, value: PrimitiveValue];
|
|
379
388
|
type SerovalReferenceNode = [type: SerovalNodeType.Reference, value: number];
|
|
380
389
|
type SerovalSemiPrimitiveNode =
|
|
381
|
-
| [type: SerovalNodeType.
|
|
382
|
-
| [type: SerovalNodeType.
|
|
390
|
+
| [type: SerovalNodeType.BigInt, value: string]
|
|
391
|
+
| [type: SerovalNodeType.Date, value: string, id: number]
|
|
392
|
+
| [type: SerovalNodeType.RegExp, value: string, id: number]
|
|
383
393
|
| [
|
|
384
394
|
type: SerovalNodeType.TypedArray,
|
|
385
|
-
value: [constructor: string, array:
|
|
395
|
+
value: [constructor: string, array: string, byteOffset: number],
|
|
396
|
+
id: number
|
|
397
|
+
]
|
|
398
|
+
| [
|
|
399
|
+
type: SerovalNodeType.BigIntTypedArray,
|
|
400
|
+
value: [constructor: string, array: string, byteOffset: number],
|
|
386
401
|
id: number
|
|
387
402
|
];
|
|
388
403
|
|
|
@@ -429,7 +444,7 @@ type SerovalIterableNode = [
|
|
|
429
444
|
id: number,
|
|
430
445
|
];
|
|
431
446
|
|
|
432
|
-
type SerovalNode =
|
|
447
|
+
export type SerovalNode =
|
|
433
448
|
| SerovalPrimitiveNode
|
|
434
449
|
| SerovalReferenceNode
|
|
435
450
|
| SerovalSemiPrimitiveNode
|
|
@@ -451,7 +466,7 @@ function isReferenceInStack(
|
|
|
451
466
|
}
|
|
452
467
|
|
|
453
468
|
function generateRef(
|
|
454
|
-
ctx:
|
|
469
|
+
ctx: ParserContext,
|
|
455
470
|
current: unknown,
|
|
456
471
|
): number | SerovalReferenceNode {
|
|
457
472
|
// Check if reference number already exists
|
|
@@ -471,73 +486,95 @@ function generateRef(
|
|
|
471
486
|
}
|
|
472
487
|
|
|
473
488
|
function generateSemiPrimitiveValue(
|
|
474
|
-
ctx:
|
|
489
|
+
ctx: ParserContext,
|
|
475
490
|
current: unknown,
|
|
476
491
|
id: number,
|
|
477
492
|
): SerovalNode | undefined {
|
|
493
|
+
if (typeof current === 'bigint') {
|
|
494
|
+
assert(ctx.features & Feature.BigInt, 'Unsupported type "BigInt"');
|
|
495
|
+
return [SerovalNodeType.BigInt, `${current}n`];
|
|
496
|
+
}
|
|
478
497
|
if (constructorCheck<Date>(current, Date)) {
|
|
479
|
-
return [SerovalNodeType.Date, current, id];
|
|
498
|
+
return [SerovalNodeType.Date, current.toISOString(), id];
|
|
480
499
|
}
|
|
481
500
|
if (constructorCheck<RegExp>(current, RegExp)) {
|
|
482
|
-
return [SerovalNodeType.RegExp, current, id];
|
|
501
|
+
return [SerovalNodeType.RegExp, String(current), id];
|
|
483
502
|
}
|
|
484
503
|
if (constructorCheck<Int8Array>(current, Int8Array)) {
|
|
485
|
-
assert(ctx.features
|
|
486
|
-
return [SerovalNodeType.TypedArray, ['Int8Array', current], id];
|
|
504
|
+
assert(ctx.features & Feature.TypedArray, 'Unsupported value type "Int8Array"');
|
|
505
|
+
return [SerovalNodeType.TypedArray, ['Int8Array', current.toString(), current.byteOffset], id];
|
|
487
506
|
}
|
|
488
507
|
if (constructorCheck<Int16Array>(current, Int16Array)) {
|
|
489
|
-
assert(ctx.features
|
|
490
|
-
return [SerovalNodeType.TypedArray, ['Int16Array', current], id];
|
|
508
|
+
assert(ctx.features & Feature.TypedArray, 'Unsupported value type "Int16Array"');
|
|
509
|
+
return [SerovalNodeType.TypedArray, ['Int16Array', current.toString(), current.byteOffset], id];
|
|
491
510
|
}
|
|
492
511
|
if (constructorCheck<Int32Array>(current, Int32Array)) {
|
|
493
|
-
assert(ctx.features
|
|
494
|
-
return [SerovalNodeType.TypedArray, ['Int32Array', current], id];
|
|
512
|
+
assert(ctx.features & Feature.TypedArray, 'Unsupported value type "Int32Array"');
|
|
513
|
+
return [SerovalNodeType.TypedArray, ['Int32Array', current.toString(), current.byteOffset], id];
|
|
495
514
|
}
|
|
496
515
|
if (constructorCheck<Uint8Array>(current, Uint8Array)) {
|
|
497
|
-
assert(ctx.features
|
|
498
|
-
return [SerovalNodeType.TypedArray, ['Uint8Array', current], id];
|
|
516
|
+
assert(ctx.features & Feature.TypedArray, 'Unsupported value type "Uint8Array"');
|
|
517
|
+
return [SerovalNodeType.TypedArray, ['Uint8Array', current.toString(), current.byteOffset], id];
|
|
499
518
|
}
|
|
500
519
|
if (constructorCheck<Uint16Array>(current, Uint16Array)) {
|
|
501
|
-
assert(ctx.features
|
|
502
|
-
return [SerovalNodeType.TypedArray, ['Uint16Array', current], id];
|
|
520
|
+
assert(ctx.features & Feature.TypedArray, 'Unsupported value type "Uint16Array"');
|
|
521
|
+
return [SerovalNodeType.TypedArray, ['Uint16Array', current.toString(), current.byteOffset], id];
|
|
503
522
|
}
|
|
504
523
|
if (constructorCheck<Uint32Array>(current, Uint32Array)) {
|
|
505
|
-
assert(ctx.features
|
|
506
|
-
return [SerovalNodeType.TypedArray, ['Uint32Array', current], id];
|
|
524
|
+
assert(ctx.features & Feature.TypedArray, 'Unsupported value type "Uint32Array"');
|
|
525
|
+
return [SerovalNodeType.TypedArray, ['Uint32Array', current.toString(), current.byteOffset], id];
|
|
507
526
|
}
|
|
508
527
|
if (constructorCheck<Uint8ClampedArray>(current, Uint8ClampedArray)) {
|
|
509
|
-
assert(ctx.features
|
|
510
|
-
return [SerovalNodeType.TypedArray, ['Uint8ClampedArray', current], id];
|
|
528
|
+
assert(ctx.features & Feature.TypedArray, 'Unsupported value type "Uint8ClampedArray"');
|
|
529
|
+
return [SerovalNodeType.TypedArray, ['Uint8ClampedArray', current.toString(), current.byteOffset], id];
|
|
511
530
|
}
|
|
512
531
|
if (constructorCheck<Float32Array>(current, Float32Array)) {
|
|
513
|
-
assert(ctx.features
|
|
514
|
-
return [SerovalNodeType.TypedArray, ['Float32Array', current], id];
|
|
532
|
+
assert(ctx.features & Feature.TypedArray, 'Unsupported value type "Float32Array"');
|
|
533
|
+
return [SerovalNodeType.TypedArray, ['Float32Array', current.toString(), current.byteOffset], id];
|
|
515
534
|
}
|
|
516
535
|
if (constructorCheck<Float64Array>(current, Float64Array)) {
|
|
517
|
-
assert(ctx.features
|
|
518
|
-
return [SerovalNodeType.TypedArray, ['Float64Array', current], id];
|
|
536
|
+
assert(ctx.features & Feature.TypedArray, 'Unsupported value type "Float64Array"');
|
|
537
|
+
return [SerovalNodeType.TypedArray, ['Float64Array', current.toString(), current.byteOffset], id];
|
|
519
538
|
}
|
|
520
539
|
if (constructorCheck<BigInt64Array>(current, BigInt64Array)) {
|
|
521
540
|
assert(
|
|
522
|
-
ctx.features
|
|
523
|
-
&& ctx.features.has(Feature.BigInt),
|
|
541
|
+
ctx.features & (Feature.BigIntTypedArray),
|
|
524
542
|
'Unsupported value type "BigInt64Array"',
|
|
525
543
|
);
|
|
526
|
-
|
|
544
|
+
let result = '';
|
|
545
|
+
const cap = current.length - 1;
|
|
546
|
+
for (let i = 0; i < cap; i++) {
|
|
547
|
+
result += `${current[i]}n,`;
|
|
548
|
+
}
|
|
549
|
+
result += `"${current[cap]}"`;
|
|
550
|
+
return [
|
|
551
|
+
SerovalNodeType.BigIntTypedArray,
|
|
552
|
+
['BigInt64Array', result, current.byteOffset],
|
|
553
|
+
id,
|
|
554
|
+
];
|
|
527
555
|
}
|
|
528
556
|
if (constructorCheck<BigUint64Array>(current, BigUint64Array)) {
|
|
529
557
|
assert(
|
|
530
|
-
ctx.features
|
|
531
|
-
&& ctx.features.has(Feature.BigInt),
|
|
558
|
+
ctx.features & (Feature.BigIntTypedArray),
|
|
532
559
|
'Unsupported value type "BigUint64Array"',
|
|
533
560
|
);
|
|
534
|
-
|
|
561
|
+
let result = '';
|
|
562
|
+
const cap = current.length - 1;
|
|
563
|
+
for (let i = 0; i < cap; i++) {
|
|
564
|
+
result += `"${current[i]}n",`;
|
|
565
|
+
}
|
|
566
|
+
result += `"${current[cap]}"`;
|
|
567
|
+
return [
|
|
568
|
+
SerovalNodeType.BigIntTypedArray,
|
|
569
|
+
['BigInt64Array', result, current.byteOffset],
|
|
570
|
+
id,
|
|
571
|
+
];
|
|
535
572
|
}
|
|
536
573
|
return undefined;
|
|
537
574
|
}
|
|
538
575
|
|
|
539
576
|
function serializePropertiesSync(
|
|
540
|
-
ctx:
|
|
577
|
+
ctx: ParserContext,
|
|
541
578
|
properties: Record<string, unknown>,
|
|
542
579
|
): SerovalDictionaryNode {
|
|
543
580
|
const keys = Object.keys(properties);
|
|
@@ -566,12 +603,12 @@ function serializePropertiesSync(
|
|
|
566
603
|
return [keyNodes, valueNodes, size];
|
|
567
604
|
}
|
|
568
605
|
|
|
569
|
-
|
|
570
|
-
ctx:
|
|
606
|
+
function generateTreeSync(
|
|
607
|
+
ctx: ParserContext,
|
|
571
608
|
current: ServerValue,
|
|
572
609
|
): SerovalNode {
|
|
573
610
|
if (isPrimitive(current)) {
|
|
574
|
-
return [SerovalNodeType.Primitive, current];
|
|
611
|
+
return [SerovalNodeType.Primitive, serializePrimitive(current)];
|
|
575
612
|
}
|
|
576
613
|
// Non-primitive values needs a reference ID
|
|
577
614
|
// mostly because the values themselves are stateful
|
|
@@ -584,7 +621,7 @@ export function generateTreeSync(
|
|
|
584
621
|
return semiPrimitive;
|
|
585
622
|
}
|
|
586
623
|
if (constructorCheck<Set<ServerValue>>(current, Set)) {
|
|
587
|
-
assert(ctx.features
|
|
624
|
+
assert(ctx.features & Feature.Set, 'Unsupported type "Set"');
|
|
588
625
|
const len = current.size;
|
|
589
626
|
const nodes = new Array<SerovalNode>(len);
|
|
590
627
|
const deferred = new Array<ServerValue>(len);
|
|
@@ -605,7 +642,7 @@ export function generateTreeSync(
|
|
|
605
642
|
return [SerovalNodeType.Set, nodes, id];
|
|
606
643
|
}
|
|
607
644
|
if (constructorCheck<Map<ServerValue, ServerValue>>(current, Map)) {
|
|
608
|
-
assert(ctx.features
|
|
645
|
+
assert(ctx.features & Feature.Map, 'Unsupported type "Map"');
|
|
609
646
|
const len = current.size;
|
|
610
647
|
const keyNodes = new Array<SerovalNode>(len);
|
|
611
648
|
const valueNodes = new Array<SerovalNode>(len);
|
|
@@ -651,7 +688,7 @@ export function generateTreeSync(
|
|
|
651
688
|
}
|
|
652
689
|
return [SerovalNodeType.Array, nodes, id];
|
|
653
690
|
}
|
|
654
|
-
if (current instanceof AggregateError && ctx.features
|
|
691
|
+
if (current instanceof AggregateError && ctx.features & Feature.AggregateError) {
|
|
655
692
|
const options = getErrorOptions(current);
|
|
656
693
|
const optionsNode = options
|
|
657
694
|
? serializePropertiesSync(ctx, options)
|
|
@@ -671,7 +708,7 @@ export function generateTreeSync(
|
|
|
671
708
|
];
|
|
672
709
|
}
|
|
673
710
|
if (isIterable(current)) {
|
|
674
|
-
assert(ctx.features
|
|
711
|
+
assert(ctx.features & Feature.SymbolIterator, 'Unsupported type "Iterable"');
|
|
675
712
|
const options = getIterableOptions(current);
|
|
676
713
|
return [SerovalNodeType.Iterable, [
|
|
677
714
|
// Parse options first before the items
|
|
@@ -690,8 +727,16 @@ export function generateTreeSync(
|
|
|
690
727
|
throw new Error('Unsupported value');
|
|
691
728
|
}
|
|
692
729
|
|
|
730
|
+
export function parseSync(
|
|
731
|
+
ctx: ParserContext,
|
|
732
|
+
current: ServerValue,
|
|
733
|
+
) {
|
|
734
|
+
const result = generateTreeSync(ctx, current);
|
|
735
|
+
return [result, createRef(ctx, current), result[0] === SerovalNodeType.Object] as const;
|
|
736
|
+
}
|
|
737
|
+
|
|
693
738
|
async function serializePropertiesAsync(
|
|
694
|
-
ctx:
|
|
739
|
+
ctx: ParserContext,
|
|
695
740
|
properties: Record<string, unknown>,
|
|
696
741
|
): Promise<SerovalDictionaryNode> {
|
|
697
742
|
const keys = Object.keys(properties);
|
|
@@ -720,12 +765,12 @@ async function serializePropertiesAsync(
|
|
|
720
765
|
return [keyNodes, valueNodes, size];
|
|
721
766
|
}
|
|
722
767
|
|
|
723
|
-
|
|
724
|
-
ctx:
|
|
768
|
+
async function generateTreeAsync(
|
|
769
|
+
ctx: ParserContext,
|
|
725
770
|
current: AsyncServerValue,
|
|
726
771
|
): Promise<SerovalNode> {
|
|
727
772
|
if (isPrimitive(current)) {
|
|
728
|
-
return [SerovalNodeType.Primitive, current];
|
|
773
|
+
return [SerovalNodeType.Primitive, serializePrimitive(current)];
|
|
729
774
|
}
|
|
730
775
|
const id = generateRef(ctx, current);
|
|
731
776
|
if (Array.isArray(id)) {
|
|
@@ -736,7 +781,7 @@ export async function generateTreeAsync(
|
|
|
736
781
|
return semiPrimitive;
|
|
737
782
|
}
|
|
738
783
|
if (isPromise(current)) {
|
|
739
|
-
assert(ctx.features
|
|
784
|
+
assert(ctx.features & Feature.Promise, 'Unsupported type "Promise"');
|
|
740
785
|
return current.then(async (value) => [
|
|
741
786
|
SerovalNodeType.Promise,
|
|
742
787
|
await generateTreeAsync(ctx, value),
|
|
@@ -744,7 +789,7 @@ export async function generateTreeAsync(
|
|
|
744
789
|
]);
|
|
745
790
|
}
|
|
746
791
|
if (constructorCheck<Set<AsyncServerValue>>(current, Set)) {
|
|
747
|
-
assert(ctx.features
|
|
792
|
+
assert(ctx.features & Feature.Set, 'Unsupported type "Set"');
|
|
748
793
|
const len = current.size;
|
|
749
794
|
const nodes = new Array<SerovalNode>(len);
|
|
750
795
|
const deferred = new Array<AsyncServerValue>(len);
|
|
@@ -765,7 +810,7 @@ export async function generateTreeAsync(
|
|
|
765
810
|
return [SerovalNodeType.Set, nodes, id];
|
|
766
811
|
}
|
|
767
812
|
if (constructorCheck<Map<AsyncServerValue, AsyncServerValue>>(current, Map)) {
|
|
768
|
-
assert(ctx.features
|
|
813
|
+
assert(ctx.features & Feature.Map, 'Unsupported type "Map"');
|
|
769
814
|
const len = current.size;
|
|
770
815
|
const keyNodes = new Array<SerovalNode>(len);
|
|
771
816
|
const valueNodes = new Array<SerovalNode>(len);
|
|
@@ -812,7 +857,7 @@ export async function generateTreeAsync(
|
|
|
812
857
|
}
|
|
813
858
|
return [SerovalNodeType.Array, nodes, id];
|
|
814
859
|
}
|
|
815
|
-
if (current instanceof AggregateError) {
|
|
860
|
+
if (current instanceof AggregateError && ctx.features & Feature.AggregateError) {
|
|
816
861
|
const options = getErrorOptions(current);
|
|
817
862
|
const optionsNode = options
|
|
818
863
|
? await serializePropertiesAsync(ctx, options)
|
|
@@ -832,7 +877,7 @@ export async function generateTreeAsync(
|
|
|
832
877
|
];
|
|
833
878
|
}
|
|
834
879
|
if (isIterable(current)) {
|
|
835
|
-
assert(ctx.features
|
|
880
|
+
assert(ctx.features & Feature.SymbolIterator, 'Unsupported type "Iterable"');
|
|
836
881
|
const options = getIterableOptions(current);
|
|
837
882
|
return [SerovalNodeType.Iterable, [
|
|
838
883
|
options
|
|
@@ -852,10 +897,17 @@ export async function generateTreeAsync(
|
|
|
852
897
|
throw new Error('Unsupported value');
|
|
853
898
|
}
|
|
854
899
|
|
|
900
|
+
export async function parseAsync(
|
|
901
|
+
ctx: ParserContext,
|
|
902
|
+
current: AsyncServerValue,
|
|
903
|
+
) {
|
|
904
|
+
const result = await generateTreeAsync(ctx, current);
|
|
905
|
+
return [result, createRef(ctx, current), result[0] === SerovalNodeType.Object] as const;
|
|
906
|
+
}
|
|
907
|
+
|
|
855
908
|
export function serializePrimitive(
|
|
856
|
-
ctx: SerializationContext,
|
|
857
909
|
value: PrimitiveValue,
|
|
858
|
-
): string {
|
|
910
|
+
): string | number | null {
|
|
859
911
|
// Shortened forms
|
|
860
912
|
if (value === true) {
|
|
861
913
|
return '!0';
|
|
@@ -867,11 +919,7 @@ export function serializePrimitive(
|
|
|
867
919
|
return 'void 0';
|
|
868
920
|
}
|
|
869
921
|
if (value === null) {
|
|
870
|
-
return
|
|
871
|
-
}
|
|
872
|
-
if (typeof value === 'bigint') {
|
|
873
|
-
assert(ctx.features.has(Feature.BigInt), 'Unsupported type "BigInt"');
|
|
874
|
-
return `${value}n`;
|
|
922
|
+
return null;
|
|
875
923
|
}
|
|
876
924
|
if (typeof value === 'string') {
|
|
877
925
|
return quote(value);
|
|
@@ -886,7 +934,7 @@ export function serializePrimitive(
|
|
|
886
934
|
if (Object.is(value, -Infinity)) {
|
|
887
935
|
return '-1/0';
|
|
888
936
|
}
|
|
889
|
-
return
|
|
937
|
+
return value;
|
|
890
938
|
}
|
|
891
939
|
|
|
892
940
|
const IDENTIFIER_CHECK = /^([$A-Z_][0-9A-Z_$]*)$/i;
|
|
@@ -909,15 +957,14 @@ function serializeAssignments(
|
|
|
909
957
|
ctx.assignments = mainAssignments;
|
|
910
958
|
// Test if key is a valid number or JS identifier
|
|
911
959
|
// so that we don't have to serialize the key and wrap with brackets
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
}
|
|
960
|
+
const isIdentifier = check >= 0 || IDENTIFIER_CHECK.test(key);
|
|
961
|
+
createObjectAssign(
|
|
962
|
+
ctx,
|
|
963
|
+
targetRef,
|
|
964
|
+
isIdentifier ? key : quote(key),
|
|
965
|
+
refParam,
|
|
966
|
+
!(isIdentifier && Number.isNaN(check)),
|
|
967
|
+
);
|
|
921
968
|
ctx.assignments = parentAssignment;
|
|
922
969
|
}
|
|
923
970
|
ctx.stack.pop();
|
|
@@ -937,22 +984,19 @@ function serializeObject(
|
|
|
937
984
|
const check = Number(key);
|
|
938
985
|
// Test if key is a valid number or JS identifier
|
|
939
986
|
// so that we don't have to serialize the key and wrap with brackets
|
|
940
|
-
const isIdentifier = IDENTIFIER_CHECK.test(key)
|
|
987
|
+
const isIdentifier = check >= 0 || IDENTIFIER_CHECK.test(key);
|
|
988
|
+
const validKey = isIdentifier ? key : quote(key);
|
|
941
989
|
if (isReferenceInStack(ctx, val)) {
|
|
942
990
|
const refParam = getRefParam(ctx, val[1]);
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
createObjectComputedAssign(ctx, sourceID, quote(key), refParam);
|
|
951
|
-
}
|
|
952
|
-
} else if (isIdentifier) {
|
|
953
|
-
result += `${key}:${serializeTree(ctx, val)},`;
|
|
991
|
+
createObjectAssign(
|
|
992
|
+
ctx,
|
|
993
|
+
sourceID,
|
|
994
|
+
validKey,
|
|
995
|
+
refParam,
|
|
996
|
+
!(isIdentifier && Number.isNaN(check)),
|
|
997
|
+
);
|
|
954
998
|
} else {
|
|
955
|
-
result += `${
|
|
999
|
+
result += `${validKey}:${serializeTree(ctx, val)},`;
|
|
956
1000
|
}
|
|
957
1001
|
}
|
|
958
1002
|
ctx.stack.pop();
|
|
@@ -965,7 +1009,7 @@ export function serializeTree(
|
|
|
965
1009
|
): string {
|
|
966
1010
|
switch (type) {
|
|
967
1011
|
case SerovalNodeType.Primitive:
|
|
968
|
-
return
|
|
1012
|
+
return String(value);
|
|
969
1013
|
case SerovalNodeType.Reference:
|
|
970
1014
|
return getRefParam(ctx, value);
|
|
971
1015
|
case SerovalNodeType.Promise: {
|
|
@@ -986,19 +1030,17 @@ export function serializeTree(
|
|
|
986
1030
|
}
|
|
987
1031
|
return assignRef(ctx, id, serialized);
|
|
988
1032
|
}
|
|
1033
|
+
case SerovalNodeType.BigInt:
|
|
1034
|
+
return value;
|
|
989
1035
|
case SerovalNodeType.Date:
|
|
990
|
-
return assignRef(ctx, id, `new Date("${value
|
|
1036
|
+
return assignRef(ctx, id, `new Date("${value}")`);
|
|
991
1037
|
case SerovalNodeType.RegExp:
|
|
992
|
-
return assignRef(ctx, id,
|
|
1038
|
+
return assignRef(ctx, id, value);
|
|
1039
|
+
case SerovalNodeType.BigIntTypedArray:
|
|
993
1040
|
case SerovalNodeType.TypedArray: {
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
values += `${serializePrimitive(ctx, value[1][i])},`;
|
|
998
|
-
}
|
|
999
|
-
let args = values ? `[${values.substring(0, values.length - 1)}]` : '[]';
|
|
1000
|
-
if (value[1].byteOffset !== 0) {
|
|
1001
|
-
args += `,${value[1].byteOffset}`;
|
|
1041
|
+
let args = `[${value[1]}]`;
|
|
1042
|
+
if (value[2] !== 0) {
|
|
1043
|
+
args += `,${value[2]}`;
|
|
1002
1044
|
}
|
|
1003
1045
|
return assignRef(ctx, id, `new ${value[0]}(${args})`);
|
|
1004
1046
|
}
|
|
@@ -1087,7 +1129,7 @@ export function serializeTree(
|
|
|
1087
1129
|
for (let i = 0; i < size; i++) {
|
|
1088
1130
|
const item = value[i];
|
|
1089
1131
|
// Check if index is a hole
|
|
1090
|
-
if (
|
|
1132
|
+
if (item) {
|
|
1091
1133
|
// Check if item is a parent
|
|
1092
1134
|
if (isReferenceInStack(ctx, item)) {
|
|
1093
1135
|
createArrayAssign(ctx, id, i, getRefParam(ctx, item[1]));
|
|
@@ -1115,7 +1157,7 @@ export function serializeTree(
|
|
|
1115
1157
|
// either through class or custom properties
|
|
1116
1158
|
// Make sure to assign extra properties
|
|
1117
1159
|
if (value[1]) {
|
|
1118
|
-
if (ctx.features
|
|
1160
|
+
if (ctx.features & Feature.ObjectAssign) {
|
|
1119
1161
|
const options = serializeObject(ctx, id, value[1]);
|
|
1120
1162
|
serialized = `Object.assign(${serialized},${options})`;
|
|
1121
1163
|
} else {
|
|
@@ -1132,7 +1174,7 @@ export function serializeTree(
|
|
|
1132
1174
|
case SerovalNodeType.Error: {
|
|
1133
1175
|
let serialized = `new ${value[0]}(${quote(value[1])})`;
|
|
1134
1176
|
if (value[2]) {
|
|
1135
|
-
if (ctx.features
|
|
1177
|
+
if (ctx.features & Feature.ObjectAssign) {
|
|
1136
1178
|
const options = serializeObject(ctx, id, value[2]);
|
|
1137
1179
|
serialized = `Object.assign(${serialized},${options})`;
|
|
1138
1180
|
} else {
|
|
@@ -1152,20 +1194,20 @@ export function serializeTree(
|
|
|
1152
1194
|
const values = serializeTree(ctx, value[1]);
|
|
1153
1195
|
ctx.stack = parent;
|
|
1154
1196
|
let serialized: string;
|
|
1155
|
-
if (ctx.features
|
|
1197
|
+
if (ctx.features & Feature.ArrayPrototypeValues) {
|
|
1156
1198
|
serialized = `${values}.values()`;
|
|
1157
1199
|
} else {
|
|
1158
1200
|
serialized = `${values}[Symbol.iterator]()`;
|
|
1159
1201
|
}
|
|
1160
|
-
if (ctx.features
|
|
1202
|
+
if (ctx.features & Feature.ArrowFunction) {
|
|
1161
1203
|
serialized = `{[Symbol.iterator]:()=>${serialized}}`;
|
|
1162
|
-
} else if (ctx.features
|
|
1204
|
+
} else if (ctx.features & Feature.MethodShorthand) {
|
|
1163
1205
|
serialized = `{[Symbol.iterator](){return ${serialized}}}`;
|
|
1164
1206
|
} else {
|
|
1165
1207
|
serialized = `{[Symbol.iterator]:function(){return ${serialized}}}`;
|
|
1166
1208
|
}
|
|
1167
1209
|
if (value[0]) {
|
|
1168
|
-
if (ctx.features
|
|
1210
|
+
if (ctx.features & Feature.ObjectAssign) {
|
|
1169
1211
|
const options = serializeObject(ctx, id, value[0]);
|
|
1170
1212
|
serialized = `Object.assign(${serialized},${options})`;
|
|
1171
1213
|
} else {
|
|
@@ -1181,7 +1223,7 @@ export function serializeTree(
|
|
|
1181
1223
|
}
|
|
1182
1224
|
case SerovalNodeType.NullConstructor: {
|
|
1183
1225
|
let serialized = 'Object.create(null)';
|
|
1184
|
-
if (ctx.features
|
|
1226
|
+
if (ctx.features & Feature.ObjectAssign) {
|
|
1185
1227
|
const fields = serializeObject(ctx, id, value);
|
|
1186
1228
|
if (fields !== '{}') {
|
|
1187
1229
|
serialized = `Object.assign(${serialized},${fields})`;
|
package/src/types.ts
CHANGED
|
@@ -4,8 +4,7 @@ export type PrimitiveValue =
|
|
|
4
4
|
| string
|
|
5
5
|
| number
|
|
6
6
|
| undefined
|
|
7
|
-
| null
|
|
8
|
-
| bigint;
|
|
7
|
+
| null;
|
|
9
8
|
|
|
10
9
|
export type ErrorValue =
|
|
11
10
|
| Error
|
|
@@ -33,7 +32,8 @@ export type TypedArrayValue =
|
|
|
33
32
|
export type SemiPrimitiveValue =
|
|
34
33
|
| RegExp
|
|
35
34
|
| Date
|
|
36
|
-
| TypedArrayValue
|
|
35
|
+
| TypedArrayValue
|
|
36
|
+
| bigint;
|
|
37
37
|
|
|
38
38
|
export type CommonServerValue =
|
|
39
39
|
| PrimitiveValue
|