seroval 1.4.0 → 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 (48) hide show
  1. package/dist/cjs/development/index.cjs +553 -350
  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 +553 -350
  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/node.d.ts +1 -1
  28. package/dist/types/core/string.d.ts.map +1 -1
  29. package/dist/types/core/tree/index.d.ts +4 -1
  30. package/dist/types/core/tree/index.d.ts.map +1 -1
  31. package/dist/types/core/types.d.ts +6 -11
  32. package/dist/types/core/types.d.ts.map +1 -1
  33. package/package.json +1 -1
  34. package/src/core/base-primitives.ts +17 -18
  35. package/src/core/compat.ts +3 -1
  36. package/src/core/constants.ts +18 -4
  37. package/src/core/constructors.ts +2 -1
  38. package/src/core/context/async-parser.ts +102 -50
  39. package/src/core/context/deserializer.ts +269 -105
  40. package/src/core/context/parser.ts +12 -10
  41. package/src/core/context/serializer.ts +31 -36
  42. package/src/core/context/sync-parser.ts +149 -75
  43. package/src/core/cross/index.ts +2 -0
  44. package/src/core/errors.ts +33 -0
  45. package/src/core/node.ts +2 -2
  46. package/src/core/string.ts +3 -1
  47. package/src/core/tree/index.ts +10 -1
  48. package/src/core/types.ts +10 -19
@@ -101,22 +101,28 @@ export function createAsyncParserContext(
101
101
  }
102
102
 
103
103
  export class AsyncParsePluginContext {
104
- constructor(private _p: AsyncParserContext) {}
104
+ constructor(
105
+ private _p: AsyncParserContext,
106
+ private depth: number,
107
+ ) {}
105
108
 
106
109
  parse<T>(current: T): Promise<SerovalNode> {
107
- return parseAsync(this._p, current);
110
+ return parseAsync(this._p, this.depth, current);
108
111
  }
109
112
  }
110
113
 
