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