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