seroval 1.5.5 → 1.6.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/index.d.ts +761 -0
- package/dist/index.js +2928 -0
- package/package.json +14 -23
- package/dist/cjs/development/index.cjs +0 -4230
- package/dist/cjs/development/index.cjs.map +0 -7
- package/dist/cjs/production/index.cjs +0 -3
- package/dist/esm/development/index.mjs +0 -4207
- package/dist/esm/development/index.mjs.map +0 -7
- package/dist/esm/production/index.mjs +0 -3
- package/dist/types/core/Serializer.d.ts +0 -28
- package/dist/types/core/Serializer.d.ts.map +0 -1
- package/dist/types/core/base-primitives.d.ts +0 -28
- package/dist/types/core/base-primitives.d.ts.map +0 -1
- package/dist/types/core/compat.d.ts +0 -15
- package/dist/types/core/compat.d.ts.map +0 -1
- package/dist/types/core/constants.d.ts +0 -105
- package/dist/types/core/constants.d.ts.map +0 -1
- package/dist/types/core/constructors.d.ts +0 -50
- package/dist/types/core/constructors.d.ts.map +0 -1
- package/dist/types/core/context/async-parser.d.ts +0 -20
- package/dist/types/core/context/async-parser.d.ts.map +0 -1
- package/dist/types/core/context/deserializer.d.ts +0 -52
- package/dist/types/core/context/deserializer.d.ts.map +0 -1
- package/dist/types/core/context/parser.d.ts +0 -62
- package/dist/types/core/context/parser.d.ts.map +0 -1
- package/dist/types/core/context/serializer.d.ts +0 -103
- package/dist/types/core/context/serializer.d.ts.map +0 -1
- package/dist/types/core/context/sync-parser.d.ts +0 -61
- package/dist/types/core/context/sync-parser.d.ts.map +0 -1
- package/dist/types/core/cross/index.d.ts +0 -24
- package/dist/types/core/cross/index.d.ts.map +0 -1
- package/dist/types/core/errors.d.ts +0 -47
- package/dist/types/core/errors.d.ts.map +0 -1
- package/dist/types/core/function-string.d.ts +0 -3
- package/dist/types/core/function-string.d.ts.map +0 -1
- package/dist/types/core/keys.d.ts +0 -4
- package/dist/types/core/keys.d.ts.map +0 -1
- package/dist/types/core/literals.d.ts +0 -10
- package/dist/types/core/literals.d.ts.map +0 -1
- package/dist/types/core/node.d.ts +0 -8
- package/dist/types/core/node.d.ts.map +0 -1
- package/dist/types/core/opaque-reference.d.ts +0 -9
- package/dist/types/core/opaque-reference.d.ts.map +0 -1
- package/dist/types/core/plugin.d.ts +0 -52
- package/dist/types/core/plugin.d.ts.map +0 -1
- package/dist/types/core/reference.d.ts +0 -6
- package/dist/types/core/reference.d.ts.map +0 -1
- package/dist/types/core/sequence.d.ts +0 -11
- package/dist/types/core/sequence.d.ts.map +0 -1
- package/dist/types/core/special-reference.d.ts +0 -16
- package/dist/types/core/special-reference.d.ts.map +0 -1
- package/dist/types/core/stream.d.ts +0 -17
- package/dist/types/core/stream.d.ts.map +0 -1
- package/dist/types/core/string.d.ts +0 -4
- package/dist/types/core/string.d.ts.map +0 -1
- package/dist/types/core/symbols.d.ts +0 -14
- package/dist/types/core/symbols.d.ts.map +0 -1
- package/dist/types/core/tree/index.d.ts +0 -21
- package/dist/types/core/tree/index.d.ts.map +0 -1
- package/dist/types/core/types.d.ts +0 -233
- package/dist/types/core/types.d.ts.map +0 -1
- package/dist/types/core/utils/error.d.ts +0 -6
- package/dist/types/core/utils/error.d.ts.map +0 -1
- package/dist/types/core/utils/get-identifier.d.ts +0 -2
- package/dist/types/core/utils/get-identifier.d.ts.map +0 -1
- package/dist/types/core/utils/get-object-flag.d.ts +0 -3
- package/dist/types/core/utils/get-object-flag.d.ts.map +0 -1
- package/dist/types/core/utils/is-valid-identifier.d.ts +0 -2
- package/dist/types/core/utils/is-valid-identifier.d.ts.map +0 -1
- package/dist/types/core/utils/promise-to-result.d.ts +0 -2
- package/dist/types/core/utils/promise-to-result.d.ts.map +0 -1
- package/dist/types/core/utils/typed-array.d.ts +0 -6
- package/dist/types/core/utils/typed-array.d.ts.map +0 -1
- package/dist/types/core/utils/valid-properties.d.ts +0 -3
- package/dist/types/core/utils/valid-properties.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -18
- package/dist/types/index.d.ts.map +0 -1
- package/src/core/Serializer.ts +0 -119
- package/src/core/base-primitives.ts +0 -537
- package/src/core/compat.ts +0 -23
- package/src/core/constants.ts +0 -202
- package/src/core/constructors.ts +0 -265
- package/src/core/context/async-parser.ts +0 -663
- package/src/core/context/deserializer.ts +0 -832
- package/src/core/context/parser.ts +0 -335
- package/src/core/context/serializer.ts +0 -1524
- package/src/core/context/sync-parser.ts +0 -943
- package/src/core/cross/index.ts +0 -190
- package/src/core/errors.ts +0 -196
- 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 -105
- package/src/core/reference.ts +0 -66
- package/src/core/sequence.ts +0 -59
- package/src/core/special-reference.ts +0 -42
- package/src/core/stream.ts +0 -71
- package/src/core/string.ts +0 -86
- package/src/core/symbols.ts +0 -20
- package/src/core/tree/index.ts +0 -134
- package/src/core/types.ts +0 -377
- 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/promise-to-result.ts +0 -9
- package/src/core/utils/typed-array.ts +0 -56
- package/src/core/utils/valid-properties.ts +0 -34
- package/src/index.ts +0 -36
|
@@ -1,1524 +0,0 @@
|
|
|
1
|
-
import { Feature } from '../compat';
|
|
2
|
-
import {
|
|
3
|
-
CONSTANT_STRING,
|
|
4
|
-
ERROR_CONSTRUCTOR_STRING,
|
|
5
|
-
NIL,
|
|
6
|
-
SerovalNodeType,
|
|
7
|
-
SerovalObjectFlags,
|
|
8
|
-
SYMBOL_STRING,
|
|
9
|
-
} from '../constants';
|
|
10
|
-
import {
|
|
11
|
-
SERIALIZED_ASYNC_ITERATOR_CONSTRUCTOR,
|
|
12
|
-
SERIALIZED_ITERATOR_CONSTRUCTOR,
|
|
13
|
-
} from '../constructors';
|
|
14
|
-
import {
|
|
15
|
-
SerovalMissingPluginError,
|
|
16
|
-
SerovalSerializationError,
|
|
17
|
-
SerovalUnsupportedNodeError,
|
|
18
|
-
} from '../errors';
|
|
19
|
-
import { createEffectfulFunction, createFunction } from '../function-string';
|
|
20
|
-
import { GLOBAL_CONTEXT_REFERENCES, REFERENCES_KEY } from '../keys';
|
|
21
|
-
import type { PluginAccessOptions } from '../plugin';
|
|
22
|
-
import { SerovalMode } from '../plugin';
|
|
23
|
-
import { SPECIAL_REF_STRING } from '../special-reference';
|
|
24
|
-
import { deserializeString, serializeString } from '../string';
|
|
25
|
-
import type {
|
|
26
|
-
SerovalAggregateErrorNode,
|
|
27
|
-
SerovalArrayBufferNode,
|
|
28
|
-
SerovalArrayNode,
|
|
29
|
-
SerovalAsyncIteratorFactoryInstanceNode,
|
|
30
|
-
SerovalAsyncIteratorFactoryNode,
|
|
31
|
-
SerovalBigIntTypedArrayNode,
|
|
32
|
-
SerovalBoxedNode,
|
|
33
|
-
SerovalDataViewNode,
|
|
34
|
-
SerovalDateNode,
|
|
35
|
-
SerovalErrorNode,
|
|
36
|
-
SerovalIndexedValueNode,
|
|
37
|
-
SerovalIteratorFactoryInstanceNode,
|
|
38
|
-
SerovalIteratorFactoryNode,
|
|
39
|
-
SerovalMapNode,
|
|
40
|
-
SerovalNode,
|
|
41
|
-
SerovalNodeWithID,
|
|
42
|
-
SerovalNullConstructorNode,
|
|
43
|
-
SerovalObjectNode,
|
|
44
|
-
SerovalObjectRecordKey,
|
|
45
|
-
SerovalObjectRecordNode,
|
|
46
|
-
SerovalPluginNode,
|
|
47
|
-
SerovalPromiseConstructorNode,
|
|
48
|
-
SerovalPromiseNode,
|
|
49
|
-
SerovalPromiseRejectNode,
|
|
50
|
-
SerovalPromiseResolveNode,
|
|
51
|
-
SerovalReferenceNode,
|
|
52
|
-
SerovalRegExpNode,
|
|
53
|
-
SerovalSequenceNode,
|
|
54
|
-
SerovalSetNode,
|
|
55
|
-
SerovalStreamConstructorNode,
|
|
56
|
-
SerovalStreamNextNode,
|
|
57
|
-
SerovalStreamReturnNode,
|
|
58
|
-
SerovalStreamThrowNode,
|
|
59
|
-
SerovalTypedArrayNode,
|
|
60
|
-
} from '../types';
|
|
61
|
-
import getIdentifier from '../utils/get-identifier';
|
|
62
|
-
import { isValidIdentifier } from '../utils/is-valid-identifier';
|
|
63
|
-
import { isValidKey } from '../utils/valid-properties';
|
|
64
|
-
|
|
65
|
-
const enum AssignmentType {
|
|
66
|
-
Index = 0,
|
|
67
|
-
Add = 1,
|
|
68
|
-
Set = 2,
|
|
69
|
-
Delete = 3,
|
|
70
|
-
Define = 4,
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
interface IndexAssignment {
|
|
74
|
-
t: AssignmentType.Index;
|
|
75
|
-
s: string;
|
|
76
|
-
k: undefined;
|
|
77
|
-
v: string;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
interface SetAssignment {
|
|
81
|
-
t: AssignmentType.Set;
|
|
82
|
-
s: string;
|
|
83
|
-
k: string;
|
|
84
|
-
v: string;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
interface AddAssignment {
|
|
88
|
-
t: AssignmentType.Add;
|
|
89
|
-
s: string;
|
|
90
|
-
k: undefined;
|
|
91
|
-
v: string;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
interface DeleteAssignment {
|
|
95
|
-
t: AssignmentType.Delete;
|
|
96
|
-
s: string;
|
|
97
|
-
k: string;
|
|
98
|
-
v: undefined;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Defines an own `__proto__` data property (see `createObjectAssign`).
|
|
102
|
-
// `k` holds the serialized value; `v` is unused so this never participates
|
|
103
|
-
// in the value-based merging done by `mergeAssignments`.
|
|
104
|
-
interface DefineAssignment {
|
|
105
|
-
t: AssignmentType.Define;
|
|
106
|
-
s: string;
|
|
107
|
-
k: string;
|
|
108
|
-
v: undefined;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Array of assignments to be done (used for recursion)
|
|
112
|
-
type Assignment =
|
|
113
|
-
| IndexAssignment
|
|
114
|
-
| AddAssignment
|
|
115
|
-
| SetAssignment
|
|
116
|
-
| DeleteAssignment
|
|
117
|
-
| DefineAssignment;
|
|
118
|
-
|
|
119
|
-
export interface FlaggedObject {
|
|
120
|
-
type: SerovalObjectFlags;
|
|
121
|
-
value: string;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function getAssignmentExpression(assignment: Assignment): string {
|
|
125
|
-
switch (assignment.t) {
|
|
126
|
-
case AssignmentType.Index:
|
|
127
|
-
return assignment.s + '=' + assignment.v;
|
|
128
|
-
case AssignmentType.Set:
|
|
129
|
-
return assignment.s + '.set(' + assignment.k + ',' + assignment.v + ')';
|
|
130
|
-
case AssignmentType.Add:
|
|
131
|
-
return assignment.s + '.add(' + assignment.v + ')';
|
|
132
|
-
case AssignmentType.Delete:
|
|
133
|
-
return assignment.s + '.delete(' + assignment.k + ')';
|
|
134
|
-
case AssignmentType.Define:
|
|
135
|
-
return (
|
|
136
|
-
'Object.defineProperty(' +
|
|
137
|
-
assignment.s +
|
|
138
|
-
',"__proto__",{value:' +
|
|
139
|
-
assignment.k +
|
|
140
|
-
',configurable:!0,enumerable:!0,writable:!0})'
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function mergeAssignments(assignments: Assignment[]): Assignment[] {
|
|
146
|
-
const newAssignments: Assignment[] = [];
|
|
147
|
-
let current = assignments[0];
|
|
148
|
-
for (
|
|
149
|
-
let i = 1, len = assignments.length, item: Assignment, prev = current;
|
|
150
|
-
i < len;
|
|
151
|
-
i++
|
|
152
|
-
) {
|
|
153
|
-
item = assignments[i];
|
|
154
|
-
if (item.t === AssignmentType.Index && item.v === prev.v) {
|
|
155
|
-
// Merge if the right-hand value is the same
|
|
156
|
-
// saves at least 2 chars
|
|
157
|
-
current = {
|
|
158
|
-
t: AssignmentType.Index,
|
|
159
|
-
s: item.s,
|
|
160
|
-
k: NIL,
|
|
161
|
-
v: getAssignmentExpression(current),
|
|
162
|
-
} as IndexAssignment;
|
|
163
|
-
} else if (item.t === AssignmentType.Set && item.s === prev.s) {
|
|
164
|
-
// Maps has chaining methods, merge if source is the same
|
|
165
|
-
current = {
|
|
166
|
-
t: AssignmentType.Set,
|
|
167
|
-
s: getAssignmentExpression(current),
|
|
168
|
-
k: item.k,
|
|
169
|
-
v: item.v,
|
|
170
|
-
} as SetAssignment;
|
|
171
|
-
} else if (item.t === AssignmentType.Add && item.s === prev.s) {
|
|
172
|
-
// Sets has chaining methods too
|
|
173
|
-
current = {
|
|
174
|
-
t: AssignmentType.Add,
|
|
175
|
-
s: getAssignmentExpression(current),
|
|
176
|
-
k: NIL,
|
|
177
|
-
v: item.v,
|
|
178
|
-
} as AddAssignment;
|
|
179
|
-
} else if (item.t === AssignmentType.Delete && item.s === prev.s) {
|
|
180
|
-
// Maps has chaining methods, merge if source is the same
|
|
181
|
-
current = {
|
|
182
|
-
t: AssignmentType.Delete,
|
|
183
|
-
s: getAssignmentExpression(current),
|
|
184
|
-
k: item.k,
|
|
185
|
-
v: NIL,
|
|
186
|
-
} as DeleteAssignment;
|
|
187
|
-
} else {
|
|
188
|
-
// Different assignment, push current
|
|
189
|
-
newAssignments.push(current);
|
|
190
|
-
current = item;
|
|
191
|
-
}
|
|
192
|
-
prev = item;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
newAssignments.push(current);
|
|
196
|
-
|
|
197
|
-
return newAssignments;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function resolveAssignments(assignments: Assignment[]): string | undefined {
|
|
201
|
-
if (assignments.length) {
|
|
202
|
-
let result = '';
|
|
203
|
-
const merged = mergeAssignments(assignments);
|
|
204
|
-
for (let i = 0, len = merged.length; i < len; i++) {
|
|
205
|
-
result += getAssignmentExpression(merged[i]) + ',';
|
|
206
|
-
}
|
|
207
|
-
return result;
|
|
208
|
-
}
|
|
209
|
-
return NIL;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const NULL_CONSTRUCTOR = 'Object.create(null)';
|
|
213
|
-
const SET_CONSTRUCTOR = 'new Set';
|
|
214
|
-
const MAP_CONSTRUCTOR = 'new Map';
|
|
215
|
-
|
|
216
|
-
const PROMISE_RESOLVE = 'Promise.resolve';
|
|
217
|
-
const PROMISE_REJECT = 'Promise.reject';
|
|
218
|
-
|
|
219
|
-
const OBJECT_FLAG_CONSTRUCTOR: Record<SerovalObjectFlags, string | undefined> =
|
|
220
|
-
{
|
|
221
|
-
[SerovalObjectFlags.Frozen]: 'Object.freeze',
|
|
222
|
-
[SerovalObjectFlags.Sealed]: 'Object.seal',
|
|
223
|
-
[SerovalObjectFlags.NonExtensible]: 'Object.preventExtensions',
|
|
224
|
-
[SerovalObjectFlags.None]: NIL,
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
type SerovalNodeWithProperties =
|
|
228
|
-
| SerovalObjectNode
|
|
229
|
-
| SerovalNullConstructorNode
|
|
230
|
-
| SerovalAggregateErrorNode
|
|
231
|
-
| SerovalErrorNode;
|
|
232
|
-
|
|
233
|
-
export interface BaseSerializerContextOptions extends PluginAccessOptions {
|
|
234
|
-
features: number;
|
|
235
|
-
markedRefs: number[] | Set<number>;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export interface BaseSerializerContext extends PluginAccessOptions {
|
|
239
|
-
readonly mode: SerovalMode;
|
|
240
|
-
|
|
241
|
-
features: number;
|
|
242
|
-
/*
|
|
243
|
-
* To check if an object is synchronously referencing itself
|
|
244
|
-
*/
|
|
245
|
-
stack: number[];
|
|
246
|
-
/**
|
|
247
|
-
* Array of object mutations
|
|
248
|
-
*/
|
|
249
|
-
flags: FlaggedObject[];
|
|
250
|
-
/**
|
|
251
|
-
* Array of assignments to be done (used for recursion)
|
|
252
|
-
*/
|
|
253
|
-
assignments: Assignment[];
|
|
254
|
-
/**
|
|
255
|
-
* Refs that are...referenced
|
|
256
|
-
*/
|
|
257
|
-
marked: Set<number>;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
export interface CrossContextOptions {
|
|
261
|
-
scopeId?: string;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export function createBaseSerializerContext(
|
|
265
|
-
mode: SerovalMode,
|
|
266
|
-
options: BaseSerializerContextOptions,
|
|
267
|
-
): BaseSerializerContext {
|
|
268
|
-
return {
|
|
269
|
-
mode,
|
|
270
|
-
plugins: options.plugins,
|
|
271
|
-
features: options.features,
|
|
272
|
-
marked: new Set(options.markedRefs),
|
|
273
|
-
stack: [],
|
|
274
|
-
flags: [],
|
|
275
|
-
assignments: [],
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
export interface VanillaSerializerState {
|
|
280
|
-
valid: Map<number, number>;
|
|
281
|
-
vars: string[];
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function createVanillaSerializerState(): VanillaSerializerState {
|
|
285
|
-
return {
|
|
286
|
-
valid: new Map(),
|
|
287
|
-
vars: [],
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
export interface VanillaSerializerContext {
|
|
292
|
-
mode: SerovalMode.Vanilla;
|
|
293
|
-
base: BaseSerializerContext;
|
|
294
|
-
state: VanillaSerializerState;
|
|
295
|
-
child: SerializePluginContext | undefined;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
export type VanillaSerializerContextOptions = BaseSerializerContextOptions;
|
|
299
|
-
|
|
300
|
-
export function createVanillaSerializerContext(
|
|
301
|
-
options: VanillaSerializerContextOptions,
|
|
302
|
-
): VanillaSerializerContext {
|
|
303
|
-
return {
|
|
304
|
-
mode: SerovalMode.Vanilla,
|
|
305
|
-
base: createBaseSerializerContext(SerovalMode.Vanilla, options),
|
|
306
|
-
state: createVanillaSerializerState(),
|
|
307
|
-
child: NIL,
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
export interface CrossSerializerContext {
|
|
312
|
-
mode: SerovalMode.Cross;
|
|
313
|
-
base: BaseSerializerContext;
|
|
314
|
-
state: CrossContextOptions;
|
|
315
|
-
child: SerializePluginContext | undefined;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
export interface CrossSerializerContextOptions
|
|
319
|
-
extends BaseSerializerContextOptions,
|
|
320
|
-
CrossContextOptions {
|
|
321
|
-
// empty
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
export function createCrossSerializerContext(
|
|
325
|
-
options: CrossSerializerContextOptions,
|
|
326
|
-
): CrossSerializerContext {
|
|
327
|
-
return {
|
|
328
|
-
mode: SerovalMode.Cross,
|
|
329
|
-
base: createBaseSerializerContext(SerovalMode.Cross, options),
|
|
330
|
-
state: options,
|
|
331
|
-
child: NIL,
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
type SerializerContext = VanillaSerializerContext | CrossSerializerContext;
|
|
336
|
-
|
|
337
|
-
export class SerializePluginContext {
|
|
338
|
-
constructor(private _p: SerializerContext) {}
|
|
339
|
-
|
|
340
|
-
serialize(node: SerovalNode) {
|
|
341
|
-
return serialize(this._p, node);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Creates the reference param (identifier) from the given reference ID
|
|
347
|
-
* Calling this function means the value has been referenced somewhere
|
|
348
|
-
*/
|
|
349
|
-
function getVanillaRefParam(
|
|
350
|
-
state: VanillaSerializerState,
|
|
351
|
-
index: number,
|
|
352
|
-
): string {
|
|
353
|
-
/**
|
|
354
|
-
* Creates a new reference ID from a given reference ID
|
|
355
|
-
* This new reference ID means that the reference itself
|
|
356
|
-
* has been referenced at least once, and is used to generate
|
|
357
|
-
* the variables
|
|
358
|
-
*/
|
|
359
|
-
let actualIndex = state.valid.get(index);
|
|
360
|
-
if (actualIndex == null) {
|
|
361
|
-
actualIndex = state.valid.size;
|
|
362
|
-
state.valid.set(index, actualIndex);
|
|
363
|
-
}
|
|
364
|
-
let identifier = state.vars[actualIndex];
|
|
365
|
-
if (identifier == null) {
|
|
366
|
-
identifier = getIdentifier(actualIndex);
|
|
367
|
-
state.vars[actualIndex] = identifier;
|
|
368
|
-
}
|
|
369
|
-
return identifier;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
function getCrossRefParam(id: number): string {
|
|
373
|
-
return GLOBAL_CONTEXT_REFERENCES + '[' + id + ']';
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Converts the ID of a reference into a identifier string
|
|
378
|
-
* that is used to refer to the object instance in the
|
|
379
|
-
* generated script.
|
|
380
|
-
*/
|
|
381
|
-
function getRefParam(ctx: SerializerContext, id: number): string {
|
|
382
|
-
return ctx.mode === SerovalMode.Vanilla
|
|
383
|
-
? getVanillaRefParam(ctx.state, id)
|
|
384
|
-
: getCrossRefParam(id);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
function markSerializerRef(ctx: BaseSerializerContext, id: number): void {
|
|
388
|
-
ctx.marked.add(id);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
function isSerializerRefMarked(
|
|
392
|
-
ctx: BaseSerializerContext,
|
|
393
|
-
id: number,
|
|
394
|
-
): boolean {
|
|
395
|
-
return ctx.marked.has(id);
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
function pushObjectFlag(
|
|
399
|
-
ctx: SerializerContext,
|
|
400
|
-
flag: SerovalObjectFlags,
|
|
401
|
-
id: number,
|
|
402
|
-
): void {
|
|
403
|
-
if (flag !== SerovalObjectFlags.None) {
|
|
404
|
-
markSerializerRef(ctx.base, id);
|
|
405
|
-
ctx.base.flags.push({
|
|
406
|
-
type: flag,
|
|
407
|
-
value: getRefParam(ctx, id),
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
function resolveFlags(ctx: BaseSerializerContext): string | undefined {
|
|
413
|
-
let result = '';
|
|
414
|
-
for (let i = 0, current = ctx.flags, len = current.length; i < len; i++) {
|
|
415
|
-
const flag = current[i];
|
|
416
|
-
result += OBJECT_FLAG_CONSTRUCTOR[flag.type] + '(' + flag.value + '),';
|
|
417
|
-
}
|
|
418
|
-
return result;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
function resolvePatches(ctx: BaseSerializerContext): string | undefined {
|
|
422
|
-
const assignments = resolveAssignments(ctx.assignments);
|
|
423
|
-
const flags = resolveFlags(ctx);
|
|
424
|
-
if (assignments) {
|
|
425
|
-
if (flags) {
|
|
426
|
-
return assignments + flags;
|
|
427
|
-
}
|
|
428
|
-
return assignments;
|
|
429
|
-
}
|
|
430
|
-
return flags;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
/**
|
|
434
|
-
* Generates the inlined assignment for the reference
|
|
435
|
-
* This is different from the assignments array as this one
|
|
436
|
-
* signifies creation rather than mutation
|
|
437
|
-
*/
|
|
438
|
-
function createAssignment(
|
|
439
|
-
ctx: BaseSerializerContext,
|
|
440
|
-
source: string,
|
|
441
|
-
value: string,
|
|
442
|
-
): void {
|
|
443
|
-
ctx.assignments.push({
|
|
444
|
-
t: AssignmentType.Index,
|
|
445
|
-
s: source,
|
|
446
|
-
k: NIL,
|
|
447
|
-
v: value,
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
function createAddAssignment(
|
|
452
|
-
ctx: SerializerContext,
|
|
453
|
-
ref: number,
|
|
454
|
-
value: string,
|
|
455
|
-
): void {
|
|
456
|
-
ctx.base.assignments.push({
|
|
457
|
-
t: AssignmentType.Add,
|
|
458
|
-
s: getRefParam(ctx, ref),
|
|
459
|
-
k: NIL,
|
|
460
|
-
v: value,
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
function createSetAssignment(
|
|
465
|
-
ctx: SerializerContext,
|
|
466
|
-
ref: number,
|
|
467
|
-
key: string,
|
|
468
|
-
value: string,
|
|
469
|
-
): void {
|
|
470
|
-
ctx.base.assignments.push({
|
|
471
|
-
t: AssignmentType.Set,
|
|
472
|
-
s: getRefParam(ctx, ref),
|
|
473
|
-
k: key,
|
|
474
|
-
v: value,
|
|
475
|
-
});
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
function createDeleteAssignment(
|
|
479
|
-
ctx: SerializerContext,
|
|
480
|
-
ref: number,
|
|
481
|
-
key: string,
|
|
482
|
-
): void {
|
|
483
|
-
ctx.base.assignments.push({
|
|
484
|
-
t: AssignmentType.Delete,
|
|
485
|
-
s: getRefParam(ctx, ref),
|
|
486
|
-
k: key,
|
|
487
|
-
v: NIL,
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
function createArrayAssign(
|
|
492
|
-
ctx: SerializerContext,
|
|
493
|
-
ref: number,
|
|
494
|
-
index: number | string,
|
|
495
|
-
value: string,
|
|
496
|
-
): void {
|
|
497
|
-
createAssignment(ctx.base, getRefParam(ctx, ref) + '[' + index + ']', value);
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
function createObjectAssign(
|
|
501
|
-
ctx: SerializerContext,
|
|
502
|
-
ref: number,
|
|
503
|
-
key: string,
|
|
504
|
-
value: string,
|
|
505
|
-
): void {
|
|
506
|
-
if (!isValidKey(key)) {
|
|
507
|
-
// `obj.__proto__ = x`, including the bracket form `obj["__proto__"] = x`,
|
|
508
|
-
// invokes the prototype setter rather than creating an own property.
|
|
509
|
-
// Define the property instead so the round-trip preserves it as an actual
|
|
510
|
-
// own property (matches the inline path in `serializeProperty`).
|
|
511
|
-
ctx.base.assignments.push({
|
|
512
|
-
t: AssignmentType.Define,
|
|
513
|
-
s: getRefParam(ctx, ref),
|
|
514
|
-
k: value,
|
|
515
|
-
v: NIL,
|
|
516
|
-
});
|
|
517
|
-
return;
|
|
518
|
-
}
|
|
519
|
-
createAssignment(ctx.base, getRefParam(ctx, ref) + '.' + key, value);
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
function createSequenceAssign(
|
|
523
|
-
ctx: SerializerContext,
|
|
524
|
-
ref: number,
|
|
525
|
-
index: number | string,
|
|
526
|
-
value: string,
|
|
527
|
-
): void {
|
|
528
|
-
createAssignment(
|
|
529
|
-
ctx.base,
|
|
530
|
-
getRefParam(ctx, ref) + '.v[' + index + ']',
|
|
531
|
-
value,
|
|
532
|
-
);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
/**
|
|
536
|
-
* Checks if the value is in the stack. Stack here is a reference
|
|
537
|
-
* structure to know if a object is to be accessed in a TDZ.
|
|
538
|
-
*/
|
|
539
|
-
function isIndexedValueInStack(
|
|
540
|
-
ctx: BaseSerializerContext,
|
|
541
|
-
node: SerovalNode,
|
|
542
|
-
): boolean {
|
|
543
|
-
return node.t === SerovalNodeType.IndexedValue && ctx.stack.includes(node.i);
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
/**
|
|
547
|
-
* Produces an assignment expression. `id` generates a reference
|
|
548
|
-
* parameter (through `getRefParam`) and has the option to
|
|
549
|
-
* return the reference parameter directly or assign a value to
|
|
550
|
-
* it.
|
|
551
|
-
*/
|
|
552
|
-
function assignIndexedValue(
|
|
553
|
-
ctx: SerializerContext,
|
|
554
|
-
index: number,
|
|
555
|
-
value: string,
|
|
556
|
-
): string {
|
|
557
|
-
if (
|
|
558
|
-
ctx.mode === SerovalMode.Vanilla &&
|
|
559
|
-
!isSerializerRefMarked(ctx.base, index)
|
|
560
|
-
) {
|
|
561
|
-
return value;
|
|
562
|
-
}
|
|
563
|
-
/**
|
|
564
|
-
* In cross-reference, we have to assume that
|
|
565
|
-
* every reference are going to be referenced
|
|
566
|
-
* in the future, and so we need to store
|
|
567
|
-
* all of it into the reference array.
|
|
568
|
-
*
|
|
569
|
-
* otherwise in vanilla, we only do this if it
|
|
570
|
-
* is actually referenced
|
|
571
|
-
*/
|
|
572
|
-
return getRefParam(ctx, index) + '=' + value;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
function serializeReference(node: SerovalReferenceNode): string {
|
|
576
|
-
return REFERENCES_KEY + '.get("' + node.s + '")';
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
function serializeArrayItem(
|
|
580
|
-
ctx: SerializerContext,
|
|
581
|
-
id: number,
|
|
582
|
-
item: SerovalNode | 0,
|
|
583
|
-
index: number,
|
|
584
|
-
): string {
|
|
585
|
-
// Check if index is a hole
|
|
586
|
-
if (item) {
|
|
587
|
-
// Check if item is a parent
|
|
588
|
-
if (isIndexedValueInStack(ctx.base, item)) {
|
|
589
|
-
markSerializerRef(ctx.base, id);
|
|
590
|
-
createArrayAssign(
|
|
591
|
-
ctx,
|
|
592
|
-
id,
|
|
593
|
-
index,
|
|
594
|
-
getRefParam(ctx, (item as SerovalIndexedValueNode).i),
|
|
595
|
-
);
|
|
596
|
-
return '';
|
|
597
|
-
}
|
|
598
|
-
return serialize(ctx, item);
|
|
599
|
-
}
|
|
600
|
-
return '';
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
function serializeArray(
|
|
604
|
-
ctx: SerializerContext,
|
|
605
|
-
node: SerovalArrayNode,
|
|
606
|
-
): string {
|
|
607
|
-
const id = node.i;
|
|
608
|
-
const list = node.a;
|
|
609
|
-
const len = list.length;
|
|
610
|
-
if (len > 0) {
|
|
611
|
-
ctx.base.stack.push(id);
|
|
612
|
-
let values = serializeArrayItem(ctx, id, list[0], 0);
|
|
613
|
-
// This is different than Map and Set
|
|
614
|
-
// because we also need to serialize
|
|
615
|
-
// the holes of the Array
|
|
616
|
-
let isHoley = values === '';
|
|
617
|
-
for (let i = 1, item: string; i < len; i++) {
|
|
618
|
-
item = serializeArrayItem(ctx, id, list[i], i);
|
|
619
|
-
values += ',' + item;
|
|
620
|
-
isHoley = item === '';
|
|
621
|
-
}
|
|
622
|
-
ctx.base.stack.pop();
|
|
623
|
-
pushObjectFlag(ctx, node.o, node.i);
|
|
624
|
-
return '[' + values + (isHoley ? ',]' : ']');
|
|
625
|
-
}
|
|
626
|
-
return '[]';
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
function serializeProperty(
|
|
630
|
-
ctx: SerializerContext,
|
|
631
|
-
source: SerovalNodeWithProperties,
|
|
632
|
-
key: SerovalObjectRecordKey,
|
|
633
|
-
val: SerovalNode,
|
|
634
|
-
): string {
|
|
635
|
-
if (typeof key === 'string') {
|
|
636
|
-
const check = Number(key);
|
|
637
|
-
const isIdentifier =
|
|
638
|
-
// Test if key is a valid positive number or JS identifier
|
|
639
|
-
// so that we don't have to serialize the key and wrap with brackets
|
|
640
|
-
(check >= 0 &&
|
|
641
|
-
// It's also important to consider that if the key is
|
|
642
|
-
// indeed numeric, we need to make sure that when
|
|
643
|
-
// converted back into a string, it's still the same
|
|
644
|
-
// to the original key. This allows us to differentiate
|
|
645
|
-
// keys that has numeric formats but in a different
|
|
646
|
-
// format, which can cause unintentional key declaration
|
|
647
|
-
// Example: { 0x1: 1 } vs { '0x1': 1 }
|
|
648
|
-
check.toString() === key) ||
|
|
649
|
-
isValidIdentifier(key);
|
|
650
|
-
if (isIndexedValueInStack(ctx.base, val)) {
|
|
651
|
-
const refParam = getRefParam(ctx, (val as SerovalIndexedValueNode).i);
|
|
652
|
-
markSerializerRef(ctx.base, source.i);
|
|
653
|
-
// Strict identifier check, make sure
|
|
654
|
-
// that it isn't numeric (except NaN)
|
|
655
|
-
if (isIdentifier && check !== check) {
|
|
656
|
-
createObjectAssign(ctx, source.i, key, refParam);
|
|
657
|
-
} else {
|
|
658
|
-
createArrayAssign(
|
|
659
|
-
ctx,
|
|
660
|
-
source.i,
|
|
661
|
-
isIdentifier ? key : '"' + key + '"',
|
|
662
|
-
refParam,
|
|
663
|
-
);
|
|
664
|
-
}
|
|
665
|
-
return '';
|
|
666
|
-
}
|
|
667
|
-
if (isValidKey(key)) {
|
|
668
|
-
return (isIdentifier ? key : '"' + key + '"') + ':' + serialize(ctx, val);
|
|
669
|
-
}
|
|
670
|
-
// `__proto__` as an identifier or string key in an object literal is the
|
|
671
|
-
// prototype setter, not an own property; use a computed key so the
|
|
672
|
-
// round-trip preserves it as an actual own property.
|
|
673
|
-
return '["' + key + '"]:' + serialize(ctx, val);
|
|
674
|
-
}
|
|
675
|
-
return '[' + serialize(ctx, key) + ']:' + serialize(ctx, val);
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
function serializeProperties(
|
|
679
|
-
ctx: SerializerContext,
|
|
680
|
-
source: SerovalNodeWithProperties,
|
|
681
|
-
record: SerovalObjectRecordNode,
|
|
682
|
-
): string {
|
|
683
|
-
const keys = record.k;
|
|
684
|
-
const len = keys.length;
|
|
685
|
-
if (len > 0) {
|
|
686
|
-
const values = record.v;
|
|
687
|
-
ctx.base.stack.push(source.i);
|
|
688
|
-
let result = serializeProperty(ctx, source, keys[0], values[0]);
|
|
689
|
-
for (let i = 1, item = result; i < len; i++) {
|
|
690
|
-
item = serializeProperty(ctx, source, keys[i], values[i]);
|
|
691
|
-
result += (item && result && ',') + item;
|
|
692
|
-
}
|
|
693
|
-
ctx.base.stack.pop();
|
|
694
|
-
return '{' + result + '}';
|
|
695
|
-
}
|
|
696
|
-
return '{}';
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
function serializeObject(
|
|
700
|
-
ctx: SerializerContext,
|
|
701
|
-
node: SerovalObjectNode,
|
|
702
|
-
): string {
|
|
703
|
-
pushObjectFlag(ctx, node.o, node.i);
|
|
704
|
-
return serializeProperties(ctx, node, node.p);
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
function serializeWithObjectAssign(
|
|
708
|
-
ctx: SerializerContext,
|
|
709
|
-
source: SerovalNodeWithProperties,
|
|
710
|
-
value: SerovalObjectRecordNode,
|
|
711
|
-
serialized: string,
|
|
712
|
-
): string {
|
|
713
|
-
const fields = serializeProperties(ctx, source, value);
|
|
714
|
-
if (fields !== '{}') {
|
|
715
|
-
return 'Object.assign(' + serialized + ',' + fields + ')';
|
|
716
|
-
}
|
|
717
|
-
return serialized;
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
function serializeStringKeyAssignment(
|
|
721
|
-
ctx: SerializerContext,
|
|
722
|
-
source: SerovalNodeWithProperties,
|
|
723
|
-
mainAssignments: Assignment[],
|
|
724
|
-
key: string,
|
|
725
|
-
value: SerovalNode,
|
|
726
|
-
): void {
|
|
727
|
-
const base = ctx.base;
|
|
728
|
-
const serialized = serialize(ctx, value);
|
|
729
|
-
const check = Number(key);
|
|
730
|
-
const isIdentifier =
|
|
731
|
-
// Test if key is a valid positive number or JS identifier
|
|
732
|
-
// so that we don't have to serialize the key and wrap with brackets
|
|
733
|
-
(check >= 0 &&
|
|
734
|
-
// It's also important to consider that if the key is
|
|
735
|
-
// indeed numeric, we need to make sure that when
|
|
736
|
-
// converted back into a string, it's still the same
|
|
737
|
-
// to the original key. This allows us to differentiate
|
|
738
|
-
// keys that has numeric formats but in a different
|
|
739
|
-
// format, which can cause unintentional key declaration
|
|
740
|
-
// Example: { 0x1: 1 } vs { '0x1': 1 }
|
|
741
|
-
check.toString() === key) ||
|
|
742
|
-
isValidIdentifier(key);
|
|
743
|
-
if (isIndexedValueInStack(base, value)) {
|
|
744
|
-
// Strict identifier check, make sure
|
|
745
|
-
// that it isn't numeric (except NaN)
|
|
746
|
-
if (isIdentifier && check !== check) {
|
|
747
|
-
createObjectAssign(ctx, source.i, key, serialized);
|
|
748
|
-
} else {
|
|
749
|
-
createArrayAssign(
|
|
750
|
-
ctx,
|
|
751
|
-
source.i,
|
|
752
|
-
isIdentifier ? key : '"' + key + '"',
|
|
753
|
-
serialized,
|
|
754
|
-
);
|
|
755
|
-
}
|
|
756
|
-
} else {
|
|
757
|
-
const parentAssignment = base.assignments;
|
|
758
|
-
base.assignments = mainAssignments;
|
|
759
|
-
if (isIdentifier && check !== check) {
|
|
760
|
-
createObjectAssign(ctx, source.i, key, serialized);
|
|
761
|
-
} else {
|
|
762
|
-
createArrayAssign(
|
|
763
|
-
ctx,
|
|
764
|
-
source.i,
|
|
765
|
-
isIdentifier ? key : '"' + key + '"',
|
|
766
|
-
serialized,
|
|
767
|
-
);
|
|
768
|
-
}
|
|
769
|
-
base.assignments = parentAssignment;
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
function serializeAssignment(
|
|
774
|
-
ctx: SerializerContext,
|
|
775
|
-
source: SerovalNodeWithProperties,
|
|
776
|
-
mainAssignments: Assignment[],
|
|
777
|
-
key: SerovalObjectRecordKey,
|
|
778
|
-
value: SerovalNode,
|
|
779
|
-
): void {
|
|
780
|
-
if (typeof key === 'string') {
|
|
781
|
-
serializeStringKeyAssignment(ctx, source, mainAssignments, key, value);
|
|
782
|
-
} else {
|
|
783
|
-
const base = ctx.base;
|
|
784
|
-
const parent = base.stack;
|
|
785
|
-
base.stack = [];
|
|
786
|
-
const serialized = serialize(ctx, value);
|
|
787
|
-
base.stack = parent;
|
|
788
|
-
const parentAssignment = base.assignments;
|
|
789
|
-
base.assignments = mainAssignments;
|
|
790
|
-
createArrayAssign(ctx, source.i, serialize(ctx, key), serialized);
|
|
791
|
-
base.assignments = parentAssignment;
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
function serializeAssignments(
|
|
796
|
-
ctx: SerializerContext,
|
|
797
|
-
source: SerovalNodeWithProperties,
|
|
798
|
-
node: SerovalObjectRecordNode,
|
|
799
|
-
): string | undefined {
|
|
800
|
-
const keys = node.k;
|
|
801
|
-
const len = keys.length;
|
|
802
|
-
if (len > 0) {
|
|
803
|
-
const mainAssignments: Assignment[] = [];
|
|
804
|
-
const values = node.v;
|
|
805
|
-
ctx.base.stack.push(source.i);
|
|
806
|
-
for (let i = 0; i < len; i++) {
|
|
807
|
-
serializeAssignment(ctx, source, mainAssignments, keys[i], values[i]);
|
|
808
|
-
}
|
|
809
|
-
ctx.base.stack.pop();
|
|
810
|
-
return resolveAssignments(mainAssignments);
|
|
811
|
-
}
|
|
812
|
-
return NIL;
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
function serializeDictionary(
|
|
816
|
-
ctx: SerializerContext,
|
|
817
|
-
node: SerovalNodeWithProperties,
|
|
818
|
-
init: string,
|
|
819
|
-
): string {
|
|
820
|
-
if (node.p) {
|
|
821
|
-
const base = ctx.base;
|
|
822
|
-
if (base.features & Feature.ObjectAssign) {
|
|
823
|
-
init = serializeWithObjectAssign(ctx, node, node.p, init);
|
|
824
|
-
} else {
|
|
825
|
-
markSerializerRef(base, node.i);
|
|
826
|
-
const assignments = serializeAssignments(ctx, node, node.p);
|
|
827
|
-
if (assignments) {
|
|
828
|
-
return (
|
|
829
|
-
'(' +
|
|
830
|
-
assignIndexedValue(ctx, node.i, init) +
|
|
831
|
-
',' +
|
|
832
|
-
assignments +
|
|
833
|
-
getRefParam(ctx, node.i) +
|
|
834
|
-
')'
|
|
835
|
-
);
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
return init;
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
function serializeNullConstructor(
|
|
843
|
-
ctx: SerializerContext,
|
|
844
|
-
node: SerovalNullConstructorNode,
|
|
845
|
-
): string {
|
|
846
|
-
pushObjectFlag(ctx, node.o, node.i);
|
|
847
|
-
return serializeDictionary(ctx, node, NULL_CONSTRUCTOR);
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
function serializeDate(node: SerovalDateNode): string {
|
|
851
|
-
return 'new Date("' + node.s + '")';
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
function serializeRegExp(
|
|
855
|
-
ctx: SerializerContext,
|
|
856
|
-
node: SerovalRegExpNode,
|
|
857
|
-
): string {
|
|
858
|
-
if (ctx.base.features & Feature.RegExp) {
|
|
859
|
-
return '/' + deserializeString(node.c) + '/' + node.m;
|
|
860
|
-
}
|
|
861
|
-
throw new SerovalUnsupportedNodeError(node);
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
function serializeSetItem(
|
|
865
|
-
ctx: SerializerContext,
|
|
866
|
-
id: number,
|
|
867
|
-
item: SerovalNode,
|
|
868
|
-
): string {
|
|
869
|
-
const base = ctx.base;
|
|
870
|
-
if (isIndexedValueInStack(base, item)) {
|
|
871
|
-
markSerializerRef(base, id);
|
|
872
|
-
createAddAssignment(
|
|
873
|
-
ctx,
|
|
874
|
-
id,
|
|
875
|
-
getRefParam(ctx, (item as SerovalIndexedValueNode).i),
|
|
876
|
-
);
|
|
877
|
-
return '';
|
|
878
|
-
}
|
|
879
|
-
return serialize(ctx, item);
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
function serializeSet(ctx: SerializerContext, node: SerovalSetNode): string {
|
|
883
|
-
let serialized = SET_CONSTRUCTOR;
|
|
884
|
-
const items = node.a;
|
|
885
|
-
const size = items.length;
|
|
886
|
-
const id = node.i;
|
|
887
|
-
if (size > 0) {
|
|
888
|
-
ctx.base.stack.push(id);
|
|
889
|
-
let result = serializeSetItem(ctx, id, items[0]);
|
|
890
|
-
for (let i = 1, item = result; i < size; i++) {
|
|
891
|
-
item = serializeSetItem(ctx, id, items[i]);
|
|
892
|
-
result += (item && result && ',') + item;
|
|
893
|
-
}
|
|
894
|
-
ctx.base.stack.pop();
|
|
895
|
-
if (result) {
|
|
896
|
-
serialized += '([' + result + '])';
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
return serialized;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
function serializeMapEntry(
|
|
903
|
-
ctx: SerializerContext,
|
|
904
|
-
id: number,
|
|
905
|
-
key: SerovalNode,
|
|
906
|
-
val: SerovalNode,
|
|
907
|
-
sentinel: string,
|
|
908
|
-
): string {
|
|
909
|
-
const base = ctx.base;
|
|
910
|
-
if (isIndexedValueInStack(base, key)) {
|
|
911
|
-
// Create reference for the map instance
|
|
912
|
-
const keyRef = getRefParam(ctx, (key as SerovalIndexedValueNode).i);
|
|
913
|
-
markSerializerRef(base, id);
|
|
914
|
-
// Check if value is a parent
|
|
915
|
-
if (isIndexedValueInStack(base, val)) {
|
|
916
|
-
const valueRef = getRefParam(ctx, (val as SerovalIndexedValueNode).i);
|
|
917
|
-
// Register an assignment since
|
|
918
|
-
// both key and value are a parent of this
|
|
919
|
-
// Map instance
|
|
920
|
-
createSetAssignment(ctx, id, keyRef, valueRef);
|
|
921
|
-
return '';
|
|
922
|
-
}
|
|
923
|
-
// Reset the stack
|
|
924
|
-
// This is required because the serialized
|
|
925
|
-
// value is no longer part of the expression
|
|
926
|
-
// tree and has been moved to the deferred
|
|
927
|
-
// assignment
|
|
928
|
-
if (
|
|
929
|
-
val.t !== SerovalNodeType.IndexedValue &&
|
|
930
|
-
val.i != null &&
|
|
931
|
-
isSerializerRefMarked(base, val.i)
|
|
932
|
-
) {
|
|
933
|
-
// We use a trick here using sequence (or comma) expressions
|
|
934
|
-
// basically we serialize the intended object in place WITHOUT
|
|
935
|
-
// actually returning it, this is by returning a placeholder
|
|
936
|
-
// value that we will remove sometime after.
|
|
937
|
-
const serialized =
|
|
938
|
-
'(' + serialize(ctx, val) + ',[' + sentinel + ',' + sentinel + '])';
|
|
939
|
-
createSetAssignment(ctx, id, keyRef, getRefParam(ctx, val.i));
|
|
940
|
-
createDeleteAssignment(ctx, id, sentinel);
|
|
941
|
-
return serialized;
|
|
942
|
-
}
|
|
943
|
-
const parent = base.stack;
|
|
944
|
-
base.stack = [];
|
|
945
|
-
createSetAssignment(ctx, id, keyRef, serialize(ctx, val));
|
|
946
|
-
base.stack = parent;
|
|
947
|
-
return '';
|
|
948
|
-
}
|
|
949
|
-
if (isIndexedValueInStack(base, val)) {
|
|
950
|
-
// Create ref for the Map instance
|
|
951
|
-
const valueRef = getRefParam(ctx, (val as SerovalIndexedValueNode).i);
|
|
952
|
-
markSerializerRef(base, id);
|
|
953
|
-
if (
|
|
954
|
-
key.t !== SerovalNodeType.IndexedValue &&
|
|
955
|
-
key.i != null &&
|
|
956
|
-
isSerializerRefMarked(base, key.i)
|
|
957
|
-
) {
|
|
958
|
-
const serialized =
|
|
959
|
-
'(' + serialize(ctx, key) + ',[' + sentinel + ',' + sentinel + '])';
|
|
960
|
-
createSetAssignment(ctx, id, getRefParam(ctx, key.i), valueRef);
|
|
961
|
-
createDeleteAssignment(ctx, id, sentinel);
|
|
962
|
-
return serialized;
|
|
963
|
-
}
|
|
964
|
-
// Reset stack for the key serialization
|
|
965
|
-
const parent = base.stack;
|
|
966
|
-
base.stack = [];
|
|
967
|
-
createSetAssignment(ctx, id, serialize(ctx, key), valueRef);
|
|
968
|
-
base.stack = parent;
|
|
969
|
-
return '';
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
return '[' + serialize(ctx, key) + ',' + serialize(ctx, val) + ']';
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
function serializeMap(ctx: SerializerContext, node: SerovalMapNode): string {
|
|
976
|
-
let serialized = MAP_CONSTRUCTOR;
|
|
977
|
-
const keys = node.e.k;
|
|
978
|
-
const size = keys.length;
|
|
979
|
-
const id = node.i;
|
|
980
|
-
const sentinel = node.f;
|
|
981
|
-
const sentinelId = getRefParam(ctx, sentinel.i);
|
|
982
|
-
const base = ctx.base;
|
|
983
|
-
if (size > 0) {
|
|
984
|
-
const vals = node.e.v;
|
|
985
|
-
base.stack.push(id);
|
|
986
|
-
let result = serializeMapEntry(ctx, id, keys[0], vals[0], sentinelId);
|
|
987
|
-
for (let i = 1, item = result; i < size; i++) {
|
|
988
|
-
item = serializeMapEntry(ctx, id, keys[i], vals[i], sentinelId);
|
|
989
|
-
result += (item && result && ',') + item;
|
|
990
|
-
}
|
|
991
|
-
base.stack.pop();
|
|
992
|
-
// Check if there are any values
|
|
993
|
-
// so that the empty Map constructor
|
|
994
|
-
// can be used instead
|
|
995
|
-
if (result) {
|
|
996
|
-
serialized += '([' + result + '])';
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
if (sentinel.t === SerovalNodeType.SpecialReference) {
|
|
1000
|
-
markSerializerRef(base, sentinel.i);
|
|
1001
|
-
serialized = '(' + serialize(ctx, sentinel) + ',' + serialized + ')';
|
|
1002
|
-
}
|
|
1003
|
-
return serialized;
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
function serializeArrayBuffer(
|
|
1007
|
-
ctx: SerializerContext,
|
|
1008
|
-
node: SerovalArrayBufferNode,
|
|
1009
|
-
): string {
|
|
1010
|
-
return getConstructor(ctx, node.f) + '("' + node.s + '")';
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
function serializeTypedArray(
|
|
1014
|
-
ctx: SerializerContext,
|
|
1015
|
-
node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
|
|
1016
|
-
): string {
|
|
1017
|
-
return (
|
|
1018
|
-
'new ' +
|
|
1019
|
-
node.c +
|
|
1020
|
-
'(' +
|
|
1021
|
-
serialize(ctx, node.f) +
|
|
1022
|
-
',' +
|
|
1023
|
-
node.b +
|
|
1024
|
-
',' +
|
|
1025
|
-
node.l +
|
|
1026
|
-
')'
|
|
1027
|
-
);
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
function serializeDataView(
|
|
1031
|
-
ctx: SerializerContext,
|
|
1032
|
-
node: SerovalDataViewNode,
|
|
1033
|
-
): string {
|
|
1034
|
-
return (
|
|
1035
|
-
'new DataView(' + serialize(ctx, node.f) + ',' + node.b + ',' + node.l + ')'
|
|
1036
|
-
);
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
function serializeAggregateError(
|
|
1040
|
-
ctx: SerializerContext,
|
|
1041
|
-
node: SerovalAggregateErrorNode,
|
|
1042
|
-
): string {
|
|
1043
|
-
const id = node.i;
|
|
1044
|
-
// `AggregateError` might've been extended
|
|
1045
|
-
// either through class or custom properties
|
|
1046
|
-
// Make sure to assign extra properties
|
|
1047
|
-
ctx.base.stack.push(id);
|
|
1048
|
-
const serialized = serializeDictionary(
|
|
1049
|
-
ctx,
|
|
1050
|
-
node,
|
|
1051
|
-
'new AggregateError([],"' + node.m + '")',
|
|
1052
|
-
);
|
|
1053
|
-
ctx.base.stack.pop();
|
|
1054
|
-
return serialized;
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
function serializeError(
|
|
1058
|
-
ctx: SerializerContext,
|
|
1059
|
-
node: SerovalErrorNode,
|
|
1060
|
-
): string {
|
|
1061
|
-
return serializeDictionary(
|
|
1062
|
-
ctx,
|
|
1063
|
-
node,
|
|
1064
|
-
'new ' + ERROR_CONSTRUCTOR_STRING[node.s] + '("' + node.m + '")',
|
|
1065
|
-
);
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
function serializePromise(
|
|
1069
|
-
ctx: SerializerContext,
|
|
1070
|
-
node: SerovalPromiseNode,
|
|
1071
|
-
): string {
|
|
1072
|
-
let serialized: string;
|
|
1073
|
-
// Check if resolved value is a parent expression
|
|
1074
|
-
const fulfilled = node.f;
|
|
1075
|
-
const id = node.i;
|
|
1076
|
-
const promiseConstructor = node.s ? PROMISE_RESOLVE : PROMISE_REJECT;
|
|
1077
|
-
const base = ctx.base;
|
|
1078
|
-
if (isIndexedValueInStack(base, fulfilled)) {
|
|
1079
|
-
// A Promise trick, reference the value
|
|
1080
|
-
// inside the `then` expression so that
|
|
1081
|
-
// the Promise evaluates after the parent
|
|
1082
|
-
// has initialized
|
|
1083
|
-
const ref = getRefParam(ctx, (fulfilled as SerovalIndexedValueNode).i);
|
|
1084
|
-
serialized =
|
|
1085
|
-
promiseConstructor +
|
|
1086
|
-
(node.s
|
|
1087
|
-
? '().then(' + createFunction([], ref) + ')'
|
|
1088
|
-
: '().catch(' + createEffectfulFunction([], 'throw ' + ref) + ')');
|
|
1089
|
-
} else {
|
|
1090
|
-
base.stack.push(id);
|
|
1091
|
-
const result = serialize(ctx, fulfilled);
|
|
1092
|
-
base.stack.pop();
|
|
1093
|
-
// just inline the value/reference here
|
|
1094
|
-
serialized = promiseConstructor + '(' + result + ')';
|
|
1095
|
-
}
|
|
1096
|
-
return serialized;
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
function serializeBoxed(
|
|
1100
|
-
ctx: SerializerContext,
|
|
1101
|
-
node: SerovalBoxedNode,
|
|
1102
|
-
): string {
|
|
1103
|
-
return 'Object(' + serialize(ctx, node.f) + ')';
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
function getConstructor(
|
|
1107
|
-
ctx: SerializerContext,
|
|
1108
|
-
node: SerovalNodeWithID,
|
|
1109
|
-
): string {
|
|
1110
|
-
const current = serialize(ctx, node);
|
|
1111
|
-
return node.t === SerovalNodeType.IndexedValue
|
|
1112
|
-
? current
|
|
1113
|
-
: '(' + current + ')';
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
function serializePromiseConstructor(
|
|
1117
|
-
ctx: SerializerContext,
|
|
1118
|
-
node: SerovalPromiseConstructorNode,
|
|
1119
|
-
): string {
|
|
1120
|
-
if (ctx.mode === SerovalMode.Vanilla) {
|
|
1121
|
-
throw new SerovalUnsupportedNodeError(node);
|
|
1122
|
-
}
|
|
1123
|
-
const resolver = assignIndexedValue(
|
|
1124
|
-
ctx,
|
|
1125
|
-
node.s,
|
|
1126
|
-
getConstructor(ctx, node.f) + '()',
|
|
1127
|
-
);
|
|
1128
|
-
return '(' + resolver + ').p';
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
function serializePromiseResolve(
|
|
1132
|
-
ctx: SerializerContext,
|
|
1133
|
-
node: SerovalPromiseResolveNode,
|
|
1134
|
-
): string {
|
|
1135
|
-
if (ctx.mode === SerovalMode.Vanilla) {
|
|
1136
|
-
throw new SerovalUnsupportedNodeError(node);
|
|
1137
|
-
}
|
|
1138
|
-
return (
|
|
1139
|
-
getConstructor(ctx, node.a[0]) +
|
|
1140
|
-
'(' +
|
|
1141
|
-
getRefParam(ctx, node.i) +
|
|
1142
|
-
',' +
|
|
1143
|
-
serialize(ctx, node.a[1]) +
|
|
1144
|
-
')'
|
|
1145
|
-
);
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
function serializePromiseReject(
|
|
1149
|
-
ctx: SerializerContext,
|
|
1150
|
-
node: SerovalPromiseRejectNode,
|
|
1151
|
-
): string {
|
|
1152
|
-
if (ctx.mode === SerovalMode.Vanilla) {
|
|
1153
|
-
throw new SerovalUnsupportedNodeError(node);
|
|
1154
|
-
}
|
|
1155
|
-
return (
|
|
1156
|
-
getConstructor(ctx, node.a[0]) +
|
|
1157
|
-
'(' +
|
|
1158
|
-
getRefParam(ctx, node.i) +
|
|
1159
|
-
',' +
|
|
1160
|
-
serialize(ctx, node.a[1]) +
|
|
1161
|
-
')'
|
|
1162
|
-
);
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
function serializePlugin(
|
|
1166
|
-
ctx: SerializerContext,
|
|
1167
|
-
node: SerovalPluginNode,
|
|
1168
|
-
): string {
|
|
1169
|
-
const currentPlugins = ctx.base.plugins;
|
|
1170
|
-
if (currentPlugins) {
|
|
1171
|
-
for (let i = 0, len = currentPlugins.length; i < len; i++) {
|
|
1172
|
-
const plugin = currentPlugins[i];
|
|
1173
|
-
if (plugin.tag === node.c) {
|
|
1174
|
-
if (ctx.child == null) {
|
|
1175
|
-
ctx.child = new SerializePluginContext(ctx);
|
|
1176
|
-
}
|
|
1177
|
-
return plugin.serialize(node.s, ctx.child, {
|
|
1178
|
-
id: node.i,
|
|
1179
|
-
});
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
throw new SerovalMissingPluginError(node.c);
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
|
-
function serializeIteratorFactory(
|
|
1187
|
-
ctx: SerializerContext,
|
|
1188
|
-
node: SerovalIteratorFactoryNode,
|
|
1189
|
-
): string {
|
|
1190
|
-
let result = '';
|
|
1191
|
-
let initialized = false;
|
|
1192
|
-
if (node.f.t !== SerovalNodeType.IndexedValue) {
|
|
1193
|
-
markSerializerRef(ctx.base, node.f.i);
|
|
1194
|
-
result = '(' + serialize(ctx, node.f) + ',';
|
|
1195
|
-
initialized = true;
|
|
1196
|
-
}
|
|
1197
|
-
result += assignIndexedValue(
|
|
1198
|
-
ctx,
|
|
1199
|
-
node.i,
|
|
1200
|
-
'(' +
|
|
1201
|
-
SERIALIZED_ITERATOR_CONSTRUCTOR +
|
|
1202
|
-
')(' +
|
|
1203
|
-
getRefParam(ctx, node.f.i) +
|
|
1204
|
-
')',
|
|
1205
|
-
);
|
|
1206
|
-
if (initialized) {
|
|
1207
|
-
result += ')';
|
|
1208
|
-
}
|
|
1209
|
-
return result;
|
|
1210
|
-
}
|
|
1211
|
-
|
|
1212
|
-
function serializeIteratorFactoryInstance(
|
|
1213
|
-
ctx: SerializerContext,
|
|
1214
|
-
node: SerovalIteratorFactoryInstanceNode,
|
|
1215
|
-
): string {
|
|
1216
|
-
return getConstructor(ctx, node.a[0]) + '(' + serialize(ctx, node.a[1]) + ')';
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
function serializeAsyncIteratorFactory(
|
|
1220
|
-
ctx: SerializerContext,
|
|
1221
|
-
node: SerovalAsyncIteratorFactoryNode,
|
|
1222
|
-
): string {
|
|
1223
|
-
const promise = node.a[0];
|
|
1224
|
-
const symbol = node.a[1];
|
|
1225
|
-
const base = ctx.base;
|
|
1226
|
-
|
|
1227
|
-
let result = '';
|
|
1228
|
-
|
|
1229
|
-
if (promise.t !== SerovalNodeType.IndexedValue) {
|
|
1230
|
-
markSerializerRef(base, promise.i);
|
|
1231
|
-
result += '(' + serialize(ctx, promise);
|
|
1232
|
-
}
|
|
1233
|
-
if (symbol.t !== SerovalNodeType.IndexedValue) {
|
|
1234
|
-
markSerializerRef(base, symbol.i);
|
|
1235
|
-
result += (result ? ',' : '(') + serialize(ctx, symbol);
|
|
1236
|
-
}
|
|
1237
|
-
if (result) {
|
|
1238
|
-
result += ',';
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
const iterator = assignIndexedValue(
|
|
1242
|
-
ctx,
|
|
1243
|
-
node.i,
|
|
1244
|
-
'(' +
|
|
1245
|
-
SERIALIZED_ASYNC_ITERATOR_CONSTRUCTOR +
|
|
1246
|
-
')(' +
|
|
1247
|
-
getRefParam(ctx, symbol.i) +
|
|
1248
|
-
',' +
|
|
1249
|
-
getRefParam(ctx, promise.i) +
|
|
1250
|
-
')',
|
|
1251
|
-
);
|
|
1252
|
-
|
|
1253
|
-
if (result) {
|
|
1254
|
-
return result + iterator + ')';
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
|
-
return iterator;
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
function serializeAsyncIteratorFactoryInstance(
|
|
1261
|
-
ctx: SerializerContext,
|
|
1262
|
-
node: SerovalAsyncIteratorFactoryInstanceNode,
|
|
1263
|
-
): string {
|
|
1264
|
-
return getConstructor(ctx, node.a[0]) + '(' + serialize(ctx, node.a[1]) + ')';
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
function serializeStreamConstructor(
|
|
1268
|
-
ctx: SerializerContext,
|
|
1269
|
-
node: SerovalStreamConstructorNode,
|
|
1270
|
-
): string {
|
|
1271
|
-
const result = assignIndexedValue(
|
|
1272
|
-
ctx,
|
|
1273
|
-
node.i,
|
|
1274
|
-
getConstructor(ctx, node.f) + '()',
|
|
1275
|
-
);
|
|
1276
|
-
const len = node.a.length;
|
|
1277
|
-
if (len) {
|
|
1278
|
-
let values = serialize(ctx, node.a[0]);
|
|
1279
|
-
for (let i = 1; i < len; i++) {
|
|
1280
|
-
values += ',' + serialize(ctx, node.a[i]);
|
|
1281
|
-
}
|
|
1282
|
-
return '(' + result + ',' + values + ',' + getRefParam(ctx, node.i) + ')';
|
|
1283
|
-
}
|
|
1284
|
-
return result;
|
|
1285
|
-
}
|
|
1286
|
-
|
|
1287
|
-
function serializeStreamNext(
|
|
1288
|
-
ctx: SerializerContext,
|
|
1289
|
-
node: SerovalStreamNextNode,
|
|
1290
|
-
): string {
|
|
1291
|
-
return getRefParam(ctx, node.i) + '.next(' + serialize(ctx, node.f) + ')';
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
function serializeStreamThrow(
|
|
1295
|
-
ctx: SerializerContext,
|
|
1296
|
-
node: SerovalStreamThrowNode,
|
|
1297
|
-
): string {
|
|
1298
|
-
return getRefParam(ctx, node.i) + '.throw(' + serialize(ctx, node.f) + ')';
|
|
1299
|
-
}
|
|
1300
|
-
|
|
1301
|
-
function serializeStreamReturn(
|
|
1302
|
-
ctx: SerializerContext,
|
|
1303
|
-
node: SerovalStreamReturnNode,
|
|
1304
|
-
): string {
|
|
1305
|
-
return getRefParam(ctx, node.i) + '.return(' + serialize(ctx, node.f) + ')';
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
function serializeSequenceItem(
|
|
1309
|
-
ctx: SerializerContext,
|
|
1310
|
-
id: number,
|
|
1311
|
-
index: number,
|
|
1312
|
-
item: SerovalNode,
|
|
1313
|
-
): string {
|
|
1314
|
-
const base = ctx.base;
|
|
1315
|
-
if (isIndexedValueInStack(base, item)) {
|
|
1316
|
-
markSerializerRef(base, id);
|
|
1317
|
-
createSequenceAssign(
|
|
1318
|
-
ctx,
|
|
1319
|
-
id,
|
|
1320
|
-
index,
|
|
1321
|
-
getRefParam(ctx, (item as SerovalIndexedValueNode).i),
|
|
1322
|
-
);
|
|
1323
|
-
return '';
|
|
1324
|
-
}
|
|
1325
|
-
return serialize(ctx, item);
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
function serializeSequence(
|
|
1329
|
-
ctx: SerializerContext,
|
|
1330
|
-
node: SerovalSequenceNode,
|
|
1331
|
-
): string {
|
|
1332
|
-
const items = node.a;
|
|
1333
|
-
const size = items.length;
|
|
1334
|
-
const id = node.i;
|
|
1335
|
-
if (size > 0) {
|
|
1336
|
-
ctx.base.stack.push(id);
|
|
1337
|
-
let result = serializeSequenceItem(ctx, id, 0, items[0]);
|
|
1338
|
-
for (let i = 1, item = result; i < size; i++) {
|
|
1339
|
-
item = serializeSequenceItem(ctx, id, i, items[i]);
|
|
1340
|
-
result += (item && result && ',') + item;
|
|
1341
|
-
}
|
|
1342
|
-
ctx.base.stack.pop();
|
|
1343
|
-
if (result) {
|
|
1344
|
-
return (
|
|
1345
|
-
'{__SEROVAL_SEQUENCE__:!0,v:[' +
|
|
1346
|
-
result +
|
|
1347
|
-
'],t:' +
|
|
1348
|
-
node.s +
|
|
1349
|
-
',d:' +
|
|
1350
|
-
node.l +
|
|
1351
|
-
'}'
|
|
1352
|
-
);
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
return '{__SEROVAL_SEQUENCE__:!0,v:[],t:-1,d:0}';
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
function serializeAssignable(
|
|
1359
|
-
ctx: SerializerContext,
|
|
1360
|
-
node: SerovalNode,
|
|
1361
|
-
): string {
|
|
1362
|
-
switch (node.t) {
|
|
1363
|
-
case SerovalNodeType.WKSymbol:
|
|
1364
|
-
return SYMBOL_STRING[node.s];
|
|
1365
|
-
case SerovalNodeType.Reference:
|
|
1366
|
-
return serializeReference(node);
|
|
1367
|
-
case SerovalNodeType.Array:
|
|
1368
|
-
return serializeArray(ctx, node);
|
|
1369
|
-
case SerovalNodeType.Object:
|
|
1370
|
-
return serializeObject(ctx, node);
|
|
1371
|
-
case SerovalNodeType.NullConstructor:
|
|
1372
|
-
return serializeNullConstructor(ctx, node);
|
|
1373
|
-
case SerovalNodeType.Date:
|
|
1374
|
-
return serializeDate(node);
|
|
1375
|
-
case SerovalNodeType.RegExp:
|
|
1376
|
-
return serializeRegExp(ctx, node);
|
|
1377
|
-
case SerovalNodeType.Set:
|
|
1378
|
-
return serializeSet(ctx, node);
|
|
1379
|
-
case SerovalNodeType.Map:
|
|
1380
|
-
return serializeMap(ctx, node);
|
|
1381
|
-
case SerovalNodeType.ArrayBuffer:
|
|
1382
|
-
return serializeArrayBuffer(ctx, node);
|
|
1383
|
-
case SerovalNodeType.BigIntTypedArray:
|
|
1384
|
-
case SerovalNodeType.TypedArray:
|
|
1385
|
-
return serializeTypedArray(ctx, node);
|
|
1386
|
-
case SerovalNodeType.DataView:
|
|
1387
|
-
return serializeDataView(ctx, node);
|
|
1388
|
-
case SerovalNodeType.AggregateError:
|
|
1389
|
-
return serializeAggregateError(ctx, node);
|
|
1390
|
-
case SerovalNodeType.Error:
|
|
1391
|
-
return serializeError(ctx, node);
|
|
1392
|
-
case SerovalNodeType.Promise:
|
|
1393
|
-
return serializePromise(ctx, node);
|
|
1394
|
-
case SerovalNodeType.Boxed:
|
|
1395
|
-
return serializeBoxed(ctx, node);
|
|
1396
|
-
case SerovalNodeType.PromiseConstructor:
|
|
1397
|
-
return serializePromiseConstructor(ctx, node);
|
|
1398
|
-
case SerovalNodeType.Plugin:
|
|
1399
|
-
return serializePlugin(ctx, node);
|
|
1400
|
-
case SerovalNodeType.SpecialReference:
|
|
1401
|
-
return SPECIAL_REF_STRING[node.s];
|
|
1402
|
-
case SerovalNodeType.Sequence:
|
|
1403
|
-
return serializeSequence(ctx, node);
|
|
1404
|
-
default:
|
|
1405
|
-
throw new SerovalUnsupportedNodeError(node);
|
|
1406
|
-
}
|
|
1407
|
-
}
|
|
1408
|
-
|
|
1409
|
-
function serialize(ctx: SerializerContext, node: SerovalNode): string {
|
|
1410
|
-
switch (node.t) {
|
|
1411
|
-
case SerovalNodeType.Constant:
|
|
1412
|
-
return CONSTANT_STRING[node.s];
|
|
1413
|
-
case SerovalNodeType.Number:
|
|
1414
|
-
return '' + node.s;
|
|
1415
|
-
case SerovalNodeType.String:
|
|
1416
|
-
return '"' + node.s + '"';
|
|
1417
|
-
case SerovalNodeType.BigInt:
|
|
1418
|
-
return node.s + 'n';
|
|
1419
|
-
case SerovalNodeType.IndexedValue:
|
|
1420
|
-
return getRefParam(ctx, node.i);
|
|
1421
|
-
case SerovalNodeType.PromiseSuccess:
|
|
1422
|
-
return serializePromiseResolve(ctx, node);
|
|
1423
|
-
case SerovalNodeType.PromiseFailure:
|
|
1424
|
-
return serializePromiseReject(ctx, node);
|
|
1425
|
-
case SerovalNodeType.IteratorFactory:
|
|
1426
|
-
return serializeIteratorFactory(ctx, node);
|
|
1427
|
-
case SerovalNodeType.IteratorFactoryInstance:
|
|
1428
|
-
return serializeIteratorFactoryInstance(ctx, node);
|
|
1429
|
-
case SerovalNodeType.AsyncIteratorFactory:
|
|
1430
|
-
return serializeAsyncIteratorFactory(ctx, node);
|
|
1431
|
-
case SerovalNodeType.AsyncIteratorFactoryInstance:
|
|
1432
|
-
return serializeAsyncIteratorFactoryInstance(ctx, node);
|
|
1433
|
-
case SerovalNodeType.StreamConstructor:
|
|
1434
|
-
return serializeStreamConstructor(ctx, node);
|
|
1435
|
-
case SerovalNodeType.StreamNext:
|
|
1436
|
-
return serializeStreamNext(ctx, node);
|
|
1437
|
-
case SerovalNodeType.StreamThrow:
|
|
1438
|
-
return serializeStreamThrow(ctx, node);
|
|
1439
|
-
case SerovalNodeType.StreamReturn:
|
|
1440
|
-
return serializeStreamReturn(ctx, node);
|
|
1441
|
-
default:
|
|
1442
|
-
return assignIndexedValue(ctx, node.i, serializeAssignable(ctx, node));
|
|
1443
|
-
}
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
export function serializeRoot(
|
|
1447
|
-
ctx: SerializerContext,
|
|
1448
|
-
node: SerovalNode,
|
|
1449
|
-
): string {
|
|
1450
|
-
try {
|
|
1451
|
-
return serialize(ctx, node);
|
|
1452
|
-
} catch (error) {
|
|
1453
|
-
throw error instanceof SerovalSerializationError
|
|
1454
|
-
? error
|
|
1455
|
-
: new SerovalSerializationError(error);
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
|
|
1459
|
-
export function serializeTopVanilla(
|
|
1460
|
-
ctx: VanillaSerializerContext,
|
|
1461
|
-
tree: SerovalNode,
|
|
1462
|
-
): string {
|
|
1463
|
-
const result = serialize(ctx, tree);
|
|
1464
|
-
// Shared references detected
|
|
1465
|
-
if (tree.i != null && ctx.state.vars.length) {
|
|
1466
|
-
const patches = resolvePatches(ctx.base);
|
|
1467
|
-
let body = result;
|
|
1468
|
-
if (patches) {
|
|
1469
|
-
// Get (or create) a ref from the source
|
|
1470
|
-
const index = getRefParam(ctx, tree.i);
|
|
1471
|
-
body = result + ',' + patches + index;
|
|
1472
|
-
if (!result.startsWith(index + '=')) {
|
|
1473
|
-
body = index + '=' + body;
|
|
1474
|
-
}
|
|
1475
|
-
body = '(' + body + ')';
|
|
1476
|
-
}
|
|
1477
|
-
return '(' + createFunction(ctx.state.vars, body) + ')()';
|
|
1478
|
-
}
|
|
1479
|
-
if (tree.t === SerovalNodeType.Object) {
|
|
1480
|
-
return '(' + result + ')';
|
|
1481
|
-
}
|
|
1482
|
-
return result;
|
|
1483
|
-
}
|
|
1484
|
-
|
|
1485
|
-
export function serializeTopCross(
|
|
1486
|
-
ctx: CrossSerializerContext,
|
|
1487
|
-
tree: SerovalNode,
|
|
1488
|
-
): string {
|
|
1489
|
-
// Get the serialized result
|
|
1490
|
-
const result = serialize(ctx, tree);
|
|
1491
|
-
// If the node is a non-reference, return
|
|
1492
|
-
// the result immediately
|
|
1493
|
-
const id = tree.i;
|
|
1494
|
-
if (id == null) {
|
|
1495
|
-
return result;
|
|
1496
|
-
}
|
|
1497
|
-
// Get the patches
|
|
1498
|
-
const patches = resolvePatches(ctx.base);
|
|
1499
|
-
// Get the variable that represents the root
|
|
1500
|
-
const ref = getRefParam(ctx, id);
|
|
1501
|
-
const scopeId = ctx.state.scopeId;
|
|
1502
|
-
// Parameters needed for scoping
|
|
1503
|
-
const params = scopeId == null ? '' : GLOBAL_CONTEXT_REFERENCES;
|
|
1504
|
-
// If there are patches, append it after the result
|
|
1505
|
-
const body = patches ? '(' + result + ',' + patches + ref + ')' : result;
|
|
1506
|
-
// If there are no params, there's no need to generate a function
|
|
1507
|
-
if (params === '') {
|
|
1508
|
-
if (tree.t === SerovalNodeType.Object && !patches) {
|
|
1509
|
-
return '(' + body + ')';
|
|
1510
|
-
}
|
|
1511
|
-
return body;
|
|
1512
|
-
}
|
|
1513
|
-
// Get the arguments for the IIFE
|
|
1514
|
-
const args =
|
|
1515
|
-
scopeId == null
|
|
1516
|
-
? '()'
|
|
1517
|
-
: '(' +
|
|
1518
|
-
GLOBAL_CONTEXT_REFERENCES +
|
|
1519
|
-
'["' +
|
|
1520
|
-
serializeString(scopeId) +
|
|
1521
|
-
'"])';
|
|
1522
|
-
// Create the IIFE
|
|
1523
|
-
return '(' + createFunction([params], body) + ')' + args;
|
|
1524
|
-
}
|