seroval 0.7.0 → 0.8.0

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 (41) hide show
  1. package/dist/cjs/development/index.cjs +1109 -1039
  2. package/dist/cjs/development/index.cjs.map +4 -4
  3. package/dist/cjs/production/index.cjs +3 -3
  4. package/dist/esm/development/index.mjs +1109 -1039
  5. package/dist/esm/development/index.mjs.map +4 -4
  6. package/dist/esm/production/index.mjs +3 -3
  7. package/dist/types/assert.d.ts +1 -1
  8. package/dist/types/context.d.ts +2 -2
  9. package/dist/types/index.d.ts +3 -4
  10. package/dist/types/string.d.ts +1 -1
  11. package/dist/types/tree/UnsupportedTypeError.d.ts +3 -0
  12. package/dist/types/tree/async.d.ts +3 -3
  13. package/dist/types/tree/constants.d.ts +11 -0
  14. package/dist/types/tree/deserialize.d.ts +2 -2
  15. package/dist/types/tree/primitives.d.ts +9 -15
  16. package/dist/types/tree/serialize.d.ts +2 -2
  17. package/dist/types/tree/shared.d.ts +10 -8
  18. package/dist/types/tree/sync.d.ts +3 -3
  19. package/dist/types/tree/types.d.ts +64 -71
  20. package/dist/types/tree/web-api.d.ts +2 -2
  21. package/dist/types/types.d.ts +4 -4
  22. package/package.json +10 -8
  23. package/src/assert.ts +2 -2
  24. package/src/compat.ts +0 -1
  25. package/src/context.ts +10 -7
  26. package/src/get-identifier.ts +1 -1
  27. package/src/index.ts +35 -26
  28. package/src/string.ts +2 -2
  29. package/src/tree/UnsupportedTypeError.ts +8 -0
  30. package/src/tree/async.ts +245 -233
  31. package/src/tree/constants.ts +72 -0
  32. package/src/tree/deserialize.ts +96 -93
  33. package/src/tree/primitives.ts +81 -134
  34. package/src/tree/reference.ts +4 -3
  35. package/src/tree/serialize.ts +251 -197
  36. package/src/tree/shared.ts +31 -22
  37. package/src/tree/symbols.ts +13 -13
  38. package/src/tree/sync.ts +226 -198
  39. package/src/tree/types.ts +74 -93
  40. package/src/tree/web-api.ts +10 -7
  41. package/src/types.ts +7 -3
@@ -1,26 +1,26 @@
1
1
  /* eslint-disable @typescript-eslint/no-use-before-define */
2
2
  import { Feature } from '../compat';
