seroval 0.10.3 → 0.11.0

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.
@@ -1,7 +1,6 @@
1
1
  /* eslint-disable no-await-in-loop */
2
2
  /* eslint-disable @typescript-eslint/no-use-before-define */
3
- import assert from '../assert';
4
- import { Feature } from '../compat';
3
+ import { BIGINT_FLAG, Feature } from '../compat';
5
4
  import type { CrossParserContext } from './context';
6
5
  import {
7
6
  createCrossIndexedValue,
@@ -24,6 +23,7 @@ import {
24
23
  createDataViewNode,
25
24
  createSymbolNode,
26
25
  createFunctionNode,
26
+ serializeArrayBuffer,
27
27
  } from './primitives';
28
28
  import { hasReferenceID } from '../reference';
29
29
  import {
@@ -36,7 +36,9 @@ import type {
36
36
  SerovalAggregateErrorNode,
37
37
  SerovalArrayNode,
38
38
  SerovalBoxedNode,
39
+ SerovalCustomEventNode,
39
40
  SerovalErrorNode,
41
+ SerovalEventNode,
40
42
  SerovalFormDataNode,
41
43
  SerovalHeadersNode,
42
44
  SerovalMapNode,
@@ -47,6 +49,8 @@ import type {
47
49
  SerovalObjectRecordNode,
48
50
  SerovalPlainRecordNode,
49
51
  SerovalPromiseNode,
52
+ SerovalRequestNode,
53
+ SerovalResponseNode,
50
54
  SerovalSetNode,
51
55
  } from '../types';
52
56
  import {
@@ -67,8 +71,14 @@ import {
67
71
  createRegExpNode,
68
72
  createStringNode,
69
73
  } from '../base-primitives';
70
- import { createURLNode, createURLSearchParamsNode } from '../web-api';
74
+ import { createDOMExceptionNode, createURLNode, createURLSearchParamsNode } from '../web-api';
71
75
  import promiseToResult from '../promise-to-result';
76
+ import {
77
+ createCustomEventOptions,
78
+ createEventOptions,
79
+ createRequestOptions,
80
+ createResponseOptions,
81
+ } from '../constructors';
72
82
 
73
83
  type ObjectLikeNode =
74
84
  | SerovalObjectNode
@@ -127,7 +137,6 @@ async function generateMapNode(
127
137
  id: number,
128
138
  current: Map<unknown, unknown>,
129
139
  ): Promise<SerovalMapNode> {
130
- assert(ctx.features & Feature.Map, new UnsupportedTypeError(current));
131
140
  const len = current.size;
132
141
  const keyNodes = new Array<SerovalNode>(len);
133
142
  const valueNodes = new Array<SerovalNode>(len);
@@ -172,7 +181,6 @@ async function generateSetNode(
172
181
  id: number,
173
182
  current: Set<unknown>,
174
183
  ): Promise<SerovalSetNode> {
175
- assert(ctx.features & Feature.Set, new UnsupportedTypeError(current));
176
184
  const len = current.size;
177
185
  const nodes = new Array<SerovalNode>(len);
178
186
  const deferred = new Array<unknown>(len);
@@ -299,7 +307,6 @@ async function generatePromiseNode(
299
307
  id: number,
300
308
  current: Promise<unknown>,
301
309
  ): Promise<SerovalPromiseNode> {
302
- assert(ctx.features & Feature.Promise, new UnsupportedTypeError(current));
303
310
  const [status, result] = await promiseToResult(current);
304
311
  return {
305
312
  t: SerovalNodeType.Promise,
@@ -394,7 +401,6 @@ async function generateHeadersNode(
394
401
  id: number,
395
402
  current: Headers,
396
403
  ): Promise<SerovalHeadersNode> {
397
- assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
398
404
  const items: Record<string, string> = {};
399
405
  current.forEach((value, key) => {
400
406
  items[key] = value;
@@ -420,7 +426,6 @@ async function generateFormDataNode(
420
426
  id: number,
421
427
  current: FormData,
422
428
  ): Promise<SerovalFormDataNode> {
423
- assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
424
429
  const items: Record<string, FormDataEntryValue> = {};
425
430
  current.forEach((value, key) => {
426
431
  items[key] = value;
@@ -462,6 +467,97 @@ async function generateBoxedNode(
462
467
  };
463
468
  }
464
469
 
470
+ async function generateRequestNode(
471
+ ctx: CrossParserContext,
472
+ id: number,
473
+ current: Request,
474
+ ): Promise<SerovalRequestNode> {
475
+ return {
476
+ t: SerovalNodeType.Request,
477
+ i: id,
478
+ s: serializeString(current.url),
479
+ l: undefined,
480
+ c: undefined,
481
+ m: undefined,
482
+ p: undefined,
483
+ e: undefined,
484
+ f: await parseObject(
485
+ ctx,
486
+ createRequestOptions(current, current.body ? await current.clone().arrayBuffer() : null),
487
+ ),
488
+ a: undefined,
489
+ b: undefined,
490
+ o: undefined,
491
+ };
492
+ }
493
+ async function generateResponseNode(
494
+ ctx: CrossParserContext,
495
+ id: number,
496
+ current: Response,
497
+ ): Promise<SerovalResponseNode> {
498
+ return {
499
+ t: SerovalNodeType.Response,
500
+ i: id,
501
+ s: undefined,
502
+ l: undefined,
503
+ c: undefined,
504
+ m: undefined,
505
+ p: undefined,
506
+ e: undefined,
507
+ f: undefined,
508
+ a: [
509
+ current.body
510
+ ? serializeArrayBuffer(ctx, await current.clone().arrayBuffer())
511
+ : NULL_NODE,
512
+ await parseObject(ctx, createResponseOptions(current)),
513
+ ],
514
+ b: undefined,
515
+ o: undefined,
516
+ };
517
+ }
518
+
519
+ async function generateEventNode(
520
+ ctx: CrossParserContext,
521
+ id: number,
522
+ current: Event,
523
+ ): Promise<SerovalEventNode> {
524
+ return {
525
+ t: SerovalNodeType.Event,
526
+ i: id,
527
+ s: serializeString(current.type),
528
+ l: undefined,
529
+ c: undefined,
530
+ m: undefined,
531
+ p: undefined,
532
+ e: undefined,
533
+ a: undefined,
534
+ f: await parseObject(ctx, createEventOptions(current)),
535
+ b: undefined,
536
+ o: undefined,
537
+ };
538
+ }
539
+
540
+ async function generateCustomEventNode(
541
+ ctx: CrossParserContext,
542
+ id: number,
543
+ current: CustomEvent,
544
+ ): Promise<SerovalCustomEventNode> {
545
+ return {
546
+ t: SerovalNodeType.CustomEvent,
547
+ i: id,
548
+ s: serializeString(current.type),
549
+ l: undefined,
550
+ c: undefined,
551
+ m: undefined,
552
+ p: undefined,
553
+ e: undefined,
554
+ a: undefined,
555
+ f: await parseObject(ctx, createCustomEventOptions(current)),
556
+ b: undefined,
557
+ o: undefined,
558
+ };
559
+ }
560
+
465
561
  async function parseObject(
466
562
  ctx: CrossParserContext,
467
563
  current: object | null,
@@ -483,49 +579,17 @@ async function parseObject(
483
579
  if (Array.isArray(current)) {
484
580
  return generateArrayNode(ctx, id, current);
485
581
  }
486
- switch (current.constructor) {
582
+ const currentClass = current.constructor;
583
+ switch (currentClass) {
487
584
  case Number:
488
585
  case Boolean:
489
586
  case String:
490
587
  case BigInt:
491
- case Function:
492
- case Symbol:
493
588
  return generateBoxedNode(ctx, id, current);
494
589
  case Date:
495
590
  return createDateNode(id, current as unknown as Date);
496
591
  case RegExp:
497
592
  return createRegExpNode(id, current as unknown as RegExp);
498
- case Promise:
499
- return generatePromiseNode(ctx, id, current as unknown as Promise<unknown>);
500
- case ArrayBuffer:
501
- return createArrayBufferNode(id, current as unknown as ArrayBuffer);
502
- case Int8Array:
503
- case Int16Array:
504
- case Int32Array:
505
- case Uint8Array:
506
- case Uint16Array:
507
- case Uint32Array:
508
- case Uint8ClampedArray:
509
- case Float32Array:
510
- case Float64Array:
511
- return createTypedArrayNode(ctx, id, current as unknown as TypedArrayValue);
512
- case BigInt64Array:
513
- case BigUint64Array:
514
- return createBigIntTypedArrayNode(ctx, id, current as unknown as BigIntTypedArrayValue);
515
- case DataView:
516
- return createDataViewNode(ctx, id, current as unknown as DataView);
517
- case Map:
518
- return generateMapNode(
519
- ctx,
520
- id,
521
- current as unknown as Map<unknown, unknown>,
522
- );
523
- case Set:
524
- return generateSetNode(
525
- ctx,
526
- id,
527
- current as unknown as Set<unknown>,
528
- );
529
593
  case Object:
530
594
  return generateObjectNode(
531
595
  ctx,
@@ -540,11 +604,6 @@ async function parseObject(
540
604
  current as Record<string, unknown>,
541
605
  true,
542
606
  );
543
- case AggregateError:
544
- if (ctx.features & Feature.AggregateError) {
545
- return generateAggregateErrorNode(ctx, id, current as unknown as AggregateError);
546
- }
547
- return generateErrorNode(ctx, id, current as unknown as AggregateError);
548
607
  case Error:
549
608
  case EvalError:
550
609
  case RangeError:
@@ -553,36 +612,106 @@ async function parseObject(
553
612
  case TypeError:
554
613
  case URIError:
555
614
  return generateErrorNode(ctx, id, current as unknown as Error);
556
- case URL:
557
- return createURLNode(ctx, id, current as unknown as URL);
558
- case URLSearchParams:
559
- return createURLSearchParamsNode(ctx, id, current as unknown as URLSearchParams);
560
- case Blob:
561
- return createBlobNode(ctx, id, current as unknown as Blob);
562
- case File:
563
- return createFileNode(ctx, id, current as unknown as File);
564
- case Headers:
565
- return generateHeadersNode(ctx, id, current as unknown as Headers);
566
- case FormData:
567
- return generateFormDataNode(ctx, id, current as unknown as FormData);
568
615
  default:
569
616
  break;
570
617
  }
571
- if (current instanceof AggregateError) {
572
- if (ctx.features & Feature.AggregateError) {
573
- return generateAggregateErrorNode(ctx, id, current);
618
+ // Typed Arrays
619
+ if (ctx.features & Feature.TypedArray) {
620
+ switch (currentClass) {
621
+ case ArrayBuffer:
622
+ return createArrayBufferNode(id, current as unknown as ArrayBuffer);
623
+ case Int8Array:
624
+ case Int16Array:
625
+ case Int32Array:
626
+ case Uint8Array:
627
+ case Uint16Array:
628
+ case Uint32Array:
629
+ case Uint8ClampedArray:
630
+ case Float32Array:
631
+ case Float64Array:
632
+ return createTypedArrayNode(ctx, id, current as unknown as TypedArrayValue);
633
+ case DataView:
634
+ return createDataViewNode(ctx, id, current as unknown as DataView);
635
+ default:
636
+ break;
574
637
  }
575
- return generateErrorNode(ctx, id, current);
576
638
  }
639
+ // BigInt Typed Arrays
640
+ if ((ctx.features & BIGINT_FLAG) === BIGINT_FLAG) {
641
+ switch (currentClass) {
642
+ case BigInt64Array:
643
+ case BigUint64Array:
644
+ return createBigIntTypedArrayNode(ctx, id, current as unknown as BigIntTypedArrayValue);
645
+ default:
646
+ break;
647
+ }
648
+ }
649
+ // ES Collection
650
+ if (ctx.features & Feature.Map && currentClass === Map) {
651
+ return generateMapNode(
652
+ ctx,
653
+ id,
654
+ current as unknown as Map<unknown, unknown>,
655
+ );
656
+ }
657
+ if (ctx.features & Feature.Set && currentClass === Set) {
658
+ return generateSetNode(
659
+ ctx,
660
+ id,
661
+ current as unknown as Set<unknown>,
662
+ );
663
+ }
664
+ // Web APIs
665
+ if (ctx.features & Feature.WebAPI) {
666
+ switch (currentClass) {
667
+ case URL:
668
+ return createURLNode(id, current as unknown as URL);
669
+ case URLSearchParams:
670
+ return createURLSearchParamsNode(id, current as unknown as URLSearchParams);
671
+ case Blob:
672
+ return createBlobNode(ctx, id, current as unknown as Blob);
673
+ case File:
674
+ return createFileNode(ctx, id, current as unknown as File);
675
+ case Headers:
676
+ return generateHeadersNode(ctx, id, current as unknown as Headers);
677
+ case FormData:
678
+ return generateFormDataNode(ctx, id, current as unknown as FormData);
679
+ case Request:
680
+ return generateRequestNode(ctx, id, current as unknown as Request);
681
+ case Response:
682
+ return generateResponseNode(ctx, id, current as unknown as Response);
683
+ case Event:
684
+ return generateEventNode(ctx, id, current as unknown as Event);
685
+ case CustomEvent:
686
+ return generateCustomEventNode(ctx, id, current as unknown as CustomEvent);
687
+ case DOMException:
688
+ return createDOMExceptionNode(id, current as unknown as DOMException);
689
+ default:
690
+ break;
691
+ }
692
+ }
693
+ if (
694
+ (ctx.features & Feature.AggregateError)
695
+ && (currentClass === AggregateError || current instanceof AggregateError)
696
+ ) {
697
+ return generateAggregateErrorNode(ctx, id, current as unknown as AggregateError);
698
+ }
699
+ // Promises
700
+ if (
701
+ (ctx.features & Feature.Promise)
702
+ && (currentClass === Promise || current instanceof Promise)
703
+ ) {
704
+ return generatePromiseNode(ctx, id, current as unknown as Promise<unknown>);
705
+ }
706
+ // Slow path. We only need to handle Errors and Iterators
707
+ // since they have very broad implementations.
577
708
  if (current instanceof Error) {
578
709
  return generateErrorNode(ctx, id, current);
579
710
  }
580
- if (current instanceof Promise) {
581
- return generatePromiseNode(ctx, id, current);
582
- }
583
711
  // Generator functions don't have a global constructor
584
- if (Symbol.iterator in current) {
585
- return generateObjectNode(ctx, id, current, !!current.constructor);
712
+ // despite existing
713
+ if (ctx.features & Feature.Symbol && Symbol.iterator in current) {
714
+ return generateObjectNode(ctx, id, current, !!currentClass);
586
715
  }
587
716
  throw new UnsupportedTypeError(current);
588
717
  }
@@ -591,23 +720,26 @@ export default async function crossParseAsync<T>(
591
720
  ctx: CrossParserContext,
592
721
  current: T,
593
722
  ): Promise<SerovalNode> {
594
- switch (typeof current) {
723
+ const t = typeof current;
724
+ if (ctx.features & Feature.BigInt && t === 'bigint') {
725
+ return createBigIntNode(ctx, current as bigint);
726
+ }
727
+ switch (t) {
595
728
  case 'boolean':
596
729
  return current ? TRUE_NODE : FALSE_NODE;
597
730
  case 'undefined':
598
731
  return UNDEFINED_NODE;
599
732
  case 'string':
600
- return createStringNode(current);
733
+ return createStringNode(current as string);
601
734
  case 'number':
602
- return createNumberNode(current);
603
- case 'bigint':
604
- return createBigIntNode(ctx, current);
735
+ return createNumberNode(current as number);
605
736
  case 'object':
606
- return parseObject(ctx, current);
737
+ return parseObject(ctx, current as object);
607
738
  case 'symbol':
608
- return createSymbolNode(ctx, current);
739
+ return createSymbolNode(ctx, current as symbol);
609
740
  case 'function':
610
- return createFunctionNode(ctx, current);
741
+ // eslint-disable-next-line @typescript-eslint/ban-types
742
+ return createFunctionNode(ctx, current as Function);
611
743
  default:
612
744
  throw new UnsupportedTypeError(current);
613
745
  }
@@ -39,6 +39,11 @@ import type {
39
39
  SerovalReadableStreamEnqueueNode,
40
40
  SerovalReadableStreamErrorNode,
41
41
  SerovalReadableStreamConstructorNode,
42
+ SerovalRequestNode,
43
+ SerovalResponseNode,
44
+ SerovalEventNode,
45
+ SerovalCustomEventNode,
46
+ SerovalDOMExceptionNode,
42
47
  } from '../types';
43
48
  import {
44
49
  SerovalObjectRecordSpecialKey,
@@ -767,6 +772,52 @@ function serializeReadableStreamConstructor(
767
772
  return assignIndexedValue(node.i, GLOBAL_CONTEXT_API + '.' + GLOBAL_CONTEXT_STREAM_CONSTRUCTOR + '()');
768
773
  }
769
774
 
775
+ function serializeRequest(
776
+ ctx: CrossSerializerContext,
777
+ node: SerovalRequestNode,
778
+ ): string {
779
+ return assignIndexedValue(node.i, 'new Request("' + node.s + '",' + crossSerializeTree(ctx, node.f) + ')');
780
+ }
781
+
782
+ function serializeResponse(
783
+ ctx: CrossSerializerContext,
784
+ node: SerovalResponseNode,
785
+ ): string {
786
+ return assignIndexedValue(
787
+ node.i,
788
+ 'new Response(' + crossSerializeTree(ctx, node.a[0]) + ',' + crossSerializeTree(ctx, node.a[1]) + ')',
789
+ );
790
+ }
791
+
792
+ function serializeEvent(
793
+ ctx: CrossSerializerContext,
794
+ node: SerovalEventNode,
795
+ ): string {
796
+ return assignIndexedValue(
797
+ node.i,
798
+ 'new Event("' + node.s + '",' + crossSerializeTree(ctx, node.f) + ')',
799
+ );
800
+ }
801
+
802
+ function serializeCustomEvent(
803
+ ctx: CrossSerializerContext,
804
+ node: SerovalCustomEventNode,
805
+ ): string {
806
+ return assignIndexedValue(
807
+ node.i,
808
+ 'new CustomEvent("' + node.s + '",' + crossSerializeTree(ctx, node.f) + ')',
809
+ );
810
+ }
811
+
812
+ function serializeDOMException(
813
+ node: SerovalDOMExceptionNode,
814
+ ): string {
815
+ return assignIndexedValue(
816
+ node.i,
817
+ 'new DOMException("' + node.s + '","' + node.c + '")',
818
+ );
819
+ }
820
+
770
821
  export default function crossSerializeTree(
771
822
  ctx: CrossSerializerContext,
772
823
  node: SerovalNode,
@@ -841,6 +892,16 @@ export default function crossSerializeTree(
841
892
  return serializeReadableStreamEnqueue(ctx, node);
842
893
  case SerovalNodeType.ReadableStreamError:
843
894
  return serializeReadableStreamError(ctx, node);
895
+ case SerovalNodeType.Request:
896
+ return serializeRequest(ctx, node);
897
+ case SerovalNodeType.Response:
898
+ return serializeResponse(ctx, node);
899
+ case SerovalNodeType.Event:
900
+ return serializeEvent(ctx, node);
901
+ case SerovalNodeType.CustomEvent:
902
+ return serializeCustomEvent(ctx, node);
903
+ case SerovalNodeType.DOMException:
904
+ return serializeDOMException(node);
844
905
  default:
845
906
  throw new Error('invariant');
846
907
  }