seroval 0.10.4 → 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,6 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-use-before-define */
2
- import assert from '../assert';
3
- import { Feature } from '../compat';
2
+ import { BIGINT_FLAG, Feature } from '../compat';
4
3
  import type { ParserContext } from './context';
5
4
  import { createIndexedValue } from './context';
6
5
  import { serializeString } from '../string';
@@ -32,7 +31,9 @@ import type {
32
31
  SerovalAggregateErrorNode,
33
32
  SerovalArrayNode,
34
33
  SerovalBoxedNode,
34
+ SerovalCustomEventNode,
35
35
  SerovalErrorNode,
36
+ SerovalEventNode,
36
37
  SerovalFormDataNode,
37
38
  SerovalHeadersNode,
38
39
  SerovalMapNode,
@@ -58,7 +59,8 @@ import {
58
59
  createRegExpNode,
59
60
  createStringNode,
60
61
  } from '../base-primitives';
61
- import { createURLNode, createURLSearchParamsNode } from '../web-api';
62
+ import { createDOMExceptionNode, createURLNode, createURLSearchParamsNode } from '../web-api';
63
+ import { createCustomEventOptions, createEventOptions } from '../constructors';
62
64
 
63
65
  type ObjectLikeNode = SerovalObjectNode | SerovalNullConstructorNode;
64
66
 
@@ -111,7 +113,6 @@ function generateMapNode(
111
113
  id: number,
112
114
  current: Map<unknown, unknown>,
113
115
  ): SerovalMapNode {
114
- assert(ctx.features & Feature.Map, new UnsupportedTypeError(current));
115
116
  const len = current.size;
116
117
  const keyNodes = new Array<SerovalSyncNode>(len);
117
118
  const valueNodes = new Array<SerovalSyncNode>(len);
@@ -156,7 +157,6 @@ function generateSetNode(
156
157
  id: number,
157
158
  current: Set<unknown>,
158
159
  ): SerovalSetNode {
159
- assert(ctx.features & Feature.Set, new UnsupportedTypeError(current));
160
160
  const len = current.size;
161
161
  const nodes = new Array<SerovalSyncNode>(len);
162
162
  const deferred = new Array<unknown>(len);
@@ -352,7 +352,6 @@ function generateHeadersNode(
352
352
  id: number,
353
353
  current: Headers,
354
354
  ): SerovalHeadersNode {
355
- assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
356
355
  const items: Record<string, string> = {};
357
356
  // TS Headers not an Iterable
358
357
  current.forEach((value, key) => {
@@ -379,7 +378,6 @@ function generateFormDataNode(
379
378
  id: number,
380
379
  current: FormData,
381
380
  ): SerovalFormDataNode {
382
- assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
383
381
  const items: Record<string, FormDataEntryValue> = {};
384
382
  // TS FormData isn't an Iterable sadly
385
383
  current.forEach((value, key) => {
@@ -422,6 +420,44 @@ function generateBoxedNode(
422
420
  };
423
421
  }
424
422
 
423
+ function generateEventNode(ctx: ParserContext, id: number, current: Event): SerovalEventNode {
424
+ return {
425
+ t: SerovalNodeType.Event,
426
+ i: id,
427
+ s: serializeString(current.type),
428
+ l: undefined,
429
+ c: undefined,
430
+ m: undefined,
431
+ p: undefined,
432
+ e: undefined,
433
+ a: undefined,
434
+ f: parseObject(ctx, createEventOptions(current)),
435
+ b: undefined,
436
+ o: undefined,
437
+ };
438
+ }
439
+
440
+ function generateCustomEventNode(
441
+ ctx: ParserContext,
442
+ id: number,
443
+ current: CustomEvent,
444
+ ): SerovalCustomEventNode {
445
+ return {
446
+ t: SerovalNodeType.CustomEvent,
447
+ i: id,
448
+ s: serializeString(current.type),
449
+ l: undefined,
450
+ c: undefined,
451
+ m: undefined,
452
+ p: undefined,
453
+ e: undefined,
454
+ a: undefined,
455
+ f: parseObject(ctx, createCustomEventOptions(current)),
456
+ b: undefined,
457
+ o: undefined,
458
+ };
459
+ }
460
+
425
461
  function parseObject(
426
462
  ctx: ParserContext,
427
463
  current: object | null,
@@ -442,40 +478,18 @@ function parseObject(
442
478
  if (Array.isArray(current)) {
443
479
  return generateArrayNode(ctx, id, current);
444
480
  }
481
+ const currentClass = current.constructor;
445
482
  // Fast path
446
- switch (current.constructor) {
483
+ switch (currentClass) {
447
484
  case Number:
448
485
  case Boolean:
449
486
  case String:
450
487
  case BigInt:
451
- case Function:
452
- case Symbol:
453
488
  return generateBoxedNode(ctx, id, current);
454
489
  case Date:
455
490
  return createDateNode(id, current as unknown as Date);
456
491
  case RegExp:
457
492
  return createRegExpNode(id, current as unknown as RegExp);
458
- case ArrayBuffer:
459
- return createArrayBufferNode(id, current as unknown as ArrayBuffer);
460
- case Int8Array:
461
- case Int16Array:
462
- case Int32Array:
463
- case Uint8Array:
464
- case Uint16Array:
465
- case Uint32Array:
466
- case Uint8ClampedArray:
467
- case Float32Array:
468
- case Float64Array:
469
- return createTypedArrayNode(ctx, id, current as unknown as TypedArrayValue);
470
- case BigInt64Array:
471
- case BigUint64Array:
472
- return createBigIntTypedArrayNode(ctx, id, current as unknown as BigIntTypedArrayValue);
473
- case DataView:
474
- return createDataViewNode(ctx, id, current as unknown as DataView);
475
- case Map:
476
- return generateMapNode(ctx, id, current as unknown as Map<unknown, unknown>);
477
- case Set:
478
- return generateSetNode(ctx, id, current as unknown as Set<unknown>);
479
493
  case Object:
480
494
  return generateObjectNode(
481
495
  ctx,
@@ -490,12 +504,6 @@ function parseObject(
490
504
  current as unknown as Record<string, unknown>,
491
505
  true,
492
506
  );
493
- case AggregateError:
494
- // Compile-down AggregateError to Error if disabled
495
- if (ctx.features & Feature.AggregateError) {
496
- return generateAggregateErrorNode(ctx, id, current as unknown as AggregateError);
497
- }
498
- return generateErrorNode(ctx, id, current as unknown as AggregateError);
499
507
  case Error:
500
508
  case EvalError:
501
509
  case RangeError:
@@ -504,32 +512,86 @@ function parseObject(
504
512
  case TypeError:
505
513
  case URIError:
506
514
  return generateErrorNode(ctx, id, current as unknown as Error);
507
- case URL:
508
- return createURLNode(ctx, id, current as unknown as URL);
509
- case URLSearchParams:
510
- return createURLSearchParamsNode(ctx, id, current as unknown as URLSearchParams);
511
- case Headers:
512
- return generateHeadersNode(ctx, id, current as unknown as Headers);
513
- case FormData:
514
- return generateFormDataNode(ctx, id, current as unknown as FormData);
515
515
  default:
516
516
  break;
517
517
  }
518
- // Slow path. We only need to handle Errors and Iterators
519
- // since they have very broad implementations.
520
- if (current instanceof AggregateError) {
521
- if (ctx.features & Feature.AggregateError) {
522
- return generateAggregateErrorNode(ctx, id, current);
518
+ // Typed Arrays
519
+ if (ctx.features & Feature.TypedArray) {
520
+ switch (currentClass) {
521
+ case ArrayBuffer:
522
+ return createArrayBufferNode(id, current as unknown as ArrayBuffer);
523
+ case Int8Array:
524
+ case Int16Array:
525
+ case Int32Array:
526
+ case Uint8Array:
527
+ case Uint16Array:
528
+ case Uint32Array:
529
+ case Uint8ClampedArray:
530
+ case Float32Array:
531
+ case Float64Array:
532
+ return createTypedArrayNode(ctx, id, current as unknown as TypedArrayValue);
533
+ case DataView:
534
+ return createDataViewNode(ctx, id, current as unknown as DataView);
535
+ default:
536
+ break;
523
537
  }
524
- return generateErrorNode(ctx, id, current);
525
538
  }
539
+ // BigInt Typed Arrays
540
+ if ((ctx.features & BIGINT_FLAG) === BIGINT_FLAG) {
541
+ switch (currentClass) {
542
+ case BigInt64Array:
543
+ case BigUint64Array:
544
+ return createBigIntTypedArrayNode(ctx, id, current as unknown as BigIntTypedArrayValue);
545
+ default:
546
+ break;
547
+ }
548
+ }
549
+ // ES Collection
550
+ if (ctx.features & Feature.Map && currentClass === Map) {
551
+ return generateMapNode(ctx, id, current as unknown as Map<unknown, unknown>);
552
+ }
553
+ if (ctx.features & Feature.Set && currentClass === Set) {
554
+ return generateSetNode(ctx, id, current as unknown as Set<unknown>);
555
+ }
556
+ // Web APIs
557
+ if (ctx.features & Feature.WebAPI) {
558
+ switch (currentClass) {
559
+ case URL:
560
+ return createURLNode(id, current as unknown as URL);
561
+ case URLSearchParams:
562
+ return createURLSearchParamsNode(id, current as unknown as URLSearchParams);
563
+ case Headers:
564
+ return generateHeadersNode(ctx, id, current as unknown as Headers);
565
+ case FormData:
566
+ return generateFormDataNode(ctx, id, current as unknown as FormData);
567
+ case Event:
568
+ return generateEventNode(ctx, id, current as unknown as Event);
569
+ case CustomEvent:
570
+ return generateCustomEventNode(ctx, id, current as unknown as CustomEvent);
571
+ case DOMException:
572
+ return createDOMExceptionNode(id, current as unknown as DOMException);
573
+ default:
574
+ break;
575
+ }
576
+ }
577
+ if (
578
+ (ctx.features & Feature.AggregateError)
579
+ && (
580
+ currentClass === AggregateError
581
+ || current instanceof AggregateError
582
+ )
583
+ ) {
584
+ return generateAggregateErrorNode(ctx, id, current as unknown as AggregateError);
585
+ }
586
+ // Slow path. We only need to handle Errors and Iterators
587
+ // since they have very broad implementations.
526
588
  if (current instanceof Error) {
527
589
  return generateErrorNode(ctx, id, current);
528
590
  }
529
591
  // Generator functions don't have a global constructor
530
592
  // despite existing
531
- if (Symbol.iterator in current) {
532
- return generateObjectNode(ctx, id, current, !!current.constructor);
593
+ if ((ctx.features & Feature.Symbol) && Symbol.iterator in current) {
594
+ return generateObjectNode(ctx, id, current, !!currentClass);
533
595
  }
534
596
  throw new UnsupportedTypeError(current);
535
597
  }
@@ -538,23 +600,26 @@ export default function parseSync<T>(
538
600
  ctx: ParserContext,
539
601
  current: T,
540
602
  ): SerovalSyncNode {
541
- switch (typeof current) {
603
+ const t = typeof current;
604
+ if (ctx.features & Feature.BigInt && t === 'bigint') {
605
+ return createBigIntNode(ctx, current as bigint);
606
+ }
607
+ switch (t) {
542
608
  case 'boolean':
543
609
  return current ? TRUE_NODE : FALSE_NODE;
544
610
  case 'undefined':
545
611
  return UNDEFINED_NODE;
546
612
  case 'string':
547
- return createStringNode(current);
613
+ return createStringNode(current as string);
548
614
  case 'number':
549
- return createNumberNode(current);
550
- case 'bigint':
551
- return createBigIntNode(ctx, current);
615
+ return createNumberNode(current as number);
552
616
  case 'object':
553
- return parseObject(ctx, current);
617
+ return parseObject(ctx, current as object);
554
618
  case 'symbol':
555
- return createSymbolNode(ctx, current);
619
+ return createSymbolNode(ctx, current as symbol);
556
620
  case 'function':
557
- return createFunctionNode(ctx, current);
621
+ // eslint-disable-next-line @typescript-eslint/ban-types
622
+ return createFunctionNode(ctx, current as Function);
558
623
  default:
559
624
  throw new UnsupportedTypeError(current);
560
625
  }
package/src/core/types.ts CHANGED
@@ -340,6 +340,48 @@ export interface SerovalReadableStreamErrorNode extends SerovalBaseNode {
340
340
  f: SerovalNode;
341
341
  }
342
342
 
343
+ export interface SerovalRequestNode extends SerovalBaseNode {
344
+ t: SerovalNodeType.Request;
345
+ i: number;
346
+ // Request URL
347
+ s: string;
348
+ // This is just a shortcut for serializing the option fields
349
+ f: SerovalNode;
350
+ }
351
+
352
+ export interface SerovalResponseNode extends SerovalBaseNode {
353
+ t: SerovalNodeType.Response;
354
+ i: number;
355
+ // This is just a shortcut for serializing the option fields
356
+ a: [body: SerovalNode, options: SerovalNode];
357
+ }
358
+
359
+ export interface SerovalEventNode extends SerovalBaseNode {
360
+ t: SerovalNodeType.Event;
361
+ i: number;
362
+ // Event type
363
+ s: string;
364
+ // Event options
365
+ f: SerovalNode;
366
+ }
367
+
368
+ export interface SerovalCustomEventNode extends SerovalBaseNode {
369
+ t: SerovalNodeType.CustomEvent;
370
+ i: number;
371
+ // Event type
372
+ s: string;
373
+ f: SerovalNode;
374
+ }
375
+
376
+ export interface SerovalDOMExceptionNode extends SerovalBaseNode {
377
+ t: SerovalNodeType.DOMException;
378
+ i: number;
379
+ // Message
380
+ s: string;
381
+ // name
382
+ c: string;
383
+ }
384
+
343
385
  export type SerovalSyncNode =
344
386
  | SerovalPrimitiveNode
345
387
  | SerovalIndexedValueNode
@@ -362,7 +404,10 @@ export type SerovalSyncNode =
362
404
  | SerovalFileNode
363
405
  | SerovalHeadersNode
364
406
  | SerovalFormDataNode
365
- | SerovalBoxedNode;
407
+ | SerovalBoxedNode
408
+ | SerovalEventNode
409
+ | SerovalCustomEventNode
410
+ | SerovalDOMExceptionNode;
366
411
 
367
412
  export type SerovalAsyncNode =
368
413
  | SerovalPromiseNode
@@ -374,7 +419,9 @@ export type SerovalAsyncNode =
374
419
  | SerovalReadableStreamConstructorNode
375
420
  | SerovalReadableStreamEnqueueNode
376
421
  | SerovalReadableStreamCloseNode
377
- | SerovalReadableStreamErrorNode;
422
+ | SerovalReadableStreamErrorNode
423
+ | SerovalRequestNode
424
+ | SerovalResponseNode;
378
425
 
379
426
  export type SerovalNode =
380
427
  | SerovalSyncNode
@@ -1,17 +1,11 @@
1
- import UnsupportedTypeError from './UnsupportedTypeError';
2
- import assert from './assert';
3
- import { Feature } from './compat';
4
1
  import { SerovalNodeType } from './constants';
5
- import type { BaseParserContext } from './context';
6
2
  import { serializeString } from './string';
7
- import type { SerovalURLNode, SerovalURLSearchParamsNode } from './types';
3
+ import type { SerovalDOMExceptionNode, SerovalURLNode, SerovalURLSearchParamsNode } from './types';
8
4
 
9
5
  export function createURLNode(
10
- ctx: BaseParserContext,
11
6
  id: number,
12
7
  current: URL,
13
8
  ): SerovalURLNode {
14
- assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
15
9
  return {
16
10
  t: SerovalNodeType.URL,
17
11
  i: id,
@@ -29,11 +23,9 @@ export function createURLNode(
29
23
  }
30
24
 
31
25
  export function createURLSearchParamsNode(
32
- ctx: BaseParserContext,
33
26
  id: number,
34
27
  current: URLSearchParams,
35
28
  ): SerovalURLSearchParamsNode {
36
- assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
37
29
  return {
38
30
  t: SerovalNodeType.URLSearchParams,
39
31
  i: id,
@@ -49,3 +41,23 @@ export function createURLSearchParamsNode(
49
41
  o: undefined,
50
42
  };
51
43
  }
44
+
45
+ export function createDOMExceptionNode(
46
+ id: number,
47
+ current: DOMException,
48
+ ): SerovalDOMExceptionNode {
49
+ return {
50
+ t: SerovalNodeType.DOMException,
51
+ i: id,
52
+ s: serializeString(current.message),
53
+ l: undefined,
54
+ c: serializeString(current.name),
55
+ m: undefined,
56
+ p: undefined,
57
+ e: undefined,
58
+ a: undefined,
59
+ f: undefined,
60
+ b: undefined,
61
+ o: undefined,
62
+ };
63
+ }