seroval 0.4.0-alpha.9 → 0.4.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.
@@ -7,7 +7,6 @@ import {
7
7
  markRef,
8
8
  } from '../context';
9
9
  import quote from '../quote';
10
- import { isReferenceInStack } from './shared';
11
10
  import {
12
11
  SerovalAggregateErrorNode,
13
12
  SerovalArrayNode,
@@ -20,18 +19,19 @@ import {
20
19
  SerovalNullConstructorNode,
21
20
  SerovalObjectRecordNode,
22
21
  SerovalPromiseNode,
22
+ SerovalReferenceNode,
23
23
  SerovalSetNode,
24
24
  SerovalTypedArrayNode,
25
25
  } from './types';
26
26
 
27
27
  function getAssignmentExpression(assignment: Assignment): string {
28
- switch (assignment.type) {
28
+ switch (assignment.t) {
29
29
  case 'index':
30
- return `${assignment.source}=${assignment.value}`;
30
+ return assignment.s + '=' + assignment.v;
31
31
  case 'map':
32
- return `${assignment.source}.set(${assignment.key},${assignment.value})`;
32
+ return assignment.s + '.set(' + assignment.k + ',' + assignment.v + ')';
33
33
  case 'set':
34
- return `${assignment.source}.add(${assignment.value})`;
34
+ return assignment.s + '.add(' + assignment.v + ')';
35
35
  default:
36
36
  return '';
37
37
  }
@@ -41,31 +41,34 @@ function mergeAssignments(assignments: Assignment[]) {
41
41
  const newAssignments = [];
42
42
  let current = assignments[0];
43
43
  let prev = current;
44
+ let item: Assignment;
44
45
  for (let i = 1, len = assignments.length; i < len; i++) {
45
- const item = assignments[i];
46
- if (item.type === prev.type) {
47
- if (item.type === 'index' && item.value === prev.value) {
46
+ item = assignments[i];
47
+ if (item.t === prev.t) {
48
+ if (item.t === 'index' && item.v === prev.v) {
48
49
  // Merge if the right-hand value is the same
49
50
  // saves at least 2 chars
50
51
  current = {
51
- type: 'index',
52
- source: item.source,
53
- value: getAssignmentExpression(current),
52
+ t: 'index',
53
+ s: item.s,
54
+ k: undefined,
55
+ v: getAssignmentExpression(current),
54
56
  };
55
- } else if (item.type === 'map' && item.source === prev.source) {
57
+ } else if (item.t === 'map' && item.s === prev.s) {
56
58
  // Maps has chaining methods, merge if source is the same
57
59
  current = {
58
- type: 'map',
59
- source: getAssignmentExpression(current),
60
- key: item.key,
61
- value: item.value,
60
+ t: 'map',
61
+ s: getAssignmentExpression(current),
62
+ k: item.k,
63
+ v: item.v,
62
64
  };
63
- } else if (item.type === 'set' && item.source === prev.source) {
65
+ } else if (item.t === 'set' && item.s === prev.s) {
64
66
  // Sets has chaining methods too
65
67
  current = {
66
- type: 'set',
67
- source: getAssignmentExpression(current),
68
- value: item.value,
68
+ t: 'set',
69
+ s: getAssignmentExpression(current),
70
+ k: undefined,
71
+ v: item.v,
69
72
  };
70
73
  } else {
71
74
  // Different assignment, push current
@@ -89,7 +92,7 @@ function resolveAssignments(assignments: Assignment[]) {
89
92
  let result = '';
90
93
  const merged = mergeAssignments(assignments);
91
94
  for (let i = 0, len = merged.length; i < len; i++) {
92
- result += `${getAssignmentExpression(merged[i])},`;
95
+ result += getAssignmentExpression(merged[i]) + ',';
93
96
  }
94
97
  return result;
95
98
  }
@@ -105,16 +108,6 @@ export function resolvePatches(ctx: SerializationContext) {
105
108
  * This is different from the assignments array as this one
106
109
  * signifies creation rather than mutation
107
110
  */
108
- function assignRef(
109
- ctx: SerializationContext,
110
- index: number,
111
- value: string,
112
- ) {
113
- if (ctx.markedRefs[index]) {
114
- return `${getRefParam(ctx, index)}=${value}`;
115
- }
116
- return value;
117
- }
118
111
 
119
112
  function createAssignment(
120
113
  ctx: SerializationContext,
@@ -122,9 +115,10 @@ function createAssignment(
122
115
  value: string,
123
116
  ) {
124
117
  ctx.assignments.push({
125
- type: 'index',
126
- source,
127
- value,
118
+ t: 'index',
119
+ s: source,
120
+ k: undefined,
121
+ v: value,
128
122
  });
129
123
  }
130
124
 
@@ -135,9 +129,10 @@ function createSetAdd(
135
129
  ) {
136
130
  markRef(ctx, ref);
137
131
  ctx.assignments.push({
138
- type: 'set',
139
- source: getRefParam(ctx, ref),
140
- value,
132
+ t: 'set',
133
+ s: getRefParam(ctx, ref),
134
+ k: undefined,
135
+ v: value,
141
136
  });
142
137
  }
143
138
 
@@ -149,10 +144,10 @@ function createMapSet(
149
144
  ) {
150
145
  markRef(ctx, ref);
151
146
  ctx.assignments.push({
152
- type: 'map',
153
- source: getRefParam(ctx, ref),
154
- key,
155
- value,
147
+ t: 'map',
148
+ s: getRefParam(ctx, ref),
149
+ k: key,
150
+ v: value,
156
151
  });
157
152
  }
158
153
 
@@ -163,7 +158,7 @@ function createArrayAssign(
163
158
  value: string,
164
159
  ) {
165
160
  markRef(ctx, ref);
166
- createAssignment(ctx, `${getRefParam(ctx, ref)}[${index}]`, value);
161
+ createAssignment(ctx, getRefParam(ctx, ref) + '[' + index.toString() + ']', value);
167
162
  }
168
163
 
169
164
  function createObjectAssign(
@@ -173,39 +168,74 @@ function createObjectAssign(
173
168
  value: string,
174
169
  ) {
175
170
  markRef(ctx, ref);
176
- createAssignment(ctx, `${getRefParam(ctx, ref)}.${key}`, value);
171
+ createAssignment(ctx, getRefParam(ctx, ref) + '.' + key, value);
172
+ }
173
+
174
+ function assignRef(
175
+ ctx: SerializationContext,
176
+ index: number,
177
+ value: string,
178
+ ) {
179
+ if (ctx.markedRefs.has(index)) {
180
+ return getRefParam(ctx, index) + '=' + value;
181
+ }
182
+ return value;
183
+ }
184
+
185
+ function isReferenceInStack(
186
+ ctx: SerializationContext,
187
+ node: SerovalNode,
188
+ ): node is SerovalReferenceNode {
189
+ return node.t === SerovalNodeType.Reference && ctx.stack.includes(node.i);
177
190
  }
178
191
 
179
192
  const IDENTIFIER_CHECK = /^([$A-Z_][0-9A-Z_$]*)$/i;
180
193
 
181
- function serializeAssignments(
194
+ function serializeNodeList(
182
195
  ctx: SerializationContext,
183
- targetRef: number,
184
- node: SerovalObjectRecordNode,
196
+ node: SerovalArrayNode | SerovalIterableNode,
185
197
  ) {
186
- ctx.stack.push(targetRef);
187
- const mainAssignments: Assignment[] = [];
188
- for (let i = 0; i < node.s; i++) {
189
- const parentStack = ctx.stack;
190
- ctx.stack = [];
191
- const refParam = serializeTree(ctx, node.v[i]);
192
- ctx.stack = parentStack;
193
- const key = node.k[i];
194
- const check = Number(key);
195
- const parentAssignment = ctx.assignments;
196
- ctx.assignments = mainAssignments;
197
- // Test if key is a valid number or JS identifier
198
- // so that we don't have to serialize the key and wrap with brackets
199
- const isIdentifier = check >= 0 || IDENTIFIER_CHECK.test(key);
200
- if (isIdentifier && Number.isNaN(check)) {
201
- createObjectAssign(ctx, targetRef, key, refParam);
198
+ // This is different than Map and Set
199
+ // because we also need to serialize
200
+ // the holes of the Array
201
+ const size = node.a.length;
202
+ let values = '';
203
+ let item: SerovalNode;
204
+ let isHoley = false;
205
+ for (let i = 0; i < size; i++) {
206
+ if (i !== 0) {
207
+ // Add an empty item
208
+ values += ',';
209
+ }
210
+ item = node.a[i];
211
+ // Check if index is a hole
212
+ if (item) {
213
+ // Check if item is a parent
214
+ if (isReferenceInStack(ctx, item)) {
215
+ createArrayAssign(ctx, node.i, i, getRefParam(ctx, item.i));
216
+ isHoley = true;
217
+ } else {
218
+ values += serializeTree(ctx, item);
219
+ isHoley = false;
220
+ }
202
221
  } else {
203
- createArrayAssign(ctx, targetRef, isIdentifier ? key : quote(key), refParam);
222
+ isHoley = true;
204
223
  }
205
- ctx.assignments = parentAssignment;
206
224
  }
225
+ if (isHoley) {
226
+ values += ',';
227
+ }
228
+ return '[' + values + ']';
229
+ }
230
+
231
+ function serializeArray(
232
+ ctx: SerializationContext,
233
+ node: SerovalArrayNode,
234
+ ) {
235
+ ctx.stack.push(node.i);
236
+ const result = serializeNodeList(ctx, node);
207
237
  ctx.stack.pop();
208
- return resolveAssignments(mainAssignments);
238
+ return assignRef(ctx, node.i, result);
209
239
  }
210
240
 
211
241
  function serializeObject(
@@ -218,59 +248,114 @@ function serializeObject(
218
248
  }
219
249
  let result = '';
220
250
  ctx.stack.push(sourceID);
251
+ let key: string;
252
+ let val: SerovalNode;
253
+ let check: number;
254
+ let isIdentifier: boolean;
255
+ let refParam: string;
256
+ let hasPrev = false;
221
257
  for (let i = 0; i < node.s; i++) {
222
- const key = node.k[i];
223
- const val = node.v[i];
224
- const check = Number(key);
258
+ key = node.k[i];
259
+ val = node.v[i];
260
+ check = Number(key);
225
261
  // Test if key is a valid number or JS identifier
226
262
  // so that we don't have to serialize the key and wrap with brackets
227
- const isIdentifier = check >= 0 || IDENTIFIER_CHECK.test(key);
263
+ isIdentifier = check >= 0 || IDENTIFIER_CHECK.test(key);
228
264
  if (isReferenceInStack(ctx, val)) {
229
- const refParam = getRefParam(ctx, val.i);
265
+ refParam = getRefParam(ctx, val.i);
230
266
  if (isIdentifier && Number.isNaN(check)) {
231
267
  createObjectAssign(ctx, sourceID, key, refParam);
232
268
  } else {
233
269
  createArrayAssign(ctx, sourceID, isIdentifier ? key : quote(key), refParam);
234
270
  }
235
271
  } else {
236
- result += `${isIdentifier ? key : quote(key)}:${serializeTree(ctx, val)},`;
272
+ if (hasPrev) {
273
+ result += ',';
274
+ }
275
+ result += isIdentifier ? key : quote(key);
276
+ result += ':' + serializeTree(ctx, val);
277
+ hasPrev = true;
237
278
  }
238
279
  }
239
280
  ctx.stack.pop();
240
- return `{${result.substring(0, result.length - 1)}}`;
281
+ return '{' + result + '}';
241
282
  }
242
283
 
243
- function serializePromise(
284
+ function serializeWithObjectAssign(
244
285
  ctx: SerializationContext,
245
- node: SerovalPromiseNode,
286
+ value: SerovalObjectRecordNode,
287
+ id: number,
288
+ serialized: string,
246
289
  ) {
247
- let serialized: string;
248
- // Check if resolved value is a parent expression
249
- if (isReferenceInStack(ctx, node.n)) {
250
- // A Promise trick, reference the value
251
- // inside the `then` expression so that
252
- // the Promise evaluates after the parent
253
- // has initialized
254
- serialized = `Promise.resolve().then(()=>${getRefParam(ctx, node.n.i)})`;
255
- } else {
256
- ctx.stack.push(node.i);
257
- const result = serializeTree(ctx, node.n);
258
- ctx.stack.pop();
259
- // just inline the value/reference here
260
- serialized = `Promise.resolve(${result})`;
290
+ const fields = serializeObject(ctx, id, value);
291
+ if (fields !== '{}') {
292
+ return 'Object.assign(' + serialized + ',' + fields + ')';
261
293
  }
262
- return assignRef(ctx, node.i, serialized);
294
+ return serialized;
263
295
  }
264
296
 
265
- function serializeTypedArray(
297
+ function serializeAssignments(
266
298
  ctx: SerializationContext,
267
- node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
299
+ sourceID: number,
300
+ node: SerovalObjectRecordNode,
268
301
  ) {
269
- let args = `[${node.s}]`;
270
- if (node.l !== 0) {
271
- args += `,${node.l}`;
302
+ ctx.stack.push(sourceID);
303
+ const mainAssignments: Assignment[] = [];
304
+ let parentStack: number[];
305
+ let refParam: string;
306
+ let key: string;
307
+ let check: number;
308
+ let parentAssignment: Assignment[];
309
+ let isIdentifier: boolean;
310
+ for (let i = 0; i < node.s; i++) {
311
+ parentStack = ctx.stack;
312
+ ctx.stack = [];
313
+ refParam = serializeTree(ctx, node.v[i]);
314
+ ctx.stack = parentStack;
315
+ key = node.k[i];
316
+ check = Number(key);
317
+ parentAssignment = ctx.assignments;
318
+ ctx.assignments = mainAssignments;
319
+ // Test if key is a valid number or JS identifier
320
+ // so that we don't have to serialize the key and wrap with brackets
321
+ isIdentifier = check >= 0 || IDENTIFIER_CHECK.test(key);
322
+ if (isIdentifier && Number.isNaN(check)) {
323
+ createObjectAssign(ctx, sourceID, key, refParam);
324
+ } else {
325
+ createArrayAssign(ctx, sourceID, isIdentifier ? key : quote(key), refParam);
326
+ }
327
+ ctx.assignments = parentAssignment;
272
328
  }
273
- return assignRef(ctx, node.i, `new ${node.c}(${args})`);
329
+ ctx.stack.pop();
330
+ return resolveAssignments(mainAssignments);
331
+ }
332
+
333
+ function serializeDictionary(
334
+ ctx: SerializationContext,
335
+ i: number,
336
+ d: SerovalObjectRecordNode | undefined,
337
+ init: string,
338
+ ) {
339
+ if (d) {
340
+ if (ctx.features & Feature.ObjectAssign) {
341
+ init = serializeWithObjectAssign(ctx, d, i, init);
342
+ } else {
343
+ markRef(ctx, i);
344
+ const assignments = serializeAssignments(ctx, i, d);
345
+ if (assignments) {
346
+ const ref = getRefParam(ctx, i);
347
+ return '(' + assignRef(ctx, i, init) + ',' + assignments + ref + ')';
348
+ }
349
+ }
350
+ }
351
+ return assignRef(ctx, i, init);
352
+ }
353
+
354
+ function serializeNullConstructor(
355
+ ctx: SerializationContext,
356
+ node: SerovalNullConstructorNode,
357
+ ) {
358
+ return serializeDictionary(ctx, node.i, node.d, 'Object.create(null)');
274
359
  }
275
360
 
276
361
  function serializeSet(
@@ -282,18 +367,24 @@ function serializeSet(
282
367
  if (size) {
283
368
  let result = '';
284
369
  ctx.stack.push(node.i);
370
+ let item: SerovalNode;
371
+ let hasPrev = false;
285
372
  for (let i = 0; i < size; i++) {
286
- const item = node.a[i];
373
+ item = node.a[i];
287
374
  if (isReferenceInStack(ctx, item)) {
288
375
  createSetAdd(ctx, node.i, getRefParam(ctx, item.i));
289
376
  } else {
290
377
  // Push directly
291
- result += `${serializeTree(ctx, item)},`;
378
+ if (hasPrev) {
379
+ result += ',';
380
+ }
381
+ result += serializeTree(ctx, item);
382
+ hasPrev = true;
292
383
  }
293
384
  }
294
385
  ctx.stack.pop();
295
386
  if (result) {
296
- serialized += `([${result.substring(0, result.length - 1)}])`;
387
+ serialized += '([' + result + '])';
297
388
  }
298
389
  }
299
390
  return assignRef(ctx, node.i, serialized);
@@ -307,16 +398,22 @@ function serializeMap(
307
398
  if (node.d.s) {
308
399
  let result = '';
309
400
  ctx.stack.push(node.i);
401
+ let key: SerovalNode;
402
+ let val: SerovalNode;
403
+ let keyRef: string;
404
+ let valueRef: string;
405
+ let parent: number[];
406
+ let hasPrev = false;
310
407
  for (let i = 0; i < node.d.s; i++) {
311
408
  // Check if key is a parent
312
- const key = node.d.k[i];
313
- const val = node.d.v[i];
409
+ key = node.d.k[i];
410
+ val = node.d.v[i];
314
411
  if (isReferenceInStack(ctx, key)) {
315
412
  // Create reference for the map instance
316
- const keyRef = getRefParam(ctx, key.i);
413
+ keyRef = getRefParam(ctx, key.i);
317
414
  // Check if value is a parent
318
415
  if (isReferenceInStack(ctx, val)) {
319
- const valueRef = getRefParam(ctx, val.i);
416
+ valueRef = getRefParam(ctx, val.i);
320
417
  // Register an assignment since
321
418
  // both key and value are a parent of this
322
419
  // Map instance
@@ -327,21 +424,25 @@ function serializeMap(
327
424
  // value is no longer part of the expression
328
425
  // tree and has been moved to the deferred
329
426
  // assignment
330
- const parent = ctx.stack;
427
+ parent = ctx.stack;
331
428
  ctx.stack = [];
332
429
  createMapSet(ctx, node.i, keyRef, serializeTree(ctx, val));
333
430
  ctx.stack = parent;
334
431
  }
335
432
  } else if (isReferenceInStack(ctx, val)) {
336
433
  // Create ref for the Map instance
337
- const valueRef = getRefParam(ctx, val.i);
434
+ valueRef = getRefParam(ctx, val.i);
338
435
  // Reset stack for the key serialization
339
- const parent = ctx.stack;
436
+ parent = ctx.stack;
340
437
  ctx.stack = [];
341
438
  createMapSet(ctx, node.i, serializeTree(ctx, key), valueRef);
342
439
  ctx.stack = parent;
343
440
  } else {
344
- result += `[${serializeTree(ctx, key)},${serializeTree(ctx, val)}],`;
441
+ if (hasPrev) {
442
+ result += ',';
443
+ }
444
+ result += '[' + serializeTree(ctx, key) + ',' + serializeTree(ctx, val) + ']';
445
+ hasPrev = true;
345
446
  }
346
447
  }
347
448
  ctx.stack.pop();
@@ -349,110 +450,70 @@ function serializeMap(
349
450
  // so that the empty Map constructor
350
451
  // can be used instead
351
452
  if (result) {
352
- serialized += `([${result.substring(0, result.length - 1)}])`;
453
+ serialized += '([' + result + '])';
353
454
  }
354
455
  }
355
456
  return assignRef(ctx, node.i, serialized);
356
457
  }
357
458
 
358
- function serializeNodeList(
359
- ctx: SerializationContext,
360
- node: SerovalArrayNode | SerovalIterableNode,
361
- ) {
362
- // This is different than Map and Set
363
- // because we also need to serialize
364
- // the holes of the Array
365
- const size = node.a.length;
366
- let values = '';
367
- for (let i = 0; i < size; i++) {
368
- const item = node.a[i];
369
- // Check if index is a hole
370
- if (item) {
371
- // Check if item is a parent
372
- if (isReferenceInStack(ctx, item)) {
373
- createArrayAssign(ctx, node.i, i, getRefParam(ctx, item.i));
374
- values += ',';
375
- } else {
376
- values += serializeTree(ctx, item);
377
- if (i < size - 1) {
378
- values += ',';
379
- }
380
- }
381
- } else {
382
- // Add an empty item
383
- values += ',';
384
- }
385
- }
386
- return `[${values}]`;
387
- }
388
-
389
- function serializeArray(
459
+ function serializeAggregateError(
390
460
  ctx: SerializationContext,
391
- node: SerovalArrayNode,
461
+ node: SerovalAggregateErrorNode,
392
462
  ) {
463
+ // Serialize the required arguments
393
464
  ctx.stack.push(node.i);
394
- const result = serializeNodeList(ctx, node);
465
+ const serialized = 'new AggregateError(' + serializeTree(ctx, node.n) + ',' + quote(node.m) + ')';
395
466
  ctx.stack.pop();
396
- return assignRef(ctx, node.i, result);
467
+ // `AggregateError` might've been extended
468
+ // either through class or custom properties
469
+ // Make sure to assign extra properties
470
+ return serializeDictionary(ctx, node.i, node.d, serialized);
397
471
  }
398
472
 
399
- function serializeWithObjectAssign(
473
+ function serializeError(
400
474
  ctx: SerializationContext,
401
- value: SerovalObjectRecordNode,
402
- id: number,
403
- serialized: string,
475
+ node: SerovalErrorNode,
404
476
  ) {
405
- const fields = serializeObject(ctx, id, value);
406
- if (fields !== '{}') {
407
- return `Object.assign(${serialized},${fields})`;
408
- }
409
- return serialized;
477
+ const serialized = 'new ' + node.c + '(' + quote(node.m) + ')';
478
+ return serializeDictionary(ctx, node.i, node.d, serialized);
410
479
  }
411
480
 
412
- function serializeAggregateError(
481
+ function serializePromise(
413
482
  ctx: SerializationContext,
414
- node: SerovalAggregateErrorNode,
483
+ node: SerovalPromiseNode,
415
484
  ) {
416
- // Serialize the required arguments
417
- ctx.stack.push(node.i);
418
- let serialized = `new AggregateError(${serializeTree(ctx, node.n)},${quote(node.m)})`;
419
- ctx.stack.pop();
420
- // `AggregateError` might've been extended
421
- // either through class or custom properties
422
- // Make sure to assign extra properties
423
- if (node.d) {
424
- if (ctx.features & Feature.ObjectAssign) {
425
- serialized = serializeWithObjectAssign(ctx, node.d, node.i, serialized);
485
+ let serialized: string;
486
+ // Check if resolved value is a parent expression
487
+ if (isReferenceInStack(ctx, node.n)) {
488
+ // A Promise trick, reference the value
489
+ // inside the `then` expression so that
490
+ // the Promise evaluates after the parent
491
+ // has initialized
492
+ const ref = getRefParam(ctx, node.n.i);
493
+ if (ctx.features & Feature.ArrowFunction) {
494
+ serialized = 'Promise.resolve().then(()=>' + ref + ')';
426
495
  } else {
427
- markRef(ctx, node.i);
428
- const assignments = serializeAssignments(ctx, node.i, node.d);
429
- if (assignments) {
430
- const ref = getRefParam(ctx, node.i);
431
- return `(${assignRef(ctx, node.i, serialized)},${assignments}${ref})`;
432
- }
496
+ serialized = 'Promise.resolve().then(function(){return ' + ref + '})';
433
497
  }
498
+ } else {
499
+ ctx.stack.push(node.i);
500
+ const result = serializeTree(ctx, node.n);
501
+ ctx.stack.pop();
502
+ // just inline the value/reference here
503
+ serialized = 'Promise.resolve(' + result + ')';
434
504
  }
435
505
  return assignRef(ctx, node.i, serialized);
436
506
  }
437
507
 
438
- function serializeError(
508
+ function serializeTypedArray(
439
509
  ctx: SerializationContext,
440
- node: SerovalErrorNode,
510
+ node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
441
511
  ) {
442
- let serialized = `new ${node.c}(${quote(node.m)})`;
443
- if (node.d) {
444
- if (ctx.features & Feature.ObjectAssign) {
445
- serialized = serializeWithObjectAssign(ctx, node.d, node.i, serialized);
446
- } else {
447
- markRef(ctx, node.i);
448
- const assignments = serializeAssignments(ctx, node.i, node.d);
449
- if (assignments) {
450
- const ref = getRefParam(ctx, node.i);
451
- return `(${assignRef(ctx, node.i, serialized)},${assignments}${ref})`;
452
- }
453
- }
512
+ let args = '[' + node.s + ']';
513
+ if (node.l !== 0) {
514
+ args += ',' + node.l.toString();
454
515
  }
455
- return assignRef(ctx, node.i, serialized);
516
+ return assignRef(ctx, node.i, 'new ' + node.c + '(' + args + ')');
456
517
  }
457
518
 
458
519
  function serializeIterable(
@@ -463,50 +524,20 @@ function serializeIterable(
463
524
  ctx.stack = [];
464
525
  const values = serializeNodeList(ctx, node);
465
526
  ctx.stack = parent;
466
- let serialized: string;
527
+ let serialized = values;
467
528
  if (ctx.features & Feature.ArrayPrototypeValues) {
468
- serialized = `${values}.values()`;
529
+ serialized += '.values()';
469
530
  } else {
470
- serialized = `${values}[Symbol.iterator]()`;
531
+ serialized += '[Symbol.iterator]()';
471
532
  }
472
533
  if (ctx.features & Feature.ArrowFunction) {
473
- serialized = `{[Symbol.iterator]:()=>${serialized}}`;
534
+ serialized = '{[Symbol.iterator]:()=>' + serialized + '}';
474
535
  } else if (ctx.features & Feature.MethodShorthand) {
475
- serialized = `{[Symbol.iterator](){return ${serialized}}}`;
476
- } else {
477
- serialized = `{[Symbol.iterator]:function(){return ${serialized}}}`;
478
- }
479
- if (node.d) {
480
- if (ctx.features & Feature.ObjectAssign) {
481
- serialized = serializeWithObjectAssign(ctx, node.d, node.i, serialized);
482
- } else {
483
- markRef(ctx, node.i);
484
- const assignments = serializeAssignments(ctx, node.i, node.d);
485
- if (assignments) {
486
- const ref = getRefParam(ctx, node.i);
487
- return `(${assignRef(ctx, node.i, serialized)},${assignments}${ref})`;
488
- }
489
- }
490
- }
491
- return assignRef(ctx, node.i, serialized);
492
- }
493
-
494
- function serializeNullConstructor(
495
- ctx: SerializationContext,
496
- node: SerovalNullConstructorNode,
497
- ) {
498
- let serialized = 'Object.create(null)';
499
- if (ctx.features & Feature.ObjectAssign) {
500
- serialized = serializeWithObjectAssign(ctx, node.d, node.i, serialized);
536
+ serialized = '{[Symbol.iterator](){return ' + serialized + '}}';
501
537
  } else {
502
- markRef(ctx, node.i);
503
- const assignments = serializeAssignments(ctx, node.i, node.d);
504
- if (assignments) {
505
- const ref = getRefParam(ctx, node.i);
506
- return `(${assignRef(ctx, node.i, serialized)},${assignments}${ref})`;
507
- }
538
+ serialized = '{[Symbol.iterator]:function(){return ' + serialized + '}}';
508
539
  }
509
- return assignRef(ctx, node.i, serialized);
540
+ return serializeDictionary(ctx, node.i, node.d, serialized);
510
541
  }
511
542
 
512
543
  export default function serializeTree(
@@ -516,35 +547,35 @@ export default function serializeTree(
516
547
  switch (node.t) {
517
548
  case SerovalNodeType.Primitive:
518
549
  return String(node.s);
519
- case SerovalNodeType.Reference:
520
- return getRefParam(ctx, node.i);
521
- case SerovalNodeType.Promise:
522
- return serializePromise(ctx, node);
523
550
  case SerovalNodeType.BigInt:
524
551
  return node.s;
552
+ case SerovalNodeType.Reference:
553
+ return getRefParam(ctx, node.i);
554
+ case SerovalNodeType.Array:
555
+ return serializeArray(ctx, node);
556
+ case SerovalNodeType.Object:
557
+ return assignRef(ctx, node.i, serializeObject(ctx, node.i, node.d));
558
+ case SerovalNodeType.NullConstructor:
559
+ return serializeNullConstructor(ctx, node);
525
560
  case SerovalNodeType.Date:
526
- return assignRef(ctx, node.i, `new Date("${node.s}")`);
561
+ return assignRef(ctx, node.i, 'new Date("' + node.s + '")');
527
562
  case SerovalNodeType.RegExp:
528
563
  return assignRef(ctx, node.i, node.s);
529
- case SerovalNodeType.BigIntTypedArray:
530
- case SerovalNodeType.TypedArray:
531
- return serializeTypedArray(ctx, node);
532
564
  case SerovalNodeType.Set:
533
565
  return serializeSet(ctx, node);
534
566
  case SerovalNodeType.Map:
535
567
  return serializeMap(ctx, node);
536
- case SerovalNodeType.Array:
537
- return serializeArray(ctx, node);
568
+ case SerovalNodeType.BigIntTypedArray:
569
+ case SerovalNodeType.TypedArray:
570
+ return serializeTypedArray(ctx, node);
538
571
  case SerovalNodeType.AggregateError:
539
572
  return serializeAggregateError(ctx, node);
540
573
  case SerovalNodeType.Error:
541
574
  return serializeError(ctx, node);
542
575
  case SerovalNodeType.Iterable:
543
576
  return serializeIterable(ctx, node);
544
- case SerovalNodeType.NullConstructor:
545
- return serializeNullConstructor(ctx, node);
546
- case SerovalNodeType.Object:
547
- return assignRef(ctx, node.i, serializeObject(ctx, node.i, node.d));
577
+ case SerovalNodeType.Promise:
578
+ return serializePromise(ctx, node);
548
579
  default:
549
580
  throw new Error('Unsupported type');
550
581
  }