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.
- package/README.md +81 -55
- package/dist/cjs/development/index.cjs +999 -831
- package/dist/cjs/development/index.cjs.map +4 -4
- package/dist/cjs/production/index.cjs +2 -2
- package/dist/esm/development/index.mjs +999 -831
- 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/serialize.d.ts +1 -1
- package/dist/types/tree/shared.d.ts +4 -8
- package/dist/types/tree/types.d.ts +108 -59
- 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 +362 -163
- package/src/tree/primitives.ts +150 -0
- package/src/tree/serialize.ts +308 -282
- package/src/tree/shared.ts +43 -119
- package/src/tree/sync.ts +295 -146
- package/src/tree/types.ts +143 -65
- 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,17 +7,31 @@ import {
|
|
|
7
7
|
markRef,
|
|
8
8
|
} from '../context';
|
|
9
9
|
import quote from '../quote';
|
|
10
|
-
import {
|
|
11
|
-
|
|
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.
|
|
28
|
+
switch (assignment.t) {
|
|
15
29
|
case 'index':
|
|
16
|
-
return
|
|
30
|
+
return assignment.s + '=' + assignment.v;
|
|
17
31
|
case 'map':
|
|
18
|
-
return
|
|
32
|
+
return assignment.s + '.set(' + assignment.k + ',' + assignment.v + ')';
|
|
19
33
|
case 'set':
|
|
20
|
-
return
|
|
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
|
-
|
|
32
|
-
if (item.
|
|
33
|
-
if (item.
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
52
|
+
t: 'index',
|
|
53
|
+
s: item.s,
|
|
54
|
+
k: undefined,
|
|
55
|
+
v: getAssignmentExpression(current),
|
|
40
56
|
};
|
|
41
|
-
} else if (item.
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
60
|
+
t: 'map',
|
|
61
|
+
s: getAssignmentExpression(current),
|
|
62
|
+
k: item.k,
|
|
63
|
+
v: item.v,
|
|
48
64
|
};
|
|
49
|
-
} else if (item.
|
|
65
|
+
} else if (item.t === 'set' && item.s === prev.s) {
|
|
50
66
|
// Sets has chaining methods too
|
|
51
67
|
current = {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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 +=
|
|
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
|
-
|
|
112
|
-
source,
|
|
113
|
-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
|
|
139
|
-
|
|
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,
|
|
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,
|
|
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
|
|
194
|
+
function serializeNodeList(
|
|
168
195
|
ctx: SerializationContext,
|
|
169
|
-
|
|
170
|
-
[keys, values, size]: SerovalDictionaryNode,
|
|
196
|
+
node: SerovalArrayNode | SerovalIterableNode,
|
|
171
197
|
) {
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
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
|
|
238
|
+
return assignRef(ctx, node.i, result);
|
|
195
239
|
}
|
|
196
240
|
|
|
197
241
|
function serializeObject(
|
|
198
242
|
ctx: SerializationContext,
|
|
199
243
|
sourceID: number,
|
|
200
|
-
|
|
244
|
+
node: SerovalObjectRecordNode,
|
|
201
245
|
) {
|
|
202
|
-
if (
|
|
246
|
+
if (node.s === 0) {
|
|
203
247
|
return '{}';
|
|
204
248
|
}
|
|
205
249
|
let result = '';
|
|
206
250
|
ctx.stack.push(sourceID);
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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
|
-
|
|
263
|
+
isIdentifier = check >= 0 || IDENTIFIER_CHECK.test(key);
|
|
214
264
|
if (isReferenceInStack(ctx, val)) {
|
|
215
|
-
|
|
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
|
-
|
|
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
|
|
281
|
+
return '{' + result + '}';
|
|
227
282
|
}
|
|
228
283
|
|
|
229
|
-
function
|
|
284
|
+
function serializeWithObjectAssign(
|
|
230
285
|
ctx: SerializationContext,
|
|
231
|
-
value:
|
|
286
|
+
value: SerovalObjectRecordNode,
|
|
232
287
|
id: number,
|
|
288
|
+
serialized: string,
|
|
233
289
|
) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
|
294
|
+
return serialized;
|
|
250
295
|
}
|
|
251
296
|
|
|
252
|
-
function
|
|
297
|
+
function serializeAssignments(
|
|
253
298
|
ctx: SerializationContext,
|
|
254
|
-
|
|
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
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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,
|
|
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
|
-
|
|
269
|
-
id: number,
|
|
363
|
+
node: SerovalSetNode,
|
|
270
364
|
) {
|
|
271
365
|
let serialized = 'new Set';
|
|
272
|
-
const size =
|
|
366
|
+
const size = node.a.length;
|
|
273
367
|
if (size) {
|
|
274
368
|
let result = '';
|
|
275
|
-
ctx.stack.push(
|
|
369
|
+
ctx.stack.push(node.i);
|
|
370
|
+
let item: SerovalNode;
|
|
371
|
+
let hasPrev = false;
|
|
276
372
|
for (let i = 0; i < size; i++) {
|
|
277
|
-
|
|
373
|
+
item = node.a[i];
|
|
278
374
|
if (isReferenceInStack(ctx, item)) {
|
|
279
|
-
createSetAdd(ctx,
|
|
375
|
+
createSetAdd(ctx, node.i, getRefParam(ctx, item.i));
|
|
280
376
|
} else {
|
|
281
377
|
// Push directly
|
|
282
|
-
|
|
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 +=
|
|
387
|
+
serialized += '([' + result + '])';
|
|
288
388
|
}
|
|
289
389
|
}
|
|
290
|
-
return assignRef(ctx,
|
|
390
|
+
return assignRef(ctx, node.i, serialized);
|
|
291
391
|
}
|
|
292
392
|
|
|
293
393
|
function serializeMap(
|
|
294
394
|
ctx: SerializationContext,
|
|
295
|
-
|
|
296
|
-
values: SerovalNode[],
|
|
297
|
-
size: number,
|
|
298
|
-
id: number,
|
|
395
|
+
node: SerovalMapNode,
|
|
299
396
|
) {
|
|
300
397
|
let serialized = 'new Map';
|
|
301
|
-
if (
|
|
398
|
+
if (node.d.s) {
|
|
302
399
|
let result = '';
|
|
303
|
-
ctx.stack.push(
|
|
304
|
-
|
|
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
|
-
|
|
307
|
-
|
|
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
|
-
|
|
413
|
+
keyRef = getRefParam(ctx, key.i);
|
|
311
414
|
// Check if value is a parent
|
|
312
415
|
if (isReferenceInStack(ctx, val)) {
|
|
313
|
-
|
|
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,
|
|
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
|
-
|
|
427
|
+
parent = ctx.stack;
|
|
325
428
|
ctx.stack = [];
|
|
326
|
-
createMapSet(ctx,
|
|
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
|
-
|
|
434
|
+
valueRef = getRefParam(ctx, val.i);
|
|
332
435
|
// Reset stack for the key serialization
|
|
333
|
-
|
|
436
|
+
parent = ctx.stack;
|
|
334
437
|
ctx.stack = [];
|
|
335
|
-
createMapSet(ctx,
|
|
438
|
+
createMapSet(ctx, node.i, serializeTree(ctx, key), valueRef);
|
|
336
439
|
ctx.stack = parent;
|
|
337
440
|
} else {
|
|
338
|
-
|
|
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 +=
|
|
453
|
+
serialized += '([' + result + '])';
|
|
347
454
|
}
|
|
348
455
|
}
|
|
349
|
-
return assignRef(ctx,
|
|
456
|
+
return assignRef(ctx, node.i, serialized);
|
|
350
457
|
}
|
|
351
458
|
|
|
352
|
-
function
|
|
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
|
-
|
|
387
|
-
id: number,
|
|
461
|
+
node: SerovalAggregateErrorNode,
|
|
388
462
|
) {
|
|
389
|
-
|
|
390
|
-
|
|
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
|
-
|
|
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
|
|
473
|
+
function serializeError(
|
|
396
474
|
ctx: SerializationContext,
|
|
397
|
-
|
|
398
|
-
id: number,
|
|
399
|
-
serialized: string,
|
|
475
|
+
node: SerovalErrorNode,
|
|
400
476
|
) {
|
|
401
|
-
const
|
|
402
|
-
|
|
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
|
|
481
|
+
function serializePromise(
|
|
409
482
|
ctx: SerializationContext,
|
|
410
|
-
|
|
411
|
-
options: SerovalDictionaryNode | undefined,
|
|
412
|
-
errors: SerovalNode,
|
|
413
|
-
id: number,
|
|
483
|
+
node: SerovalPromiseNode,
|
|
414
484
|
) {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
if (ctx.features & Feature.
|
|
424
|
-
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
|
-
|
|
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,
|
|
505
|
+
return assignRef(ctx, node.i, serialized);
|
|
435
506
|
}
|
|
436
507
|
|
|
437
|
-
function
|
|
508
|
+
function serializeTypedArray(
|
|
438
509
|
ctx: SerializationContext,
|
|
439
|
-
|
|
440
|
-
message: string,
|
|
441
|
-
options: SerovalDictionaryNode | undefined,
|
|
442
|
-
id: number,
|
|
510
|
+
node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
|
|
443
511
|
) {
|
|
444
|
-
let
|
|
445
|
-
if (
|
|
446
|
-
|
|
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,
|
|
516
|
+
return assignRef(ctx, node.i, 'new ' + node.c + '(' + args + ')');
|
|
458
517
|
}
|
|
459
518
|
|
|
460
519
|
function serializeIterable(
|
|
461
520
|
ctx: SerializationContext,
|
|
462
|
-
|
|
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,
|
|
525
|
+
const values = serializeNodeList(ctx, node);
|
|
469
526
|
ctx.stack = parent;
|
|
470
|
-
let serialized
|
|
527
|
+
let serialized = values;
|
|
471
528
|
if (ctx.features & Feature.ArrayPrototypeValues) {
|
|
472
|
-
serialized
|
|
529
|
+
serialized += '.values()';
|
|
473
530
|
} else {
|
|
474
|
-
serialized
|
|
531
|
+
serialized += '[Symbol.iterator]()';
|
|
475
532
|
}
|
|
476
533
|
if (ctx.features & Feature.ArrowFunction) {
|
|
477
|
-
serialized =
|
|
534
|
+
serialized = '{[Symbol.iterator]:()=>' + serialized + '}';
|
|
478
535
|
} else if (ctx.features & Feature.MethodShorthand) {
|
|
479
|
-
serialized =
|
|
536
|
+
serialized = '{[Symbol.iterator](){return ' + serialized + '}}';
|
|
480
537
|
} else {
|
|
481
|
-
serialized =
|
|
538
|
+
serialized = '{[Symbol.iterator]:function(){return ' + serialized + '}}';
|
|
482
539
|
}
|
|
483
|
-
|
|
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
|
-
|
|
545
|
+
node: SerovalNode,
|
|
520
546
|
): string {
|
|
521
|
-
switch (
|
|
547
|
+
switch (node.t) {
|
|
522
548
|
case SerovalNodeType.Primitive:
|
|
523
|
-
return String(
|
|
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
|
|
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,
|
|
561
|
+
return assignRef(ctx, node.i, 'new Date("' + node.s + '")');
|
|
532
562
|
case SerovalNodeType.RegExp:
|
|
533
|
-
return assignRef(ctx,
|
|
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,
|
|
565
|
+
return serializeSet(ctx, node);
|
|
539
566
|
case SerovalNodeType.Map:
|
|
540
|
-
return serializeMap(ctx,
|
|
541
|
-
case SerovalNodeType.
|
|
542
|
-
|
|
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,
|
|
572
|
+
return serializeAggregateError(ctx, node);
|
|
545
573
|
case SerovalNodeType.Error:
|
|
546
|
-
return serializeError(ctx,
|
|
574
|
+
return serializeError(ctx, node);
|
|
547
575
|
case SerovalNodeType.Iterable:
|
|
548
|
-
return serializeIterable(ctx,
|
|
549
|
-
case SerovalNodeType.
|
|
550
|
-
return
|
|
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
|
}
|