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.
- package/README.md +81 -55
- package/dist/cjs/development/index.cjs +894 -933
- package/dist/cjs/development/index.cjs.map +4 -4
- package/dist/cjs/production/index.cjs +2 -2
- package/dist/esm/development/index.mjs +894 -933
- package/dist/esm/development/index.mjs.map +4 -4
- package/dist/esm/production/index.mjs +2 -2
- package/dist/types/compat.d.ts +10 -25
- package/dist/types/context.d.ts +17 -15
- package/dist/types/index.d.ts +2 -1
- package/dist/types/tree/primitives.d.ts +17 -0
- package/dist/types/tree/shared.d.ts +4 -8
- package/dist/types/types.d.ts +3 -2
- package/package.json +2 -2
- package/src/compat.ts +10 -246
- package/src/context.ts +37 -26
- package/src/index.ts +33 -41
- package/src/quote.ts +1 -1
- package/src/tree/async.ts +319 -197
- package/src/tree/primitives.ts +150 -0
- package/src/tree/serialize.ts +266 -235
- package/src/tree/shared.ts +43 -175
- package/src/tree/sync.ts +255 -180
- package/src/types.ts +4 -1
- package/dist/types/checks.d.ts +0 -5
- package/src/checks.ts +0 -40
package/src/tree/serialize.ts
CHANGED
|
@@ -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.
|
|
28
|
+
switch (assignment.t) {
|
|
29
29
|
case 'index':
|
|
30
|
-
return
|
|
30
|
+
return assignment.s + '=' + assignment.v;
|
|
31
31
|
case 'map':
|
|
32
|
-
return
|
|
32
|
+
return assignment.s + '.set(' + assignment.k + ',' + assignment.v + ')';
|
|
33
33
|
case 'set':
|
|
34
|
-
return
|
|
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
|
-
|
|
46
|
-
if (item.
|
|
47
|
-
if (item.
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
t: 'index',
|
|
53
|
+
s: item.s,
|
|
54
|
+
k: undefined,
|
|
55
|
+
v: getAssignmentExpression(current),
|
|
54
56
|
};
|
|
55
|
-
} else if (item.
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
t: 'map',
|
|
61
|
+
s: getAssignmentExpression(current),
|
|
62
|
+
k: item.k,
|
|
63
|
+
v: item.v,
|
|
62
64
|
};
|
|
63
|
-
} else if (item.
|
|
65
|
+
} else if (item.t === 'set' && item.s === prev.s) {
|
|
64
66
|
// Sets has chaining methods too
|
|
65
67
|
current = {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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 +=
|
|
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
|
-
|
|
126
|
-
source,
|
|
127
|
-
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
153
|
-
|
|
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,
|
|
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,
|
|
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
|
|
194
|
+
function serializeNodeList(
|
|
182
195
|
ctx: SerializationContext,
|
|
183
|
-
|
|
184
|
-
node: SerovalObjectRecordNode,
|
|
196
|
+
node: SerovalArrayNode | SerovalIterableNode,
|
|
185
197
|
) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (
|
|
201
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
263
|
+
isIdentifier = check >= 0 || IDENTIFIER_CHECK.test(key);
|
|
228
264
|
if (isReferenceInStack(ctx, val)) {
|
|
229
|
-
|
|
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
|
-
|
|
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
|
|
281
|
+
return '{' + result + '}';
|
|
241
282
|
}
|
|
242
283
|
|
|
243
|
-
function
|
|
284
|
+
function serializeWithObjectAssign(
|
|
244
285
|
ctx: SerializationContext,
|
|
245
|
-
|
|
286
|
+
value: SerovalObjectRecordNode,
|
|
287
|
+
id: number,
|
|
288
|
+
serialized: string,
|
|
246
289
|
) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
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
|
|
294
|
+
return serialized;
|
|
263
295
|
}
|
|
264
296
|
|
|
265
|
-
function
|
|
297
|
+
function serializeAssignments(
|
|
266
298
|
ctx: SerializationContext,
|
|
267
|
-
|
|
299
|
+
sourceID: number,
|
|
300
|
+
node: SerovalObjectRecordNode,
|
|
268
301
|
) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 +=
|
|
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
|
-
|
|
313
|
-
|
|
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
|
-
|
|
413
|
+
keyRef = getRefParam(ctx, key.i);
|
|
317
414
|
// Check if value is a parent
|
|
318
415
|
if (isReferenceInStack(ctx, val)) {
|
|
319
|
-
|
|
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
|
-
|
|
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
|
-
|
|
434
|
+
valueRef = getRefParam(ctx, val.i);
|
|
338
435
|
// Reset stack for the key serialization
|
|
339
|
-
|
|
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
|
-
|
|
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 +=
|
|
453
|
+
serialized += '([' + result + '])';
|
|
353
454
|
}
|
|
354
455
|
}
|
|
355
456
|
return assignRef(ctx, node.i, serialized);
|
|
356
457
|
}
|
|
357
458
|
|
|
358
|
-
function
|
|
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:
|
|
461
|
+
node: SerovalAggregateErrorNode,
|
|
392
462
|
) {
|
|
463
|
+
// Serialize the required arguments
|
|
393
464
|
ctx.stack.push(node.i);
|
|
394
|
-
const
|
|
465
|
+
const serialized = 'new AggregateError(' + serializeTree(ctx, node.n) + ',' + quote(node.m) + ')';
|
|
395
466
|
ctx.stack.pop();
|
|
396
|
-
|
|
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
|
|
473
|
+
function serializeError(
|
|
400
474
|
ctx: SerializationContext,
|
|
401
|
-
|
|
402
|
-
id: number,
|
|
403
|
-
serialized: string,
|
|
475
|
+
node: SerovalErrorNode,
|
|
404
476
|
) {
|
|
405
|
-
const
|
|
406
|
-
|
|
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
|
|
481
|
+
function serializePromise(
|
|
413
482
|
ctx: SerializationContext,
|
|
414
|
-
node:
|
|
483
|
+
node: SerovalPromiseNode,
|
|
415
484
|
) {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
if (ctx.features & Feature.
|
|
425
|
-
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
|
-
|
|
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
|
|
508
|
+
function serializeTypedArray(
|
|
439
509
|
ctx: SerializationContext,
|
|
440
|
-
node:
|
|
510
|
+
node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
|
|
441
511
|
) {
|
|
442
|
-
let
|
|
443
|
-
if (node.
|
|
444
|
-
|
|
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,
|
|
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
|
|
527
|
+
let serialized = values;
|
|
467
528
|
if (ctx.features & Feature.ArrayPrototypeValues) {
|
|
468
|
-
serialized
|
|
529
|
+
serialized += '.values()';
|
|
469
530
|
} else {
|
|
470
|
-
serialized
|
|
531
|
+
serialized += '[Symbol.iterator]()';
|
|
471
532
|
}
|
|
472
533
|
if (ctx.features & Feature.ArrowFunction) {
|
|
473
|
-
serialized =
|
|
534
|
+
serialized = '{[Symbol.iterator]:()=>' + serialized + '}';
|
|
474
535
|
} else if (ctx.features & Feature.MethodShorthand) {
|
|
475
|
-
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
|
-
|
|
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
|
|
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,
|
|
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.
|
|
537
|
-
|
|
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.
|
|
545
|
-
return
|
|
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
|
}
|