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/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: boolean[];
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: Set<Feature>;
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 createSerializationContext(options: Partial<Options> = {}): SerializationContext {
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: parseTargets(result.target),
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[current] = true;
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[index]) {
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 createObjectIdentifierAssign(
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
- createAssignment(ctx, `${getRefParam(ctx, ref)}.${key}`, value);
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.Date, value: Date, id: number]
382
- | [type: SerovalNodeType.RegExp, value: RegExp, id: number]
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: TypedArrayValue],
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: SerializationContext,
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: SerializationContext,
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.has(Feature.TypedArray), 'Unsupported value type "Int8Array"');
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.has(Feature.TypedArray), 'Unsupported value type "Int16Array"');
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.has(Feature.TypedArray), 'Unsupported value type "Int32Array"');
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.has(Feature.TypedArray), 'Unsupported value type "Uint8Array"');
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.has(Feature.TypedArray), 'Unsupported value type "Uint16Array"');
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.has(Feature.TypedArray), 'Unsupported value type "Uint32Array"');
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.has(Feature.TypedArray), 'Unsupported value type "Uint8ClampedArray"');
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.has(Feature.TypedArray), 'Unsupported value type "Float32Array"');
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.has(Feature.TypedArray), 'Unsupported value type "Float64Array"');
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.has(Feature.TypedArray)
523
- && ctx.features.has(Feature.BigInt),
541
+ ctx.features & (Feature.BigIntTypedArray),
524
542
  'Unsupported value type "BigInt64Array"',
525
543
  );
526
- return [SerovalNodeType.TypedArray, ['BigInt64Array', current], id];
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.has(Feature.TypedArray)
531
- && ctx.features.has(Feature.BigInt),
558
+ ctx.features & (Feature.BigIntTypedArray),
532
559
  'Unsupported value type "BigUint64Array"',
533
560
  );
534
- return [SerovalNodeType.TypedArray, ['BigUint64Array', current], id];
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: SerializationContext,
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
- export function generateTreeSync(
570
- ctx: SerializationContext,
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.has(Feature.Set), 'Unsupported type "Set"');
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.has(Feature.Map), 'Unsupported type "Map"');
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.has(Feature.AggregateError)) {
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.has(Feature.SymbolIterator), 'Unsupported type "Iterable"');
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: SerializationContext,
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
- export async function generateTreeAsync(
724
- ctx: SerializationContext,
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.has(Feature.Promise), 'Unsupported type "Promise"');
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.has(Feature.Set), 'Unsupported type "Set"');
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.has(Feature.Map), 'Unsupported type "Map"');
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.has(Feature.SymbolIterator), 'Unsupported type "Iterable"');
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 'null';
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 String(value);
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
- if (IDENTIFIER_CHECK.test(key) || check >= 0) {
913
- if (!Number.isNaN(check)) {
914
- createObjectComputedAssign(ctx, targetRef, key, refParam);
915
- } else {
916
- createObjectIdentifierAssign(ctx, targetRef, key, refParam);
917
- }
918
- } else {
919
- createObjectComputedAssign(ctx, targetRef, quote(key), refParam);
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) || check >= 0;
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
- if (isIdentifier) {
944
- if (!Number.isNaN(check)) {
945
- createObjectComputedAssign(ctx, sourceID, key, refParam);
946
- } else {
947
- createObjectIdentifierAssign(ctx, sourceID, key, refParam);
948
- }
949
- } else {
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 += `${quote(key)}:${serializeTree(ctx, val)},`;
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 serializePrimitive(ctx, value);
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.toISOString()}")`);
1036
+ return assignRef(ctx, id, `new Date("${value}")`);
991
1037
  case SerovalNodeType.RegExp:
992
- return assignRef(ctx, id, String(value));
1038
+ return assignRef(ctx, id, value);
1039
+ case SerovalNodeType.BigIntTypedArray:
993
1040
  case SerovalNodeType.TypedArray: {
994
- // BigInt typed arrays are broken for toString()
995
- let values = '';
996
- for (let i = 0, len = value[1].length; i < len; i++) {
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 (i in value) {
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.has(Feature.ObjectAssign)) {
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.has(Feature.ObjectAssign)) {
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.has(Feature.ArrayPrototypeValues)) {
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.has(Feature.ArrowFunction)) {
1202
+ if (ctx.features & Feature.ArrowFunction) {
1161
1203
  serialized = `{[Symbol.iterator]:()=>${serialized}}`;
1162
- } else if (ctx.features.has(Feature.MethodShorthand)) {
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.has(Feature.ObjectAssign)) {
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.has(Feature.ObjectAssign)) {
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