seroval 1.3.2 → 1.4.1
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 +2817 -2700
- package/dist/cjs/development/index.cjs.map +4 -4
- package/dist/cjs/production/index.cjs +3 -17
- package/dist/esm/development/index.mjs +2817 -2700
- package/dist/esm/development/index.mjs.map +4 -4
- package/dist/esm/production/index.mjs +3 -17
- package/dist/types/core/base-primitives.d.ts +3 -4
- package/dist/types/core/base-primitives.d.ts.map +1 -1
- package/dist/types/core/compat.d.ts +3 -2
- package/dist/types/core/compat.d.ts.map +1 -1
- package/dist/types/core/constants.d.ts +2 -1
- package/dist/types/core/constants.d.ts.map +1 -1
- package/dist/types/core/constructors.d.ts +54 -0
- package/dist/types/core/constructors.d.ts.map +1 -0
- package/dist/types/core/context/async-parser.d.ts +20 -0
- package/dist/types/core/context/async-parser.d.ts.map +1 -0
- package/dist/types/core/context/deserializer.d.ts +40 -38
- package/dist/types/core/context/deserializer.d.ts.map +1 -1
- package/dist/types/core/context/parser.d.ts +34 -19
- package/dist/types/core/context/parser.d.ts.map +1 -1
- package/dist/types/core/context/serializer.d.ts +38 -99
- package/dist/types/core/context/serializer.d.ts.map +1 -1
- package/dist/types/core/context/sync-parser.d.ts +59 -0
- package/dist/types/core/context/sync-parser.d.ts.map +1 -0
- package/dist/types/core/cross/index.d.ts +12 -13
- package/dist/types/core/cross/index.d.ts.map +1 -1
- package/dist/types/core/errors.d.ts +9 -0
- package/dist/types/core/errors.d.ts.map +1 -1
- package/dist/types/core/function-string.d.ts +2 -2
- package/dist/types/core/function-string.d.ts.map +1 -1
- package/dist/types/core/literals.d.ts.map +1 -1
- package/dist/types/core/node.d.ts +1 -1
- package/dist/types/core/node.d.ts.map +1 -1
- package/dist/types/core/plugin.d.ts +13 -11
- package/dist/types/core/plugin.d.ts.map +1 -1
- package/dist/types/core/reference.d.ts.map +1 -1
- package/dist/types/core/special-reference.d.ts +3 -2
- package/dist/types/core/special-reference.d.ts.map +1 -1
- package/dist/types/core/stream.d.ts +1 -2
- package/dist/types/core/stream.d.ts.map +1 -1
- package/dist/types/core/string.d.ts.map +1 -1
- package/dist/types/core/symbols.d.ts +14 -0
- package/dist/types/core/symbols.d.ts.map +1 -0
- package/dist/types/core/tree/index.d.ts +7 -3
- package/dist/types/core/tree/index.d.ts.map +1 -1
- package/dist/types/core/types.d.ts +4 -11
- package/dist/types/core/types.d.ts.map +1 -1
- package/dist/types/core/utils/iterator-to-sequence.d.ts.map +1 -1
- package/dist/types/index.d.ts +10 -5
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +18 -21
- package/dist/types/core/context/parser/async.d.ts +0 -24
- package/dist/types/core/context/parser/async.d.ts.map +0 -1
- package/dist/types/core/context/parser/stream.d.ts +0 -43
- package/dist/types/core/context/parser/stream.d.ts.map +0 -1
- package/dist/types/core/context/parser/sync.d.ts +0 -30
- package/dist/types/core/context/parser/sync.d.ts.map +0 -1
- package/dist/types/core/cross/async.d.ts +0 -8
- package/dist/types/core/cross/async.d.ts.map +0 -1
- package/dist/types/core/cross/deserializer.d.ts +0 -9
- package/dist/types/core/cross/deserializer.d.ts.map +0 -1
- package/dist/types/core/cross/parser.d.ts +0 -6
- package/dist/types/core/cross/parser.d.ts.map +0 -1
- package/dist/types/core/cross/serializer.d.ts +0 -16
- package/dist/types/core/cross/serializer.d.ts.map +0 -1
- package/dist/types/core/cross/stream.d.ts +0 -8
- package/dist/types/core/cross/stream.d.ts.map +0 -1
- package/dist/types/core/cross/sync.d.ts +0 -8
- package/dist/types/core/cross/sync.d.ts.map +0 -1
- package/dist/types/core/tree/async.d.ts +0 -8
- package/dist/types/core/tree/async.d.ts.map +0 -1
- package/dist/types/core/tree/deserializer.d.ts +0 -13
- package/dist/types/core/tree/deserializer.d.ts.map +0 -1
- package/dist/types/core/tree/serializer.d.ts +0 -29
- package/dist/types/core/tree/serializer.d.ts.map +0 -1
- package/dist/types/core/tree/sync.d.ts +0 -8
- package/dist/types/core/tree/sync.d.ts.map +0 -1
- package/dist/types/core/utils/assert.d.ts +0 -2
- package/dist/types/core/utils/assert.d.ts.map +0 -1
- package/dist/types/core/utils/deferred.d.ts +0 -7
- package/dist/types/core/utils/deferred.d.ts.map +0 -1
- package/src/core/Serializer.ts +0 -119
- package/src/core/base-primitives.ts +0 -542
- package/src/core/compat.ts +0 -20
- package/src/core/constants.ts +0 -185
- package/src/core/context/deserializer.ts +0 -456
- package/src/core/context/parser/async.ts +0 -495
- package/src/core/context/parser/stream.ts +0 -323
- package/src/core/context/parser/sync.ts +0 -404
- package/src/core/context/parser.ts +0 -270
- package/src/core/context/serializer.ts +0 -1180
- package/src/core/cross/async.ts +0 -9
- package/src/core/cross/deserializer.ts +0 -16
- package/src/core/cross/index.ts +0 -170
- package/src/core/cross/parser.ts +0 -7
- package/src/core/cross/serializer.ts +0 -72
- package/src/core/cross/stream.ts +0 -9
- package/src/core/cross/sync.ts +0 -9
- package/src/core/errors.ts +0 -102
- package/src/core/function-string.ts +0 -31
- package/src/core/keys.ts +0 -17
- package/src/core/literals.ts +0 -43
- package/src/core/node.ts +0 -40
- package/src/core/opaque-reference.ts +0 -9
- package/src/core/plugin.ts +0 -91
- package/src/core/reference.ts +0 -63
- package/src/core/special-reference.ts +0 -114
- package/src/core/stream.ts +0 -205
- package/src/core/string.ts +0 -84
- package/src/core/tree/async.ts +0 -9
- package/src/core/tree/deserializer.ts +0 -26
- package/src/core/tree/index.ts +0 -111
- package/src/core/tree/serializer.ts +0 -98
- package/src/core/tree/sync.ts +0 -9
- package/src/core/types.ts +0 -370
- package/src/core/utils/assert.ts +0 -5
- package/src/core/utils/deferred.ts +0 -22
- package/src/core/utils/error.ts +0 -73
- package/src/core/utils/get-identifier.ts +0 -18
- package/src/core/utils/get-object-flag.ts +0 -14
- package/src/core/utils/is-valid-identifier.ts +0 -12
- package/src/core/utils/iterator-to-sequence.ts +0 -66
- package/src/core/utils/promise-to-result.ts +0 -9
- package/src/core/utils/typed-array.ts +0 -56
- package/src/index.ts +0 -18
|
@@ -1,1180 +0,0 @@
|
|
|
1
|
-
import { Feature } from '../compat';
|
|
2
|
-
import {
|
|
3
|
-
CONSTANT_STRING,
|
|
4
|
-
ERROR_CONSTRUCTOR_STRING,
|
|
5
|
-
NIL,
|
|
6
|
-
SYMBOL_STRING,
|
|
7
|
-
SerovalNodeType,
|
|
8
|
-
SerovalObjectFlags,
|
|
9
|
-
} from '../constants';
|
|
10
|
-
import {
|
|
11
|
-
SerovalMissingPluginError,
|
|
12
|
-
SerovalSerializationError,
|
|
13
|
-
SerovalUnsupportedNodeError,
|
|
14
|
-
} from '../errors';
|
|
15
|
-
import { createEffectfulFunction, createFunction } from '../function-string';
|
|
16
|
-
import { REFERENCES_KEY } from '../keys';
|
|
17
|
-
import type { Plugin, PluginAccessOptions, SerovalMode } from '../plugin';
|
|
18
|
-
import { serializeSpecialReferenceValue } from '../special-reference';
|
|
19
|
-
import type {
|
|
20
|
-
SerovalAggregateErrorNode,
|
|
21
|
-
SerovalArrayBufferNode,
|
|
22
|
-
SerovalArrayNode,
|
|
23
|
-
SerovalAsyncIteratorFactoryInstanceNode,
|
|
24
|
-
SerovalAsyncIteratorFactoryNode,
|
|
25
|
-
SerovalBigIntTypedArrayNode,
|
|
26
|
-
SerovalBoxedNode,
|
|
27
|
-
SerovalDataViewNode,
|
|
28
|
-
SerovalDateNode,
|
|
29
|
-
SerovalErrorNode,
|
|
30
|
-
SerovalIndexedValueNode,
|
|
31
|
-
SerovalIteratorFactoryInstanceNode,
|
|
32
|
-
SerovalIteratorFactoryNode,
|
|
33
|
-
SerovalMapNode,
|
|
34
|
-
SerovalNode,
|
|
35
|
-
SerovalNodeWithID,
|
|
36
|
-
SerovalNullConstructorNode,
|
|
37
|
-
SerovalObjectNode,
|
|
38
|
-
SerovalObjectRecordKey,
|
|
39
|
-
SerovalObjectRecordNode,
|
|
40
|
-
SerovalPluginNode,
|
|
41
|
-
SerovalPromiseConstructorNode,
|
|
42
|
-
SerovalPromiseNode,
|
|
43
|
-
SerovalPromiseRejectNode,
|
|
44
|
-
SerovalPromiseResolveNode,
|
|
45
|
-
SerovalReferenceNode,
|
|
46
|
-
SerovalRegExpNode,
|
|
47
|
-
SerovalSetNode,
|
|
48
|
-
SerovalSpecialReferenceNode,
|
|
49
|
-
SerovalStreamConstructorNode,
|
|
50
|
-
SerovalStreamNextNode,
|
|
51
|
-
SerovalStreamReturnNode,
|
|
52
|
-
SerovalStreamThrowNode,
|
|
53
|
-
SerovalTypedArrayNode,
|
|
54
|
-
SerovalWKSymbolNode,
|
|
55
|
-
} from '../types';
|
|
56
|
-
import { isValidIdentifier } from '../utils/is-valid-identifier';
|
|
57
|
-
|
|
58
|
-
const enum AssignmentType {
|
|
59
|
-
Index = 0,
|
|
60
|
-
Add = 1,
|
|
61
|
-
Set = 2,
|
|
62
|
-
Delete = 3,
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
interface IndexAssignment {
|
|
66
|
-
t: AssignmentType.Index;
|
|
67
|
-
s: string;
|
|
68
|
-
k: undefined;
|
|
69
|
-
v: string;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
interface SetAssignment {
|
|
73
|
-
t: AssignmentType.Set;
|
|
74
|
-
s: string;
|
|
75
|
-
k: string;
|
|
76
|
-
v: string;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
interface AddAssignment {
|
|
80
|
-
t: AssignmentType.Add;
|
|
81
|
-
s: string;
|
|
82
|
-
k: undefined;
|
|
83
|
-
v: string;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
interface DeleteAssignment {
|
|
87
|
-
t: AssignmentType.Delete;
|
|
88
|
-
s: string;
|
|
89
|
-
k: string;
|
|
90
|
-
v: undefined;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Array of assignments to be done (used for recursion)
|
|
94
|
-
type Assignment =
|
|
95
|
-
| IndexAssignment
|
|
96
|
-
| AddAssignment
|
|
97
|
-
| SetAssignment
|
|
98
|
-
| DeleteAssignment;
|
|
99
|
-
|
|
100
|
-
export interface FlaggedObject {
|
|
101
|
-
type: SerovalObjectFlags;
|
|
102
|
-
value: string;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function getAssignmentExpression(assignment: Assignment): string {
|
|
106
|
-
switch (assignment.t) {
|
|
107
|
-
case AssignmentType.Index:
|
|
108
|
-
return assignment.s + '=' + assignment.v;
|
|
109
|
-
case AssignmentType.Set:
|
|
110
|
-
return assignment.s + '.set(' + assignment.k + ',' + assignment.v + ')';
|
|
111
|
-
case AssignmentType.Add:
|
|
112
|
-
return assignment.s + '.add(' + assignment.v + ')';
|
|
113
|
-
case AssignmentType.Delete:
|
|
114
|
-
return assignment.s + '.delete(' + assignment.k + ')';
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function mergeAssignments(assignments: Assignment[]): Assignment[] {
|
|
119
|
-
const newAssignments: Assignment[] = [];
|
|
120
|
-
let current = assignments[0];
|
|
121
|
-
for (
|
|
122
|
-
let i = 1, len = assignments.length, item: Assignment, prev = current;
|
|
123
|
-
i < len;
|
|
124
|
-
i++
|
|
125
|
-
) {
|
|
126
|
-
item = assignments[i];
|
|
127
|
-
if (item.t === AssignmentType.Index && item.v === prev.v) {
|
|
128
|
-
// Merge if the right-hand value is the same
|
|
129
|
-
// saves at least 2 chars
|
|
130
|
-
current = {
|
|
131
|
-
t: AssignmentType.Index,
|
|
132
|
-
s: item.s,
|
|
133
|
-
k: NIL,
|
|
134
|
-
v: getAssignmentExpression(current),
|
|
135
|
-
} as IndexAssignment;
|
|
136
|
-
} else if (item.t === AssignmentType.Set && item.s === prev.s) {
|
|
137
|
-
// Maps has chaining methods, merge if source is the same
|
|
138
|
-
current = {
|
|
139
|
-
t: AssignmentType.Set,
|
|
140
|
-
s: getAssignmentExpression(current),
|
|
141
|
-
k: item.k,
|
|
142
|
-
v: item.v,
|
|
143
|
-
} as SetAssignment;
|
|
144
|
-
} else if (item.t === AssignmentType.Add && item.s === prev.s) {
|
|
145
|
-
// Sets has chaining methods too
|
|
146
|
-
current = {
|
|
147
|
-
t: AssignmentType.Add,
|
|
148
|
-
s: getAssignmentExpression(current),
|
|
149
|
-
k: NIL,
|
|
150
|
-
v: item.v,
|
|
151
|
-
} as AddAssignment;
|
|
152
|
-
} else if (item.t === AssignmentType.Delete && item.s === prev.s) {
|
|
153
|
-
// Maps has chaining methods, merge if source is the same
|
|
154
|
-
current = {
|
|
155
|
-
t: AssignmentType.Delete,
|
|
156
|
-
s: getAssignmentExpression(current),
|
|
157
|
-
k: item.k,
|
|
158
|
-
v: NIL,
|
|
159
|
-
} as DeleteAssignment;
|
|
160
|
-
} else {
|
|
161
|
-
// Different assignment, push current
|
|
162
|
-
newAssignments.push(current);
|
|
163
|
-
current = item;
|
|
164
|
-
}
|
|
165
|
-
prev = item;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
newAssignments.push(current);
|
|
169
|
-
|
|
170
|
-
return newAssignments;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function resolveAssignments(assignments: Assignment[]): string | undefined {
|
|
174
|
-
if (assignments.length) {
|
|
175
|
-
let result = '';
|
|
176
|
-
const merged = mergeAssignments(assignments);
|
|
177
|
-
for (let i = 0, len = merged.length; i < len; i++) {
|
|
178
|
-
result += getAssignmentExpression(merged[i]) + ',';
|
|
179
|
-
}
|
|
180
|
-
return result;
|
|
181
|
-
}
|
|
182
|
-
return NIL;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const NULL_CONSTRUCTOR = 'Object.create(null)';
|
|
186
|
-
const SET_CONSTRUCTOR = 'new Set';
|
|
187
|
-
const MAP_CONSTRUCTOR = 'new Map';
|
|
188
|
-
|
|
189
|
-
const PROMISE_RESOLVE = 'Promise.resolve';
|
|
190
|
-
const PROMISE_REJECT = 'Promise.reject';
|
|
191
|
-
|
|
192
|
-
const OBJECT_FLAG_CONSTRUCTOR: Record<SerovalObjectFlags, string | undefined> =
|
|
193
|
-
{
|
|
194
|
-
[SerovalObjectFlags.Frozen]: 'Object.freeze',
|
|
195
|
-
[SerovalObjectFlags.Sealed]: 'Object.seal',
|
|
196
|
-
[SerovalObjectFlags.NonExtensible]: 'Object.preventExtensions',
|
|
197
|
-
[SerovalObjectFlags.None]: NIL,
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
type SerovalNodeWithProperties =
|
|
201
|
-
| SerovalObjectNode
|
|
202
|
-
| SerovalNullConstructorNode
|
|
203
|
-
| SerovalAggregateErrorNode
|
|
204
|
-
| SerovalErrorNode;
|
|
205
|
-
|
|
206
|
-
export interface BaseSerializerContextOptions extends PluginAccessOptions {
|
|
207
|
-
features: number;
|
|
208
|
-
markedRefs: number[] | Set<number>;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
export default abstract class BaseSerializerContext
|
|
212
|
-
implements PluginAccessOptions
|
|
213
|
-
{
|
|
214
|
-
/**
|
|
215
|
-
* @private
|
|
216
|
-
*/
|
|
217
|
-
features: number;
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* To check if an object is synchronously referencing itself
|
|
221
|
-
* @private
|
|
222
|
-
*/
|
|
223
|
-
stack: number[] = [];
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Array of object mutations
|
|
227
|
-
* @private
|
|
228
|
-
*/
|
|
229
|
-
flags: FlaggedObject[] = [];
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Array of assignments to be done (used for recursion)
|
|
233
|
-
* @private
|
|
234
|
-
*/
|
|
235
|
-
assignments: Assignment[] = [];
|
|
236
|
-
|
|
237
|
-
plugins?: Plugin<any, any>[] | undefined;
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Refs that are...referenced
|
|
241
|
-
* @private
|
|
242
|
-
*/
|
|
243
|
-
marked: Set<number>;
|
|
244
|
-
|
|
245
|
-
constructor(options: BaseSerializerContextOptions) {
|
|
246
|
-
this.plugins = options.plugins;
|
|
247
|
-
this.features = options.features;
|
|
248
|
-
this.marked = new Set(options.markedRefs);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
abstract readonly mode: SerovalMode;
|
|
252
|
-
|
|
253
|
-
createFunction(parameters: string[], body: string): string {
|
|
254
|
-
return createFunction(this.features, parameters, body);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
createEffectfulFunction(parameters: string[], body: string): string {
|
|
258
|
-
return createEffectfulFunction(this.features, parameters, body);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* A tiny function that tells if a reference
|
|
263
|
-
* is to be accessed. This is a requirement for
|
|
264
|
-
* deciding whether or not we should generate
|
|
265
|
-
* an identifier for the object
|
|
266
|
-
*/
|
|
267
|
-
protected markRef(id: number): void {
|
|
268
|
-
this.marked.add(id);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
protected isMarked(id: number): boolean {
|
|
272
|
-
return this.marked.has(id);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Converts the ID of a reference into a identifier string
|
|
277
|
-
* that is used to refer to the object instance in the
|
|
278
|
-
* generated script.
|
|
279
|
-
*/
|
|
280
|
-
abstract getRefParam(id: number): string;
|
|
281
|
-
|
|
282
|
-
protected pushObjectFlag(flag: SerovalObjectFlags, id: number): void {
|
|
283
|
-
if (flag !== SerovalObjectFlags.None) {
|
|
284
|
-
this.markRef(id);
|
|
285
|
-
this.flags.push({
|
|
286
|
-
type: flag,
|
|
287
|
-
value: this.getRefParam(id),
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
private resolveFlags(): string | undefined {
|
|
293
|
-
let result = '';
|
|
294
|
-
for (let i = 0, current = this.flags, len = current.length; i < len; i++) {
|
|
295
|
-
const flag = current[i];
|
|
296
|
-
result += OBJECT_FLAG_CONSTRUCTOR[flag.type] + '(' + flag.value + '),';
|
|
297
|
-
}
|
|
298
|
-
return result;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
protected resolvePatches(): string | undefined {
|
|
302
|
-
const assignments = resolveAssignments(this.assignments);
|
|
303
|
-
const flags = this.resolveFlags();
|
|
304
|
-
if (assignments) {
|
|
305
|
-
if (flags) {
|
|
306
|
-
return assignments + flags;
|
|
307
|
-
}
|
|
308
|
-
return assignments;
|
|
309
|
-
}
|
|
310
|
-
return flags;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* Generates the inlined assignment for the reference
|
|
315
|
-
* This is different from the assignments array as this one
|
|
316
|
-
* signifies creation rather than mutation
|
|
317
|
-
*/
|
|
318
|
-
protected createAssignment(source: string, value: string): void {
|
|
319
|
-
this.assignments.push({
|
|
320
|
-
t: AssignmentType.Index,
|
|
321
|
-
s: source,
|
|
322
|
-
k: NIL,
|
|
323
|
-
v: value,
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
protected createAddAssignment(ref: number, value: string): void {
|
|
328
|
-
this.assignments.push({
|
|
329
|
-
t: AssignmentType.Add,
|
|
330
|
-
s: this.getRefParam(ref),
|
|
331
|
-
k: NIL,
|
|
332
|
-
v: value,
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
protected createSetAssignment(ref: number, key: string, value: string): void {
|
|
337
|
-
this.assignments.push({
|
|
338
|
-
t: AssignmentType.Set,
|
|
339
|
-
s: this.getRefParam(ref),
|
|
340
|
-
k: key,
|
|
341
|
-
v: value,
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
protected createDeleteAssignment(ref: number, key: string): void {
|
|
346
|
-
this.assignments.push({
|
|
347
|
-
t: AssignmentType.Delete,
|
|
348
|
-
s: this.getRefParam(ref),
|
|
349
|
-
k: key,
|
|
350
|
-
v: NIL,
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
protected createArrayAssign(
|
|
355
|
-
ref: number,
|
|
356
|
-
index: number | string,
|
|
357
|
-
value: string,
|
|
358
|
-
): void {
|
|
359
|
-
this.createAssignment(this.getRefParam(ref) + '[' + index + ']', value);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
protected createObjectAssign(ref: number, key: string, value: string): void {
|
|
363
|
-
this.createAssignment(this.getRefParam(ref) + '.' + key, value);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Checks if the value is in the stack. Stack here is a reference
|
|
368
|
-
* structure to know if a object is to be accessed in a TDZ.
|
|
369
|
-
*/
|
|
370
|
-
isIndexedValueInStack(node: SerovalNode): boolean {
|
|
371
|
-
return (
|
|
372
|
-
node.t === SerovalNodeType.IndexedValue && this.stack.includes(node.i)
|
|
373
|
-
);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Produces an assignment expression. `id` generates a reference
|
|
378
|
-
* parameter (through `getRefParam`) and has the option to
|
|
379
|
-
* return the reference parameter directly or assign a value to
|
|
380
|
-
* it.
|
|
381
|
-
*/
|
|
382
|
-
protected abstract assignIndexedValue(id: number, value: string): string;
|
|
383
|
-
|
|
384
|
-
protected serializeReference(node: SerovalReferenceNode): string {
|
|
385
|
-
return this.assignIndexedValue(
|
|
386
|
-
node.i,
|
|
387
|
-
REFERENCES_KEY + '.get("' + node.s + '")',
|
|
388
|
-
);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
protected serializeArrayItem(
|
|
392
|
-
id: number,
|
|
393
|
-
item: SerovalNode | undefined,
|
|
394
|
-
index: number,
|
|
395
|
-
): string {
|
|
396
|
-
// Check if index is a hole
|
|
397
|
-
if (item) {
|
|
398
|
-
// Check if item is a parent
|
|
399
|
-
if (this.isIndexedValueInStack(item)) {
|
|
400
|
-
this.markRef(id);
|
|
401
|
-
this.createArrayAssign(
|
|
402
|
-
id,
|
|
403
|
-
index,
|
|
404
|
-
this.getRefParam((item as SerovalIndexedValueNode).i),
|
|
405
|
-
);
|
|
406
|
-
return '';
|
|
407
|
-
}
|
|
408
|
-
return this.serialize(item);
|
|
409
|
-
}
|
|
410
|
-
return '';
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
protected serializeArray(node: SerovalArrayNode): string {
|
|
414
|
-
const id = node.i;
|
|
415
|
-
if (node.l) {
|
|
416
|
-
this.stack.push(id);
|
|
417
|
-
const list = node.a;
|
|
418
|
-
let values = this.serializeArrayItem(id, list[0], 0);
|
|
419
|
-
// This is different than Map and Set
|
|
420
|
-
// because we also need to serialize
|
|
421
|
-
// the holes of the Array
|
|
422
|
-
let isHoley = values === '';
|
|
423
|
-
for (let i = 1, len = node.l, item: string; i < len; i++) {
|
|
424
|
-
item = this.serializeArrayItem(id, list[i], i);
|
|
425
|
-
values += ',' + item;
|
|
426
|
-
isHoley = item === '';
|
|
427
|
-
}
|
|
428
|
-
this.stack.pop();
|
|
429
|
-
this.pushObjectFlag(node.o, node.i);
|
|
430
|
-
return this.assignIndexedValue(id, '[' + values + (isHoley ? ',]' : ']'));
|
|
431
|
-
}
|
|
432
|
-
return this.assignIndexedValue(id, '[]');
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
protected serializeProperty(
|
|
436
|
-
source: SerovalNodeWithProperties,
|
|
437
|
-
key: SerovalObjectRecordKey,
|
|
438
|
-
val: SerovalNode,
|
|
439
|
-
): string {
|
|
440
|
-
if (typeof key === 'string') {
|
|
441
|
-
const check = Number(key);
|
|
442
|
-
const isIdentifier =
|
|
443
|
-
// Test if key is a valid positive number or JS identifier
|
|
444
|
-
// so that we don't have to serialize the key and wrap with brackets
|
|
445
|
-
(check >= 0 &&
|
|
446
|
-
// It's also important to consider that if the key is
|
|
447
|
-
// indeed numeric, we need to make sure that when
|
|
448
|
-
// converted back into a string, it's still the same
|
|
449
|
-
// to the original key. This allows us to differentiate
|
|
450
|
-
// keys that has numeric formats but in a different
|
|
451
|
-
// format, which can cause unintentional key declaration
|
|
452
|
-
// Example: { 0x1: 1 } vs { '0x1': 1 }
|
|
453
|
-
check.toString() === key) ||
|
|
454
|
-
isValidIdentifier(key);
|
|
455
|
-
if (this.isIndexedValueInStack(val)) {
|
|
456
|
-
const refParam = this.getRefParam((val as SerovalIndexedValueNode).i);
|
|
457
|
-
this.markRef(source.i);
|
|
458
|
-
// Strict identifier check, make sure
|
|
459
|
-
// that it isn't numeric (except NaN)
|
|
460
|
-
if (isIdentifier && check !== check) {
|
|
461
|
-
this.createObjectAssign(source.i, key, refParam);
|
|
462
|
-
} else {
|
|
463
|
-
this.createArrayAssign(
|
|
464
|
-
source.i,
|
|
465
|
-
isIdentifier ? key : '"' + key + '"',
|
|
466
|
-
refParam,
|
|
467
|
-
);
|
|
468
|
-
}
|
|
469
|
-
return '';
|
|
470
|
-
}
|
|
471
|
-
return (isIdentifier ? key : '"' + key + '"') + ':' + this.serialize(val);
|
|
472
|
-
}
|
|
473
|
-
return '[' + this.serialize(key) + ']:' + this.serialize(val);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
protected serializeProperties(
|
|
477
|
-
source: SerovalNodeWithProperties,
|
|
478
|
-
record: SerovalObjectRecordNode,
|
|
479
|
-
): string {
|
|
480
|
-
const len = record.s;
|
|
481
|
-
if (len) {
|
|
482
|
-
const keys = record.k;
|
|
483
|
-
const values = record.v;
|
|
484
|
-
this.stack.push(source.i);
|
|
485
|
-
let result = this.serializeProperty(source, keys[0], values[0]);
|
|
486
|
-
for (let i = 1, item = result; i < len; i++) {
|
|
487
|
-
item = this.serializeProperty(source, keys[i], values[i]);
|
|
488
|
-
result += (item && result && ',') + item;
|
|
489
|
-
}
|
|
490
|
-
this.stack.pop();
|
|
491
|
-
return '{' + result + '}';
|
|
492
|
-
}
|
|
493
|
-
return '{}';
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
protected serializeObject(node: SerovalObjectNode): string {
|
|
497
|
-
this.pushObjectFlag(node.o, node.i);
|
|
498
|
-
return this.assignIndexedValue(
|
|
499
|
-
node.i,
|
|
500
|
-
this.serializeProperties(node, node.p),
|
|
501
|
-
);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
protected serializeWithObjectAssign(
|
|
505
|
-
source: SerovalNodeWithProperties,
|
|
506
|
-
value: SerovalObjectRecordNode,
|
|
507
|
-
serialized: string,
|
|
508
|
-
): string {
|
|
509
|
-
const fields = this.serializeProperties(source, value);
|
|
510
|
-
if (fields !== '{}') {
|
|
511
|
-
return 'Object.assign(' + serialized + ',' + fields + ')';
|
|
512
|
-
}
|
|
513
|
-
return serialized;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
private serializeStringKeyAssignment(
|
|
517
|
-
source: SerovalNodeWithProperties,
|
|
518
|
-
mainAssignments: Assignment[],
|
|
519
|
-
key: string,
|
|
520
|
-
value: SerovalNode,
|
|
521
|
-
): void {
|
|
522
|
-
const serialized = this.serialize(value);
|
|
523
|
-
const check = Number(key);
|
|
524
|
-
const isIdentifier =
|
|
525
|
-
// Test if key is a valid positive number or JS identifier
|
|
526
|
-
// so that we don't have to serialize the key and wrap with brackets
|
|
527
|
-
(check >= 0 &&
|
|
528
|
-
// It's also important to consider that if the key is
|
|
529
|
-
// indeed numeric, we need to make sure that when
|
|
530
|
-
// converted back into a string, it's still the same
|
|
531
|
-
// to the original key. This allows us to differentiate
|
|
532
|
-
// keys that has numeric formats but in a different
|
|
533
|
-
// format, which can cause unintentional key declaration
|
|
534
|
-
// Example: { 0x1: 1 } vs { '0x1': 1 }
|
|
535
|
-
check.toString() === key) ||
|
|
536
|
-
isValidIdentifier(key);
|
|
537
|
-
if (this.isIndexedValueInStack(value)) {
|
|
538
|
-
// Strict identifier check, make sure
|
|
539
|
-
// that it isn't numeric (except NaN)
|
|
540
|
-
if (isIdentifier && check !== check) {
|
|
541
|
-
this.createObjectAssign(source.i, key, serialized);
|
|
542
|
-
} else {
|
|
543
|
-
this.createArrayAssign(
|
|
544
|
-
source.i,
|
|
545
|
-
isIdentifier ? key : '"' + key + '"',
|
|
546
|
-
serialized,
|
|
547
|
-
);
|
|
548
|
-
}
|
|
549
|
-
} else {
|
|
550
|
-
const parentAssignment = this.assignments;
|
|
551
|
-
this.assignments = mainAssignments;
|
|
552
|
-
if (isIdentifier && check !== check) {
|
|
553
|
-
this.createObjectAssign(source.i, key, serialized);
|
|
554
|
-
} else {
|
|
555
|
-
this.createArrayAssign(
|
|
556
|
-
source.i,
|
|
557
|
-
isIdentifier ? key : '"' + key + '"',
|
|
558
|
-
serialized,
|
|
559
|
-
);
|
|
560
|
-
}
|
|
561
|
-
this.assignments = parentAssignment;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
protected serializeAssignment(
|
|
566
|
-
source: SerovalNodeWithProperties,
|
|
567
|
-
mainAssignments: Assignment[],
|
|
568
|
-
key: SerovalObjectRecordKey,
|
|
569
|
-
value: SerovalNode,
|
|
570
|
-
): void {
|
|
571
|
-
if (typeof key === 'string') {
|
|
572
|
-
this.serializeStringKeyAssignment(source, mainAssignments, key, value);
|
|
573
|
-
} else {
|
|
574
|
-
const parent = this.stack;
|
|
575
|
-
this.stack = [];
|
|
576
|
-
const serialized = this.serialize(value);
|
|
577
|
-
this.stack = parent;
|
|
578
|
-
const parentAssignment = this.assignments;
|
|
579
|
-
this.assignments = mainAssignments;
|
|
580
|
-
this.createArrayAssign(source.i, this.serialize(key), serialized);
|
|
581
|
-
this.assignments = parentAssignment;
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
protected serializeAssignments(
|
|
586
|
-
source: SerovalNodeWithProperties,
|
|
587
|
-
node: SerovalObjectRecordNode,
|
|
588
|
-
): string | undefined {
|
|
589
|
-
const len = node.s;
|
|
590
|
-
if (len) {
|
|
591
|
-
const mainAssignments: Assignment[] = [];
|
|
592
|
-
const keys = node.k;
|
|
593
|
-
const values = node.v;
|
|
594
|
-
this.stack.push(source.i);
|
|
595
|
-
for (let i = 0; i < len; i++) {
|
|
596
|
-
this.serializeAssignment(source, mainAssignments, keys[i], values[i]);
|
|
597
|
-
}
|
|
598
|
-
this.stack.pop();
|
|
599
|
-
return resolveAssignments(mainAssignments);
|
|
600
|
-
}
|
|
601
|
-
return NIL;
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
protected serializeDictionary(
|
|
605
|
-
node: SerovalNodeWithProperties,
|
|
606
|
-
init: string,
|
|
607
|
-
): string {
|
|
608
|
-
if (node.p) {
|
|
609
|
-
if (this.features & Feature.ObjectAssign) {
|
|
610
|
-
init = this.serializeWithObjectAssign(node, node.p, init);
|
|
611
|
-
} else {
|
|
612
|
-
this.markRef(node.i);
|
|
613
|
-
const assignments = this.serializeAssignments(node, node.p);
|
|
614
|
-
if (assignments) {
|
|
615
|
-
return (
|
|
616
|
-
'(' +
|
|
617
|
-
this.assignIndexedValue(node.i, init) +
|
|
618
|
-
',' +
|
|
619
|
-
assignments +
|
|
620
|
-
this.getRefParam(node.i) +
|
|
621
|
-
')'
|
|
622
|
-
);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
return this.assignIndexedValue(node.i, init);
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
protected serializeNullConstructor(node: SerovalNullConstructorNode): string {
|
|
630
|
-
this.pushObjectFlag(node.o, node.i);
|
|
631
|
-
return this.serializeDictionary(node, NULL_CONSTRUCTOR);
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
protected serializeDate(node: SerovalDateNode): string {
|
|
635
|
-
return this.assignIndexedValue(node.i, 'new Date("' + node.s + '")');
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
protected serializeRegExp(node: SerovalRegExpNode): string {
|
|
639
|
-
return this.assignIndexedValue(node.i, '/' + node.c + '/' + node.m);
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
protected serializeSetItem(id: number, item: SerovalNode): string {
|
|
643
|
-
if (this.isIndexedValueInStack(item)) {
|
|
644
|
-
this.markRef(id);
|
|
645
|
-
this.createAddAssignment(
|
|
646
|
-
id,
|
|
647
|
-
this.getRefParam((item as SerovalIndexedValueNode).i),
|
|
648
|
-
);
|
|
649
|
-
return '';
|
|
650
|
-
}
|
|
651
|
-
return this.serialize(item);
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
protected serializeSet(node: SerovalSetNode): string {
|
|
655
|
-
let serialized = SET_CONSTRUCTOR;
|
|
656
|
-
const size = node.l;
|
|
657
|
-
const id = node.i;
|
|
658
|
-
if (size) {
|
|
659
|
-
const items = node.a;
|
|
660
|
-
this.stack.push(id);
|
|
661
|
-
let result = this.serializeSetItem(id, items[0]);
|
|
662
|
-
for (let i = 1, item = result; i < size; i++) {
|
|
663
|
-
item = this.serializeSetItem(id, items[i]);
|
|
664
|
-
result += (item && result && ',') + item;
|
|
665
|
-
}
|
|
666
|
-
this.stack.pop();
|
|
667
|
-
if (result) {
|
|
668
|
-
serialized += '([' + result + '])';
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
return this.assignIndexedValue(id, serialized);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
protected serializeMapEntry(
|
|
675
|
-
id: number,
|
|
676
|
-
key: SerovalNode,
|
|
677
|
-
val: SerovalNode,
|
|
678
|
-
sentinel: string,
|
|
679
|
-
): string {
|
|
680
|
-
if (this.isIndexedValueInStack(key)) {
|
|
681
|
-
// Create reference for the map instance
|
|
682
|
-
const keyRef = this.getRefParam((key as SerovalIndexedValueNode).i);
|
|
683
|
-
this.markRef(id);
|
|
684
|
-
// Check if value is a parent
|
|
685
|
-
if (this.isIndexedValueInStack(val)) {
|
|
686
|
-
const valueRef = this.getRefParam((val as SerovalIndexedValueNode).i);
|
|
687
|
-
// Register an assignment since
|
|
688
|
-
// both key and value are a parent of this
|
|
689
|
-
// Map instance
|
|
690
|
-
this.createSetAssignment(id, keyRef, valueRef);
|
|
691
|
-
return '';
|
|
692
|
-
}
|
|
693
|
-
// Reset the stack
|
|
694
|
-
// This is required because the serialized
|
|
695
|
-
// value is no longer part of the expression
|
|
696
|
-
// tree and has been moved to the deferred
|
|
697
|
-
// assignment
|
|
698
|
-
if (
|
|
699
|
-
val.t !== SerovalNodeType.IndexedValue &&
|
|
700
|
-
val.i != null &&
|
|
701
|
-
this.isMarked(val.i)
|
|
702
|
-
) {
|
|
703
|
-
// We use a trick here using sequence (or comma) expressions
|
|
704
|
-
// basically we serialize the intended object in place WITHOUT
|
|
705
|
-
// actually returning it, this is by returning a placeholder
|
|
706
|
-
// value that we will remove sometime after.
|
|
707
|
-
const serialized =
|
|
708
|
-
'(' + this.serialize(val) + ',[' + sentinel + ',' + sentinel + '])';
|
|
709
|
-
this.createSetAssignment(id, keyRef, this.getRefParam(val.i));
|
|
710
|
-
this.createDeleteAssignment(id, sentinel);
|
|
711
|
-
return serialized;
|
|
712
|
-
}
|
|
713
|
-
const parent = this.stack;
|
|
714
|
-
this.stack = [];
|
|
715
|
-
this.createSetAssignment(id, keyRef, this.serialize(val));
|
|
716
|
-
this.stack = parent;
|
|
717
|
-
return '';
|
|
718
|
-
}
|
|
719
|
-
if (this.isIndexedValueInStack(val)) {
|
|
720
|
-
// Create ref for the Map instance
|
|
721
|
-
const valueRef = this.getRefParam((val as SerovalIndexedValueNode).i);
|
|
722
|
-
this.markRef(id);
|
|
723
|
-
if (
|
|
724
|
-
key.t !== SerovalNodeType.IndexedValue &&
|
|
725
|
-
key.i != null &&
|
|
726
|
-
this.isMarked(key.i)
|
|
727
|
-
) {
|
|
728
|
-
const serialized =
|
|
729
|
-
'(' + this.serialize(key) + ',[' + sentinel + ',' + sentinel + '])';
|
|
730
|
-
this.createSetAssignment(id, this.getRefParam(key.i), valueRef);
|
|
731
|
-
this.createDeleteAssignment(id, sentinel);
|
|
732
|
-
return serialized;
|
|
733
|
-
}
|
|
734
|
-
// Reset stack for the key serialization
|
|
735
|
-
const parent = this.stack;
|
|
736
|
-
this.stack = [];
|
|
737
|
-
this.createSetAssignment(id, this.serialize(key), valueRef);
|
|
738
|
-
this.stack = parent;
|
|
739
|
-
return '';
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
return '[' + this.serialize(key) + ',' + this.serialize(val) + ']';
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
protected serializeMap(node: SerovalMapNode): string {
|
|
746
|
-
let serialized = MAP_CONSTRUCTOR;
|
|
747
|
-
const size = node.e.s;
|
|
748
|
-
const id = node.i;
|
|
749
|
-
const sentinel = node.f;
|
|
750
|
-
const sentinelId = this.getRefParam(sentinel.i);
|
|
751
|
-
if (size) {
|
|
752
|
-
const keys = node.e.k;
|
|
753
|
-
const vals = node.e.v;
|
|
754
|
-
this.stack.push(id);
|
|
755
|
-
let result = this.serializeMapEntry(id, keys[0], vals[0], sentinelId);
|
|
756
|
-
for (let i = 1, item = result; i < size; i++) {
|
|
757
|
-
item = this.serializeMapEntry(id, keys[i], vals[i], sentinelId);
|
|
758
|
-
result += (item && result && ',') + item;
|
|
759
|
-
}
|
|
760
|
-
this.stack.pop();
|
|
761
|
-
// Check if there are any values
|
|
762
|
-
// so that the empty Map constructor
|
|
763
|
-
// can be used instead
|
|
764
|
-
if (result) {
|
|
765
|
-
serialized += '([' + result + '])';
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
if (sentinel.t === SerovalNodeType.SpecialReference) {
|
|
769
|
-
this.markRef(sentinel.i);
|
|
770
|
-
serialized = '(' + this.serialize(sentinel) + ',' + serialized + ')';
|
|
771
|
-
}
|
|
772
|
-
return this.assignIndexedValue(id, serialized);
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
protected serializeArrayBuffer(node: SerovalArrayBufferNode): string {
|
|
776
|
-
let result = 'new Uint8Array(';
|
|
777
|
-
const buffer = node.s;
|
|
778
|
-
const len = buffer.length;
|
|
779
|
-
if (len) {
|
|
780
|
-
result += '[' + buffer[0];
|
|
781
|
-
for (let i = 1; i < len; i++) {
|
|
782
|
-
result += ',' + buffer[i];
|
|
783
|
-
}
|
|
784
|
-
result += ']';
|
|
785
|
-
}
|
|
786
|
-
return this.assignIndexedValue(node.i, result + ').buffer');
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
protected serializeTypedArray(
|
|
790
|
-
node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
|
|
791
|
-
): string {
|
|
792
|
-
return this.assignIndexedValue(
|
|
793
|
-
node.i,
|
|
794
|
-
'new ' +
|
|
795
|
-
node.c +
|
|
796
|
-
'(' +
|
|
797
|
-
this.serialize(node.f) +
|
|
798
|
-
',' +
|
|
799
|
-
node.b +
|
|
800
|
-
',' +
|
|
801
|
-
node.l +
|
|
802
|
-
')',
|
|
803
|
-
);
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
protected serializeDataView(node: SerovalDataViewNode): string {
|
|
807
|
-
return this.assignIndexedValue(
|
|
808
|
-
node.i,
|
|
809
|
-
'new DataView(' +
|
|
810
|
-
this.serialize(node.f) +
|
|
811
|
-
',' +
|
|
812
|
-
node.b +
|
|
813
|
-
',' +
|
|
814
|
-
node.l +
|
|
815
|
-
')',
|
|
816
|
-
);
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
protected serializeAggregateError(node: SerovalAggregateErrorNode): string {
|
|
820
|
-
const id = node.i;
|
|
821
|
-
// `AggregateError` might've been extended
|
|
822
|
-
// either through class or custom properties
|
|
823
|
-
// Make sure to assign extra properties
|
|
824
|
-
this.stack.push(id);
|
|
825
|
-
const serialized = this.serializeDictionary(
|
|
826
|
-
node,
|
|
827
|
-
'new AggregateError([],"' + node.m + '")',
|
|
828
|
-
);
|
|
829
|
-
this.stack.pop();
|
|
830
|
-
return serialized;
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
protected serializeError(node: SerovalErrorNode): string {
|
|
834
|
-
return this.serializeDictionary(
|
|
835
|
-
node,
|
|
836
|
-
'new ' + ERROR_CONSTRUCTOR_STRING[node.s] + '("' + node.m + '")',
|
|
837
|
-
);
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
protected serializePromise(node: SerovalPromiseNode): string {
|
|
841
|
-
let serialized: string;
|
|
842
|
-
// Check if resolved value is a parent expression
|
|
843
|
-
const fulfilled = node.f;
|
|
844
|
-
const id = node.i;
|
|
845
|
-
const promiseConstructor = node.s ? PROMISE_RESOLVE : PROMISE_REJECT;
|
|
846
|
-
if (this.isIndexedValueInStack(fulfilled)) {
|
|
847
|
-
// A Promise trick, reference the value
|
|
848
|
-
// inside the `then` expression so that
|
|
849
|
-
// the Promise evaluates after the parent
|
|
850
|
-
// has initialized
|
|
851
|
-
const ref = this.getRefParam((fulfilled as SerovalIndexedValueNode).i);
|
|
852
|
-
serialized =
|
|
853
|
-
promiseConstructor +
|
|
854
|
-
(node.s
|
|
855
|
-
? '().then(' + this.createFunction([], ref) + ')'
|
|
856
|
-
: '().catch(' +
|
|
857
|
-
this.createEffectfulFunction([], 'throw ' + ref) +
|
|
858
|
-
')');
|
|
859
|
-
} else {
|
|
860
|
-
this.stack.push(id);
|
|
861
|
-
const result = this.serialize(fulfilled);
|
|
862
|
-
this.stack.pop();
|
|
863
|
-
// just inline the value/reference here
|
|
864
|
-
serialized = promiseConstructor + '(' + result + ')';
|
|
865
|
-
}
|
|
866
|
-
return this.assignIndexedValue(id, serialized);
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
protected serializeWellKnownSymbol(node: SerovalWKSymbolNode): string {
|
|
870
|
-
return this.assignIndexedValue(node.i, SYMBOL_STRING[node.s]);
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
protected serializeBoxed(node: SerovalBoxedNode): string {
|
|
874
|
-
return this.assignIndexedValue(
|
|
875
|
-
node.i,
|
|
876
|
-
'Object(' + this.serialize(node.f) + ')',
|
|
877
|
-
);
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
protected serializePlugin(node: SerovalPluginNode): string {
|
|
881
|
-
const currentPlugins = this.plugins;
|
|
882
|
-
if (currentPlugins) {
|
|
883
|
-
for (let i = 0, len = currentPlugins.length; i < len; i++) {
|
|
884
|
-
const plugin = currentPlugins[i];
|
|
885
|
-
if (plugin.tag === node.c) {
|
|
886
|
-
return this.assignIndexedValue(
|
|
887
|
-
node.i,
|
|
888
|
-
plugin.serialize(node.s, this, {
|
|
889
|
-
id: node.i,
|
|
890
|
-
}),
|
|
891
|
-
);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
throw new SerovalMissingPluginError(node.c);
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
private getConstructor(node: SerovalNodeWithID): string {
|
|
899
|
-
const current = this.serialize(node);
|
|
900
|
-
return current === this.getRefParam(node.i) ? current : '(' + current + ')';
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
protected serializePromiseConstructor(
|
|
904
|
-
node: SerovalPromiseConstructorNode,
|
|
905
|
-
): string {
|
|
906
|
-
const resolver = this.assignIndexedValue(node.s, '{p:0,s:0,f:0}');
|
|
907
|
-
return this.assignIndexedValue(
|
|
908
|
-
node.i,
|
|
909
|
-
this.getConstructor(node.f) + '(' + resolver + ')',
|
|
910
|
-
);
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
protected serializePromiseResolve(node: SerovalPromiseResolveNode): string {
|
|
914
|
-
return (
|
|
915
|
-
this.getConstructor(node.a[0]) +
|
|
916
|
-
'(' +
|
|
917
|
-
this.getRefParam(node.i) +
|
|
918
|
-
',' +
|
|
919
|
-
this.serialize(node.a[1]) +
|
|
920
|
-
')'
|
|
921
|
-
);
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
protected serializePromiseReject(node: SerovalPromiseRejectNode): string {
|
|
925
|
-
return (
|
|
926
|
-
this.getConstructor(node.a[0]) +
|
|
927
|
-
'(' +
|
|
928
|
-
this.getRefParam(node.i) +
|
|
929
|
-
',' +
|
|
930
|
-
this.serialize(node.a[1]) +
|
|
931
|
-
')'
|
|
932
|
-
);
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
protected serializeSpecialReference(
|
|
936
|
-
node: SerovalSpecialReferenceNode,
|
|
937
|
-
): string {
|
|
938
|
-
return this.assignIndexedValue(
|
|
939
|
-
node.i,
|
|
940
|
-
serializeSpecialReferenceValue(this.features, node.s),
|
|
941
|
-
);
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
protected serializeIteratorFactory(node: SerovalIteratorFactoryNode): string {
|
|
945
|
-
let result = '';
|
|
946
|
-
let initialized = false;
|
|
947
|
-
if (node.f.t !== SerovalNodeType.IndexedValue) {
|
|
948
|
-
this.markRef(node.f.i);
|
|
949
|
-
result = '(' + this.serialize(node.f) + ',';
|
|
950
|
-
initialized = true;
|
|
951
|
-
}
|
|
952
|
-
result += this.assignIndexedValue(
|
|
953
|
-
node.i,
|
|
954
|
-
this.createFunction(
|
|
955
|
-
['s'],
|
|
956
|
-
this.createFunction(
|
|
957
|
-
['i', 'c', 'd', 't'],
|
|
958
|
-
'(i=0,t={[' +
|
|
959
|
-
this.getRefParam(node.f.i) +
|
|
960
|
-
']:' +
|
|
961
|
-
this.createFunction([], 't') +
|
|
962
|
-
',next:' +
|
|
963
|
-
this.createEffectfulFunction(
|
|
964
|
-
[],
|
|
965
|
-
'if(i>s.d)return{done:!0,value:void 0};if(d=s.v[c=i++],c===s.t)throw d;return{done:c===s.d,value:d}',
|
|
966
|
-
) +
|
|
967
|
-
'})',
|
|
968
|
-
),
|
|
969
|
-
),
|
|
970
|
-
);
|
|
971
|
-
if (initialized) {
|
|
972
|
-
result += ')';
|
|
973
|
-
}
|
|
974
|
-
return result;
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
protected serializeIteratorFactoryInstance(
|
|
978
|
-
node: SerovalIteratorFactoryInstanceNode,
|
|
979
|
-
): string {
|
|
980
|
-
return (
|
|
981
|
-
this.getConstructor(node.a[0]) + '(' + this.serialize(node.a[1]) + ')'
|
|
982
|
-
);
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
protected serializeAsyncIteratorFactory(
|
|
986
|
-
node: SerovalAsyncIteratorFactoryNode,
|
|
987
|
-
): string {
|
|
988
|
-
const promise = node.a[0];
|
|
989
|
-
const symbol = node.a[1];
|
|
990
|
-
|
|
991
|
-
let result = '';
|
|
992
|
-
|
|
993
|
-
if (promise.t !== SerovalNodeType.IndexedValue) {
|
|
994
|
-
this.markRef(promise.i);
|
|
995
|
-
result += '(' + this.serialize(promise);
|
|
996
|
-
}
|
|
997
|
-
if (symbol.t !== SerovalNodeType.IndexedValue) {
|
|
998
|
-
this.markRef(symbol.i);
|
|
999
|
-
result += (result ? ',' : '(') + this.serialize(symbol);
|
|
1000
|
-
}
|
|
1001
|
-
if (result) {
|
|
1002
|
-
result += ',';
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
const iterator = this.assignIndexedValue(
|
|
1006
|
-
node.i,
|
|
1007
|
-
this.createFunction(
|
|
1008
|
-
['s'],
|
|
1009
|
-
this.createFunction(
|
|
1010
|
-
['b', 'c', 'p', 'd', 'e', 't', 'f'],
|
|
1011
|
-
/**
|
|
1012
|
-
* b = resolved values
|
|
1013
|
-
* c = b size
|
|
1014
|
-
* p = pending promises
|
|
1015
|
-
* d = index where the resolved value stops
|
|
1016
|
-
* e = if the last value is a throw
|
|
1017
|
-
* t = placeholder variable
|
|
1018
|
-
* f = finalize
|
|
1019
|
-
*/
|
|
1020
|
-
'(b=[],c=0,p=[],d=-1,e=!1,f=' +
|
|
1021
|
-
this.createEffectfulFunction(
|
|
1022
|
-
['i', 'l'],
|
|
1023
|
-
'for(i=0,l=p.length;i<l;i++)p[i].s({done:!0,value:void 0})',
|
|
1024
|
-
) +
|
|
1025
|
-
',s.on({next:' +
|
|
1026
|
-
this.createEffectfulFunction(
|
|
1027
|
-
['v', 't'],
|
|
1028
|
-
'if(t=p.shift())t.s({done:!1,value:v});b.push(v)',
|
|
1029
|
-
) +
|
|
1030
|
-
',throw:' +
|
|
1031
|
-
this.createEffectfulFunction(
|
|
1032
|
-
['v', 't'],
|
|
1033
|
-
'if(t=p.shift())t.f(v);f(),d=b.length,e=!0,b.push(v)',
|
|
1034
|
-
) +
|
|
1035
|
-
',return:' +
|
|
1036
|
-
this.createEffectfulFunction(
|
|
1037
|
-
['v', 't'],
|
|
1038
|
-
'if(t=p.shift())t.s({done:!0,value:v});f(),d=b.length,b.push(v)',
|
|
1039
|
-
) +
|
|
1040
|
-
'}),t={[' +
|
|
1041
|
-
this.getRefParam(symbol.i) +
|
|
1042
|
-
']:' +
|
|
1043
|
-
this.createFunction([], 't.p') +
|
|
1044
|
-
',next:' +
|
|
1045
|
-
this.createEffectfulFunction(
|
|
1046
|
-
['i', 't', 'v'],
|
|
1047
|
-
'if(d===-1){return((i=c++)>=b.length)?(' +
|
|
1048
|
-
this.getRefParam(promise.i) +
|
|
1049
|
-
'(t={p:0,s:0,f:0}),p.push(t),t.p):{done:!1,value:b[i]}}if(c>d)return{done:!0,value:void 0};if(v=b[i=c++],i!==d)return{done:!1,value:v};if(e)throw v;return{done:!0,value:v}',
|
|
1050
|
-
) +
|
|
1051
|
-
'})',
|
|
1052
|
-
),
|
|
1053
|
-
),
|
|
1054
|
-
);
|
|
1055
|
-
|
|
1056
|
-
if (result) {
|
|
1057
|
-
return result + iterator + ')';
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
return iterator;
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
protected serializeAsyncIteratorFactoryInstance(
|
|
1064
|
-
node: SerovalAsyncIteratorFactoryInstanceNode,
|
|
1065
|
-
): string {
|
|
1066
|
-
return (
|
|
1067
|
-
this.getConstructor(node.a[0]) + '(' + this.serialize(node.a[1]) + ')'
|
|
1068
|
-
);
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
protected serializeStreamConstructor(
|
|
1072
|
-
node: SerovalStreamConstructorNode,
|
|
1073
|
-
): string {
|
|
1074
|
-
const result = this.assignIndexedValue(
|
|
1075
|
-
node.i,
|
|
1076
|
-
this.getConstructor(node.f) + '()',
|
|
1077
|
-
);
|
|
1078
|
-
const len = node.a.length;
|
|
1079
|
-
if (len) {
|
|
1080
|
-
let values = this.serialize(node.a[0]);
|
|
1081
|
-
for (let i = 1; i < len; i++) {
|
|
1082
|
-
values += ',' + this.serialize(node.a[i]);
|
|
1083
|
-
}
|
|
1084
|
-
return '(' + result + ',' + values + ',' + this.getRefParam(node.i) + ')';
|
|
1085
|
-
}
|
|
1086
|
-
return result;
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
protected serializeStreamNext(node: SerovalStreamNextNode): string {
|
|
1090
|
-
return this.getRefParam(node.i) + '.next(' + this.serialize(node.f) + ')';
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
protected serializeStreamThrow(node: SerovalStreamThrowNode): string {
|
|
1094
|
-
return this.getRefParam(node.i) + '.throw(' + this.serialize(node.f) + ')';
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
protected serializeStreamReturn(node: SerovalStreamReturnNode): string {
|
|
1098
|
-
return this.getRefParam(node.i) + '.return(' + this.serialize(node.f) + ')';
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
serialize(node: SerovalNode): string {
|
|
1102
|
-
try {
|
|
1103
|
-
switch (node.t) {
|
|
1104
|
-
case SerovalNodeType.Constant:
|
|
1105
|
-
return CONSTANT_STRING[node.s];
|
|
1106
|
-
case SerovalNodeType.Number:
|
|
1107
|
-
return '' + node.s;
|
|
1108
|
-
case SerovalNodeType.String:
|
|
1109
|
-
return '"' + node.s + '"';
|
|
1110
|
-
case SerovalNodeType.BigInt:
|
|
1111
|
-
return node.s + 'n';
|
|
1112
|
-
case SerovalNodeType.IndexedValue:
|
|
1113
|
-
return this.getRefParam(node.i);
|
|
1114
|
-
case SerovalNodeType.Reference:
|
|
1115
|
-
return this.serializeReference(node);
|
|
1116
|
-
case SerovalNodeType.Array:
|
|
1117
|
-
return this.serializeArray(node);
|
|
1118
|
-
case SerovalNodeType.Object:
|
|
1119
|
-
return this.serializeObject(node);
|
|
1120
|
-
case SerovalNodeType.NullConstructor:
|
|
1121
|
-
return this.serializeNullConstructor(node);
|
|
1122
|
-
case SerovalNodeType.Date:
|
|
1123
|
-
return this.serializeDate(node);
|
|
1124
|
-
case SerovalNodeType.RegExp:
|
|
1125
|
-
return this.serializeRegExp(node);
|
|
1126
|
-
case SerovalNodeType.Set:
|
|
1127
|
-
return this.serializeSet(node);
|
|
1128
|
-
case SerovalNodeType.Map:
|
|
1129
|
-
return this.serializeMap(node);
|
|
1130
|
-
case SerovalNodeType.ArrayBuffer:
|
|
1131
|
-
return this.serializeArrayBuffer(node);
|
|
1132
|
-
case SerovalNodeType.BigIntTypedArray:
|
|
1133
|
-
case SerovalNodeType.TypedArray:
|
|
1134
|
-
return this.serializeTypedArray(node);
|
|
1135
|
-
case SerovalNodeType.DataView:
|
|
1136
|
-
return this.serializeDataView(node);
|
|
1137
|
-
case SerovalNodeType.AggregateError:
|
|
1138
|
-
return this.serializeAggregateError(node);
|
|
1139
|
-
case SerovalNodeType.Error:
|
|
1140
|
-
return this.serializeError(node);
|
|
1141
|
-
case SerovalNodeType.Promise:
|
|
1142
|
-
return this.serializePromise(node);
|
|
1143
|
-
case SerovalNodeType.WKSymbol:
|
|
1144
|
-
return this.serializeWellKnownSymbol(node);
|
|
1145
|
-
case SerovalNodeType.Boxed:
|
|
1146
|
-
return this.serializeBoxed(node);
|
|
1147
|
-
case SerovalNodeType.PromiseConstructor:
|
|
1148
|
-
return this.serializePromiseConstructor(node);
|
|
1149
|
-
case SerovalNodeType.PromiseSuccess:
|
|
1150
|
-
return this.serializePromiseResolve(node);
|
|
1151
|
-
case SerovalNodeType.PromiseFailure:
|
|
1152
|
-
return this.serializePromiseReject(node);
|
|
1153
|
-
case SerovalNodeType.Plugin:
|
|
1154
|
-
return this.serializePlugin(node);
|
|
1155
|
-
case SerovalNodeType.SpecialReference:
|
|
1156
|
-
return this.serializeSpecialReference(node);
|
|
1157
|
-
case SerovalNodeType.IteratorFactory:
|
|
1158
|
-
return this.serializeIteratorFactory(node);
|
|
1159
|
-
case SerovalNodeType.IteratorFactoryInstance:
|
|
1160
|
-
return this.serializeIteratorFactoryInstance(node);
|
|
1161
|
-
case SerovalNodeType.AsyncIteratorFactory:
|
|
1162
|
-
return this.serializeAsyncIteratorFactory(node);
|
|
1163
|
-
case SerovalNodeType.AsyncIteratorFactoryInstance:
|
|
1164
|
-
return this.serializeAsyncIteratorFactoryInstance(node);
|
|
1165
|
-
case SerovalNodeType.StreamConstructor:
|
|
1166
|
-
return this.serializeStreamConstructor(node);
|
|
1167
|
-
case SerovalNodeType.StreamNext:
|
|
1168
|
-
return this.serializeStreamNext(node);
|
|
1169
|
-
case SerovalNodeType.StreamThrow:
|
|
1170
|
-
return this.serializeStreamThrow(node);
|
|
1171
|
-
case SerovalNodeType.StreamReturn:
|
|
1172
|
-
return this.serializeStreamReturn(node);
|
|
1173
|
-
default:
|
|
1174
|
-
throw new SerovalUnsupportedNodeError(node);
|
|
1175
|
-
}
|
|
1176
|
-
} catch (error) {
|
|
1177
|
-
throw new SerovalSerializationError(error);
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
}
|