3
- import {
3
+ import type {
4
4
  SerializationContext,
5
5
  Assignment,
6
+ } from '../context';
7
+ import {
6
8
  getRefParam,
7
9
  markRef,
8
10
  } from '../context';
11
+ import { serializeConstant } from './constants';
9
12
  import { GLOBAL_KEY } from './reference';
10
13
  import { isValidIdentifier } from './shared';
11
14
  import { SYMBOL_STRING } from './symbols';
12
- import {
15
+ import type {
13
16
  SerovalAggregateErrorNode,
14
17
  SerovalArrayNode,
15
18
  SerovalBigIntTypedArrayNode,
16
19
  SerovalErrorNode,
17
- SerovalIterableNode,
18
20
  SerovalMapNode,
19
21
  SerovalNode,
20
- SerovalNodeType,
21
22
  SerovalNullConstructorNode,
22
23
  SerovalObjectNode,
23
- SerovalObjectRecordNode,
24
24
  SerovalPromiseNode,
25
25
  SerovalIndexedValueNode,
26
26
  SerovalSetNode,
@@ -36,6 +36,14 @@ import {
36
36
  SerovalURLSearchParamsNode,
37
37
  SerovalReferenceNode,
38
38
  SerovalFormDataNode,
39
+ SerovalObjectRecordNode,
40
+ SerovalObjectRecordKey,
41
+ SerovalBoxedNode,
42
+ SerovalWKSymbolNode,
43
+ } from './types';
44
+ import {
45
+ SerovalNodeType,
46
+ SerovalObjectRecordSpecialKey,
39
47
  } from './types';
40
48
 
41
49
  function getAssignmentExpression(assignment: Assignment): string {
@@ -53,8 +61,8 @@ function getAssignmentExpression(assignment: Assignment): string {
53
61
  }
54
62
  }
55
63
 
56
- function mergeAssignments(assignments: Assignment[]) {
57
- const newAssignments = [];
64
+ function mergeAssignments(assignments: Assignment[]): Assignment[] {
65
+ const newAssignments: Assignment[] = [];
58
66
  let current = assignments[0];
59
67
  let prev = current;
60
68
  let item: Assignment;
@@ -128,7 +136,7 @@ function mergeAssignments(assignments: Assignment[]) {
128
136
  return newAssignments;
129
137
  }
130
138
 
131
- function resolveAssignments(assignments: Assignment[]) {
139
+ function resolveAssignments(assignments: Assignment[]): string | undefined {
132
140
  if (assignments.length) {
133
141
  let result = '';
134
142
  const merged = mergeAssignments(assignments);
@@ -140,7 +148,7 @@ function resolveAssignments(assignments: Assignment[]) {
140
148
  return undefined;
141
149
  }
142
150
 
143
- export function resolvePatches(ctx: SerializationContext) {
151
+ export function resolvePatches(ctx: SerializationContext): string | undefined {
144
152
  return resolveAssignments(ctx.assignments);
145
153
  }
146
154
 
@@ -154,7 +162,7 @@ function createAssignment(
154
162
  ctx: SerializationContext,
155
163
  source: string,
156
164
  value: string,
157
- ) {
165
+ ): void {
158
166
  ctx.assignments.push({
159
167
  t: 'index',
160
168
  s: source,
@@ -167,7 +175,7 @@ function createAddAssignment(
167
175
  ctx: SerializationContext,
168
176
  ref: number,
169
177
  value: string,
170
- ) {
178
+ ): void {
171
179
  ctx.assignments.push({
172
180
  t: 'add',
173
181
  s: getRefParam(ctx, ref),
@@ -181,7 +189,7 @@ function createSetAssignment(
181
189
  ref: number,
182
190
  key: string,
183
191
  value: string,
184
- ) {
192
+ ): void {
185
193
  ctx.assignments.push({
186
194
  t: 'set',
187
195
  s: getRefParam(ctx, ref),
@@ -195,7 +203,7 @@ function createAppendAssignment(
195
203
  ref: number,
196
204
  key: string,
197
205
  value: string,
198
- ) {
206
+ ): void {
199
207
  ctx.assignments.push({
200
208
  t: 'append',
201
209
  s: getRefParam(ctx, ref),
@@ -209,7 +217,7 @@ function createArrayAssign(
209
217
  ref: number,
210
218
  index: number | string,
211
219
  value: string,
212
- ) {
220
+ ): void {
213
221
  createAssignment(ctx, getRefParam(ctx, ref) + '[' + index + ']', value);
214
222
  }
215
223
 
@@ -218,7 +226,7 @@ function createObjectAssign(
218
226
  ref: number,
219
227
  key: string,
220
228
  value: string,
221
- ) {
229
+ ): void {
222
230
  markRef(ctx, ref);
223
231
  createAssignment(ctx, getRefParam(ctx, ref) + '.' + key, value);
224
232
  }
@@ -227,7 +235,7 @@ function assignIndexedValue(
227
235
  ctx: SerializationContext,
228
236
  index: number,
229
237
  value: string,
230
- ) {
238
+ ): string {
231
239
  if (ctx.markedRefs.has(index)) {
232
240
  return getRefParam(ctx, index) + '=' + value;
233
241
  }
@@ -241,33 +249,31 @@ function isIndexedValueInStack(
241
249
  return node.t === SerovalNodeType.IndexedValue && ctx.stack.includes(node.i);
242
250
  }
243
251
 
244
- type SerovalNodeListNode =
245
- | SerovalArrayNode
246
- | SerovalIterableNode;
247
-
248
- function serializeNodeList(
252
+ function serializeArray(
249
253
  ctx: SerializationContext,
250
- node: SerovalNodeListNode,
251
- ) {
254
+ node: SerovalArrayNode,
255
+ ): string {
256
+ const id = node.i;
257
+ ctx.stack.push(id);
252
258
  // This is different than Map and Set
253
259
  // because we also need to serialize
254
260
  // the holes of the Array
255
- const size = node.l;
256
261
  let values = '';
257
- let item: SerovalNode;
262
+ let item: SerovalNode | undefined;
258
263
  let isHoley = false;
259
- for (let i = 0; i < size; i++) {
264
+ const list = node.a;
265
+ for (let i = 0, len = node.l; i < len; i++) {
260
266
  if (i !== 0) {
261
267
  // Add an empty item
262
268
  values += ',';
263
269
  }
264
- item = node.a[i];
270
+ item = list[i];
265
271
  // Check if index is a hole
266
272
  if (item) {
267
273
  // Check if item is a parent
268
274
  if (isIndexedValueInStack(ctx, item)) {
269
- markRef(ctx, node.i);
270
- createArrayAssign(ctx, node.i, i, getRefParam(ctx, item.i));
275
+ markRef(ctx, id);
276
+ createArrayAssign(ctx, id, i, getRefParam(ctx, item.i));
271
277
  isHoley = true;
272
278
  } else {
273
279
  values += serializeTree(ctx, item);
@@ -277,30 +283,46 @@ function serializeNodeList(
277
283
  isHoley = true;
278
284
  }
279
285
  }
280
- return '[' + values + (isHoley ? ',]' : ']');
286
+ ctx.stack.pop();
287
+ return assignIndexedValue(ctx, id, '[' + values + (isHoley ? ',]' : ']'));
281
288
  }
282
289
 
283
- function serializeArray(
290
+ function getIterableAccess(ctx: SerializationContext): string {
291
+ return ctx.features & Feature.ArrayPrototypeValues
292
+ ? '.values()'
293
+ : '[Symbol.iterator]()';
294
+ }
295
+
296
+ function serializeIterable(
284
297
  ctx: SerializationContext,
285
- node: SerovalArrayNode,
286
- ) {
287
- ctx.stack.push(node.i);
288
- const result = serializeNodeList(ctx, node);
289
- ctx.stack.pop();
290
- return assignIndexedValue(ctx, node.i, result);
298
+ node: SerovalNode,
299
+ ): string {
300
+ const parent = ctx.stack;
301
+ ctx.stack = [];
302
+ let serialized = serializeTree(ctx, node) + getIterableAccess(ctx);
303
+ ctx.stack = parent;
304
+ if (ctx.features & Feature.ArrowFunction) {
305
+ serialized = '[Symbol.iterator]:()=>' + serialized;
306
+ } else if (ctx.features & Feature.MethodShorthand) {
307
+ serialized = '[Symbol.iterator](){return ' + serialized + '}';
308
+ } else {
309
+ serialized = '[Symbol.iterator]:function(){return ' + serialized + '}';
310
+ }
311
+ return serialized;
291
312
  }
292
313
 
293
314
  function serializeProperties(
294
315
  ctx: SerializationContext,
295
316
  sourceID: number,
296
317
  node: SerovalObjectRecordNode,
297
- ) {
298
- if (node.s === 0) {
318
+ ): string {
319
+ const len = node.s;
320
+ if (len === 0) {
299
321
  return '{}';
300
322
  }
301
323
  let result = '';
302
324
  ctx.stack.push(sourceID);
303
- let key: string;
325
+ let key: SerovalObjectRecordKey;
304
326
  let val: SerovalNode;
305
327
  let check: number;
306
328
  let isIdentifier: boolean;
@@ -308,27 +330,34 @@ function serializeProperties(
308
330
  let hasPrev = false;
309
331
  const keys = node.k;
310
332
  const values = node.v;
311
- for (let i = 0, len = node.s; i < len; i++) {
333
+ for (let i = 0; i < len; i++) {
312
334
  key = keys[i];
313
335
  val = values[i];
314
- check = Number(key);
315
- // Test if key is a valid number or JS identifier
316
- // so that we don't have to serialize the key and wrap with brackets
317
- isIdentifier = check >= 0 || isValidIdentifier(key);
318
- if (isIndexedValueInStack(ctx, val)) {
319
- refParam = getRefParam(ctx, val.i);
320
- if (isIdentifier && Number.isNaN(check)) {
321
- markRef(ctx, sourceID);
322
- createObjectAssign(ctx, sourceID, key, refParam);
323
- } else {
324
- markRef(ctx, sourceID);
325
- createArrayAssign(ctx, sourceID, isIdentifier ? key : ('"' + key + '"'), refParam);
326
- }
327
- } else {
328
- result += (hasPrev ? ',' : '')
329
- + (isIdentifier ? key : ('"' + key + '"'))
330
- + ':' + serializeTree(ctx, val);
331
- hasPrev = true;
336
+ switch (key) {
337
+ case SerovalObjectRecordSpecialKey.SymbolIterator:
338
+ result += (hasPrev ? ',' : '') + serializeIterable(ctx, val);
339
+ hasPrev = true;
340
+ break;
341
+ default:
342
+ check = Number(key);
343
+ // Test if key is a valid number or JS identifier
344
+ // so that we don't have to serialize the key and wrap with brackets
345
+ isIdentifier = check >= 0 || isValidIdentifier(key);
346
+ if (isIndexedValueInStack(ctx, val)) {
347
+ refParam = getRefParam(ctx, val.i);
348
+ markRef(ctx, sourceID);
349
+ if (isIdentifier && Number.isNaN(check)) {
350
+ createObjectAssign(ctx, sourceID, key, refParam);
351
+ } else {
352
+ createArrayAssign(ctx, sourceID, isIdentifier ? key : ('"' + key + '"'), refParam);
353
+ }
354
+ } else {
355
+ result += (hasPrev ? ',' : '')
356
+ + (isIdentifier ? key : ('"' + key + '"'))
357
+ + ':' + serializeTree(ctx, val);
358
+ hasPrev = true;
359
+ }
360
+ break;
332
361
  }
333
362
  }
334
363
  ctx.stack.pop();
@@ -340,7 +369,7 @@ function serializeWithObjectAssign(
340
369
  value: SerovalObjectRecordNode,
341
370
  id: number,
342
371
  serialized: string,
343
- ) {
372
+ ): string {
344
373
  const fields = serializeProperties(ctx, id, value);
345
374
  if (fields !== '{}') {
346
375
  return 'Object.assign(' + serialized + ',' + fields + ')';
@@ -352,33 +381,47 @@ function serializeAssignments(
352
381
  ctx: SerializationContext,
353
382
  sourceID: number,
354
383
  node: SerovalObjectRecordNode,
355
- ) {
384
+ ): string | undefined {
356
385
  ctx.stack.push(sourceID);
357
386
  const mainAssignments: Assignment[] = [];
358
- let parentStack: number[];
359
- let refParam: string;
360
- let key: string;
361
- let check: number;
387
+ let key: SerovalObjectRecordKey;
388
+ let value: SerovalNode;
362
389
  let parentAssignment: Assignment[];
363
- let isIdentifier: boolean;
364
390
  const keys = node.k;
365
391
  const values = node.v;
366
392
  for (let i = 0, len = node.s; i < len; i++) {
367
- parentStack = ctx.stack;
368
- ctx.stack = [];
369
- refParam = serializeTree(ctx, values[i]);
370
- ctx.stack = parentStack;
371
393
  key = keys[i];
372
- check = Number(key);
394
+ value = values[i];
373
395
  parentAssignment = ctx.assignments;
374
396
  ctx.assignments = mainAssignments;
375
- // Test if key is a valid number or JS identifier
376
- // so that we don't have to serialize the key and wrap with brackets
377
- isIdentifier = check >= 0 || isValidIdentifier(key);
378
- if (isIdentifier && Number.isNaN(check)) {
379
- createObjectAssign(ctx, sourceID, key, refParam);
380
- } else {
381
- createArrayAssign(ctx, sourceID, isIdentifier ? key : ('"' + key + '"'), refParam);
397
+ switch (key) {
398
+ case SerovalObjectRecordSpecialKey.SymbolIterator: {
399
+ const parent = ctx.stack;
400
+ ctx.stack = [];
401
+ const serialized = serializeTree(ctx, value) + getIterableAccess(ctx);
402
+ ctx.stack = parent;
403
+ createArrayAssign(
404
+ ctx,
405
+ sourceID,
406
+ 'Symbol.iterator',
407
+ ctx.features & Feature.ArrowFunction
408
+ ? '()=>' + serialized
409
+ : 'function(){return ' + serialized + '}',
410
+ );
411
+ }
412
+ break;
413
+ default: {
414
+ const serialized = serializeTree(ctx, value);
415
+ const check = Number(key);
416
+ // Test if key is a valid number or JS identifier
417
+ // so that we don't have to serialize the key and wrap with brackets
418
+ const isIdentifier = check >= 0 || isValidIdentifier(key);
419
+ if (isIdentifier && Number.isNaN(check)) {
420
+ createObjectAssign(ctx, sourceID, key, serialized);
421
+ } else {
422
+ createArrayAssign(ctx, sourceID, isIdentifier ? key : ('"' + key + '"'), serialized);
423
+ }
424
+ }
382
425
  }
383
426
  ctx.assignments = parentAssignment;
384
427
  }
@@ -391,7 +434,7 @@ function serializeDictionary(
391
434
  i: number,
392
435
  d: SerovalObjectRecordNode | undefined,
393
436
  init: string,
394
- ) {
437
+ ): string {
395
438
  if (d) {
396
439
  if (ctx.features & Feature.ObjectAssign) {
397
440
  init = serializeWithObjectAssign(ctx, d, i, init);
@@ -406,36 +449,40 @@ function serializeDictionary(
406
449
  return assignIndexedValue(ctx, i, init);
407
450
  }
408
451
 
452
+ const NULL_CONSTRUCTOR = 'Object.create(null)';
453
+
409
454
  function serializeNullConstructor(
410
455
  ctx: SerializationContext,
411
456
  node: SerovalNullConstructorNode,
412
- ) {
413
- return serializeDictionary(ctx, node.i, node.d, 'Object.create(null)');
457
+ ): string {
458
+ return serializeDictionary(ctx, node.i, node.d, NULL_CONSTRUCTOR);
414
459
  }
415
460
 
416
461
  function serializeObject(
417
462
  ctx: SerializationContext,
418
463
  node: SerovalObjectNode,
419
- ) {
464
+ ): string {
420
465
  return assignIndexedValue(ctx, node.i, serializeProperties(ctx, node.i, node.d));
421
466
  }
422
467
 
423
468
  function serializeSet(
424
469
  ctx: SerializationContext,
425
470
  node: SerovalSetNode,
426
- ) {
471
+ ): string {
427
472
  let serialized = 'new Set';
428
473
  const size = node.l;
474
+ const id = node.i;
429
475
  if (size) {
430
476
  let result = '';
431
- ctx.stack.push(node.i);
432
477
  let item: SerovalNode;
433
478
  let hasPrev = false;
479
+ const items = node.a;
480
+ ctx.stack.push(id);
434
481
  for (let i = 0; i < size; i++) {
435
- item = node.a[i];
482
+ item = items[i];
436
483
  if (isIndexedValueInStack(ctx, item)) {
437
- markRef(ctx, node.i);
438
- createAddAssignment(ctx, node.i, getRefParam(ctx, item.i));
484
+ markRef(ctx, id);
485
+ createAddAssignment(ctx, id, getRefParam(ctx, item.i));
439
486
  } else {
440
487
  // Push directly
441
488
  result += (hasPrev ? ',' : '') + serializeTree(ctx, item);
@@ -447,38 +494,42 @@ function serializeSet(
447
494
  serialized += '([' + result + '])';
448
495
  }
449
496
  }
450
- return assignIndexedValue(ctx, node.i, serialized);
497
+ return assignIndexedValue(ctx, id, serialized);
451
498
  }
452
499
 
453
500
  function serializeMap(
454
501
  ctx: SerializationContext,
455
502
  node: SerovalMapNode,
456
- ) {
503
+ ): string {
457
504
  let serialized = 'new Map';
458
- if (node.d.s) {
505
+ const size = node.d.s;
506
+ const id = node.i;
507
+ if (size) {
459
508
  let result = '';
460
- ctx.stack.push(node.i);
461
509
  let key: SerovalNode;
462
510
  let val: SerovalNode;
463
511
  let keyRef: string;
464
512
  let valueRef: string;
465
513
  let parent: number[];
466
514
  let hasPrev = false;
467
- for (let i = 0; i < node.d.s; i++) {
515
+ const keys = node.d.k;
516
+ const vals = node.d.v;
517
+ ctx.stack.push(id);
518
+ for (let i = 0; i < size; i++) {
468
519
  // Check if key is a parent
469
- key = node.d.k[i];
470
- val = node.d.v[i];
520
+ key = keys[i];
521
+ val = vals[i];
471
522
  if (isIndexedValueInStack(ctx, key)) {
472
523
  // Create reference for the map instance
473
- keyRef = getRefParam(ctx, key.i);
474
- markRef(ctx, node.i);
524
+ keyRef = getRefParam(ctx, id);
525
+ markRef(ctx, id);
475
526
  // Check if value is a parent
476
527
  if (isIndexedValueInStack(ctx, val)) {
477
528
  valueRef = getRefParam(ctx, val.i);
478
529
  // Register an assignment since
479
530
  // both key and value are a parent of this
480
531
  // Map instance
481
- createSetAssignment(ctx, node.i, keyRef, valueRef);
532
+ createSetAssignment(ctx, id, keyRef, valueRef);
482
533
  } else {
483
534
  // Reset the stack
484
535
  // This is required because the serialized
@@ -487,17 +538,17 @@ function serializeMap(
487
538
  // assignment
488
539
  parent = ctx.stack;
489
540
  ctx.stack = [];
490
- createSetAssignment(ctx, node.i, keyRef, serializeTree(ctx, val));
541
+ createSetAssignment(ctx, id, keyRef, serializeTree(ctx, val));
491
542
  ctx.stack = parent;
492
543
  }
493
544
  } else if (isIndexedValueInStack(ctx, val)) {
494
545
  // Create ref for the Map instance
495
546
  valueRef = getRefParam(ctx, val.i);
496
- markRef(ctx, node.i);
547
+ markRef(ctx, id);
497
548
  // Reset stack for the key serialization
498
549
  parent = ctx.stack;
499
550
  ctx.stack = [];
500
- createSetAssignment(ctx, node.i, serializeTree(ctx, key), valueRef);
551
+ createSetAssignment(ctx, id, serializeTree(ctx, key), valueRef);
501
552
  ctx.stack = parent;
502
553
  } else {
503
554
  result += (hasPrev ? ',[' : '[') + serializeTree(ctx, key) + ',' + serializeTree(ctx, val) + ']';
@@ -512,67 +563,71 @@ function serializeMap(
512
563
  serialized += '([' + result + '])';
513
564
  }
514
565
  }
515
- return assignIndexedValue(ctx, node.i, serialized);
566
+ return assignIndexedValue(ctx, id, serialized);
516
567
  }
517
568
 
518
569
  function serializeAggregateError(
519
570
  ctx: SerializationContext,
520
571
  node: SerovalAggregateErrorNode,
521
- ) {
572
+ ): string {
522
573
  // Serialize the required arguments
523
- ctx.stack.push(node.i);
574
+ const id = node.i;
575
+ ctx.stack.push(id);
524
576
  const serialized = 'new AggregateError([],"' + node.m + '")';
525
577
  ctx.stack.pop();
526
578
  // `AggregateError` might've been extended
527
579
  // either through class or custom properties
528
580
  // Make sure to assign extra properties
529
- return serializeDictionary(ctx, node.i, node.d, serialized);
581
+ return serializeDictionary(ctx, id, node.d, serialized);
530
582
  }
531
583
 
532
584
  function serializeError(
533
585
  ctx: SerializationContext,
534
586
  node: SerovalErrorNode,
535
- ) {
536
- const serialized = 'new ' + node.c + '("' + node.m + '")';
537
- return serializeDictionary(ctx, node.i, node.d, serialized);
587
+ ): string {
588
+ return serializeDictionary(ctx, node.i, node.d, 'new ' + node.c + '("' + node.m + '")');
538
589
  }
539
590
 
540
591
  function serializePromise(
541
592
  ctx: SerializationContext,
542
593
  node: SerovalPromiseNode,
543
- ) {
594
+ ): string {
544
595
  let serialized: string;
545
596
  // Check if resolved value is a parent expression
546
- if (isIndexedValueInStack(ctx, node.f)) {
597
+ const fulfilled = node.f;
598
+ const id = node.i;
599
+ if (isIndexedValueInStack(ctx, fulfilled)) {
547
600
  // A Promise trick, reference the value
548
601
  // inside the `then` expression so that
549
602
  // the Promise evaluates after the parent
550
603
  // has initialized
551
- const ref = getRefParam(ctx, node.f.i);
604
+ const ref = getRefParam(ctx, fulfilled.i);
552
605
  if (ctx.features & Feature.ArrowFunction) {
553
606
  serialized = 'Promise.resolve().then(()=>' + ref + ')';
554
607
  } else {
555
608
  serialized = 'Promise.resolve().then(function(){return ' + ref + '})';
556
609
  }
557
610
  } else {
558
- ctx.stack.push(node.i);
559
- const result = serializeTree(ctx, node.f);
611
+ ctx.stack.push(id);
612
+ const result = serializeTree(ctx, fulfilled);
560
613
  ctx.stack.pop();
561
614
  // just inline the value/reference here
562
615
  serialized = 'Promise.resolve(' + result + ')';
563
616
  }
564
- return assignIndexedValue(ctx, node.i, serialized);
617
+ return assignIndexedValue(ctx, id, serialized);
565
618
  }
566
619
 
567
620
  function serializeArrayBuffer(
568
621
  ctx: SerializationContext,
569
622
  node: SerovalArrayBufferNode,
570
- ) {
623
+ ): string {
571
624
  let result = 'new Uint8Array(';
572
- if (node.s.length) {
625
+ const buffer = node.s;
626
+ const len = buffer.length;
627
+ if (len) {
573
628
  result += '[';
574
- for (let i = 0, len = node.s.length; i < len; i++) {
575
- result += ((i > 0) ? ',' : '') + node.s[i];
629
+ for (let i = 0; i < len; i++) {
630
+ result += ((i > 0) ? ',' : '') + buffer[i];
576
631
  }
577
632
  result += ']';
578
633
  }
@@ -582,121 +637,115 @@ function serializeArrayBuffer(
582
637
  function serializeTypedArray(
583
638
  ctx: SerializationContext,
584
639
  node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
585
- ) {
586
- const args = serializeTree(ctx, node.f) + ',' + node.b + ',' + node.l;
587
- return assignIndexedValue(ctx, node.i, 'new ' + node.c + '(' + args + ')');
588
- }
589
-
590
- function serializeIterable(
591
- ctx: SerializationContext,
592
- node: SerovalIterableNode,
593
- ) {
594
- const parent = ctx.stack;
595
- ctx.stack = [];
596
- const values = serializeNodeList(ctx, node);
597
- ctx.stack = parent;
598
- let serialized = values;
599
- if (ctx.features & Feature.ArrayPrototypeValues) {
600
- serialized += '.values()';
601
- } else {
602
- serialized += '[Symbol.iterator]()';
603
- }
604
- if (ctx.features & Feature.ArrowFunction) {
605
- serialized = '{[Symbol.iterator]:()=>' + serialized + '}';
606
- } else if (ctx.features & Feature.MethodShorthand) {
607
- serialized = '{[Symbol.iterator](){return ' + serialized + '}}';
608
- } else {
609
- serialized = '{[Symbol.iterator]:function(){return ' + serialized + '}}';
610
- }
611
- return serializeDictionary(ctx, node.i, node.d, serialized);
640
+ ): string {
641
+ return assignIndexedValue(
642
+ ctx,
643
+ node.i,
644
+ 'new ' + node.c + '(' + serializeTree(ctx, node.f) + ',' + node.b + ',' + node.l + ')',
645
+ );
612
646
  }
613
647
 
614
648
  function serializeDate(
615
649
  ctx: SerializationContext,
616
650
  node: SerovalDateNode,
617
- ) {
651
+ ): string {
618
652
  return assignIndexedValue(ctx, node.i, 'new Date("' + node.s + '")');
619
653
  }
620
654
 
621
655
  function serializeRegExp(
622
656
  ctx: SerializationContext,
623
657
  node: SerovalRegExpNode,
624
- ) {
658
+ ): string {
625
659
  return assignIndexedValue(ctx, node.i, '/' + node.c + '/' + node.m);
626
660
  }
627
661
 
628
662
  function serializeURL(
629
663
  ctx: SerializationContext,
630
664
  node: SerovalURLNode,
631
- ) {
665
+ ): string {
632
666
  return assignIndexedValue(ctx, node.i, 'new URL("' + node.s + '")');
633
667
  }
634
668
 
635
669
  function serializeURLSearchParams(
636
670
  ctx: SerializationContext,
637
671
  node: SerovalURLSearchParamsNode,
638
- ) {
639
- return assignIndexedValue(ctx, node.i, node.s ? 'new URLSearchParams("' + node.s + '")' : 'new URLSearchParams');
672
+ ): string {
673
+ return assignIndexedValue(
674
+ ctx,
675
+ node.i,
676
+ node.s ? 'new URLSearchParams("' + node.s + '")' : 'new URLSearchParams',
677
+ );
640
678
  }
641
679
 
642
680
  function serializeReference(
643
681
  ctx: SerializationContext,
644
682
  node: SerovalReferenceNode,
645
- ) {
683
+ ): string {
646
684
  return assignIndexedValue(ctx, node.i, GLOBAL_KEY + '.get("' + node.s + '")');
647
685
  }
648
686
 
649
687
  function serializeDataView(
650
688
  ctx: SerializationContext,
651
689
  node: SerovalDataViewNode,
652
- ) {
653
- const args = serializeTree(ctx, node.f) + ',' + node.b + ',' + node.l;
654
- return assignIndexedValue(ctx, node.i, 'new DataView(' + args + ')');
690
+ ): string {
691
+ return assignIndexedValue(
692
+ ctx,
693
+ node.i,
694
+ 'new DataView(' + serializeTree(ctx, node.f) + ',' + node.b + ',' + node.l + ')',
695
+ );
655
696
  }
656
697
 
657
698
  function serializeBlob(
658
699
  ctx: SerializationContext,
659
700
  node: SerovalBlobNode,
660
- ) {
661
- const args = '[' + serializeTree(ctx, node.f) + '],{type:"' + node.c + '"}';
662
- return assignIndexedValue(ctx, node.i, 'new Blob(' + args + ')');
701
+ ): string {
702
+ return assignIndexedValue(
703
+ ctx,
704
+ node.i,
705
+ 'new Blob([' + serializeTree(ctx, node.f) + '],{type:"' + node.c + '"})',
706
+ );
663
707
  }
664
708
 
665
709
  function serializeFile(
666
710
  ctx: SerializationContext,
667
711
  node: SerovalFileNode,
668
- ) {
669
- const options = '{type:"' + node.c + '",lastModified:' + node.b + '}';
670
- const args = '[' + serializeTree(ctx, node.f) + '],"' + node.m + '",' + options;
671
- return assignIndexedValue(ctx, node.i, 'new File(' + args + ')');
712
+ ): string {
713
+ return assignIndexedValue(
714
+ ctx,
715
+ node.i,
716
+ 'new File([' + serializeTree(ctx, node.f) + '],"' + node.m + '",{type:"' + node.c + '",lastModified:' + node.b + '})',
717
+ );
672
718
  }
673
719
 
674
720
  function serializeHeaders(
675
721
  ctx: SerializationContext,
676
722
  node: SerovalHeadersNode,
677
- ) {
678
- return assignIndexedValue(ctx, node.i, 'new Headers(' + serializeProperties(ctx, node.i, node.d) + ')');
723
+ ): string {
724
+ return assignIndexedValue(
725
+ ctx,
726
+ node.i,
727
+ 'new Headers(' + serializeProperties(ctx, node.i, node.d) + ')',
728
+ );
679
729
  }
680
730
 
681
731
  function serializeFormDataEntries(
682
732
  ctx: SerializationContext,
683
733
  node: SerovalFormDataNode,
684
- ) {
685
- ctx.stack.push(node.i);
686
- const mainAssignments: Assignment[] = [];
687
- let parentStack: number[];
734
+ ): string | undefined {
688
735
  let value: string;
689
736
  let key: string;
737
+ const keys = node.d.k;
738
+ const vals = node.d.v;
739
+ const id = node.i;
740
+ const mainAssignments: Assignment[] = [];
690
741
  let parentAssignment: Assignment[];
691
- for (let i = 0; i < node.d.s; i++) {
692
- parentStack = ctx.stack;
693
- ctx.stack = [];
694
- value = serializeTree(ctx, node.d.v[i]);
695
- key = node.d.k[i];
696
- ctx.stack = parentStack;
742
+ ctx.stack.push(id);
743
+ for (let i = 0, len = node.d.s; i < len; i++) {
744
+ key = keys[i];
745
+ value = serializeTree(ctx, vals[i]);
697
746
  parentAssignment = ctx.assignments;
698
747
  ctx.assignments = mainAssignments;
699
- createAppendAssignment(ctx, node.i, '"' + key + '"', value);
748
+ createAppendAssignment(ctx, id, '"' + key + '"', value);
700
749
  ctx.assignments = parentAssignment;
701
750
  }
702
751
  ctx.stack.pop();
@@ -706,17 +755,34 @@ function serializeFormDataEntries(
706
755
  function serializeFormData(
707
756
  ctx: SerializationContext,
708
757
  node: SerovalFormDataNode,
709
- ) {
710
- if (node.d.s) {
711
- markRef(ctx, node.i);
758
+ ): string {
759
+ const size = node.d.s;
760
+ const id = node.i;
761
+ if (size) {
762
+ markRef(ctx, id);
712
763
  }
713
- const result = assignIndexedValue(ctx, node.i, 'new FormData()');
714
- if (node.d.s) {
715
- return '(' + result + ',' + serializeFormDataEntries(ctx, node) + getRefParam(ctx, node.i) + ')';
764
+ const result = assignIndexedValue(ctx, id, 'new FormData()');
765
+ if (size) {
766
+ const entries = serializeFormDataEntries(ctx, node);
767
+ return '(' + result + ',' + (entries == null ? '' : entries) + getRefParam(ctx, id) + ')';
716
768
  }
717
769
  return result;
718
770
  }
719
771
 
772
+ function serializeBoxed(
773
+ ctx: SerializationContext,
774
+ node: SerovalBoxedNode,
775
+ ): string {
776
+ return assignIndexedValue(ctx, node.i, 'Object(' + serializeTree(ctx, node.f) + ')');
777
+ }
778
+
779
+ function serializeWKSymbol(
780
+ ctx: SerializationContext,
781
+ node: SerovalWKSymbolNode,
782
+ ): string {
783
+ return assignIndexedValue(ctx, node.i, SYMBOL_STRING[node.s]);
784
+ }
785
+
720
786
  export default function serializeTree(
721
787
  ctx: SerializationContext,
722
788
  node: SerovalNode,
@@ -726,20 +792,8 @@ export default function serializeTree(
726
792
  return '' + node.s;
727
793
  case SerovalNodeType.String:
728
794
  return '"' + node.s + '"';
729
- case SerovalNodeType.Boolean:
730
- return node.s ? '!0' : '!1';
731
- case SerovalNodeType.Undefined:
732
- return 'void 0';
733
- case SerovalNodeType.Null:
734
- return 'null';
735
- case SerovalNodeType.NegativeZero:
736
- return '-0';
737
- case SerovalNodeType.Infinity:
738
- return '1/0';
739
- case SerovalNodeType.NegativeInfinity:
740
- return '-1/0';
741
- case SerovalNodeType.NaN:
742
- return 'NaN';
795
+ case SerovalNodeType.Constant:
796
+ return serializeConstant(node);
743
797
  case SerovalNodeType.BigInt:
744
798
  return node.s + 'n';
745
799
  case SerovalNodeType.IndexedValue:
@@ -769,12 +823,10 @@ export default function serializeTree(
769
823
  return serializeAggregateError(ctx, node);
770
824
  case SerovalNodeType.Error:
771
825
  return serializeError(ctx, node);
772
- case SerovalNodeType.Iterable:
773
- return serializeIterable(ctx, node);
774
826
  case SerovalNodeType.Promise:
775
827
  return serializePromise(ctx, node);
776
828
  case SerovalNodeType.WKSymbol:
777
- return SYMBOL_STRING[node.s];
829
+ return serializeWKSymbol(ctx, node);
778
830
  case SerovalNodeType.URL:
779
831
  return serializeURL(ctx, node);
780
832
  case SerovalNodeType.URLSearchParams:
@@ -789,7 +841,9 @@ export default function serializeTree(
789
841
  return serializeHeaders(ctx, node);
790
842
  case SerovalNodeType.FormData:
791
843
  return serializeFormData(ctx, node);
844
+ case SerovalNodeType.Boxed:
845
+ return serializeBoxed(ctx, node);
792
846
  default:
793
- throw new Error('Unsupported type');
847
+ throw new Error('invariant');
794
848
  }
795
849
  }