seroval 1.4.1 → 1.4.2

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.
Files changed (50) hide show
  1. package/dist/cjs/development/index.cjs +54 -11
  2. package/dist/cjs/development/index.cjs.map +2 -2
  3. package/dist/cjs/production/index.cjs +2 -2
  4. package/dist/esm/development/index.mjs +54 -11
  5. package/dist/esm/development/index.mjs.map +2 -2
  6. package/dist/esm/production/index.mjs +2 -2
  7. package/dist/types/core/base-primitives.d.ts.map +1 -1
  8. package/dist/types/core/context/async-parser.d.ts.map +1 -1
  9. package/dist/types/core/context/deserializer.d.ts.map +1 -1
  10. package/dist/types/core/context/parser.d.ts.map +1 -1
  11. package/dist/types/core/context/sync-parser.d.ts.map +1 -1
  12. package/dist/types/core/literals.d.ts.map +1 -1
  13. package/dist/types/core/node.d.ts +1 -1
  14. package/dist/types/core/node.d.ts.map +1 -1
  15. package/dist/types/core/types.d.ts +4 -0
  16. package/dist/types/core/types.d.ts.map +1 -1
  17. package/package.json +3 -2
  18. package/src/core/Serializer.ts +119 -0
  19. package/src/core/base-primitives.ts +514 -0
  20. package/src/core/compat.ts +23 -0
  21. package/src/core/constants.ts +201 -0
  22. package/src/core/constructors.ts +270 -0
  23. package/src/core/context/async-parser.ts +638 -0
  24. package/src/core/context/deserializer.ts +810 -0
  25. package/src/core/context/parser.ts +335 -0
  26. package/src/core/context/serializer.ts +1406 -0
  27. package/src/core/context/sync-parser.ts +907 -0
  28. package/src/core/cross/index.ts +188 -0
  29. package/src/core/errors.ts +196 -0
  30. package/src/core/function-string.ts +32 -0
  31. package/src/core/keys.ts +17 -0
  32. package/src/core/literals.ts +43 -0
  33. package/src/core/node.ts +40 -0
  34. package/src/core/opaque-reference.ts +9 -0
  35. package/src/core/plugin.ts +100 -0
  36. package/src/core/reference.ts +66 -0
  37. package/src/core/special-reference.ts +42 -0
  38. package/src/core/stream.ts +71 -0
  39. package/src/core/string.ts +86 -0
  40. package/src/core/symbols.ts +18 -0
  41. package/src/core/tree/index.ts +134 -0
  42. package/src/core/types.ts +366 -0
  43. package/src/core/utils/error.ts +73 -0
  44. package/src/core/utils/get-identifier.ts +18 -0
  45. package/src/core/utils/get-object-flag.ts +14 -0
  46. package/src/core/utils/is-valid-identifier.ts +12 -0
  47. package/src/core/utils/iterator-to-sequence.ts +44 -0
  48. package/src/core/utils/promise-to-result.ts +9 -0
  49. package/src/core/utils/typed-array.ts +56 -0
  50. package/src/index.ts +36 -0
