seroval 0.9.0 → 0.10.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 (90) hide show
  1. package/README.md +4 -287
  2. package/dist/cjs/development/index.cjs +3529 -1140
  3. package/dist/cjs/development/index.cjs.map +4 -4
  4. package/dist/cjs/production/index.cjs +3 -3
  5. package/dist/esm/development/index.mjs +3533 -1142
  6. package/dist/esm/development/index.mjs.map +4 -4
  7. package/dist/esm/production/index.mjs +3 -3
  8. package/dist/types/core/Serializer.d.ts +15 -0
  9. package/dist/types/{tree → core}/UnsupportedTypeError.d.ts +4 -3
  10. package/dist/types/{assert.d.ts → core/assert.d.ts} +1 -1
  11. package/dist/types/core/assignments.d.ts +33 -0
  12. package/dist/types/core/base-primitives.d.ts +12 -0
  13. package/dist/types/{compat.d.ts → core/compat.d.ts} +22 -22
  14. package/dist/types/core/constants.d.ts +89 -0
  15. package/dist/types/core/context.d.ts +9 -0
  16. package/dist/types/core/cross/async.d.ts +3 -0
  17. package/dist/types/core/cross/context.d.ts +37 -0
  18. package/dist/types/core/cross/index.d.ts +8 -0
  19. package/dist/types/core/cross/primitives.d.ts +9 -0
  20. package/dist/types/core/cross/serialize.d.ts +5 -0
  21. package/dist/types/core/cross/stream.d.ts +3 -0
  22. package/dist/types/core/cross/sync.d.ts +3 -0
  23. package/dist/types/core/cross/web-api.d.ts +4 -0
  24. package/dist/types/{get-identifier.d.ts → core/get-identifier.d.ts} +1 -1
  25. package/dist/types/core/keys.d.ts +13 -0
  26. package/dist/types/{tree/constants.d.ts → core/literals.d.ts} +9 -11
  27. package/dist/types/core/promise-to-result.d.ts +1 -0
  28. package/dist/types/{tree → core}/reference.d.ts +5 -6
  29. package/dist/types/{tree → core}/shared.d.ts +13 -13
  30. package/dist/types/{string.d.ts → core/string.d.ts} +3 -3
  31. package/dist/types/core/tree/async.d.ts +3 -0
  32. package/dist/types/core/tree/context.d.ts +44 -0
  33. package/dist/types/core/tree/deserialize.d.ts +3 -0
  34. package/dist/types/core/tree/index.d.ts +14 -0
  35. package/dist/types/core/tree/primitives.d.ts +9 -0
  36. package/dist/types/core/tree/serialize.d.ts +4 -0
  37. package/dist/types/core/tree/sync.d.ts +3 -0
  38. package/dist/types/core/tree/web-api.d.ts +4 -0
  39. package/dist/types/{tree → core}/types.d.ts +228 -238
  40. package/dist/types/core/web-api.d.ts +4 -0
  41. package/dist/types/index.d.ts +9 -19
  42. package/dist/types/types.d.ts +20 -20
  43. package/package.json +5 -5
  44. package/src/core/Serializer.ts +48 -0
  45. package/src/{tree → core}/UnsupportedTypeError.ts +1 -1
  46. package/src/core/assignments.ts +159 -0
  47. package/src/{tree/primitives.ts → core/base-primitives.ts} +33 -136
  48. package/src/core/constants.ts +169 -0
  49. package/src/core/context.ts +15 -0
  50. package/src/core/cross/async.ts +614 -0
  51. package/src/core/cross/context.ts +102 -0
  52. package/src/core/cross/index.ts +169 -0
  53. package/src/core/cross/primitives.ts +137 -0
  54. package/src/core/cross/serialize.ts +847 -0
  55. package/src/core/cross/stream.ts +745 -0
  56. package/src/core/cross/sync.ts +561 -0
  57. package/src/core/cross/web-api.ts +55 -0
  58. package/src/core/header.js +61 -0
  59. package/src/core/keys.ts +41 -0
  60. package/src/core/literals.ts +28 -0
  61. package/src/core/promise-to-result.ts +9 -0
  62. package/src/{tree → core}/reference.ts +6 -7
  63. package/src/{tree → core}/shared.ts +4 -4
  64. package/src/{tree → core/tree}/async.ts +46 -34
  65. package/src/core/tree/context.ts +125 -0
  66. package/src/{tree → core/tree}/deserialize.ts +68 -55
  67. package/src/core/tree/index.ts +142 -0
  68. package/src/core/tree/primitives.ts +132 -0
  69. package/src/{tree → core/tree}/serialize.ts +87 -193
  70. package/src/{tree → core/tree}/sync.ts +50 -39
  71. package/src/{tree → core/tree}/web-api.ts +8 -52
  72. package/src/{tree → core}/types.ts +76 -60
  73. package/src/core/web-api.ts +51 -0
  74. package/src/index.ts +7 -141
  75. package/src/types.ts +1 -1
  76. package/dist/types/context.d.ts +0 -67
  77. package/dist/types/tree/async.d.ts +0 -3
  78. package/dist/types/tree/deserialize.d.ts +0 -3
  79. package/dist/types/tree/primitives.d.ts +0 -19
  80. package/dist/types/tree/serialize.d.ts +0 -4
  81. package/dist/types/tree/symbols.d.ts +0 -33
  82. package/dist/types/tree/sync.d.ts +0 -3
  83. package/dist/types/tree/web-api.d.ts +0 -6
  84. package/src/context.ts +0 -164
  85. package/src/tree/constants.ts +0 -73
  86. package/src/tree/symbols.ts +0 -65
  87. /package/src/{assert.ts → core/assert.ts} +0 -0
  88. /package/src/{compat.ts → core/compat.ts} +0 -0
  89. /package/src/{get-identifier.ts → core/get-identifier.ts} +0 -0
  90. /package/src/{string.ts → core/string.ts} +0 -0
