seroval 1.4.0 → 1.4.1

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