@@ -0,0 +1,907 @@
1
+ import {
2
+ createAggregateErrorNode,
3
+ createArrayNode,
4
+ createAsyncIteratorFactoryInstanceNode,
5
+ createBigIntNode,
6
+ createBigIntTypedArrayNode,
7
+ createBoxedNode,
8
+ createDataViewNode,
9
+ createDateNode,
10
+ createErrorNode,
11
+ createIteratorFactoryInstanceNode,
12
+ createNumberNode,
13
+ createPluginNode,
14
+ createRegExpNode,
15
+ createSetNode,
16
+ createStreamConstructorNode,
17
+ createStreamNextNode,
18
+ createStreamReturnNode,
19
+ createStreamThrowNode,
20
+ createStringNode,
21
+ createTypedArrayNode,
22
+ } from '../base-primitives';
23
+ import { Feature } from '../compat';
24
+ import { NIL, SerovalNodeType } from '../constants';
25
+ import {
26
+ SerovalDepthLimitError,
27
+ SerovalParserError,
28
+ SerovalUnsupportedTypeError,
29
+ } from '../errors';
30
+ import { FALSE_NODE, NULL_NODE, TRUE_NODE, UNDEFINED_NODE } from '../literals';
31
+ import { createSerovalNode } from '../node';
32
+ import { OpaqueReference } from '../opaque-reference';
33
+ import { type Plugin, SerovalMode } from '../plugin';
34
+ import { SpecialReference } from '../special-reference';
35
+ import type { Stream } from '../stream';
36
+ import {
37
+ createStream,
38
+ createStreamFromAsyncIterable,
39
+ isStream,
40
+ } from '../stream';
41
+ import { serializeString } from '../string';
42
+ import {
43
+ SYM_ASYNC_ITERATOR,
44
+ SYM_IS_CONCAT_SPREADABLE,
45
+ SYM_ITERATOR,
46
+ SYM_TO_STRING_TAG,
47
+ } from '../symbols';
48
+ import type {
49
+ SerovalAggregateErrorNode,
50
+ SerovalArrayNode,
51
+ SerovalBigIntTypedArrayNode,
52
+ SerovalBoxedNode,
53
+ SerovalDataViewNode,
54
+ SerovalErrorNode,
55
+ SerovalMapNode,
56
+ SerovalNode,
57
+ SerovalNullConstructorNode,
58
+ SerovalObjectNode,
59
+ SerovalObjectRecordKey,
60
+ SerovalObjectRecordNode,
61
+ SerovalPluginNode,
62
+ SerovalPromiseConstructorNode,
63
+ SerovalSetNode,
64
+ SerovalTypedArrayNode,
65
+ } from '../types';
66
+ import { getErrorOptions } from '../utils/error';
67
+ import { iteratorToSequence } from '../utils/iterator-to-sequence';
68
+ import type {
69
+ BigIntTypedArrayValue,
70
+ TypedArrayValue,
71
+ } from '../utils/typed-array';
72
+ import type { BaseParserContext, BaseParserContextOptions } from './parser';
73
+ import {
74
+ createArrayBufferNode,
75
+ createBaseParserContext,
76
+ createIndexForValue,
77
+ createMapNode,
78
+ createObjectNode,
79
+ createPromiseConstructorNode,
80
+ getReferenceNode,
81
+ parseAsyncIteratorFactory,
82
+ parseIteratorFactory,
83
+ ParserNodeType,
84
+ parseSpecialReference,
85
+ parseWellKnownSymbol,
86
+ } from './parser';
87
+
88
+ type ObjectLikeNode = SerovalObjectNode | SerovalNullConstructorNode;
89
+
90
+ export type SyncParserContextOptions = BaseParserContextOptions;
91
+
92
+ const enum ParserMode {
93
+ Sync = 1,
94
+ Stream = 2,
95
+ }
96
+
97
+ export interface SyncParserContext {
98
+ type: ParserMode.Sync;
99
+ base: BaseParserContext;
100
+ child: SyncParsePluginContext | undefined;
101
+ }
102
+
103
+ export function createSyncParserContext(
104
+ mode: SerovalMode,
105
+ options: SyncParserContextOptions,
106
+ ): SyncParserContext {
107
+ return {
108
+ type: ParserMode.Sync,
109
+ base: createBaseParserContext(mode, options),
110
+ child: NIL,
111
+ };
112
+ }
113
+
114
+ export class SyncParsePluginContext {
115
+ constructor(
116
+ private _p: SyncParserContext,
117
+ private depth: number,
118
+ ) {}
119
+
120
+ parse<T>(current: T): SerovalNode {
121
+ return parseSOS(this._p, this.depth, current);
122
+ }
123
+ }
124
+
125
+ export interface StreamParserContextOptions extends SyncParserContextOptions {
126
+ onParse: (node: SerovalNode, initial: boolean) => void;
127
+ onError?: (error: unknown) => void;
128
+ onDone?: () => void;
129
+ }
130
+
131
+ export interface StreamParserContext {
132
+ type: ParserMode.Stream;
133
+ base: BaseParserContext;
134
+ state: StreamParserState;
135
+ }
136
+ export class StreamParsePluginContext {
137
+ constructor(
138
+ private _p: StreamParserContext,
139
+ private depth: number,
140
+ ) {}
141
+
142
+ parse<T>(current: T): SerovalNode {
143
+ return parseSOS(this._p, this.depth, current);
144
+ }
145
+
146
+ parseWithError<T>(current: T): SerovalNode | undefined {
147
+ return parseWithError(this._p, this.depth, current);
148
+ }
149
+
150
+ isAlive(): boolean {
151
+ return this._p.state.alive;
152
+ }
153
+
154
+ pushPendingState(): void {
155
+ pushPendingState(this._p);
156
+ }
157
+
158
+ popPendingState(): void {
159
+ popPendingState(this._p);
160
+ }
161
+
162
+ onParse(node: SerovalNode): void {
163
+ onParse(this._p, node);
164
+ }
165
+
166
+ onError(error: unknown): void {
167
+ onError(this._p, error);
168
+ }
169
+ }
170
+
171
+ interface StreamParserState {
172
+ // Life cycle
173
+ alive: boolean;
174
+ // Number of pending things
175
+ pending: number;
176
+ //
177
+ initial: boolean;
178
+ //
179
+ buffer: SerovalNode[];
180
+ // Callbacks
181
+ onParse: (node: SerovalNode, initial: boolean) => void;
182
+ onError?: (error: unknown) => void;
183
+ onDone?: () => void;
184
+ }
185
+
186
+ function createStreamParserState(
187
+ options: StreamParserContextOptions,
188
+ ): StreamParserState {
189
+ return {
190
+ alive: true,
191
+ pending: 0,
192
+ initial: true,
193
+ buffer: [],
194
+ onParse: options.onParse,
195
+ onError: options.onError,
196
+ onDone: options.onDone,
197
+ };
198
+ }
199
+
200
+ export function createStreamParserContext(
201
+ options: StreamParserContextOptions,
202
+ ): StreamParserContext {
203
+ return {
204
+ type: ParserMode.Stream,
205
+ base: createBaseParserContext(SerovalMode.Cross, options),
206
+ state: createStreamParserState(options),
207
+ };
208
+ }
209
+
210
+ type SOSParserContext = SyncParserContext | StreamParserContext;
211
+
212
+ function parseItems(
213
+ ctx: SOSParserContext,
214
+ depth: number,
215
+ current: unknown[],
216
+ ): (SerovalNode | 0)[] {
217
+ const nodes: (SerovalNode | 0)[] = [];
218
+ for (let i = 0, len = current.length; i < len; i++) {
219
+ if (i in current) {
220
+ nodes[i] = parseSOS(ctx, depth, current[i]);
221
+ } else {
222
+ nodes[i] = 0;
223
+ }
224
+ }
225
+ return nodes;
226
+ }
227
+
228
+ function parseArray(
229
+ ctx: SOSParserContext,
230
+ depth: number,
231
+ id: number,
232
+ current: unknown[],
233
+ ): SerovalArrayNode {
234
+ return createArrayNode(id, current, parseItems(ctx, depth, current));
235
+ }
236
+
237
+ function parseProperties(
238
+ ctx: SOSParserContext,
239
+ depth: number,
240
+ properties: Record<string | symbol, unknown>,
241
+ ): SerovalObjectRecordNode {
242
+ const entries = Object.entries(properties);
243
+ const keyNodes: SerovalObjectRecordKey[] = [];
244
+ const valueNodes: SerovalNode[] = [];
245
+ for (let i = 0, len = entries.length; i < len; i++) {
246
+ keyNodes.push(serializeString(entries[i][0]));
247
+ valueNodes.push(parseSOS(ctx, depth, entries[i][1]));
248
+ }
249
+ // Check special properties, symbols in this case
250
+ if (SYM_ITERATOR in properties) {
251
+ keyNodes.push(parseWellKnownSymbol(ctx.base, SYM_ITERATOR));
252
+ valueNodes.push(
253
+ createIteratorFactoryInstanceNode(
254
+ parseIteratorFactory(ctx.base),
255
+ parseSOS(
256
+ ctx,
257
+ depth,
258
+ iteratorToSequence(properties as unknown as Iterable<unknown>),
259
+ ),
260
+ ),
261
+ );
262
+ }
263
+ if (SYM_ASYNC_ITERATOR in properties) {
264
+ keyNodes.push(parseWellKnownSymbol(ctx.base, SYM_ASYNC_ITERATOR));
265
+ valueNodes.push(
266
+ createAsyncIteratorFactoryInstanceNode(
267
+ parseAsyncIteratorFactory(ctx.base),
268
+ parseSOS(
269
+ ctx,
270
+ depth,
271
+ ctx.type === ParserMode.Sync
272
+ ? createStream()
273
+ : createStreamFromAsyncIterable(
274
+ properties as unknown as AsyncIterable<unknown>,
275
+ ),
276
+ ),
277
+ ),
278
+ );
279
+ }
280
+ if (SYM_TO_STRING_TAG in properties) {
281
+ keyNodes.push(parseWellKnownSymbol(ctx.base, SYM_TO_STRING_TAG));
282
+ valueNodes.push(createStringNode(properties[SYM_TO_STRING_TAG] as string));
283
+ }
284
+ if (SYM_IS_CONCAT_SPREADABLE in properties) {
285
+ keyNodes.push(parseWellKnownSymbol(ctx.base, SYM_IS_CONCAT_SPREADABLE));
286
+ valueNodes.push(
287
+ properties[SYM_IS_CONCAT_SPREADABLE] ? TRUE_NODE : FALSE_NODE,
288
+ );
289
+ }
290
+ return {
291
+ k: keyNodes,
292
+ v: valueNodes,
293
+ };
294
+ }
295
+
296
+ function parsePlainObject(
297
+ ctx: SOSParserContext,
298
+ depth: number,
299
+ id: number,
300
+ current: Record<string, unknown>,
301
+ empty: boolean,
302
+ ): ObjectLikeNode {
303
+ return createObjectNode(
304
+ id,
305
+ current,
306
+ empty,
307
+ parseProperties(ctx, depth, current),
308
+ );
309
+ }
310
+
311
+ function parseBoxed(
312
+ ctx: SOSParserContext,
313
+ depth: number,
314
+ id: number,
315
+ current: object,
316
+ ): SerovalBoxedNode {
317
+ return createBoxedNode(id, parseSOS(ctx, depth, current.valueOf()));
318
+ }
319
+
320
+ function parseTypedArray(
321
+ ctx: SOSParserContext,
322
+ depth: number,
323
+ id: number,
324
+ current: TypedArrayValue,
325
+ ): SerovalTypedArrayNode {
326
+ return createTypedArrayNode(
327
+ id,
328
+ current,
329
+ parseSOS(ctx, depth, current.buffer),
330
+ );
331
+ }
332
+
333
+ function parseBigIntTypedArray(
334
+ ctx: SOSParserContext,
335
+ depth: number,
336
+ id: number,
337
+ current: BigIntTypedArrayValue,
338
+ ): SerovalBigIntTypedArrayNode {
339
+ return createBigIntTypedArrayNode(
340
+ id,
341
+ current,
342
+ parseSOS(ctx, depth, current.buffer),
343
+ );
344
+ }
345
+
346
+ function parseDataView(
347
+ ctx: SOSParserContext,
348
+ depth: number,
349
+ id: number,
350
+ current: DataView,
351
+ ): SerovalDataViewNode {
352
+ return createDataViewNode(id, current, parseSOS(ctx, depth, current.buffer));
353
+ }
354
+
355
+ function parseError(
356
+ ctx: SOSParserContext,
357
+ depth: number,
358
+ id: number,
359
+ current: Error,
360
+ ): SerovalErrorNode {
361
+ const options = getErrorOptions(current, ctx.base.features);
362
+ return createErrorNode(
363
+ id,
364
+ current,
365
+ options ? parseProperties(ctx, depth, options) : NIL,
366
+ );
367
+ }
368
+
369
+ function parseAggregateError(
370
+ ctx: SOSParserContext,
371
+ depth: number,
372
+ id: number,
373
+ current: AggregateError,
374
+ ): SerovalAggregateErrorNode {
375
+ const options = getErrorOptions(current, ctx.base.features);
376
+ return createAggregateErrorNode(
377
+ id,
378
+ current,
379
+ options ? parseProperties(ctx, depth, options) : NIL,
380
+ );
381
+ }
382
+
383
+ function parseMap(
384
+ ctx: SOSParserContext,
385
+ depth: number,
386
+ id: number,
387
+ current: Map<unknown, unknown>,
388
+ ): SerovalMapNode {
389
+ const keyNodes: SerovalNode[] = [];
390
+ const valueNodes: SerovalNode[] = [];
391
+ for (const [key, value] of current.entries()) {
392
+ keyNodes.push(parseSOS(ctx, depth, key));
393
+ valueNodes.push(parseSOS(ctx, depth, value));
394
+ }
395
+ return createMapNode(ctx.base, id, keyNodes, valueNodes);
396
+ }
397
+
398
+ function parseSet(
399
+ ctx: SOSParserContext,
400
+ depth: number,
401
+ id: number,
402
+ current: Set<unknown>,
403
+ ): SerovalSetNode {
404
+ const items: SerovalNode[] = [];
405
+ for (const item of current.keys()) {
406
+ items.push(parseSOS(ctx, depth, item));
407
+ }
408
+ return createSetNode(id, items);
409
+ }
410
+
411
+ function parseStream(
412
+ ctx: SOSParserContext,
413
+ depth: number,
414
+ id: number,
415
+ current: Stream<unknown>,
416
+ ): SerovalNode {
417
+ const result = createStreamConstructorNode(
418
+ id,
419
+ parseSpecialReference(ctx.base, SpecialReference.StreamConstructor),
420
+ [],
421
+ );
422
+ if (ctx.type === ParserMode.Sync) {
423
+ return result;
424
+ }
425
+ pushPendingState(ctx);
426
+ current.on({
427
+ next: value => {
428
+ if (ctx.state.alive) {
429
+ const parsed = parseWithError(ctx, depth, value);
430
+ if (parsed) {
431
+ onParse(ctx, createStreamNextNode(id, parsed));
432
+ }
433
+ }
434
+ },
435
+ throw: value => {
436
+ if (ctx.state.alive) {
437
+ const parsed = parseWithError(ctx, depth, value);
438
+ if (parsed) {
439
+ onParse(ctx, createStreamThrowNode(id, parsed));
440
+ }
441
+ }
442
+ popPendingState(ctx);
443
+ },
444
+ return: value => {
445
+ if (ctx.state.alive) {
446
+ const parsed = parseWithError(ctx, depth, value);
447
+ if (parsed) {
448
+ onParse(ctx, createStreamReturnNode(id, parsed));
449
+ }
450
+ }
451
+ popPendingState(ctx);
452
+ },
453
+ });
454
+ return result;
455
+ }
456
+
457
+ function handlePromiseSuccess(
458
+ this: StreamParserContext,
459
+ id: number,
460
+ depth: number,
461
+ data: unknown,
462
+ ): void {
463
+ if (this.state.alive) {
464
+ const parsed = parseWithError(this, depth, data);
465
+ if (parsed) {
466
+ onParse(
467
+ this,
468
+ createSerovalNode(
469
+ SerovalNodeType.PromiseSuccess,
470
+ id,
471
+ NIL,
472
+ NIL,
473
+ NIL,
474
+ NIL,
475
+ NIL,
476
+ [
477
+ parseSpecialReference(this.base, SpecialReference.PromiseSuccess),
478
+ parsed,
479
+ ],
480
+ NIL,
481
+ NIL,
482
+ NIL,
483
+ NIL,
484
+ ),
485
+ );
486
+ }
487
+ popPendingState(this);
488
+ }
489
+ }
490
+
491
+ function handlePromiseFailure(
492
+ this: StreamParserContext,
493
+ id: number,
494
+ depth: number,
495
+ data: unknown,
496
+ ): void {
497
+ if (this.state.alive) {
498
+ const parsed = parseWithError(this, depth, data);
499
+ if (parsed) {
500
+ onParse(
501
+ this,
502
+ createSerovalNode(
503
+ SerovalNodeType.PromiseFailure,
504
+ id,
505
+ NIL,
506
+ NIL,
507
+ NIL,
508
+ NIL,
509
+ NIL,
510
+ [
511
+ parseSpecialReference(this.base, SpecialReference.PromiseFailure),
512
+ parsed,
513
+ ],
514
+ NIL,
515
+ NIL,
516
+ NIL,
517
+ NIL,
518
+ ),
519
+ );
520
+ }
521
+ }
522
+ popPendingState(this);
523
+ }
524
+
525
+ function parsePromise(
526
+ ctx: SOSParserContext,
527
+ depth: number,
528
+ id: number,
529
+ current: Promise<unknown>,
530
+ ): SerovalPromiseConstructorNode {
531
+ // Creates a unique reference for the promise resolver
532
+ const resolver = createIndexForValue(ctx.base, {});
533
+ if (ctx.type === ParserMode.Stream) {
534
+ pushPendingState(ctx);
535
+ current.then(
536
+ handlePromiseSuccess.bind(ctx, resolver, depth),
537
+ handlePromiseFailure.bind(ctx, resolver, depth),
538
+ );
539
+ }
540
+ return createPromiseConstructorNode(ctx.base, id, resolver);
541
+ }
542
+
543
+ function parsePluginSync(
544
+ ctx: SyncParserContext,
545
+ depth: number,
546
+ id: number,
547
+ current: unknown,
548
+ currentPlugins: Plugin<any, any>[],
549
+ ): SerovalPluginNode | undefined {
550
+ for (let i = 0, len = currentPlugins.length; i < len; i++) {
551
+ const plugin = currentPlugins[i];
552
+ if (plugin.parse.sync && plugin.test(current)) {
553
+ return createPluginNode(
554
+ id,
555
+ plugin.tag,
556
+ plugin.parse.sync(current, new SyncParsePluginContext(ctx, depth), {
557
+ id,
558
+ }),
559
+ );
560
+ }
561
+ }
562
+ return NIL;
563
+ }
564
+
565
+ function parsePluginStream(
566
+ ctx: StreamParserContext,
567
+ depth: number,
568
+ id: number,
569
+ current: unknown,
570
+ currentPlugins: Plugin<any, any>[],
571
+ ): SerovalPluginNode | undefined {
572
+ for (let i = 0, len = currentPlugins.length; i < len; i++) {
573
+ const plugin = currentPlugins[i];
574
+ if (plugin.parse.stream && plugin.test(current)) {
575
+ return createPluginNode(
576
+ id,
577
+ plugin.tag,
578
+ plugin.parse.stream(current, new StreamParsePluginContext(ctx, depth), {
579
+ id,
580
+ }),
581
+ );
582
+ }
583
+ }
584
+ return NIL;
585
+ }
586
+
587
+ function parsePlugin(
588
+ ctx: SOSParserContext,
589
+ depth: number,
590
+ id: number,
591
+ current: unknown,
592
+ ): SerovalPluginNode | undefined {
593
+ const currentPlugins = ctx.base.plugins;
594
+ if (currentPlugins) {
595
+ return ctx.type === ParserMode.Sync
596
+ ? parsePluginSync(ctx, depth, id, current, currentPlugins)
597
+ : parsePluginStream(ctx, depth, id, current, currentPlugins);
598
+ }
599
+ return NIL;
600
+ }
601
+
602
+ function parseObjectPhase2(
603
+ ctx: SOSParserContext,
604
+ depth: number,
605
+ id: number,
606
+ current: object,
607
+ currentClass: unknown,
608
+ ): SerovalNode {
609
+ switch (currentClass) {
610
+ case Object:
611
+ return parsePlainObject(
612
+ ctx,
613
+ depth,
614
+ id,
615
+ current as Record<string, unknown>,
616
+ false,
617
+ );
618
+ case NIL:
619
+ return parsePlainObject(
620
+ ctx,
621
+ depth,
622
+ id,
623
+ current as Record<string, unknown>,
624
+ true,
625
+ );
626
+ case Date:
627
+ return createDateNode(id, current as unknown as Date);
628
+ case Error:
629
+ case EvalError:
630
+ case RangeError:
631
+ case ReferenceError:
632
+ case SyntaxError:
633
+ case TypeError:
634
+ case URIError:
635
+ return parseError(ctx, depth, id, current as unknown as Error);
636
+ case Number:
637
+ case Boolean:
638
+ case String:
639
+ case BigInt:
640
+ return parseBoxed(ctx, depth, id, current);
641
+ case ArrayBuffer:
642
+ return createArrayBufferNode(
643
+ ctx.base,
644
+ id,
645
+ current as unknown as ArrayBuffer,
646
+ );
647
+ case Int8Array:
648
+ case Int16Array:
649
+ case Int32Array:
650
+ case Uint8Array:
651
+ case Uint16Array:
652
+ case Uint32Array:
653
+ case Uint8ClampedArray:
654
+ case Float32Array:
655
+ case Float64Array:
656
+ return parseTypedArray(
657
+ ctx,
658
+ depth,
659
+ id,
660
+ current as unknown as TypedArrayValue,
661
+ );
662
+ case DataView:
663
+ return parseDataView(ctx, depth, id, current as unknown as DataView);
664
+ case Map:
665
+ return parseMap(
666
+ ctx,
667
+ depth,
668
+ id,
669
+ current as unknown as Map<unknown, unknown>,
670
+ );
671
+ case Set:
672
+ return parseSet(ctx, depth, id, current as unknown as Set<unknown>);
673
+ default:
674
+ break;
675
+ }
676
+ // Promises
677
+ if (currentClass === Promise || current instanceof Promise) {
678
+ return parsePromise(ctx, depth, id, current as unknown as Promise<unknown>);
679
+ }
680
+ const currentFeatures = ctx.base.features;
681
+ if (currentFeatures & Feature.RegExp && currentClass === RegExp) {
682
+ return createRegExpNode(id, current as unknown as RegExp);
683
+ }
684
+ // BigInt Typed Arrays
685
+ if (currentFeatures & Feature.BigIntTypedArray) {
686
+ switch (currentClass) {
687
+ case BigInt64Array:
688
+ case BigUint64Array:
689
+ return parseBigIntTypedArray(
690
+ ctx,
691
+ depth,
692
+ id,
693
+ current as unknown as BigIntTypedArrayValue,
694
+ );
695
+ default:
696
+ break;
697
+ }
698
+ }
699
+ if (
700
+ currentFeatures & Feature.AggregateError &&
701
+ typeof AggregateError !== 'undefined' &&
702
+ (currentClass === AggregateError || current instanceof AggregateError)
703
+ ) {
704
+ return parseAggregateError(
705
+ ctx,
706
+ depth,
707
+ id,
708
+ current as unknown as AggregateError,
709
+ );
710
+ }
711
+ // Slow path. We only need to handle Errors and Iterators
712
+ // since they have very broad implementations.
713
+ if (current instanceof Error) {
714
+ return parseError(ctx, depth, id, current);
715
+ }
716
+ // Generator functions don't have a global constructor
717
+ // despite existing
718
+ if (SYM_ITERATOR in current || SYM_ASYNC_ITERATOR in current) {
719
+ return parsePlainObject(ctx, depth, id, current, !!currentClass);
720
+ }
721
+ throw new SerovalUnsupportedTypeError(current);
722
+ }
723
+
724
+ function parseObject(
725
+ ctx: SOSParserContext,
726
+ depth: number,
727
+ id: number,
728
+ current: object,
729
+ ): SerovalNode {
730
+ if (Array.isArray(current)) {
731
+ return parseArray(ctx, depth, id, current);
732
+ }
733
+ if (isStream(current)) {
734
+ return parseStream(ctx, depth, id, current);
735
+ }
736
+ const currentClass = current.constructor;
737
+ if (currentClass === OpaqueReference) {
738
+ return parseSOS(
739
+ ctx,
740
+ depth,
741
+ (current as OpaqueReference<unknown, unknown>).replacement,
742
+ );
743
+ }
744
+ const parsed = parsePlugin(ctx, depth, id, current);
745
+ if (parsed) {
746
+ return parsed;
747
+ }
748
+ return parseObjectPhase2(ctx, depth, id, current, currentClass);
749
+ }
750
+
751
+ function parseFunction(
752
+ ctx: SOSParserContext,
753
+ depth: number,
754
+ current: unknown,
755
+ ): SerovalNode {
756
+ const ref = getReferenceNode(ctx.base, current);
757
+ if (ref.type !== ParserNodeType.Fresh) {
758
+ return ref.value;
759
+ }
760
+ const plugin = parsePlugin(ctx, depth, ref.value, current);
761
+ if (plugin) {
762
+ return plugin;
763
+ }
764
+ throw new SerovalUnsupportedTypeError(current);
765
+ }
766
+
767
+ export function parseSOS<T>(
768
+ ctx: SOSParserContext,
769
+ depth: number,
770
+ current: T,
771
+ ): SerovalNode {
772
+ if (depth >= ctx.base.depthLimit) {
773
+ throw new SerovalDepthLimitError(ctx.base.depthLimit);
774
+ }
775
+ switch (typeof current) {
776
+ case 'boolean':
777
+ return current ? TRUE_NODE : FALSE_NODE;
778
+ case 'undefined':
779
+ return UNDEFINED_NODE;
780
+ case 'string':
781
+ return createStringNode(current as string);
782
+ case 'number':
783
+ return createNumberNode(current as number);
784
+ case 'bigint':
785
+ return createBigIntNode(current as bigint);
786
+ case 'object': {
787
+ if (current) {
788
+ const ref = getReferenceNode(ctx.base, current);
789
+ return ref.type === ParserNodeType.Fresh
790
+ ? parseObject(ctx, depth + 1, ref.value, current as object)
791
+ : ref.value;
792
+ }
793
+ return NULL_NODE;
794
+ }
795
+ case 'symbol':
796
+ return parseWellKnownSymbol(ctx.base, current);
797
+ case 'function': {
798
+ return parseFunction(ctx, depth, current);
799
+ }
800
+ default:
801
+ throw new SerovalUnsupportedTypeError(current);
802
+ }
803
+ }
804
+
805
+ export function parseTop<T>(ctx: SyncParserContext, current: T): SerovalNode {
806
+ try {
807
+ return parseSOS(ctx, 0, current);
808
+ } catch (error) {
809
+ throw error instanceof SerovalParserError
810
+ ? error
811
+ : new SerovalParserError(error);
812
+ }
813
+ }
814
+
815
+ function onParse(ctx: StreamParserContext, node: SerovalNode): void {
816
+ // If the value emitted happens to be during parsing, we push to the
817
+ // buffer and emit after the initial parsing is done.
818
+ if (ctx.state.initial) {
819
+ ctx.state.buffer.push(node);
820
+ } else {
821
+ onParseInternal(ctx, node, false);
822
+ }
823
+ }
824
+
825
+ function onError(ctx: StreamParserContext, error: unknown): void {
826
+ if (ctx.state.onError) {
827
+ ctx.state.onError(error);
828
+ } else {
829
+ throw error instanceof SerovalParserError
830
+ ? error
831
+ : new SerovalParserError(error);
832
+ }
833
+ }
834
+
835
+ function onDone(ctx: StreamParserContext): void {
836
+ if (ctx.state.onDone) {
837
+ ctx.state.onDone();
838
+ }
839
+ }
840
+
841
+ function onParseInternal(
842
+ ctx: StreamParserContext,
843
+ node: SerovalNode,
844
+ initial: boolean,
845
+ ): void {
846
+ try {
847
+ ctx.state.onParse(node, initial);
848
+ } catch (error) {
849
+ onError(ctx, error);
850
+ }
851
+ }
852
+
853
+ function pushPendingState(ctx: StreamParserContext): void {
854
+ ctx.state.pending++;
855
+ }
856
+
857
+ function popPendingState(ctx: StreamParserContext): void {
858
+ if (--ctx.state.pending <= 0) {
859
+ onDone(ctx);
860
+ }
861
+ }
862
+
863
+ function parseWithError<T>(
864
+ ctx: StreamParserContext,
865
+ depth: number,
866
+ current: T,
867
+ ): SerovalNode | undefined {
868
+ try {
869
+ return parseSOS(ctx, depth, current);
870
+ } catch (err) {
871
+ onError(ctx, err);
872
+ return NIL;
873
+ }
874
+ }
875
+
876
+ export function startStreamParse<T>(
877
+ ctx: StreamParserContext,
878
+ current: T,
879
+ ): void {
880
+ const parsed = parseWithError(ctx, 0, current);
881
+ if (parsed) {
882
+ onParseInternal(ctx, parsed, true);
883
+ ctx.state.initial = false;
884
+ flushStreamParse(ctx, ctx.state);
885
+
886
+ // Check if there's any pending pushes
887
+ if (ctx.state.pending <= 0) {
888
+ destroyStreamParse(ctx);
889
+ }
890
+ }
891
+ }
892
+
893
+ function flushStreamParse(
894
+ ctx: StreamParserContext,
895
+ state: StreamParserState,
896
+ ): void {
897
+ for (let i = 0, len = state.buffer.length; i < len; i++) {
898
+ onParseInternal(ctx, state.buffer[i], false);
899
+ }
900
+ }
901
+
902
+ export function destroyStreamParse(ctx: StreamParserContext): void {
903
+ if (ctx.state.alive) {
904
+ onDone(ctx);
905
+ ctx.state.alive = false;
906
+ }
907
+ }