@@ -0,0 +1,614 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ /* eslint-disable @typescript-eslint/no-use-before-define */
3
+ import assert from '../assert';
4
+ import { Feature } from '../compat';
5
+ import type { CrossParserContext } from './context';
6
+ import {
7
+ createCrossIndexedValue,
8
+ } from './context';
9
+ import { serializeString } from '../string';
10
+ import type {
11
+ BigIntTypedArrayValue,
12
+ TypedArrayValue,
13
+ } from '../../types';
14
+ import UnsupportedTypeError from '../UnsupportedTypeError';
15
+ import {
16
+ TRUE_NODE,
17
+ FALSE_NODE,
18
+ UNDEFINED_NODE,
19
+ NULL_NODE,
20
+ } from '../literals';
21
+ import {
22
+ createBigIntTypedArrayNode,
23
+ createTypedArrayNode,
24
+ createDataViewNode,
25
+ createSymbolNode,
26
+ createFunctionNode,
27
+ } from './primitives';
28
+ import { hasReferenceID } from '../reference';
29
+ import {
30
+ getErrorConstructorName,
31
+ getErrorOptions,
32
+ getObjectFlag,
33
+ isIterable,
34
+ } from '../shared';
35
+ import type {
36
+ SerovalAggregateErrorNode,
37
+ SerovalArrayNode,
38
+ SerovalBoxedNode,
39
+ SerovalErrorNode,
40
+ SerovalFormDataNode,
41
+ SerovalHeadersNode,
42
+ SerovalMapNode,
43
+ SerovalNode,
44
+ SerovalNullConstructorNode,
45
+ SerovalObjectNode,
46
+ SerovalObjectRecordKey,
47
+ SerovalObjectRecordNode,
48
+ SerovalPlainRecordNode,
49
+ SerovalPromiseNode,
50
+ SerovalSetNode,
51
+ } from '../types';
52
+ import {
53
+ SerovalObjectRecordSpecialKey,
54
+ } from '../types';
55
+ import {
56
+ createBlobNode,
57
+ createFileNode,
58
+ } from './web-api';
59
+ import { SerovalNodeType } from '../constants';
60
+ import {
61
+ createArrayBufferNode,
62
+ createBigIntNode,
63
+ createDateNode,
64
+ createIndexedValueNode,
65
+ createNumberNode,
66
+ createReferenceNode,
67
+ createRegExpNode,
68
+ createStringNode,
69
+ } from '../base-primitives';
70
+ import { createURLNode, createURLSearchParamsNode } from '../web-api';
71
+ import promiseToResult from '../promise-to-result';
72
+
73
+ type ObjectLikeNode =
74
+ | SerovalObjectNode
75
+ | SerovalNullConstructorNode
76
+ | SerovalPromiseNode;
77
+
78
+ async function generateNodeList(
79
+ ctx: CrossParserContext,
80
+ current: unknown[],
81
+ ): Promise<SerovalNode[]> {
82
+ const size = current.length;
83
+ const nodes = new Array<SerovalNode>(size);
84
+ const deferred = new Array<unknown>(size);
85
+ let item: unknown;
86
+ for (let i = 0; i < size; i++) {
87
+ if (i in current) {
88
+ item = current[i];
89
+ if (isIterable(item)) {
90
+ deferred[i] = item;
91
+ } else {
92
+ nodes[i] = await crossParseAsync(ctx, item);
93
+ }
94
+ }
95
+ }
96
+ for (let i = 0; i < size; i++) {
97
+ if (i in deferred) {
98
+ nodes[i] = await crossParseAsync(ctx, deferred[i]);
99
+ }
100
+ }
101
+ return nodes;
102
+ }
103
+
104
+ async function generateArrayNode(
105
+ ctx: CrossParserContext,
106
+ id: number,
107
+ current: unknown[],
108
+ ): Promise<SerovalArrayNode> {
109
+ return {
110
+ t: SerovalNodeType.Array,
111
+ i: id,
112
+ s: undefined,
113
+ l: current.length,
114
+ c: undefined,
115
+ m: undefined,
116
+ p: undefined,
117
+ e: undefined,
118
+ a: await generateNodeList(ctx, current),
119
+ f: undefined,
120
+ b: undefined,
121
+ o: getObjectFlag(current),
122
+ };
123
+ }
124
+
125
+ async function generateMapNode(
126
+ ctx: CrossParserContext,
127
+ id: number,
128
+ current: Map<unknown, unknown>,
129
+ ): Promise<SerovalMapNode> {
130
+ assert(ctx.features & Feature.Map, new UnsupportedTypeError(current));
131
+ const len = current.size;
132
+ const keyNodes = new Array<SerovalNode>(len);
133
+ const valueNodes = new Array<SerovalNode>(len);
134
+ const deferredKey = new Array<unknown>(len);
135
+ const deferredValue = new Array<unknown>(len);
136
+ let deferredSize = 0;
137
+ let nodeSize = 0;
138
+ for (const [key, value] of current.entries()) {
139
+ // Either key or value might be an iterable
140
+ if (isIterable(key) || isIterable(value)) {
141
+ deferredKey[deferredSize] = key;
142
+ deferredValue[deferredSize] = value;
143
+ deferredSize++;
144
+ } else {
145
+ keyNodes[nodeSize] = await crossParseAsync(ctx, key);
146
+ valueNodes[nodeSize] = await crossParseAsync(ctx, value);
147
+ nodeSize++;
148
+ }
149
+ }
150
+ for (let i = 0; i < deferredSize; i++) {
151
+ keyNodes[nodeSize + i] = await crossParseAsync(ctx, deferredKey[i]);
152
+ valueNodes[nodeSize + i] = await crossParseAsync(ctx, deferredValue[i]);
153
+ }
154
+ return {
155
+ t: SerovalNodeType.Map,
156
+ i: id,
157
+ s: undefined,
158
+ l: undefined,
159
+ c: undefined,
160
+ m: undefined,
161
+ p: undefined,
162
+ e: { k: keyNodes, v: valueNodes, s: len },
163
+ a: undefined,
164
+ f: undefined,
165
+ b: undefined,
166
+ o: undefined,
167
+ };
168
+ }
169
+
170
+ async function generateSetNode(
171
+ ctx: CrossParserContext,
172
+ id: number,
173
+ current: Set<unknown>,
174
+ ): Promise<SerovalSetNode> {
175
+ assert(ctx.features & Feature.Set, new UnsupportedTypeError(current));
176
+ const len = current.size;
177
+ const nodes = new Array<SerovalNode>(len);
178
+ const deferred = new Array<unknown>(len);
179
+ let deferredSize = 0;
180
+ let nodeSize = 0;
181
+ for (const item of current.keys()) {
182
+ // Iterables are lazy, so the evaluation must be deferred
183
+ if (isIterable(item)) {
184
+ deferred[deferredSize++] = item;
185
+ } else {
186
+ nodes[nodeSize++] = await crossParseAsync(ctx, item);
187
+ }
188
+ }
189
+ // Parse deferred items
190
+ for (let i = 0; i < deferredSize; i++) {
191
+ nodes[nodeSize + i] = await crossParseAsync(ctx, deferred[i]);
192
+ }
193
+ return {
194
+ t: SerovalNodeType.Set,
195
+ i: id,
196
+ s: undefined,
197
+ l: len,
198
+ c: undefined,
199
+ m: undefined,
200
+ p: undefined,
201
+ e: undefined,
202
+ a: nodes,
203
+ f: undefined,
204
+ b: undefined,
205
+ o: undefined,
206
+ };
207
+ }
208
+
209
+ async function generateProperties(
210
+ ctx: CrossParserContext,
211
+ properties: Record<string, unknown>,
212
+ ): Promise<SerovalObjectRecordNode> {
213
+ const keys = Object.keys(properties);
214
+ let size = keys.length;
215
+ const keyNodes = new Array<SerovalObjectRecordKey>(size);
216
+ const valueNodes = new Array<SerovalNode>(size);
217
+ const deferredKeys = new Array<SerovalObjectRecordKey>(size);
218
+ const deferredValues = new Array<unknown>(size);
219
+ let deferredSize = 0;
220
+ let nodesSize = 0;
221
+ let item: unknown;
222
+ let escaped: SerovalObjectRecordKey;
223
+ for (const key of keys) {
224
+ item = properties[key];
225
+ escaped = serializeString(key);
226
+ if (isIterable(item)) {
227
+ deferredKeys[deferredSize] = escaped;
228
+ deferredValues[deferredSize] = item;
229
+ deferredSize++;
230
+ } else {
231
+ keyNodes[nodesSize] = escaped;
232
+ valueNodes[nodesSize] = await crossParseAsync(ctx, item);
233
+ nodesSize++;
234
+ }
235
+ }
236
+ for (let i = 0; i < deferredSize; i++) {
237
+ keyNodes[nodesSize + i] = deferredKeys[i];
238
+ valueNodes[nodesSize + i] = await crossParseAsync(ctx, deferredValues[i]);
239
+ }
240
+ if (ctx.features & Feature.Symbol) {
241
+ if (Symbol.iterator in properties) {
242
+ keyNodes[size] = SerovalObjectRecordSpecialKey.SymbolIterator;
243
+ const items = Array.from(properties as Iterable<unknown>);
244
+ valueNodes[size] = await generateArrayNode(
245
+ ctx,
246
+ createCrossIndexedValue(ctx, items),
247
+ items,
248
+ );
249
+ size++;
250
+ }
251
+ }
252
+ return {
253
+ k: keyNodes,
254
+ v: valueNodes,
255
+ s: size,
256
+ };
257
+ }
258
+
259
+ async function generatePlainProperties(
260
+ ctx: CrossParserContext,
261
+ properties: Record<string, unknown>,
262
+ ): Promise<SerovalPlainRecordNode> {
263
+ const keys = Object.keys(properties);
264
+ const size = keys.length;
265
+ const keyNodes = new Array<string>(size);
266
+ const valueNodes = new Array<SerovalNode>(size);
267
+ const deferredKeys = new Array<string>(size);
268
+ const deferredValues = new Array<unknown>(size);
269
+ let deferredSize = 0;
270
+ let nodesSize = 0;
271
+ let item: unknown;
272
+ let escaped: string;
273
+ for (const key of keys) {
274
+ item = properties[key];
275
+ escaped = serializeString(key);
276
+ if (isIterable(item)) {
277
+ deferredKeys[deferredSize] = escaped;
278
+ deferredValues[deferredSize] = item;
279
+ deferredSize++;
280
+ } else {
281
+ keyNodes[nodesSize] = escaped;
282
+ valueNodes[nodesSize] = await crossParseAsync(ctx, item);
283
+ nodesSize++;
284
+ }
285
+ }
286
+ for (let i = 0; i < deferredSize; i++) {
287
+ keyNodes[nodesSize + i] = deferredKeys[i];
288
+ valueNodes[nodesSize + i] = await crossParseAsync(ctx, deferredValues[i]);
289
+ }
290
+ return {
291
+ k: keyNodes,
292
+ v: valueNodes,
293
+ s: size,
294
+ };
295
+ }
296
+
297
+ async function generatePromiseNode(
298
+ ctx: CrossParserContext,
299
+ id: number,
300
+ current: Promise<unknown>,
301
+ ): Promise<SerovalPromiseNode> {
302
+ assert(ctx.features & Feature.Promise, new UnsupportedTypeError(current));
303
+ const [status, result] = await promiseToResult(current);
304
+ return {
305
+ t: SerovalNodeType.Promise,
306
+ i: id,
307
+ s: status,
308
+ l: undefined,
309
+ c: undefined,
310
+ m: undefined,
311
+ p: undefined,
312
+ e: undefined,
313
+ a: undefined,
314
+ f: await crossParseAsync(ctx, result),
315
+ b: undefined,
316
+ o: undefined,
317
+ };
318
+ }
319
+
320
+ async function generateObjectNode(
321
+ ctx: CrossParserContext,
322
+ id: number,
323
+ current: Record<string, unknown>,
324
+ empty: boolean,
325
+ ): Promise<ObjectLikeNode> {
326
+ return {
327
+ t: empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,
328
+ i: id,
329
+ s: undefined,
330
+ l: undefined,
331
+ c: undefined,
332
+ m: undefined,
333
+ p: await generateProperties(ctx, current),
334
+ e: undefined,
335
+ a: undefined,
336
+ f: undefined,
337
+ b: undefined,
338
+ o: getObjectFlag(current),
339
+ };
340
+ }
341
+
342
+ async function generateAggregateErrorNode(
343
+ ctx: CrossParserContext,
344
+ id: number,
345
+ current: AggregateError,
346
+ ): Promise<SerovalAggregateErrorNode> {
347
+ const options = getErrorOptions(ctx, current);
348
+ const optionsNode = options
349
+ ? await generateProperties(ctx, options)
350
+ : undefined;
351
+ return {
352
+ t: SerovalNodeType.AggregateError,
353
+ i: id,
354
+ s: undefined,
355
+ l: undefined,
356
+ c: undefined,
357
+ m: serializeString(current.message),
358
+ p: optionsNode,
359
+ e: undefined,
360
+ a: undefined,
361
+ f: undefined,
362
+ b: undefined,
363
+ o: undefined,
364
+ };
365
+ }
366
+
367
+ async function generateErrorNode(
368
+ ctx: CrossParserContext,
369
+ id: number,
370
+ current: Error,
371
+ ): Promise<SerovalErrorNode> {
372
+ const options = getErrorOptions(ctx, current);
373
+ const optionsNode = options
374
+ ? await generateProperties(ctx, options)
375
+ : undefined;
376
+ return {
377
+ t: SerovalNodeType.Error,
378
+ i: id,
379
+ s: undefined,
380
+ l: undefined,
381
+ c: getErrorConstructorName(current),
382
+ m: serializeString(current.message),
383
+ p: optionsNode,
384
+ e: undefined,
385
+ a: undefined,
386
+ f: undefined,
387
+ b: undefined,
388
+ o: undefined,
389
+ };
390
+ }
391
+
392
+ async function generateHeadersNode(
393
+ ctx: CrossParserContext,
394
+ id: number,
395
+ current: Headers,
396
+ ): Promise<SerovalHeadersNode> {
397
+ assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
398
+ const items: Record<string, string> = {};
399
+ current.forEach((value, key) => {
400
+ items[key] = value;
401
+ });
402
+ return {
403
+ t: SerovalNodeType.Headers,
404
+ i: id,
405
+ s: undefined,
406
+ l: undefined,
407
+ c: undefined,
408
+ m: undefined,
409
+ p: undefined,
410
+ e: await generatePlainProperties(ctx, items),
411
+ a: undefined,
412
+ f: undefined,
413
+ b: undefined,
414
+ o: undefined,
415
+ };
416
+ }
417
+
418
+ async function generateFormDataNode(
419
+ ctx: CrossParserContext,
420
+ id: number,
421
+ current: FormData,
422
+ ): Promise<SerovalFormDataNode> {
423
+ assert(ctx.features & Feature.WebAPI, new UnsupportedTypeError(current));
424
+ const items: Record<string, FormDataEntryValue> = {};
425
+ current.forEach((value, key) => {
426
+ items[key] = value;
427
+ });
428
+ return {
429
+ t: SerovalNodeType.FormData,
430
+ i: id,
431
+ s: undefined,
432
+ l: undefined,
433
+ c: undefined,
434
+ m: undefined,
435
+ p: undefined,
436
+ e: await generatePlainProperties(ctx, items),
437
+ a: undefined,
438
+ f: undefined,
439
+ b: undefined,
440
+ o: undefined,
441
+ };
442
+ }
443
+
444
+ async function generateBoxedNode(
445
+ ctx: CrossParserContext,
446
+ id: number,
447
+ current: object,
448
+ ): Promise<SerovalBoxedNode> {
449
+ return {
450
+ t: SerovalNodeType.Boxed,
451
+ i: id,
452
+ s: undefined,
453
+ l: undefined,
454
+ c: undefined,
455
+ m: undefined,
456
+ p: undefined,
457
+ e: undefined,
458
+ a: undefined,
459
+ f: await crossParseAsync(ctx, current.valueOf()),
460
+ b: undefined,
461
+ o: undefined,
462
+ };
463
+ }
464
+
465
+ async function parseObject(
466
+ ctx: CrossParserContext,
467
+ current: object | null,
468
+ ): Promise<SerovalNode> {
469
+ if (!current) {
470
+ return NULL_NODE;
471
+ }
472
+ // Non-primitive values needs a reference ID
473
+ // mostly because the values themselves are stateful
474
+ const registeredID = ctx.refs.get(current);
475
+ if (registeredID != null) {
476
+ return createIndexedValueNode(registeredID);
477
+ }
478
+ const id = ctx.refs.size;
479
+ ctx.refs.set(current, id);
480
+ if (hasReferenceID(current)) {
481
+ return createReferenceNode(id, current);
482
+ }
483
+ if (Array.isArray(current)) {
484
+ return generateArrayNode(ctx, id, current);
485
+ }
486
+ switch (current.constructor) {
487
+ case Number:
488
+ case Boolean:
489
+ case String:
490
+ case BigInt:
491
+ case Function:
492
+ case Symbol:
493
+ return generateBoxedNode(ctx, id, current);
494
+ case Date:
495
+ return createDateNode(id, current as unknown as Date);
496
+ case RegExp:
497
+ 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
+ case Object:
530
+ return generateObjectNode(
531
+ ctx,
532
+ id,
533
+ current as Record<string, unknown>,
534
+ false,
535
+ );
536
+ case undefined:
537
+ return generateObjectNode(
538
+ ctx,
539
+ id,
540
+ current as Record<string, unknown>,
541
+ true,
542
+ );
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
+ case Error:
549
+ case EvalError:
550
+ case RangeError:
551
+ case ReferenceError:
552
+ case SyntaxError:
553
+ case TypeError:
554
+ case URIError:
555
+ 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
+ default:
569
+ break;
570
+ }
571
+ if (current instanceof AggregateError) {
572
+ if (ctx.features & Feature.AggregateError) {
573
+ return generateAggregateErrorNode(ctx, id, current);
574
+ }
575
+ return generateErrorNode(ctx, id, current);
576
+ }
577
+ if (current instanceof Error) {
578
+ return generateErrorNode(ctx, id, current);
579
+ }
580
+ if (current instanceof Promise) {
581
+ return generatePromiseNode(ctx, id, current);
582
+ }
583
+ // Generator functions don't have a global constructor
584
+ if (Symbol.iterator in current) {
585
+ return generateObjectNode(ctx, id, current, !!current.constructor);
586
+ }
587
+ throw new UnsupportedTypeError(current);
588
+ }
589
+
590
+ export default async function crossParseAsync<T>(
591
+ ctx: CrossParserContext,
592
+ current: T,
593
+ ): Promise<SerovalNode> {
594
+ switch (typeof current) {
595
+ case 'boolean':
596
+ return current ? TRUE_NODE : FALSE_NODE;
597
+ case 'undefined':
598
+ return UNDEFINED_NODE;
599
+ case 'string':
600
+ return createStringNode(current);
601
+ case 'number':
602
+ return createNumberNode(current);
603
+ case 'bigint':
604
+ return createBigIntNode(ctx, current);
605
+ case 'object':
606
+ return parseObject(ctx, current);
607
+ case 'symbol':
608
+ return createSymbolNode(ctx, current);
609
+ case 'function':
610
+ return createFunctionNode(ctx, current);
611
+ default:
612
+ throw new UnsupportedTypeError(current);
613
+ }
614
+ }
@@ -0,0 +1,102 @@
1
+ import type { Assignment, FlaggedObject } from '../assignments';
2
+ import { ALL_ENABLED } from '../compat';
3
+ import type { BaseParserContext } from '../context';
4
+ import type { SerovalNode } from '../types';
5
+
6
+ export interface CrossParserContextOptions {
7
+ scopeId?: string;
8
+ refs?: Map<unknown, number>;
9
+ disabledFeatures?: number;
10
+ }
11
+
12
+ export interface CrossParserContext {
13
+ scopeId?: string;
14
+ refs: Map<unknown, number>;
15
+ features: number;
16
+ }
17
+
18
+ export function createCrossParserContext(
19
+ options: CrossParserContextOptions = {},
20
+ ): CrossParserContext {
21
+ return {
22
+ scopeId: options.scopeId,
23
+ refs: options.refs || new Map<unknown, number>(),
24
+ features: ALL_ENABLED ^ (options.disabledFeatures || 0),
25
+ };
26
+ }
27
+
28
+ export function createCrossIndexedValue<T>(
29
+ ctx: CrossParserContext,
30
+ current: T,
31
+ ): number {
32
+ const ref = ctx.refs.get(current);
33
+ if (ref == null) {
34
+ const id = ctx.refs.size;
35
+ ctx.refs.set(current, id);
36
+ return id;
37
+ }
38
+ return ref;
39
+ }
40
+
41
+ export interface StreamingCrossParserContextOptions extends CrossParserContextOptions {
42
+ onParse: (node: SerovalNode, initial: boolean) => void;
43
+ onDone?: () => void;
44
+ }
45
+
46
+ export interface StreamingCrossParserContext extends CrossParserContext {
47
+ alive: boolean;
48
+ pending: number;
49
+ onParse(node: SerovalNode, initial: boolean): void;
50
+ onDone(): void;
51
+ }
52
+
53
+ export function createStreamingCrossParserContext(
54
+ options: StreamingCrossParserContextOptions,
55
+ ): StreamingCrossParserContext {
56
+ return {
57
+ alive: true,
58
+ pending: 0,
59
+ refs: options.refs || new Map<unknown, number>(),
60
+ features: ALL_ENABLED ^ (options.disabledFeatures || 0),
61
+ onParse: options.onParse,
62
+ onDone(): void {
63
+ if (options.onDone) {
64
+ options.onDone();
65
+ }
66
+ },
67
+ scopeId: options.scopeId,
68
+ };
69
+ }
70
+
71
+ export function pushPendingState(ctx: StreamingCrossParserContext): void {
72
+ ctx.pending++;
73
+ }
74
+
75
+ export function popPendingState(ctx: StreamingCrossParserContext): void {
76
+ if (--ctx.pending <= 0) {
77
+ ctx.onDone();
78
+ }
79
+ }
80
+
81
+ export interface CrossSerializerContext extends BaseParserContext {
82
+ stack: number[];
83
+ // Array of assignments to be done (used for recursion)
84
+ assignments: Assignment[];
85
+ // Object flags
86
+ flags: FlaggedObject[];
87
+ }
88
+
89
+ export interface CrossSerializerOptions {
90
+ features: number;
91
+ }
92
+
93
+ export function createCrossSerializerContext(
94
+ options: CrossSerializerOptions,
95
+ ): CrossSerializerContext {
96
+ return {
97
+ stack: [],
98
+ assignments: [],
99
+ features: options.features,
100
+ flags: [],
101
+ };
102
+ }