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