seroval 0.7.0 → 0.9.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/dist/cjs/development/index.cjs +1247 -1069
- package/dist/cjs/development/index.cjs.map +4 -4
- package/dist/cjs/production/index.cjs +3 -3
- package/dist/esm/development/index.mjs +1247 -1069
- package/dist/esm/development/index.mjs.map +4 -4
- package/dist/esm/production/index.mjs +3 -3
- package/dist/types/assert.d.ts +1 -1
- package/dist/types/context.d.ts +8 -2
- package/dist/types/index.d.ts +3 -4
- package/dist/types/string.d.ts +1 -1
- package/dist/types/tree/UnsupportedTypeError.d.ts +3 -0
- package/dist/types/tree/async.d.ts +3 -3
- package/dist/types/tree/constants.d.ts +11 -0
- package/dist/types/tree/deserialize.d.ts +2 -2
- package/dist/types/tree/primitives.d.ts +9 -15
- package/dist/types/tree/serialize.d.ts +2 -2
- package/dist/types/tree/shared.d.ts +12 -8
- package/dist/types/tree/sync.d.ts +3 -3
- package/dist/types/tree/types.d.ts +74 -71
- package/dist/types/tree/web-api.d.ts +2 -2
- package/dist/types/types.d.ts +4 -4
- package/package.json +11 -9
- package/src/assert.ts +2 -2
- package/src/compat.ts +0 -1
- package/src/context.ts +20 -7
- package/src/get-identifier.ts +1 -1
- package/src/index.ts +35 -26
- package/src/string.ts +2 -2
- package/src/tree/UnsupportedTypeError.ts +8 -0
- package/src/tree/async.ts +256 -233
- package/src/tree/constants.ts +73 -0
- package/src/tree/deserialize.ts +112 -93
- package/src/tree/primitives.ts +93 -134
- package/src/tree/reference.ts +3 -3
- package/src/tree/serialize.ts +307 -201
- package/src/tree/shared.ts +45 -22
- package/src/tree/symbols.ts +13 -13
- package/src/tree/sync.ts +236 -198
- package/src/tree/types.ts +87 -94
- package/src/tree/web-api.ts +14 -7
- package/src/types.ts +7 -3
- package/src/tree/iterator.ts +0 -14
package/src/tree/serialize.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-use-before-define */
|
|
2
2
|
import { Feature } from '../compat';
|
|
3
|
-
import {
|
|
3
|
+
import type {
|
|
4
4
|
SerializationContext,
|
|
5
5
|
Assignment,
|
|
6
|
+
} from '../context';
|
|
7
|
+
import {
|
|
6
8
|
getRefParam,
|
|
7
9
|
markRef,
|
|
8
10
|
} from '../context';
|
|
11
|
+
import { serializeConstant } from './constants';
|
|
9
12
|
import { GLOBAL_KEY } from './reference';
|
|
10
13
|
import { isValidIdentifier } from './shared';
|
|
11
14
|
import { SYMBOL_STRING } from './symbols';
|
|
12
|
-
import {
|
|
15
|
+
import type {
|
|
13
16
|
SerovalAggregateErrorNode,
|
|
14
17
|
SerovalArrayNode,
|
|
15
18
|
SerovalBigIntTypedArrayNode,
|
|
16
19
|
SerovalErrorNode,
|
|
17
|
-
SerovalIterableNode,
|
|
18
20
|
SerovalMapNode,
|
|
19
21
|
SerovalNode,
|
|
20
|
-
SerovalNodeType,
|
|
21
22
|
SerovalNullConstructorNode,
|
|
22
23
|
SerovalObjectNode,
|
|
23
|
-
SerovalObjectRecordNode,
|
|
24
24
|
SerovalPromiseNode,
|
|
25
25
|
SerovalIndexedValueNode,
|
|
26
26
|
SerovalSetNode,
|
|
@@ -36,6 +36,16 @@ import {
|
|
|
36
36
|
SerovalURLSearchParamsNode,
|
|
37
37
|
SerovalReferenceNode,
|
|
38
38
|
SerovalFormDataNode,
|
|
39
|
+
SerovalObjectRecordNode,
|
|
40
|
+
SerovalObjectRecordKey,
|
|
41
|
+
SerovalBoxedNode,
|
|
42
|
+
SerovalWKSymbolNode,
|
|
43
|
+
} from './types';
|
|
44
|
+
import {
|
|
45
|
+
SerovalObjectFlags,
|
|
46
|
+
|
|
47
|
+
SerovalNodeType,
|
|
48
|
+
SerovalObjectRecordSpecialKey,
|
|
39
49
|
} from './types';
|
|
40
50
|
|
|
41
51
|
function getAssignmentExpression(assignment: Assignment): string {
|
|
@@ -53,8 +63,15 @@ function getAssignmentExpression(assignment: Assignment): string {
|
|
|
53
63
|
}
|
|
54
64
|
}
|
|
55
65
|
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
const OBJECT_FLAG_CONSTRUCTOR: Record<SerovalObjectFlags, string | undefined> = {
|
|
67
|
+
[SerovalObjectFlags.Frozen]: 'Object.freeze',
|
|
68
|
+
[SerovalObjectFlags.Sealed]: 'Object.seal',
|
|
69
|
+
[SerovalObjectFlags.NonExtensible]: 'Object.preventExtensions',
|
|
70
|
+
[SerovalObjectFlags.None]: undefined,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
function mergeAssignments(assignments: Assignment[]): Assignment[] {
|
|
74
|
+
const newAssignments: Assignment[] = [];
|
|
58
75
|
let current = assignments[0];
|
|
59
76
|
let prev = current;
|
|
60
77
|
let item: Assignment;
|
|
@@ -128,7 +145,7 @@ function mergeAssignments(assignments: Assignment[]) {
|
|
|
128
145
|
return newAssignments;
|
|
129
146
|
}
|
|
130
147
|
|
|
131
|
-
function resolveAssignments(assignments: Assignment[]) {
|
|
148
|
+
function resolveAssignments(assignments: Assignment[]): string | undefined {
|
|
132
149
|
if (assignments.length) {
|
|
133
150
|
let result = '';
|
|
134
151
|
const merged = mergeAssignments(assignments);
|
|
@@ -140,8 +157,35 @@ function resolveAssignments(assignments: Assignment[]) {
|
|
|
140
157
|
return undefined;
|
|
141
158
|
}
|
|
142
159
|
|
|
143
|
-
|
|
144
|
-
|
|
160
|
+
function pushObjectFlag(ctx: SerializationContext, flag: SerovalObjectFlags, id: number): void {
|
|
161
|
+
if (flag !== SerovalObjectFlags.None) {
|
|
162
|
+
markRef(ctx, id);
|
|
163
|
+
ctx.flags.push({
|
|
164
|
+
type: flag,
|
|
165
|
+
value: getRefParam(ctx, id),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function resolveFlags(ctx: SerializationContext): string | undefined {
|
|
171
|
+
let result = '';
|
|
172
|
+
for (let i = 0, len = ctx.flags.length; i < len; i++) {
|
|
173
|
+
const flag = ctx.flags[i];
|
|
174
|
+
result += OBJECT_FLAG_CONSTRUCTOR[flag.type] + '(' + flag.value + '),';
|
|
175
|
+
}
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function resolvePatches(ctx: SerializationContext): string | undefined {
|
|
180
|
+
const assignments = resolveAssignments(ctx.assignments);
|
|
181
|
+
const flags = resolveFlags(ctx);
|
|
182
|
+
if (assignments) {
|
|
183
|
+
if (flags) {
|
|
184
|
+
return assignments + flags;
|
|
185
|
+
}
|
|
186
|
+
return assignments;
|
|
187
|
+
}
|
|
188
|
+
return flags;
|
|
145
189
|
}
|
|
146
190
|
|
|
147
191
|
/**
|
|
@@ -154,7 +198,7 @@ function createAssignment(
|
|
|
154
198
|
ctx: SerializationContext,
|
|
155
199
|
source: string,
|
|
156
200
|
value: string,
|
|
157
|
-
) {
|
|
201
|
+
): void {
|
|
158
202
|
ctx.assignments.push({
|
|
159
203
|
t: 'index',
|
|
160
204
|
s: source,
|
|
@@ -167,7 +211,7 @@ function createAddAssignment(
|
|
|
167
211
|
ctx: SerializationContext,
|
|
168
212
|
ref: number,
|
|
169
213
|
value: string,
|
|
170
|
-
) {
|
|
214
|
+
): void {
|
|
171
215
|
ctx.assignments.push({
|
|
172
216
|
t: 'add',
|
|
173
217
|
s: getRefParam(ctx, ref),
|
|
@@ -181,7 +225,7 @@ function createSetAssignment(
|
|
|
181
225
|
ref: number,
|
|
182
226
|
key: string,
|
|
183
227
|
value: string,
|
|
184
|
-
) {
|
|
228
|
+
): void {
|
|
185
229
|
ctx.assignments.push({
|
|
186
230
|
t: 'set',
|
|
187
231
|
s: getRefParam(ctx, ref),
|
|
@@ -195,7 +239,7 @@ function createAppendAssignment(
|
|
|
195
239
|
ref: number,
|
|
196
240
|
key: string,
|
|
197
241
|
value: string,
|
|
198
|
-
) {
|
|
242
|
+
): void {
|
|
199
243
|
ctx.assignments.push({
|
|
200
244
|
t: 'append',
|
|
201
245
|
s: getRefParam(ctx, ref),
|
|
@@ -209,7 +253,7 @@ function createArrayAssign(
|
|
|
209
253
|
ref: number,
|
|
210
254
|
index: number | string,
|
|
211
255
|
value: string,
|
|
212
|
-
) {
|
|
256
|
+
): void {
|
|
213
257
|
createAssignment(ctx, getRefParam(ctx, ref) + '[' + index + ']', value);
|
|
214
258
|
}
|
|
215
259
|
|
|
@@ -218,7 +262,7 @@ function createObjectAssign(
|
|
|
218
262
|
ref: number,
|
|
219
263
|
key: string,
|
|
220
264
|
value: string,
|
|
221
|
-
) {
|
|
265
|
+
): void {
|
|
222
266
|
markRef(ctx, ref);
|
|
223
267
|
createAssignment(ctx, getRefParam(ctx, ref) + '.' + key, value);
|
|
224
268
|
}
|
|
@@ -227,7 +271,7 @@ function assignIndexedValue(
|
|
|
227
271
|
ctx: SerializationContext,
|
|
228
272
|
index: number,
|
|
229
273
|
value: string,
|
|
230
|
-
) {
|
|
274
|
+
): string {
|
|
231
275
|
if (ctx.markedRefs.has(index)) {
|
|
232
276
|
return getRefParam(ctx, index) + '=' + value;
|
|
233
277
|
}
|
|
@@ -241,33 +285,31 @@ function isIndexedValueInStack(
|
|
|
241
285
|
return node.t === SerovalNodeType.IndexedValue && ctx.stack.includes(node.i);
|
|
242
286
|
}
|
|
243
287
|
|
|
244
|
-
|
|
245
|
-
| SerovalArrayNode
|
|
246
|
-
| SerovalIterableNode;
|
|
247
|
-
|
|
248
|
-
function serializeNodeList(
|
|
288
|
+
function serializeArray(
|
|
249
289
|
ctx: SerializationContext,
|
|
250
|
-
node:
|
|
251
|
-
) {
|
|
290
|
+
node: SerovalArrayNode,
|
|
291
|
+
): string {
|
|
292
|
+
const id = node.i;
|
|
293
|
+
ctx.stack.push(id);
|
|
252
294
|
// This is different than Map and Set
|
|
253
295
|
// because we also need to serialize
|
|
254
296
|
// the holes of the Array
|
|
255
|
-
const size = node.l;
|
|
256
297
|
let values = '';
|
|
257
|
-
let item: SerovalNode;
|
|
298
|
+
let item: SerovalNode | undefined;
|
|
258
299
|
let isHoley = false;
|
|
259
|
-
|
|
300
|
+
const list = node.a;
|
|
301
|
+
for (let i = 0, len = node.l; i < len; i++) {
|
|
260
302
|
if (i !== 0) {
|
|
261
303
|
// Add an empty item
|
|
262
304
|
values += ',';
|
|
263
305
|
}
|
|
264
|
-
item =
|
|
306
|
+
item = list[i];
|
|
265
307
|
// Check if index is a hole
|
|
266
308
|
if (item) {
|
|
267
309
|
// Check if item is a parent
|
|
268
310
|
if (isIndexedValueInStack(ctx, item)) {
|
|
269
|
-
markRef(ctx,
|
|
270
|
-
createArrayAssign(ctx,
|
|
311
|
+
markRef(ctx, id);
|
|
312
|
+
createArrayAssign(ctx, id, i, getRefParam(ctx, item.i));
|
|
271
313
|
isHoley = true;
|
|
272
314
|
} else {
|
|
273
315
|
values += serializeTree(ctx, item);
|
|
@@ -277,30 +319,47 @@ function serializeNodeList(
|
|
|
277
319
|
isHoley = true;
|
|
278
320
|
}
|
|
279
321
|
}
|
|
280
|
-
|
|
322
|
+
ctx.stack.pop();
|
|
323
|
+
pushObjectFlag(ctx, node.o, node.i);
|
|
324
|
+
return assignIndexedValue(ctx, id, '[' + values + (isHoley ? ',]' : ']'));
|
|
281
325
|
}
|
|
282
326
|
|
|
283
|
-
function
|
|
327
|
+
function getIterableAccess(ctx: SerializationContext): string {
|
|
328
|
+
return ctx.features & Feature.ArrayPrototypeValues
|
|
329
|
+
? '.values()'
|
|
330
|
+
: '[Symbol.iterator]()';
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function serializeIterable(
|
|
284
334
|
ctx: SerializationContext,
|
|
285
|
-
node:
|
|
286
|
-
) {
|
|
287
|
-
ctx.stack
|
|
288
|
-
|
|
289
|
-
ctx
|
|
290
|
-
|
|
335
|
+
node: SerovalNode,
|
|
336
|
+
): string {
|
|
337
|
+
const parent = ctx.stack;
|
|
338
|
+
ctx.stack = [];
|
|
339
|
+
let serialized = serializeTree(ctx, node) + getIterableAccess(ctx);
|
|
340
|
+
ctx.stack = parent;
|
|
341
|
+
if (ctx.features & Feature.ArrowFunction) {
|
|
342
|
+
serialized = '[Symbol.iterator]:()=>' + serialized;
|
|
343
|
+
} else if (ctx.features & Feature.MethodShorthand) {
|
|
344
|
+
serialized = '[Symbol.iterator](){return ' + serialized + '}';
|
|
345
|
+
} else {
|
|
346
|
+
serialized = '[Symbol.iterator]:function(){return ' + serialized + '}';
|
|
347
|
+
}
|
|
348
|
+
return serialized;
|
|
291
349
|
}
|
|
292
350
|
|
|
293
351
|
function serializeProperties(
|
|
294
352
|
ctx: SerializationContext,
|
|
295
353
|
sourceID: number,
|
|
296
354
|
node: SerovalObjectRecordNode,
|
|
297
|
-
) {
|
|
298
|
-
|
|
355
|
+
): string {
|
|
356
|
+
const len = node.s;
|
|
357
|
+
if (len === 0) {
|
|
299
358
|
return '{}';
|
|
300
359
|
}
|
|
301
360
|
let result = '';
|
|
302
361
|
ctx.stack.push(sourceID);
|
|
303
|
-
let key:
|
|
362
|
+
let key: SerovalObjectRecordKey;
|
|
304
363
|
let val: SerovalNode;
|
|
305
364
|
let check: number;
|
|
306
365
|
let isIdentifier: boolean;
|
|
@@ -308,27 +367,34 @@ function serializeProperties(
|
|
|
308
367
|
let hasPrev = false;
|
|
309
368
|
const keys = node.k;
|
|
310
369
|
const values = node.v;
|
|
311
|
-
for (let i = 0
|
|
370
|
+
for (let i = 0; i < len; i++) {
|
|
312
371
|
key = keys[i];
|
|
313
372
|
val = values[i];
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
373
|
+
switch (key) {
|
|
374
|
+
case SerovalObjectRecordSpecialKey.SymbolIterator:
|
|
375
|
+
result += (hasPrev ? ',' : '') + serializeIterable(ctx, val);
|
|
376
|
+
hasPrev = true;
|
|
377
|
+
break;
|
|
378
|
+
default:
|
|
379
|
+
check = Number(key);
|
|
380
|
+
// Test if key is a valid number or JS identifier
|
|
381
|
+
// so that we don't have to serialize the key and wrap with brackets
|
|
382
|
+
isIdentifier = check >= 0 || isValidIdentifier(key);
|
|
383
|
+
if (isIndexedValueInStack(ctx, val)) {
|
|
384
|
+
refParam = getRefParam(ctx, val.i);
|
|
385
|
+
markRef(ctx, sourceID);
|
|
386
|
+
if (isIdentifier && Number.isNaN(check)) {
|
|
387
|
+
createObjectAssign(ctx, sourceID, key, refParam);
|
|
388
|
+
} else {
|
|
389
|
+
createArrayAssign(ctx, sourceID, isIdentifier ? key : ('"' + key + '"'), refParam);
|
|
390
|
+
}
|
|
391
|
+
} else {
|
|
392
|
+
result += (hasPrev ? ',' : '')
|
|
393
|
+
+ (isIdentifier ? key : ('"' + key + '"'))
|
|
394
|
+
+ ':' + serializeTree(ctx, val);
|
|
395
|
+
hasPrev = true;
|
|
396
|
+
}
|
|
397
|
+
break;
|
|
332
398
|
}
|
|
333
399
|
}
|
|
334
400
|
ctx.stack.pop();
|
|
@@ -340,7 +406,7 @@ function serializeWithObjectAssign(
|
|
|
340
406
|
value: SerovalObjectRecordNode,
|
|
341
407
|
id: number,
|
|
342
408
|
serialized: string,
|
|
343
|
-
) {
|
|
409
|
+
): string {
|
|
344
410
|
const fields = serializeProperties(ctx, id, value);
|
|
345
411
|
if (fields !== '{}') {
|
|
346
412
|
return 'Object.assign(' + serialized + ',' + fields + ')';
|
|
@@ -352,35 +418,62 @@ function serializeAssignments(
|
|
|
352
418
|
ctx: SerializationContext,
|
|
353
419
|
sourceID: number,
|
|
354
420
|
node: SerovalObjectRecordNode,
|
|
355
|
-
) {
|
|
421
|
+
): string | undefined {
|
|
356
422
|
ctx.stack.push(sourceID);
|
|
357
423
|
const mainAssignments: Assignment[] = [];
|
|
358
|
-
let
|
|
359
|
-
let
|
|
360
|
-
let key: string;
|
|
361
|
-
let check: number;
|
|
424
|
+
let key: SerovalObjectRecordKey;
|
|
425
|
+
let value: SerovalNode;
|
|
362
426
|
let parentAssignment: Assignment[];
|
|
363
|
-
let isIdentifier: boolean;
|
|
364
427
|
const keys = node.k;
|
|
365
428
|
const values = node.v;
|
|
366
429
|
for (let i = 0, len = node.s; i < len; i++) {
|
|
367
|
-
parentStack = ctx.stack;
|
|
368
|
-
ctx.stack = [];
|
|
369
|
-
refParam = serializeTree(ctx, values[i]);
|
|
370
|
-
ctx.stack = parentStack;
|
|
371
430
|
key = keys[i];
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
431
|
+
value = values[i];
|
|
432
|
+
switch (key) {
|
|
433
|
+
case SerovalObjectRecordSpecialKey.SymbolIterator: {
|
|
434
|
+
const parent = ctx.stack;
|
|
435
|
+
ctx.stack = [];
|
|
436
|
+
const serialized = serializeTree(ctx, value) + getIterableAccess(ctx);
|
|
437
|
+
ctx.stack = parent;
|
|
438
|
+
parentAssignment = ctx.assignments;
|
|
439
|
+
ctx.assignments = mainAssignments;
|
|
440
|
+
createArrayAssign(
|
|
441
|
+
ctx,
|
|
442
|
+
sourceID,
|
|
443
|
+
'Symbol.iterator',
|
|
444
|
+
ctx.features & Feature.ArrowFunction
|
|
445
|
+
? '()=>' + serialized
|
|
446
|
+
: 'function(){return ' + serialized + '}',
|
|
447
|
+
);
|
|
448
|
+
ctx.assignments = parentAssignment;
|
|
449
|
+
}
|
|
450
|
+
break;
|
|
451
|
+
default: {
|
|
452
|
+
const serialized = serializeTree(ctx, value);
|
|
453
|
+
const check = Number(key);
|
|
454
|
+
const isIdentifier = check >= 0 || isValidIdentifier(key);
|
|
455
|
+
if (isIndexedValueInStack(ctx, value)) {
|
|
456
|
+
// Test if key is a valid number or JS identifier
|
|
457
|
+
// so that we don't have to serialize the key and wrap with brackets
|
|
458
|
+
if (isIdentifier && Number.isNaN(check)) {
|
|
459
|
+
createObjectAssign(ctx, sourceID, key, serialized);
|
|
460
|
+
} else {
|
|
461
|
+
createArrayAssign(ctx, sourceID, isIdentifier ? key : ('"' + key + '"'), serialized);
|
|
462
|
+
}
|
|
463
|
+
} else {
|
|
464
|
+
// Test if key is a valid number or JS identifier
|
|
465
|
+
// so that we don't have to serialize the key and wrap with brackets
|
|
466
|
+
parentAssignment = ctx.assignments;
|
|
467
|
+
ctx.assignments = mainAssignments;
|
|
468
|
+
if (isIdentifier && Number.isNaN(check)) {
|
|
469
|
+
createObjectAssign(ctx, sourceID, key, serialized);
|
|
470
|
+
} else {
|
|
471
|
+
createArrayAssign(ctx, sourceID, isIdentifier ? key : ('"' + key + '"'), serialized);
|
|
472
|
+
}
|
|
473
|
+
ctx.assignments = parentAssignment;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
382
476
|
}
|
|
383
|
-
ctx.assignments = parentAssignment;
|
|
384
477
|
}
|
|
385
478
|
ctx.stack.pop();
|
|
386
479
|
return resolveAssignments(mainAssignments);
|
|
@@ -391,7 +484,7 @@ function serializeDictionary(
|
|
|
391
484
|
i: number,
|
|
392
485
|
d: SerovalObjectRecordNode | undefined,
|
|
393
486
|
init: string,
|
|
394
|
-
) {
|
|
487
|
+
): string {
|
|
395
488
|
if (d) {
|
|
396
489
|
if (ctx.features & Feature.ObjectAssign) {
|
|
397
490
|
init = serializeWithObjectAssign(ctx, d, i, init);
|
|
@@ -406,36 +499,42 @@ function serializeDictionary(
|
|
|
406
499
|
return assignIndexedValue(ctx, i, init);
|
|
407
500
|
}
|
|
408
501
|
|
|
502
|
+
const NULL_CONSTRUCTOR = 'Object.create(null)';
|
|
503
|
+
|
|
409
504
|
function serializeNullConstructor(
|
|
410
505
|
ctx: SerializationContext,
|
|
411
506
|
node: SerovalNullConstructorNode,
|
|
412
|
-
) {
|
|
413
|
-
|
|
507
|
+
): string {
|
|
508
|
+
pushObjectFlag(ctx, node.o, node.i);
|
|
509
|
+
return serializeDictionary(ctx, node.i, node.d, NULL_CONSTRUCTOR);
|
|
414
510
|
}
|
|
415
511
|
|
|
416
512
|
function serializeObject(
|
|
417
513
|
ctx: SerializationContext,
|
|
418
514
|
node: SerovalObjectNode,
|
|
419
|
-
) {
|
|
515
|
+
): string {
|
|
516
|
+
pushObjectFlag(ctx, node.o, node.i);
|
|
420
517
|
return assignIndexedValue(ctx, node.i, serializeProperties(ctx, node.i, node.d));
|
|
421
518
|
}
|
|
422
519
|
|
|
423
520
|
function serializeSet(
|
|
424
521
|
ctx: SerializationContext,
|
|
425
522
|
node: SerovalSetNode,
|
|
426
|
-
) {
|
|
523
|
+
): string {
|
|
427
524
|
let serialized = 'new Set';
|
|
428
525
|
const size = node.l;
|
|
526
|
+
const id = node.i;
|
|
429
527
|
if (size) {
|
|
430
528
|
let result = '';
|
|
431
|
-
ctx.stack.push(node.i);
|
|
432
529
|
let item: SerovalNode;
|
|
433
530
|
let hasPrev = false;
|
|
531
|
+
const items = node.a;
|
|
532
|
+
ctx.stack.push(id);
|
|
434
533
|
for (let i = 0; i < size; i++) {
|
|
435
|
-
item =
|
|
534
|
+
item = items[i];
|
|
436
535
|
if (isIndexedValueInStack(ctx, item)) {
|
|
437
|
-
markRef(ctx,
|
|
438
|
-
createAddAssignment(ctx,
|
|
536
|
+
markRef(ctx, id);
|
|
537
|
+
createAddAssignment(ctx, id, getRefParam(ctx, item.i));
|
|
439
538
|
} else {
|
|
440
539
|
// Push directly
|
|
441
540
|
result += (hasPrev ? ',' : '') + serializeTree(ctx, item);
|
|
@@ -447,38 +546,42 @@ function serializeSet(
|
|
|
447
546
|
serialized += '([' + result + '])';
|
|
448
547
|
}
|
|
449
548
|
}
|
|
450
|
-
return assignIndexedValue(ctx,
|
|
549
|
+
return assignIndexedValue(ctx, id, serialized);
|
|
451
550
|
}
|
|
452
551
|
|
|
453
552
|
function serializeMap(
|
|
454
553
|
ctx: SerializationContext,
|
|
455
554
|
node: SerovalMapNode,
|
|
456
|
-
) {
|
|
555
|
+
): string {
|
|
457
556
|
let serialized = 'new Map';
|
|
458
|
-
|
|
557
|
+
const size = node.d.s;
|
|
558
|
+
const id = node.i;
|
|
559
|
+
if (size) {
|
|
459
560
|
let result = '';
|
|
460
|
-
ctx.stack.push(node.i);
|
|
461
561
|
let key: SerovalNode;
|
|
462
562
|
let val: SerovalNode;
|
|
463
563
|
let keyRef: string;
|
|
464
564
|
let valueRef: string;
|
|
465
565
|
let parent: number[];
|
|
466
566
|
let hasPrev = false;
|
|
467
|
-
|
|
567
|
+
const keys = node.d.k;
|
|
568
|
+
const vals = node.d.v;
|
|
569
|
+
ctx.stack.push(id);
|
|
570
|
+
for (let i = 0; i < size; i++) {
|
|
468
571
|
// Check if key is a parent
|
|
469
|
-
key =
|
|
470
|
-
val =
|
|
572
|
+
key = keys[i];
|
|
573
|
+
val = vals[i];
|
|
471
574
|
if (isIndexedValueInStack(ctx, key)) {
|
|
472
575
|
// Create reference for the map instance
|
|
473
|
-
keyRef = getRefParam(ctx,
|
|
474
|
-
markRef(ctx,
|
|
576
|
+
keyRef = getRefParam(ctx, id);
|
|
577
|
+
markRef(ctx, id);
|
|
475
578
|
// Check if value is a parent
|
|
476
579
|
if (isIndexedValueInStack(ctx, val)) {
|
|
477
580
|
valueRef = getRefParam(ctx, val.i);
|
|
478
581
|
// Register an assignment since
|
|
479
582
|
// both key and value are a parent of this
|
|
480
583
|
// Map instance
|
|
481
|
-
createSetAssignment(ctx,
|
|
584
|
+
createSetAssignment(ctx, id, keyRef, valueRef);
|
|
482
585
|
} else {
|
|
483
586
|
// Reset the stack
|
|
484
587
|
// This is required because the serialized
|
|
@@ -487,17 +590,17 @@ function serializeMap(
|
|
|
487
590
|
// assignment
|
|
488
591
|
parent = ctx.stack;
|
|
489
592
|
ctx.stack = [];
|
|
490
|
-
createSetAssignment(ctx,
|
|
593
|
+
createSetAssignment(ctx, id, keyRef, serializeTree(ctx, val));
|
|
491
594
|
ctx.stack = parent;
|
|
492
595
|
}
|
|
493
596
|
} else if (isIndexedValueInStack(ctx, val)) {
|
|
494
597
|
// Create ref for the Map instance
|
|
495
598
|
valueRef = getRefParam(ctx, val.i);
|
|
496
|
-
markRef(ctx,
|
|
599
|
+
markRef(ctx, id);
|
|
497
600
|
// Reset stack for the key serialization
|
|
498
601
|
parent = ctx.stack;
|
|
499
602
|
ctx.stack = [];
|
|
500
|
-
createSetAssignment(ctx,
|
|
603
|
+
createSetAssignment(ctx, id, serializeTree(ctx, key), valueRef);
|
|
501
604
|
ctx.stack = parent;
|
|
502
605
|
} else {
|
|
503
606
|
result += (hasPrev ? ',[' : '[') + serializeTree(ctx, key) + ',' + serializeTree(ctx, val) + ']';
|
|
@@ -512,67 +615,71 @@ function serializeMap(
|
|
|
512
615
|
serialized += '([' + result + '])';
|
|
513
616
|
}
|
|
514
617
|
}
|
|
515
|
-
return assignIndexedValue(ctx,
|
|
618
|
+
return assignIndexedValue(ctx, id, serialized);
|
|
516
619
|
}
|
|
517
620
|
|
|
518
621
|
function serializeAggregateError(
|
|
519
622
|
ctx: SerializationContext,
|
|
520
623
|
node: SerovalAggregateErrorNode,
|
|
521
|
-
) {
|
|
624
|
+
): string {
|
|
522
625
|
// Serialize the required arguments
|
|
523
|
-
|
|
626
|
+
const id = node.i;
|
|
627
|
+
ctx.stack.push(id);
|
|
524
628
|
const serialized = 'new AggregateError([],"' + node.m + '")';
|
|
525
629
|
ctx.stack.pop();
|
|
526
630
|
// `AggregateError` might've been extended
|
|
527
631
|
// either through class or custom properties
|
|
528
632
|
// Make sure to assign extra properties
|
|
529
|
-
return serializeDictionary(ctx,
|
|
633
|
+
return serializeDictionary(ctx, id, node.d, serialized);
|
|
530
634
|
}
|
|
531
635
|
|
|
532
636
|
function serializeError(
|
|
533
637
|
ctx: SerializationContext,
|
|
534
638
|
node: SerovalErrorNode,
|
|
535
|
-
) {
|
|
536
|
-
|
|
537
|
-
return serializeDictionary(ctx, node.i, node.d, serialized);
|
|
639
|
+
): string {
|
|
640
|
+
return serializeDictionary(ctx, node.i, node.d, 'new ' + node.c + '("' + node.m + '")');
|
|
538
641
|
}
|
|
539
642
|
|
|
540
643
|
function serializePromise(
|
|
541
644
|
ctx: SerializationContext,
|
|
542
645
|
node: SerovalPromiseNode,
|
|
543
|
-
) {
|
|
646
|
+
): string {
|
|
544
647
|
let serialized: string;
|
|
545
648
|
// Check if resolved value is a parent expression
|
|
546
|
-
|
|
649
|
+
const fulfilled = node.f;
|
|
650
|
+
const id = node.i;
|
|
651
|
+
if (isIndexedValueInStack(ctx, fulfilled)) {
|
|
547
652
|
// A Promise trick, reference the value
|
|
548
653
|
// inside the `then` expression so that
|
|
549
654
|
// the Promise evaluates after the parent
|
|
550
655
|
// has initialized
|
|
551
|
-
const ref = getRefParam(ctx,
|
|
656
|
+
const ref = getRefParam(ctx, fulfilled.i);
|
|
552
657
|
if (ctx.features & Feature.ArrowFunction) {
|
|
553
658
|
serialized = 'Promise.resolve().then(()=>' + ref + ')';
|
|
554
659
|
} else {
|
|
555
660
|
serialized = 'Promise.resolve().then(function(){return ' + ref + '})';
|
|
556
661
|
}
|
|
557
662
|
} else {
|
|
558
|
-
ctx.stack.push(
|
|
559
|
-
const result = serializeTree(ctx,
|
|
663
|
+
ctx.stack.push(id);
|
|
664
|
+
const result = serializeTree(ctx, fulfilled);
|
|
560
665
|
ctx.stack.pop();
|
|
561
666
|
// just inline the value/reference here
|
|
562
667
|
serialized = 'Promise.resolve(' + result + ')';
|
|
563
668
|
}
|
|
564
|
-
return assignIndexedValue(ctx,
|
|
669
|
+
return assignIndexedValue(ctx, id, serialized);
|
|
565
670
|
}
|
|
566
671
|
|
|
567
672
|
function serializeArrayBuffer(
|
|
568
673
|
ctx: SerializationContext,
|
|
569
674
|
node: SerovalArrayBufferNode,
|
|
570
|
-
) {
|
|
675
|
+
): string {
|
|
571
676
|
let result = 'new Uint8Array(';
|
|
572
|
-
|
|
677
|
+
const buffer = node.s;
|
|
678
|
+
const len = buffer.length;
|
|
679
|
+
if (len) {
|
|
573
680
|
result += '[';
|
|
574
|
-
for (let i = 0
|
|
575
|
-
result += ((i > 0) ? ',' : '') +
|
|
681
|
+
for (let i = 0; i < len; i++) {
|
|
682
|
+
result += ((i > 0) ? ',' : '') + buffer[i];
|
|
576
683
|
}
|
|
577
684
|
result += ']';
|
|
578
685
|
}
|
|
@@ -582,121 +689,115 @@ function serializeArrayBuffer(
|
|
|
582
689
|
function serializeTypedArray(
|
|
583
690
|
ctx: SerializationContext,
|
|
584
691
|
node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
|
|
585
|
-
) {
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
ctx: SerializationContext,
|
|
592
|
-
node: SerovalIterableNode,
|
|
593
|
-
) {
|
|
594
|
-
const parent = ctx.stack;
|
|
595
|
-
ctx.stack = [];
|
|
596
|
-
const values = serializeNodeList(ctx, node);
|
|
597
|
-
ctx.stack = parent;
|
|
598
|
-
let serialized = values;
|
|
599
|
-
if (ctx.features & Feature.ArrayPrototypeValues) {
|
|
600
|
-
serialized += '.values()';
|
|
601
|
-
} else {
|
|
602
|
-
serialized += '[Symbol.iterator]()';
|
|
603
|
-
}
|
|
604
|
-
if (ctx.features & Feature.ArrowFunction) {
|
|
605
|
-
serialized = '{[Symbol.iterator]:()=>' + serialized + '}';
|
|
606
|
-
} else if (ctx.features & Feature.MethodShorthand) {
|
|
607
|
-
serialized = '{[Symbol.iterator](){return ' + serialized + '}}';
|
|
608
|
-
} else {
|
|
609
|
-
serialized = '{[Symbol.iterator]:function(){return ' + serialized + '}}';
|
|
610
|
-
}
|
|
611
|
-
return serializeDictionary(ctx, node.i, node.d, serialized);
|
|
692
|
+
): string {
|
|
693
|
+
return assignIndexedValue(
|
|
694
|
+
ctx,
|
|
695
|
+
node.i,
|
|
696
|
+
'new ' + node.c + '(' + serializeTree(ctx, node.f) + ',' + node.b + ',' + node.l + ')',
|
|
697
|
+
);
|
|
612
698
|
}
|
|
613
699
|
|
|
614
700
|
function serializeDate(
|
|
615
701
|
ctx: SerializationContext,
|
|
616
702
|
node: SerovalDateNode,
|
|
617
|
-
) {
|
|
703
|
+
): string {
|
|
618
704
|
return assignIndexedValue(ctx, node.i, 'new Date("' + node.s + '")');
|
|
619
705
|
}
|
|
620
706
|
|
|
621
707
|
function serializeRegExp(
|
|
622
708
|
ctx: SerializationContext,
|
|
623
709
|
node: SerovalRegExpNode,
|
|
624
|
-
) {
|
|
710
|
+
): string {
|
|
625
711
|
return assignIndexedValue(ctx, node.i, '/' + node.c + '/' + node.m);
|
|
626
712
|
}
|
|
627
713
|
|
|
628
714
|
function serializeURL(
|
|
629
715
|
ctx: SerializationContext,
|
|
630
716
|
node: SerovalURLNode,
|
|
631
|
-
) {
|
|
717
|
+
): string {
|
|
632
718
|
return assignIndexedValue(ctx, node.i, 'new URL("' + node.s + '")');
|
|
633
719
|
}
|
|
634
720
|
|
|
635
721
|
function serializeURLSearchParams(
|
|
636
722
|
ctx: SerializationContext,
|
|
637
723
|
node: SerovalURLSearchParamsNode,
|
|
638
|
-
) {
|
|
639
|
-
return assignIndexedValue(
|
|
724
|
+
): string {
|
|
725
|
+
return assignIndexedValue(
|
|
726
|
+
ctx,
|
|
727
|
+
node.i,
|
|
728
|
+
node.s ? 'new URLSearchParams("' + node.s + '")' : 'new URLSearchParams',
|
|
729
|
+
);
|
|
640
730
|
}
|
|
641
731
|
|
|
642
732
|
function serializeReference(
|
|
643
733
|
ctx: SerializationContext,
|
|
644
734
|
node: SerovalReferenceNode,
|
|
645
|
-
) {
|
|
735
|
+
): string {
|
|
646
736
|
return assignIndexedValue(ctx, node.i, GLOBAL_KEY + '.get("' + node.s + '")');
|
|
647
737
|
}
|
|
648
738
|
|
|
649
739
|
function serializeDataView(
|
|
650
740
|
ctx: SerializationContext,
|
|
651
741
|
node: SerovalDataViewNode,
|
|
652
|
-
) {
|
|
653
|
-
|
|
654
|
-
|
|
742
|
+
): string {
|
|
743
|
+
return assignIndexedValue(
|
|
744
|
+
ctx,
|
|
745
|
+
node.i,
|
|
746
|
+
'new DataView(' + serializeTree(ctx, node.f) + ',' + node.b + ',' + node.l + ')',
|
|
747
|
+
);
|
|
655
748
|
}
|
|
656
749
|
|
|
657
750
|
function serializeBlob(
|
|
658
751
|
ctx: SerializationContext,
|
|
659
752
|
node: SerovalBlobNode,
|
|
660
|
-
) {
|
|
661
|
-
|
|
662
|
-
|
|
753
|
+
): string {
|
|
754
|
+
return assignIndexedValue(
|
|
755
|
+
ctx,
|
|
756
|
+
node.i,
|
|
757
|
+
'new Blob([' + serializeTree(ctx, node.f) + '],{type:"' + node.c + '"})',
|
|
758
|
+
);
|
|
663
759
|
}
|
|
664
760
|
|
|
665
761
|
function serializeFile(
|
|
666
762
|
ctx: SerializationContext,
|
|
667
763
|
node: SerovalFileNode,
|
|
668
|
-
) {
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
764
|
+
): string {
|
|
765
|
+
return assignIndexedValue(
|
|
766
|
+
ctx,
|
|
767
|
+
node.i,
|
|
768
|
+
'new File([' + serializeTree(ctx, node.f) + '],"' + node.m + '",{type:"' + node.c + '",lastModified:' + node.b + '})',
|
|
769
|
+
);
|
|
672
770
|
}
|
|
673
771
|
|
|
674
772
|
function serializeHeaders(
|
|
675
773
|
ctx: SerializationContext,
|
|
676
774
|
node: SerovalHeadersNode,
|
|
677
|
-
) {
|
|
678
|
-
return assignIndexedValue(
|
|
775
|
+
): string {
|
|
776
|
+
return assignIndexedValue(
|
|
777
|
+
ctx,
|
|
778
|
+
node.i,
|
|
779
|
+
'new Headers(' + serializeProperties(ctx, node.i, node.d) + ')',
|
|
780
|
+
);
|
|
679
781
|
}
|
|
680
782
|
|
|
681
783
|
function serializeFormDataEntries(
|
|
682
784
|
ctx: SerializationContext,
|
|
683
785
|
node: SerovalFormDataNode,
|
|
684
|
-
) {
|
|
685
|
-
ctx.stack.push(node.i);
|
|
686
|
-
const mainAssignments: Assignment[] = [];
|
|
687
|
-
let parentStack: number[];
|
|
786
|
+
): string | undefined {
|
|
688
787
|
let value: string;
|
|
689
788
|
let key: string;
|
|
789
|
+
const keys = node.d.k;
|
|
790
|
+
const vals = node.d.v;
|
|
791
|
+
const id = node.i;
|
|
792
|
+
const mainAssignments: Assignment[] = [];
|
|
690
793
|
let parentAssignment: Assignment[];
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
value = serializeTree(ctx,
|
|
695
|
-
key = node.d.k[i];
|
|
696
|
-
ctx.stack = parentStack;
|
|
794
|
+
ctx.stack.push(id);
|
|
795
|
+
for (let i = 0, len = node.d.s; i < len; i++) {
|
|
796
|
+
key = keys[i];
|
|
797
|
+
value = serializeTree(ctx, vals[i]);
|
|
697
798
|
parentAssignment = ctx.assignments;
|
|
698
799
|
ctx.assignments = mainAssignments;
|
|
699
|
-
createAppendAssignment(ctx,
|
|
800
|
+
createAppendAssignment(ctx, id, '"' + key + '"', value);
|
|
700
801
|
ctx.assignments = parentAssignment;
|
|
701
802
|
}
|
|
702
803
|
ctx.stack.pop();
|
|
@@ -706,17 +807,34 @@ function serializeFormDataEntries(
|
|
|
706
807
|
function serializeFormData(
|
|
707
808
|
ctx: SerializationContext,
|
|
708
809
|
node: SerovalFormDataNode,
|
|
709
|
-
) {
|
|
710
|
-
|
|
711
|
-
|
|
810
|
+
): string {
|
|
811
|
+
const size = node.d.s;
|
|
812
|
+
const id = node.i;
|
|
813
|
+
if (size) {
|
|
814
|
+
markRef(ctx, id);
|
|
712
815
|
}
|
|
713
|
-
const result = assignIndexedValue(ctx,
|
|
714
|
-
if (
|
|
715
|
-
|
|
816
|
+
const result = assignIndexedValue(ctx, id, 'new FormData()');
|
|
817
|
+
if (size) {
|
|
818
|
+
const entries = serializeFormDataEntries(ctx, node);
|
|
819
|
+
return '(' + result + ',' + (entries == null ? '' : entries) + getRefParam(ctx, id) + ')';
|
|
716
820
|
}
|
|
717
821
|
return result;
|
|
718
822
|
}
|
|
719
823
|
|
|
824
|
+
function serializeBoxed(
|
|
825
|
+
ctx: SerializationContext,
|
|
826
|
+
node: SerovalBoxedNode,
|
|
827
|
+
): string {
|
|
828
|
+
return assignIndexedValue(ctx, node.i, 'Object(' + serializeTree(ctx, node.f) + ')');
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
function serializeWKSymbol(
|
|
832
|
+
ctx: SerializationContext,
|
|
833
|
+
node: SerovalWKSymbolNode,
|
|
834
|
+
): string {
|
|
835
|
+
return assignIndexedValue(ctx, node.i, SYMBOL_STRING[node.s]);
|
|
836
|
+
}
|
|
837
|
+
|
|
720
838
|
export default function serializeTree(
|
|
721
839
|
ctx: SerializationContext,
|
|
722
840
|
node: SerovalNode,
|
|
@@ -726,20 +844,8 @@ export default function serializeTree(
|
|
|
726
844
|
return '' + node.s;
|
|
727
845
|
case SerovalNodeType.String:
|
|
728
846
|
return '"' + node.s + '"';
|
|
729
|
-
case SerovalNodeType.
|
|
730
|
-
return node
|
|
731
|
-
case SerovalNodeType.Undefined:
|
|
732
|
-
return 'void 0';
|
|
733
|
-
case SerovalNodeType.Null:
|
|
734
|
-
return 'null';
|
|
735
|
-
case SerovalNodeType.NegativeZero:
|
|
736
|
-
return '-0';
|
|
737
|
-
case SerovalNodeType.Infinity:
|
|
738
|
-
return '1/0';
|
|
739
|
-
case SerovalNodeType.NegativeInfinity:
|
|
740
|
-
return '-1/0';
|
|
741
|
-
case SerovalNodeType.NaN:
|
|
742
|
-
return 'NaN';
|
|
847
|
+
case SerovalNodeType.Constant:
|
|
848
|
+
return serializeConstant(node);
|
|
743
849
|
case SerovalNodeType.BigInt:
|
|
744
850
|
return node.s + 'n';
|
|
745
851
|
case SerovalNodeType.IndexedValue:
|
|
@@ -769,12 +875,10 @@ export default function serializeTree(
|
|
|
769
875
|
return serializeAggregateError(ctx, node);
|
|
770
876
|
case SerovalNodeType.Error:
|
|
771
877
|
return serializeError(ctx, node);
|
|
772
|
-
case SerovalNodeType.Iterable:
|
|
773
|
-
return serializeIterable(ctx, node);
|
|
774
878
|
case SerovalNodeType.Promise:
|
|
775
879
|
return serializePromise(ctx, node);
|
|
776
880
|
case SerovalNodeType.WKSymbol:
|
|
777
|
-
return
|
|
881
|
+
return serializeWKSymbol(ctx, node);
|
|
778
882
|
case SerovalNodeType.URL:
|
|
779
883
|
return serializeURL(ctx, node);
|
|
780
884
|
case SerovalNodeType.URLSearchParams:
|
|
@@ -789,7 +893,9 @@ export default function serializeTree(
|
|
|
789
893
|
return serializeHeaders(ctx, node);
|
|
790
894
|
case SerovalNodeType.FormData:
|
|
791
895
|
return serializeFormData(ctx, node);
|
|
896
|
+
case SerovalNodeType.Boxed:
|
|
897
|
+
return serializeBoxed(ctx, node);
|
|
792
898
|
default:
|
|
793
|
-
throw new Error('
|
|
899
|
+
throw new Error('invariant');
|
|
794
900
|
}
|
|
795
901
|
}
|