111
114
  async function parseItems(
112
115
  ctx: AsyncParserContext,
116
+ depth: number,
113
117
  current: unknown[],
114
- ): Promise<SerovalNode[]> {
115
- const nodes = [];
118
+ ): Promise<(SerovalNode | 0)[]> {
119
+ const nodes: (SerovalNode | 0)[] = [];
116
120
  for (let i = 0, len = current.length; i < len; i++) {
117
121
  // For consistency in holes
118
122
  if (i in current) {
119
- nodes[i] = await parseAsync(ctx, current[i]);
123
+ nodes[i] = await parseAsync(ctx, depth, current[i]);
124
+ } else {
125
+ nodes[i] = 0;
120
126
  }
121
127
  }
122
128
  return nodes;
@@ -124,14 +130,16 @@ async function parseItems(
124
130
 
125
131
  async function parseArray(
126
132
  ctx: AsyncParserContext,
133
+ depth: number,
127
134
  id: number,
128
135
  current: unknown[],
129
136
  ): Promise<SerovalArrayNode> {
130
- return createArrayNode(id, current, await parseItems(ctx, current));
137
+ return createArrayNode(id, current, await parseItems(ctx, depth, current));
131
138
  }
132
139
 
133
140
  async function parseProperties(
134
141
  ctx: AsyncParserContext,
142
+ depth: number,
135
143
  properties: Record<string | symbol, unknown>,
136
144
  ): Promise<SerovalObjectRecordNode> {
137
145
  const entries = Object.entries(properties);
@@ -139,7 +147,7 @@ async function parseProperties(
139
147
  const valueNodes: SerovalNode[] = [];
140
148
  for (let i = 0, len = entries.length; i < len; i++) {
141
149
  keyNodes.push(serializeString(entries[i][0]));
142
- valueNodes.push(await parseAsync(ctx, entries[i][1]));
150
+ valueNodes.push(await parseAsync(ctx, depth, entries[i][1]));
143
151
  }
144
152
  // Check special properties
145
153
  if (SYM_ITERATOR in properties) {
@@ -149,6 +157,7 @@ async function parseProperties(
149
157
  parseIteratorFactory(ctx.base),
150
158
  await parseAsync(
151
159
  ctx,
160
+ depth,
152
161
  iteratorToSequence(properties as unknown as Iterable<unknown>),
153
162
  ),
154
163
  ),
@@ -161,6 +170,7 @@ async function parseProperties(
161
170
  parseAsyncIteratorFactory(ctx.base),
162
171
  await parseAsync(
163
172
  ctx,
173
+ depth,
164
174
  createStreamFromAsyncIterable(
165
175
  properties as unknown as AsyncIterable<unknown>,
166
176
  ),
@@ -181,12 +191,12 @@ async function parseProperties(
181
191
  return {
182
192
  k: keyNodes,
183
193
  v: valueNodes,
184
- s: keyNodes.length,
185
194
  };
186
195
  }
187
196
 
188
197
  async function parsePlainObject(
189
198
  ctx: AsyncParserContext,
199
+ depth: number,
190
200
  id: number,
191
201
  current: Record<string, unknown>,
192
202
  empty: boolean,
@@ -195,53 +205,62 @@ async function parsePlainObject(
195
205
  id,
196
206
  current,
197
207
  empty,
198
- await parseProperties(ctx, current),
208
+ await parseProperties(ctx, depth, current),
199
209
  );
200
210
  }
201
211
 
202
212
  // TODO: check if parseBoxedSync can be used
203
213
  async function parseBoxed(
204
214
  ctx: AsyncParserContext,
215
+ depth: number,
205
216
  id: number,
206
217
  current: object,
207
218
  ): Promise<SerovalBoxedNode> {
208
- return createBoxedNode(id, await parseAsync(ctx, current.valueOf()));
219
+ return createBoxedNode(id, await parseAsync(ctx, depth, current.valueOf()));
209
220
  }
210
221
 
211
222
  async function parseTypedArray(
212
223
  ctx: AsyncParserContext,
224
+ depth: number,
213
225
  id: number,
214
226
  current: TypedArrayValue,
215
227
  ): Promise<SerovalTypedArrayNode> {
216
228
  return createTypedArrayNode(
217
229
  id,
218
230
  current,
219
- await parseAsync(ctx, current.buffer),
231
+ await parseAsync(ctx, depth, current.buffer),
220
232
  );
221
233
  }
222
234
 
223
235
  async function parseBigIntTypedArray(
224
236
  ctx: AsyncParserContext,
237
+ depth: number,
225
238
  id: number,
226
239
  current: BigIntTypedArrayValue,
227
240
  ): Promise<SerovalBigIntTypedArrayNode> {
228
241
  return createBigIntTypedArrayNode(
229
242
  id,
230
243
  current,
231
- await parseAsync(ctx, current.buffer),
244
+ await parseAsync(ctx, depth, current.buffer),
232
245
  );
233
246
  }
234
247
 
235
248
  async function parseDataView(
236
249
  ctx: AsyncParserContext,
250
+ depth: number,
237
251
  id: number,
238
252
  current: DataView,
239
253
  ): Promise<SerovalDataViewNode> {
240
- return createDataViewNode(id, current, await parseAsync(ctx, current.buffer));
254
+ return createDataViewNode(
255
+ id,
256
+ current,
257
+ await parseAsync(ctx, depth, current.buffer),
258
+ );
241
259
  }
242
260
 
243
261
  async function parseError(
244
262
  ctx: AsyncParserContext,
263
+ depth: number,
245
264
  id: number,
246
265
  current: Error,
247
266
  ): Promise<SerovalErrorNode> {
@@ -249,12 +268,13 @@ async function parseError(
249
268
  return createErrorNode(
250
269
  id,
251
270
  current,
252
- options ? await parseProperties(ctx, options) : NIL,
271
+ options ? await parseProperties(ctx, depth, options) : NIL,
253
272
  );
254
273
  }
255
274
 
256
275
  async function parseAggregateError(
257
276
  ctx: AsyncParserContext,
277
+ depth: number,
258
278
  id: number,
259
279
  current: AggregateError,
260
280
  ): Promise<SerovalAggregateErrorNode> {
@@ -262,38 +282,41 @@ async function parseAggregateError(
262
282
  return createAggregateErrorNode(
263
283
  id,
264
284
  current,
265
- options ? await parseProperties(ctx, options) : NIL,
285
+ options ? await parseProperties(ctx, depth, options) : NIL,
266
286
  );
267
287
  }
268
288
 
269
289
  async function parseMap(
270
290
  ctx: AsyncParserContext,
291
+ depth: number,
271
292
  id: number,
272
293
  current: Map<unknown, unknown>,
273
294
  ): Promise<SerovalMapNode> {
274
295
  const keyNodes: SerovalNode[] = [];
275
296
  const valueNodes: SerovalNode[] = [];
276
297
  for (const [key, value] of current.entries()) {
277
- keyNodes.push(await parseAsync(ctx, key));
278
- valueNodes.push(await parseAsync(ctx, value));
298
+ keyNodes.push(await parseAsync(ctx, depth, key));
299
+ valueNodes.push(await parseAsync(ctx, depth, value));
279
300
  }
280
- return createMapNode(ctx.base, id, keyNodes, valueNodes, current.size);
301
+ return createMapNode(ctx.base, id, keyNodes, valueNodes);
281
302
  }
282
303
 
283
304
  async function parseSet(
284
305
  ctx: AsyncParserContext,
306
+ depth: number,
285
307
  id: number,
286
308
  current: Set<unknown>,
287
309
  ): Promise<SerovalSetNode> {
288
310
  const items: SerovalNode[] = [];
289
311
  for (const item of current.keys()) {
290
- items.push(await parseAsync(ctx, item));
312
+ items.push(await parseAsync(ctx, depth, item));
291
313
  }
292
- return createSetNode(id, current.size, items);
314
+ return createSetNode(id, items);
293
315
  }
294
316
 
295
317
  async function parsePlugin(
296
318
  ctx: AsyncParserContext,
319
+ depth: number,
297
320
  id: number,
298
321
  current: unknown,
299
322
  ): Promise<SerovalPluginNode | undefined> {
@@ -302,15 +325,16 @@ async function parsePlugin(
302
325
  for (let i = 0, len = currentPlugins.length; i < len; i++) {
303
326
  const plugin = currentPlugins[i];
304
327
  if (plugin.parse.async && plugin.test(current)) {
305
- if (ctx.child == null) {
306
- ctx.child = new AsyncParsePluginContext(ctx);
307
- }
308
328
  return createPluginNode(
309
329
  id,
310
330
  plugin.tag,
311
- await plugin.parse.async(current, ctx.child, {
312
- id,
313
- }),
331
+ await plugin.parse.async(
332
+ current,
333
+ new AsyncParsePluginContext(ctx, depth),
334
+ {
335
+ id,
336
+ },
337
+ ),
314
338
  );
315
339
  }
316
340
  }
@@ -320,6 +344,7 @@ async function parsePlugin(
320
344
 
321
345
  async function parsePromise(
322
346
  ctx: AsyncParserContext,
347
+ depth: number,
323
348
  id: number,
324
349
  current: Promise<unknown>,
325
350
  ): Promise<SerovalPromiseNode> {
@@ -334,8 +359,8 @@ async function parsePromise(
334
359
  NIL,
335
360
  NIL,
336
361
  NIL,
362
+ await parseAsync(ctx, depth, result),
337
363
  NIL,
338
- await parseAsync(ctx, result),
339
364
  NIL,
340
365
  NIL,
341
366
  );
@@ -343,6 +368,7 @@ async function parsePromise(
343
368
 
344
369
  function parseStreamHandle<T>(
345
370
  this: AsyncParserContext,
371
+ depth: number,
346
372
  id: number,
347
373
  current: Stream<T>,
348
374
  resolve: (value: SerovalNode[] | PromiseLike<SerovalNode[]>) => void,
@@ -353,7 +379,7 @@ function parseStreamHandle<T>(
353
379
  const cleanup = current.on({
354
380
  next: value => {
355
381
  markParserRef(this.base, id);
356
- parseAsync(this, value).then(
382
+ parseAsync(this, depth, value).then(
357
383
  data => {
358
384
  sequence.push(createStreamNextNode(id, data));
359
385
  },
@@ -365,7 +391,7 @@ function parseStreamHandle<T>(
365
391
  },
366
392
  throw: value => {
367
393
  markParserRef(this.base, id);
368
- parseAsync(this, value).then(
394
+ parseAsync(this, depth, value).then(
369
395
  data => {
370
396
  sequence.push(createStreamThrowNode(id, data));
371
397
  resolve(sequence);
@@ -379,7 +405,7 @@ function parseStreamHandle<T>(
379
405
  },
380
406
  return: value => {
381
407
  markParserRef(this.base, id);
382
- parseAsync(this, value).then(
408
+ parseAsync(this, depth, value).then(
383
409
  data => {
384
410
  sequence.push(createStreamReturnNode(id, data));
385
411
  resolve(sequence);
@@ -396,35 +422,40 @@ function parseStreamHandle<T>(
396
422
 
397
423
  async function parseStream(
398
424
  ctx: AsyncParserContext,
425
+ depth: number,
399
426
  id: number,
400
427
  current: Stream<unknown>,
401
428
  ): Promise<SerovalStreamConstructorNode> {
402
429
  return createStreamConstructorNode(
403
430
  id,
404
431
  parseSpecialReference(ctx.base, SpecialReference.StreamConstructor),
405
- await new Promise<SerovalNode[]>(parseStreamHandle.bind(ctx, id, current)),
432
+ await new Promise<SerovalNode[]>(
433
+ parseStreamHandle.bind(ctx, depth, id, current),
434
+ ),
406
435
  );
407
436
  }
408
437
 
409
438
  export async function parseObjectAsync(
410
439
  ctx: AsyncParserContext,
440
+ depth: number,
411
441
  id: number,
412
442
  current: object,
413
443
  ): Promise<SerovalNode> {
414
444
  if (Array.isArray(current)) {
415
- return parseArray(ctx, id, current);
445
+ return parseArray(ctx, depth, id, current);
416
446
  }
417
447
  if (isStream(current)) {
418
- return parseStream(ctx, id, current);
448
+ return parseStream(ctx, depth, id, current);
419
449
  }
420
450
  const currentClass = current.constructor;
421
451
  if (currentClass === OpaqueReference) {
422
452
  return parseAsync(
423
453
  ctx,
454
+ depth,
424
455
  (current as OpaqueReference<unknown, unknown>).replacement,
425
456
  );
426
457
  }
427
- const parsed = await parsePlugin(ctx, id, current);
458
+ const parsed = await parsePlugin(ctx, depth, id, current);
428
459
  if (parsed) {
429
460
  return parsed;
430
461
  }
@@ -432,6 +463,7 @@ export async function parseObjectAsync(
432
463
  case Object:
433
464
  return parsePlainObject(
434
465
  ctx,
466
+ depth,
435
467
  id,
436
468
  current as Record<string, unknown>,
437
469
  false,
@@ -439,14 +471,13 @@ export async function parseObjectAsync(
439
471
  case NIL:
440
472
  return parsePlainObject(
441
473
  ctx,
474
+ depth,
442
475
  id,
443
476
  current as Record<string, unknown>,
444
477
  true,
445
478
  );
446
479
  case Date:
447
480
  return createDateNode(id, current as unknown as Date);
448
- case RegExp:
449
- return createRegExpNode(id, current as unknown as RegExp);
450
481
  case Error:
451
482
  case EvalError:
452
483
  case RangeError:
@@ -454,12 +485,12 @@ export async function parseObjectAsync(
454
485
  case SyntaxError:
455
486
  case TypeError:
456
487
  case URIError:
457
- return parseError(ctx, id, current as unknown as Error);
488
+ return parseError(ctx, depth, id, current as unknown as Error);
458
489
  case Number:
459
490
  case Boolean:
460
491
  case String:
461
492
  case BigInt:
462
- return parseBoxed(ctx, id, current);
493
+ return parseBoxed(ctx, depth, id, current);
463
494
  case ArrayBuffer:
464
495
  return createArrayBufferNode(
465
496
  ctx.base,
@@ -475,21 +506,34 @@ export async function parseObjectAsync(
475
506
  case Uint8ClampedArray:
476
507
  case Float32Array:
477
508
  case Float64Array:
478
- return parseTypedArray(ctx, id, current as unknown as TypedArrayValue);
509
+ return parseTypedArray(
510
+ ctx,
511
+ depth,
512
+ id,
513
+ current as unknown as TypedArrayValue,
514
+ );
479
515
  case DataView:
480
- return parseDataView(ctx, id, current as unknown as DataView);
516
+ return parseDataView(ctx, depth, id, current as unknown as DataView);
481
517
  case Map:
482
- return parseMap(ctx, id, current as unknown as Map<unknown, unknown>);
518
+ return parseMap(
519
+ ctx,
520
+ depth,
521
+ id,
522
+ current as unknown as Map<unknown, unknown>,
523
+ );
483
524
  case Set:
484
- return parseSet(ctx, id, current as unknown as Set<unknown>);
525
+ return parseSet(ctx, depth, id, current as unknown as Set<unknown>);
485
526
  default:
486
527
  break;
487
528
  }
488
529
  // Promises
489
530
  if (currentClass === Promise || current instanceof Promise) {
490
- return parsePromise(ctx, id, current as unknown as Promise<unknown>);
531
+ return parsePromise(ctx, depth, id, current as unknown as Promise<unknown>);
491
532
  }
492
533
  const currentFeatures = ctx.base.features;
534
+ if (currentFeatures & Feature.RegExp && currentClass === RegExp) {
535
+ return createRegExpNode(id, current as unknown as RegExp);
536
+ }
493
537
  // BigInt Typed Arrays
494
538
  if (currentFeatures & Feature.BigIntTypedArray) {
495
539
  switch (currentClass) {
@@ -497,6 +541,7 @@ export async function parseObjectAsync(
497
541
  case BigUint64Array:
498
542
  return parseBigIntTypedArray(
499
543
  ctx,
544
+ depth,
500
545
  id,
501
546
  current as unknown as BigIntTypedArrayValue,
502
547
  );
@@ -509,30 +554,36 @@ export async function parseObjectAsync(
509
554
  typeof AggregateError !== 'undefined' &&
510
555
  (currentClass === AggregateError || current instanceof AggregateError)
511
556
  ) {
512
- return parseAggregateError(ctx, id, current as unknown as AggregateError);
557
+ return parseAggregateError(
558
+ ctx,
559
+ depth,
560
+ id,
561
+ current as unknown as AggregateError,
562
+ );
513
563
  }
514
564
  // Slow path. We only need to handle Errors and Iterators
515
565
  // since they have very broad implementations.
516
566
  if (current instanceof Error) {
517
- return parseError(ctx, id, current);
567
+ return parseError(ctx, depth, id, current);
518
568
  }
519
569
  // Generator functions don't have a global constructor
520
570
  // despite existing
521
571
  if (SYM_ITERATOR in current || SYM_ASYNC_ITERATOR in current) {
522
- return parsePlainObject(ctx, id, current, !!currentClass);
572
+ return parsePlainObject(ctx, depth, id, current, !!currentClass);
523
573
  }
524
574
  throw new SerovalUnsupportedTypeError(current);
525
575
  }
526
576
 
527
577
  export async function parseFunctionAsync(
528
578
  ctx: AsyncParserContext,
579
+ depth: number,
529
580
  current: unknown,
530
581
  ): Promise<SerovalNode> {
531
582
  const ref = getReferenceNode(ctx.base, current);
532
583
  if (ref.type !== ParserNodeType.Fresh) {
533
584
  return ref.value;
534
585
  }
535
- const plugin = await parsePlugin(ctx, ref.value, current);
586
+ const plugin = await parsePlugin(ctx, depth, ref.value, current);
536
587
  if (plugin) {
537
588
  return plugin;
538
589
  }
@@ -541,6 +592,7 @@ export async function parseFunctionAsync(
541
592
 
542
593
  export async function parseAsync<T>(
543
594
  ctx: AsyncParserContext,
595
+ depth: number,
544
596
  current: T,
545
597
  ): Promise<SerovalNode> {
546
598
  switch (typeof current) {
@@ -558,7 +610,7 @@ export async function parseAsync<T>(
558
610
  if (current) {
559
611
  const ref = getReferenceNode(ctx.base, current);
560
612
  return ref.type === 0
561
- ? await parseObjectAsync(ctx, ref.value, current as object)
613
+ ? await parseObjectAsync(ctx, depth + 1, ref.value, current as object)
562
614
  : ref.value;
563
615
  }
564
616
  return NULL_NODE;
@@ -566,7 +618,7 @@ export async function parseAsync<T>(
566
618
  case 'symbol':
567
619
  return parseWellKnownSymbol(ctx.base, current);
568
620
  case 'function':
569
- return parseFunctionAsync(ctx, current);
621
+ return parseFunctionAsync(ctx, depth, current);
570
622
  default:
571
623
  throw new SerovalUnsupportedTypeError(current);
572
624
  }
@@ -577,7 +629,7 @@ export async function parseTopAsync<T>(
577
629
  current: T,
578
630
  ): Promise<SerovalNode> {
579
631
  try {
580
- return await parseAsync(ctx, current);
632
+ return await parseAsync(ctx, 0, current);
581
633
  } catch (error) {
582
634
  throw error instanceof SerovalParserError
583
635
  ? error