seroval 0.4.0-alpha.11 → 0.4.0-alpha.13

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.
package/src/tree/async.ts CHANGED
@@ -10,14 +10,9 @@ import {
10
10
  TypedArrayValue,
11
11
  } from '../types';
12
12
  import {
13
- createBigIntNode,
14
- createBigIntTypedArrayNode,
15
- createDateNode,
16
- createPrimitiveNode,
17
- createReferenceNode,
18
- createRegExpNode,
19
- createTypedArrayNode,
20
13
  FALSE_NODE,
14
+ INFINITY_NODE,
15
+ NEG_INFINITY_NODE,
21
16
  NEG_ZERO_NODE,
22
17
  NULL_NODE,
23
18
  TRUE_NODE,
@@ -32,401 +27,338 @@ import {
32
27
  import {
33
28
  SerovalAggregateErrorNode,
34
29
  SerovalArrayNode,
30
+ SerovalBigIntNode,
31
+ SerovalBigIntTypedArrayNode,
32
+ SerovalDateNode,
35
33
  SerovalErrorNode,
36
34
  SerovalIterableNode,
37
35
  SerovalMapNode,
36
+ SerovalMapRecordNode,
38
37
  SerovalNode,
39
38
  SerovalNodeType,
40
39
  SerovalNullConstructorNode,
41
40
  SerovalObjectNode,
42
41
  SerovalObjectRecordNode,
42
+ SerovalPrimitiveNode,
43
43
  SerovalPromiseNode,
44
+ SerovalReferenceNode,
45
+ SerovalRegExpNode,
44
46
  SerovalSetNode,
47
+ SerovalTypedArrayNode,
45
48
  } from './types';
46
49
 
47
- async function serializePropertiesAsync(
48
- ctx: ParserContext,
49
- properties: Record<string, AsyncServerValue>,
50
- ): Promise<SerovalObjectRecordNode> {
51
- const keys = Object.keys(properties);
52
- const size = keys.length;
53
- const keyNodes = new Array<string>(size);
54
- const valueNodes = new Array<SerovalNode>(size);
55
- const deferredKeys = new Array<string>(size);
56
- const deferredValues = new Array<AsyncServerValue>(size);
57
- let deferredSize = 0;
58
- let nodesSize = 0;
59
- let item: AsyncServerValue;
60
- for (const key of keys) {
61
- item = properties[key];
62
- if (isIterable(item)) {
63
- deferredKeys[deferredSize] = key;
64
- deferredValues[deferredSize] = item;
65
- deferredSize++;
66
- } else {
67
- keyNodes[nodesSize] = key;
68
- valueNodes[nodesSize] = await generateTreeAsync(ctx, item);
69
- nodesSize++;
70
- }
71
- }
72
- for (let i = 0; i < deferredSize; i++) {
73
- keyNodes[nodesSize + i] = deferredKeys[i];
74
- valueNodes[nodesSize + i] = await generateTreeAsync(ctx, deferredValues[i]);
50
+ type ObjectLikeNode =
51
+ | SerovalObjectNode
52
+ | SerovalNullConstructorNode
53
+ | SerovalIterableNode
54
+ | SerovalPromiseNode;
55
+
56
+ type ObjectLikeValue =
57
+ | Record<string, AsyncServerValue>
58
+ | Iterable<AsyncServerValue>
59
+ | PromiseLike<AsyncServerValue>;
60
+
61
+ class AsyncParser {
62
+ ctx: ParserContext;
63
+
64
+ constructor(ctx: ParserContext) {
65
+ this.ctx = ctx;
75
66
  }
76
- return {
77
- k: keyNodes,
78
- v: valueNodes,
79
- s: size,
80
- };
81
- }
82
67
 
83
- async function generateSetNode(
84
- ctx: ParserContext,
85
- current: Set<AsyncServerValue>,
86
- id: number,
87
- ): Promise<SerovalSetNode> {
88
- assert(ctx.features & Feature.Set, 'Unsupported type "Set"');
89
- const len = current.size;
90
- const nodes = new Array<SerovalNode>(len);
91
- const deferred = new Array<AsyncServerValue>(len);
92
- let deferredSize = 0;
93
- let nodeSize = 0;
94
- for (const item of current.keys()) {
95
- // Iterables are lazy, so the evaluation must be deferred
96
- if (isIterable(item)) {
97
- deferred[deferredSize++] = item;
98
- } else {
99
- nodes[nodeSize++] = await generateTreeAsync(ctx, item);
68
+ async generateNodeList(
69
+ current: AsyncServerValue[],
70
+ ) {
71
+ const size = current.length;
72
+ const nodes = new Array<SerovalNode>(size);
73
+ const deferred = new Array<AsyncServerValue>(size);
74
+ let item: AsyncServerValue;
75
+ for (let i = 0; i < size; i++) {
76
+ if (i in current) {
77
+ item = current[i];
78
+ if (isIterable(item)) {
79
+ deferred[i] = item;
80
+ } else {
81
+ nodes[i] = await this.parse(item);
82
+ }
83
+ }
100
84
  }
85
+ for (let i = 0; i < size; i++) {
86
+ if (i in deferred) {
87
+ nodes[i] = await this.parse(deferred[i]);
88
+ }
89
+ }
90
+ return nodes;
101
91
  }
102
- // Parse deferred items
103
- for (let i = 0; i < deferredSize; i++) {
104
- nodes[nodeSize + i] = await generateTreeAsync(ctx, deferred[i]);
92
+
93
+ async generateArrayNode(
94
+ id: number,
95
+ current: AsyncServerValue[],
96
+ ): Promise<SerovalArrayNode> {
97
+ return new SerovalArrayNode(id, await this.generateNodeList(current));
105
98
  }
106
- return {
107
- t: SerovalNodeType.Set,
108
- i: id,
109
- a: nodes,
110
- s: undefined,
111
- l: undefined,
112
- m: undefined,
113
- c: undefined,
114
- d: undefined,
115
- n: undefined,
116
- };
117
- }
118
99
 
119
- async function generateMapNode(
120
- ctx: ParserContext,
121
- current: Map<AsyncServerValue, AsyncServerValue>,
122
- id: number,
123
- ): Promise<SerovalMapNode> {
124
- assert(ctx.features & Feature.Map, 'Unsupported type "Map"');
125
- const len = current.size;
126
- const keyNodes = new Array<SerovalNode>(len);
127
- const valueNodes = new Array<SerovalNode>(len);
128
- const deferredKey = new Array<AsyncServerValue>(len);
129
- const deferredValue = new Array<AsyncServerValue>(len);
130
- let deferredSize = 0;
131
- let nodeSize = 0;
132
- for (const [key, value] of current.entries()) {
133
- // Either key or value might be an iterable
134
- if (isIterable(key) || isIterable(value)) {
135
- deferredKey[deferredSize] = key;
136
- deferredValue[deferredSize] = value;
137
- deferredSize++;
138
- } else {
139
- keyNodes[nodeSize] = await generateTreeAsync(ctx, key);
140
- valueNodes[nodeSize] = await generateTreeAsync(ctx, value);
141
- nodeSize++;
100
+ async generateMapNode(
101
+ id: number,
102
+ current: Map<AsyncServerValue, AsyncServerValue>,
103
+ ): Promise<SerovalMapNode> {
104
+ assert(this.ctx.features & Feature.Map, 'Unsupported type "Map"');
105
+ const len = current.size;
106
+ const keyNodes = new Array<SerovalNode>(len);
107
+ const valueNodes = new Array<SerovalNode>(len);
108
+ const deferredKey = new Array<AsyncServerValue>(len);
109
+ const deferredValue = new Array<AsyncServerValue>(len);
110
+ let deferredSize = 0;
111
+ let nodeSize = 0;
112
+ for (const [key, value] of current.entries()) {
113
+ // Either key or value might be an iterable
114
+ if (isIterable(key) || isIterable(value)) {
115
+ deferredKey[deferredSize] = key;
116
+ deferredValue[deferredSize] = value;
117
+ deferredSize++;
118
+ } else {
119
+ keyNodes[nodeSize] = await this.parse(key);
120
+ valueNodes[nodeSize] = await this.parse(value);
121
+ nodeSize++;
122
+ }
142
123
  }
124
+ for (let i = 0; i < deferredSize; i++) {
125
+ keyNodes[nodeSize + i] = await this.parse(deferredKey[i]);
126
+ valueNodes[nodeSize + i] = await this.parse(deferredValue[i]);
127
+ }
128
+ return new SerovalMapNode(id, new SerovalMapRecordNode(keyNodes, valueNodes, len));
143
129
  }
144
- for (let i = 0; i < deferredSize; i++) {
145
- keyNodes[nodeSize + i] = await generateTreeAsync(ctx, deferredKey[i]);
146
- valueNodes[nodeSize + i] = await generateTreeAsync(ctx, deferredValue[i]);
147
- }
148
- return {
149
- t: SerovalNodeType.Map,
150
- i: id,
151
- a: undefined,
152
- s: undefined,
153
- l: undefined,
154
- m: undefined,
155
- c: undefined,
156
- d: { k: keyNodes, v: valueNodes, s: len },
157
- n: undefined,
158
- };
159
- }
160
130
 
161
- async function generateNodeList(
162
- ctx: ParserContext,
163
- current: AsyncServerValue[],
164
- ) {
165
- const size = current.length;
166
- const nodes = new Array<SerovalNode>(size);
167
- const deferred = new Array<AsyncServerValue>(size);
168
- let item: AsyncServerValue;
169
- for (let i = 0; i < size; i++) {
170
- if (i in current) {
171
- item = current[i];
131
+ async generateSetNode(
132
+ id: number,
133
+ current: Set<AsyncServerValue>,
134
+ ): Promise<SerovalSetNode> {
135
+ assert(this.ctx.features & Feature.Set, 'Unsupported type "Set"');
136
+ const len = current.size;
137
+ const nodes = new Array<SerovalNode>(len);
138
+ const deferred = new Array<AsyncServerValue>(len);
139
+ let deferredSize = 0;
140
+ let nodeSize = 0;
141
+ for (const item of current.keys()) {
142
+ // Iterables are lazy, so the evaluation must be deferred
172
143
  if (isIterable(item)) {
173
- deferred[i] = item;
144
+ deferred[deferredSize++] = item;
174
145
  } else {
175
- nodes[i] = await generateTreeAsync(ctx, item);
146
+ nodes[nodeSize++] = await this.parse(item);
176
147
  }
177
148
  }
178
- }
179
- for (let i = 0; i < size; i++) {
180
- if (i in deferred) {
181
- nodes[i] = await generateTreeAsync(ctx, deferred[i]);
149
+ // Parse deferred items
150
+ for (let i = 0; i < deferredSize; i++) {
151
+ nodes[nodeSize + i] = await this.parse(deferred[i]);
182
152
  }
153
+ return new SerovalSetNode(id, nodes);
183
154
  }
184
- return nodes;
185
- }
186
-
187
- async function generateArrayNode(
188
- ctx: ParserContext,
189
- current: AsyncServerValue[],
190
- id: number,
191
- ): Promise<SerovalArrayNode> {
192
- return {
193
- t: SerovalNodeType.Array,
194
- i: id,
195
- a: await generateNodeList(ctx, current),
196
- s: undefined,
197
- l: undefined,
198
- m: undefined,
199
- c: undefined,
200
- d: undefined,
201
- n: undefined,
202
- };
203
- }
204
-
205
- async function generateAggregateErrorNode(
206
- ctx: ParserContext,
207
- current: AggregateError,
208
- id: number,
209
- ): Promise<SerovalAggregateErrorNode> {
210
- const options = getErrorOptions(current);
211
- const optionsNode = options
212
- ? await serializePropertiesAsync(ctx, options)
213
- : undefined;
214
- return {
215
- t: SerovalNodeType.AggregateError,
216
- i: id,
217
- a: undefined,
218
- s: undefined,
219
- l: undefined,
220
- m: current.message,
221
- c: undefined,
222
- d: optionsNode,
223
- n: await generateTreeAsync(ctx, current.errors as AsyncServerValue),
224
- };
225
- }
226
-
227
- async function generateErrorNode(
228
- ctx: ParserContext,
229
- current: Error,
230
- id: number,
231
- ): Promise<SerovalErrorNode> {
232
- const options = getErrorOptions(current);
233
- const optionsNode = options
234
- ? await serializePropertiesAsync(ctx, options)
235
- : undefined;
236
- return {
237
- t: SerovalNodeType.Error,
238
- i: id,
239
- a: undefined,
240
- s: undefined,
241
- l: undefined,
242
- m: current.message,
243
- c: getErrorConstructor(current),
244
- d: optionsNode,
245
- n: undefined,
246
- };
247
- }
248
155
 
249
- async function generateIterableNode(
250
- ctx: ParserContext,
251
- current: Iterable<AsyncServerValue>,
252
- id: number,
253
- ): Promise<SerovalIterableNode> {
254
- assert(ctx.features & Feature.SymbolIterator, 'Unsupported type "Iterable"');
255
- const options = getIterableOptions(current);
256
- return {
257
- t: SerovalNodeType.Iterable,
258
- i: id,
259
- s: undefined,
260
- l: undefined,
261
- m: undefined,
262
- c: undefined,
263
- // Parse options first before the items
264
- d: options
265
- ? await serializePropertiesAsync(ctx, options as Record<string, AsyncServerValue>)
266
- : undefined,
267
- a: await generateNodeList(ctx, Array.from(current)),
268
- n: undefined,
269
- };
270
- }
156
+ async generateProperties(
157
+ properties: Record<string, AsyncServerValue>,
158
+ ): Promise<SerovalObjectRecordNode> {
159
+ const keys = Object.keys(properties);
160
+ const size = keys.length;
161
+ const keyNodes = new Array<string>(size);
162
+ const valueNodes = new Array<SerovalNode>(size);
163
+ const deferredKeys = new Array<string>(size);
164
+ const deferredValues = new Array<AsyncServerValue>(size);
165
+ let deferredSize = 0;
166
+ let nodesSize = 0;
167
+ let item: AsyncServerValue;
168
+ for (const key of keys) {
169
+ item = properties[key];
170
+ if (isIterable(item)) {
171
+ deferredKeys[deferredSize] = key;
172
+ deferredValues[deferredSize] = item;
173
+ deferredSize++;
174
+ } else {
175
+ keyNodes[nodesSize] = key;
176
+ valueNodes[nodesSize] = await this.parse(item);
177
+ nodesSize++;
178
+ }
179
+ }
180
+ for (let i = 0; i < deferredSize; i++) {
181
+ keyNodes[nodesSize + i] = deferredKeys[i];
182
+ valueNodes[nodesSize + i] = await this.parse(deferredValues[i]);
183
+ }
184
+ return new SerovalObjectRecordNode(keyNodes, valueNodes, size);
185
+ }
271
186
 
272
- type ObjectLikeNode =
273
- | SerovalObjectNode
274
- | SerovalNullConstructorNode
275
- | SerovalIterableNode
276
- | SerovalPromiseNode;
187
+ async generateIterableNode(
188
+ id: number,
189
+ current: Iterable<AsyncServerValue>,
190
+ ): Promise<SerovalIterableNode> {
191
+ assert(this.ctx.features & Feature.SymbolIterator, 'Unsupported type "Iterable"');
192
+ const options = getIterableOptions(current);
193
+ return new SerovalIterableNode(
194
+ id,
195
+ // Parse options first before the items
196
+ options
197
+ ? await this.generateProperties(options as Record<string, AsyncServerValue>)
198
+ : undefined,
199
+ await this.generateNodeList(Array.from(current)),
200
+ );
201
+ }
277
202
 
278
- type ObjectLikeValue =
279
- | Record<string, AsyncServerValue>
280
- | Iterable<AsyncServerValue>
281
- | PromiseLike<AsyncServerValue>;
203
+ async generatePromiseNode(
204
+ id: number,
205
+ current: PromiseLike<AsyncServerValue>,
206
+ ): Promise<SerovalPromiseNode> {
207
+ assert(this.ctx.features & Feature.Promise, 'Unsupported type "Promise"');
208
+ return current.then(async (value) => new SerovalPromiseNode(id, await this.parse(value)));
209
+ }
282
210
 
283
- async function generateObjectNode(
284
- ctx: ParserContext,
285
- current: ObjectLikeValue,
286
- id: number,
287
- empty: boolean,
288
- ): Promise<ObjectLikeNode> {
289
- if (Symbol.iterator in current) {
290
- return generateIterableNode(ctx, current, id);
211
+ async generateObjectNode(
212
+ id: number,
213
+ current: ObjectLikeValue,
214
+ empty: boolean,
215
+ ): Promise<ObjectLikeNode> {
216
+ if (Symbol.iterator in current) {
217
+ return this.generateIterableNode(id, current);
218
+ }
219
+ if ('then' in current && typeof current.then === 'function') {
220
+ return this.generatePromiseNode(id, current as PromiseLike<AsyncServerValue>);
221
+ }
222
+ const properties = await this.generateProperties(current as Record<string, AsyncServerValue>);
223
+ if (empty) {
224
+ return new SerovalNullConstructorNode(id, properties);
225
+ }
226
+ return new SerovalObjectNode(id, properties);
291
227
  }
292
- if ('then' in current && typeof current.then === 'function') {
293
- return generatePromiseNode(ctx, current as PromiseLike<AsyncServerValue>, id);
228
+
229
+ async generateAggregateErrorNode(
230
+ id: number,
231
+ current: AggregateError,
232
+ ): Promise<SerovalAggregateErrorNode> {
233
+ const options = getErrorOptions(current);
234
+ const optionsNode = options
235
+ ? await this.generateProperties(options)
236
+ : undefined;
237
+ return new SerovalAggregateErrorNode(
238
+ id,
239
+ current.message,
240
+ optionsNode,
241
+ await this.parse(current.errors),
242
+ );
294
243
  }
295
- return {
296
- t: empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,
297
- i: id,
298
- s: undefined,
299
- l: undefined,
300
- m: undefined,
301
- c: undefined,
302
- d: await serializePropertiesAsync(ctx, current as Record<string, AsyncServerValue>),
303
- a: undefined,
304
- n: undefined,
305
- };
306
- }
307
244
 
308
- async function generatePromiseNode(
309
- ctx: ParserContext,
310
- current: PromiseLike<AsyncServerValue>,
311
- id: number,
312
- ): Promise<SerovalPromiseNode> {
313
- assert(ctx.features & Feature.Promise, 'Unsupported type "Promise"');
314
- return current.then(async (value) => ({
315
- t: SerovalNodeType.Promise,
316
- i: id,
317
- s: undefined,
318
- l: undefined,
319
- m: undefined,
320
- c: undefined,
321
- // Parse options first before the items
322
- d: undefined,
323
- a: undefined,
324
- n: await generateTreeAsync(ctx, value),
325
- }));
326
- }
245
+ async generateErrorNode(
246
+ id: number,
247
+ current: Error,
248
+ ): Promise<SerovalErrorNode> {
249
+ const options = getErrorOptions(current);
250
+ const optionsNode = options
251
+ ? await this.generateProperties(options)
252
+ : undefined;
253
+ return new SerovalErrorNode(id, getErrorConstructor(current), current.message, optionsNode);
254
+ }
327
255
 
328
- async function generateTreeAsync(
329
- ctx: ParserContext,
330
- current: AsyncServerValue,
331
- ): Promise<SerovalNode> {
332
- switch (typeof current) {
333
- case 'boolean':
334
- return current ? TRUE_NODE : FALSE_NODE;
335
- case 'undefined':
336
- return UNDEFINED_NODE;
337
- case 'string':
338
- return createPrimitiveNode(quote(current));
339
- case 'number':
340
- if (Object.is(current, -0)) {
341
- return NEG_ZERO_NODE;
342
- }
343
- if (Object.is(current, Infinity)) {
344
- return createPrimitiveNode('1/0');
345
- }
346
- if (Object.is(current, -Infinity)) {
347
- return createPrimitiveNode('-1/0');
348
- }
349
- return createPrimitiveNode(current);
350
- case 'bigint':
351
- return createBigIntNode(ctx, current);
352
- case 'object': {
353
- if (!current) {
354
- return NULL_NODE;
355
- }
356
- // Non-primitive values needs a reference ID
357
- // mostly because the values themselves are stateful
358
- const id = createRef(ctx, current, true);
359
- if (ctx.markedRefs[id]) {
360
- return createReferenceNode(id);
361
- }
362
- if (Array.isArray(current)) {
363
- return generateArrayNode(ctx, current, id);
364
- }
365
- switch (current.constructor) {
366
- case Date:
367
- return createDateNode(id, current as Date);
368
- case RegExp:
369
- return createRegExpNode(id, current as RegExp);
370
- case Promise:
371
- return generatePromiseNode(ctx, current as Promise<AsyncServerValue>, id);
372
- case Map:
373
- return generateMapNode(ctx, current as Map<AsyncServerValue, AsyncServerValue>, id);
374
- case Set:
375
- return generateSetNode(ctx, current as Set<AsyncServerValue>, id);
376
- case Object:
377
- return generateObjectNode(ctx, current as Record<string, AsyncServerValue>, id, false);
378
- case undefined:
379
- return generateObjectNode(ctx, current as Record<string, AsyncServerValue>, id, true);
380
- case Int8Array:
381
- case Int16Array:
382
- case Int32Array:
383
- case Uint8Array:
384
- case Uint16Array:
385
- case Uint32Array:
386
- case Uint8ClampedArray:
387
- case Float32Array:
388
- case Float64Array:
389
- return createTypedArrayNode(ctx, id, current as TypedArrayValue);
390
- case BigInt64Array:
391
- case BigUint64Array:
392
- return createBigIntTypedArrayNode(ctx, id, current as BigIntTypedArrayValue);
393
- case AggregateError:
394
- if (ctx.features & Feature.AggregateError) {
395
- return generateAggregateErrorNode(ctx, current as AggregateError, id);
396
- }
397
- return generateErrorNode(ctx, current as AggregateError, id);
398
- case Error:
399
- case EvalError:
400
- case RangeError:
401
- case ReferenceError:
402
- case SyntaxError:
403
- case TypeError:
404
- case URIError:
405
- return generateErrorNode(ctx, current as Error, id);
406
- default:
407
- break;
408
- }
409
- if (current instanceof AggregateError && ctx.features & Feature.AggregateError) {
410
- return generateAggregateErrorNode(ctx, current, id);
411
- }
412
- if (current instanceof Error) {
413
- return generateErrorNode(ctx, current, id);
414
- }
415
- if (current instanceof Promise) {
416
- return generatePromiseNode(ctx, current as PromiseLike<AsyncServerValue>, id);
417
- }
418
- // Generator functions don't have a global constructor
419
- if (Symbol.iterator in current) {
420
- return generateIterableNode(ctx, current, id);
421
- }
422
- // For Promise-like objects
423
- if ('then' in current && typeof current.then === 'function') {
424
- return generatePromiseNode(ctx, current as PromiseLike<AsyncServerValue>, id);
256
+ async parse(current: AsyncServerValue): Promise<SerovalNode> {
257
+ switch (typeof current) {
258
+ case 'boolean':
259
+ return current ? TRUE_NODE : FALSE_NODE;
260
+ case 'undefined':
261
+ return UNDEFINED_NODE;
262
+ case 'string':
263
+ return new SerovalPrimitiveNode(quote(current));
264
+ case 'number':
265
+ if (Object.is(current, -0)) {
266
+ return NEG_ZERO_NODE;
267
+ }
268
+ if (Object.is(current, Infinity)) {
269
+ return INFINITY_NODE;
270
+ }
271
+ if (Object.is(current, -Infinity)) {
272
+ return NEG_INFINITY_NODE;
273
+ }
274
+ return new SerovalPrimitiveNode(current);
275
+ case 'bigint':
276
+ assert(this.ctx.features & Feature.BigInt, 'Unsupported type "BigInt"');
277
+ return new SerovalBigIntNode(current);
278
+ case 'object': {
279
+ if (!current) {
280
+ return NULL_NODE;
281
+ }
282
+ // Non-primitive values needs a reference ID
283
+ // mostly because the values themselves are stateful
284
+ const id = createRef(this.ctx, current, true);
285
+ if (this.ctx.markedRefs[id]) {
286
+ return new SerovalReferenceNode(id);
287
+ }
288
+ if (Array.isArray(current)) {
289
+ return this.generateArrayNode(id, current);
290
+ }
291
+ switch (current.constructor) {
292
+ case Date:
293
+ return new SerovalDateNode(id, current as Date);
294
+ case RegExp:
295
+ return new SerovalRegExpNode(id, current as RegExp);
296
+ case Promise:
297
+ return this.generatePromiseNode(id, current as Promise<AsyncServerValue>);
298
+ case Int8Array:
299
+ case Int16Array:
300
+ case Int32Array:
301
+ case Uint8Array:
302
+ case Uint16Array:
303
+ case Uint32Array:
304
+ case Uint8ClampedArray:
305
+ case Float32Array:
306
+ case Float64Array:
307
+ assert(this.ctx.features & Feature.TypedArray, `Unsupported value type "${current.constructor.name}"`);
308
+ return new SerovalTypedArrayNode(id, current as TypedArrayValue);
309
+ case BigInt64Array:
310
+ case BigUint64Array:
311
+ assert(
312
+ this.ctx.features & (Feature.BigIntTypedArray),
313
+ `Unsupported value type "${current.constructor.name}"`,
314
+ );
315
+ return new SerovalBigIntTypedArrayNode(id, current as BigIntTypedArrayValue);
316
+ case Map:
317
+ return this.generateMapNode(id, current as Map<AsyncServerValue, AsyncServerValue>);
318
+ case Set:
319
+ return this.generateSetNode(id, current as Set<AsyncServerValue>);
320
+ case Object:
321
+ return this.generateObjectNode(id, current as Record<string, AsyncServerValue>, false);
322
+ case undefined:
323
+ return this.generateObjectNode(id, current as Record<string, AsyncServerValue>, true);
324
+ case AggregateError:
325
+ if (this.ctx.features & Feature.AggregateError) {
326
+ return this.generateAggregateErrorNode(id, current as AggregateError);
327
+ }
328
+ return this.generateErrorNode(id, current as AggregateError);
329
+ case Error:
330
+ case EvalError:
331
+ case RangeError:
332
+ case ReferenceError:
333
+ case SyntaxError:
334
+ case TypeError:
335
+ case URIError:
336
+ return this.generateErrorNode(id, current as Error);
337
+ default:
338
+ break;
339
+ }
340
+ if (current instanceof AggregateError && this.ctx.features & Feature.AggregateError) {
341
+ return this.generateAggregateErrorNode(id, current);
342
+ }
343
+ if (current instanceof Error) {
344
+ return this.generateErrorNode(id, current);
345
+ }
346
+ if (current instanceof Promise) {
347
+ return this.generatePromiseNode(id, current);
348
+ }
349
+ // Generator functions don't have a global constructor
350
+ if (Symbol.iterator in current) {
351
+ return this.generateIterableNode(id, current);
352
+ }
353
+ // For Promise-like objects
354
+ if ('then' in current && typeof current.then === 'function') {
355
+ return this.generatePromiseNode(id, current as PromiseLike<AsyncServerValue>);
356
+ }
357
+ throw new Error('Unsupported type');
425
358
  }
426
- throw new Error('Unsupported type');
359
+ default:
360
+ throw new Error('Unsupported type');
427
361
  }
428
- default:
429
- throw new Error('Unsupported type');
430
362
  }
431
363
  }
432
364
 
@@ -434,7 +366,7 @@ export default async function parseAsync(
434
366
  ctx: ParserContext,
435
367
  current: AsyncServerValue,
436
368
  ) {
437
- const result = await generateTreeAsync(ctx, current);
369
+ const result = await new AsyncParser(ctx).parse(current);
438
370
  const isObject = result.t === SerovalNodeType.Object
439
371
  || result.t === SerovalNodeType.Iterable;
440
372
  return [result, createRef(ctx, current, false), isObject] as const;