seroval 1.5.6 → 1.6.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.
Files changed (117) hide show
  1. package/dist/dev/index.cjs +2954 -0
  2. package/dist/dev/index.d.cts +761 -0
  3. package/dist/dev/index.d.ts +761 -0
  4. package/dist/dev/index.js +2917 -0
  5. package/dist/index.cjs +2947 -0
  6. package/dist/index.d.cts +761 -0
  7. package/dist/index.d.ts +761 -0
  8. package/dist/index.js +2910 -0
  9. package/package.json +23 -21
  10. package/dist/cjs/development/index.cjs +0 -4232
  11. package/dist/cjs/development/index.cjs.map +0 -7
  12. package/dist/cjs/production/index.cjs +0 -3
  13. package/dist/esm/development/index.mjs +0 -4209
  14. package/dist/esm/development/index.mjs.map +0 -7
  15. package/dist/esm/production/index.mjs +0 -3
  16. package/dist/types/core/Serializer.d.ts +0 -28
  17. package/dist/types/core/Serializer.d.ts.map +0 -1
  18. package/dist/types/core/base-primitives.d.ts +0 -28
  19. package/dist/types/core/base-primitives.d.ts.map +0 -1
  20. package/dist/types/core/compat.d.ts +0 -15
  21. package/dist/types/core/compat.d.ts.map +0 -1
  22. package/dist/types/core/constants.d.ts +0 -105
  23. package/dist/types/core/constants.d.ts.map +0 -1
  24. package/dist/types/core/constructors.d.ts +0 -50
  25. package/dist/types/core/constructors.d.ts.map +0 -1
  26. package/dist/types/core/context/async-parser.d.ts +0 -20
  27. package/dist/types/core/context/async-parser.d.ts.map +0 -1
  28. package/dist/types/core/context/deserializer.d.ts +0 -52
  29. package/dist/types/core/context/deserializer.d.ts.map +0 -1
  30. package/dist/types/core/context/parser.d.ts +0 -62
  31. package/dist/types/core/context/parser.d.ts.map +0 -1
  32. package/dist/types/core/context/serializer.d.ts +0 -103
  33. package/dist/types/core/context/serializer.d.ts.map +0 -1
  34. package/dist/types/core/context/sync-parser.d.ts +0 -61
  35. package/dist/types/core/context/sync-parser.d.ts.map +0 -1
  36. package/dist/types/core/cross/index.d.ts +0 -24
  37. package/dist/types/core/cross/index.d.ts.map +0 -1
  38. package/dist/types/core/errors.d.ts +0 -47
  39. package/dist/types/core/errors.d.ts.map +0 -1
  40. package/dist/types/core/function-string.d.ts +0 -3
  41. package/dist/types/core/function-string.d.ts.map +0 -1
  42. package/dist/types/core/keys.d.ts +0 -4
  43. package/dist/types/core/keys.d.ts.map +0 -1
  44. package/dist/types/core/literals.d.ts +0 -10
  45. package/dist/types/core/literals.d.ts.map +0 -1
  46. package/dist/types/core/node.d.ts +0 -8
  47. package/dist/types/core/node.d.ts.map +0 -1
  48. package/dist/types/core/opaque-reference.d.ts +0 -9
  49. package/dist/types/core/opaque-reference.d.ts.map +0 -1
  50. package/dist/types/core/plugin.d.ts +0 -52
  51. package/dist/types/core/plugin.d.ts.map +0 -1
  52. package/dist/types/core/reference.d.ts +0 -6
  53. package/dist/types/core/reference.d.ts.map +0 -1
  54. package/dist/types/core/sequence.d.ts +0 -11
  55. package/dist/types/core/sequence.d.ts.map +0 -1
  56. package/dist/types/core/special-reference.d.ts +0 -16
  57. package/dist/types/core/special-reference.d.ts.map +0 -1
  58. package/dist/types/core/stream.d.ts +0 -17
  59. package/dist/types/core/stream.d.ts.map +0 -1
  60. package/dist/types/core/string.d.ts +0 -4
  61. package/dist/types/core/string.d.ts.map +0 -1
  62. package/dist/types/core/symbols.d.ts +0 -14
  63. package/dist/types/core/symbols.d.ts.map +0 -1
  64. package/dist/types/core/tree/index.d.ts +0 -21
  65. package/dist/types/core/tree/index.d.ts.map +0 -1
  66. package/dist/types/core/types.d.ts +0 -233
  67. package/dist/types/core/types.d.ts.map +0 -1
  68. package/dist/types/core/utils/error.d.ts +0 -6
  69. package/dist/types/core/utils/error.d.ts.map +0 -1
  70. package/dist/types/core/utils/get-identifier.d.ts +0 -2
  71. package/dist/types/core/utils/get-identifier.d.ts.map +0 -1
  72. package/dist/types/core/utils/get-object-flag.d.ts +0 -3
  73. package/dist/types/core/utils/get-object-flag.d.ts.map +0 -1
  74. package/dist/types/core/utils/is-valid-identifier.d.ts +0 -2
  75. package/dist/types/core/utils/is-valid-identifier.d.ts.map +0 -1
  76. package/dist/types/core/utils/promise-to-result.d.ts +0 -2
  77. package/dist/types/core/utils/promise-to-result.d.ts.map +0 -1
  78. package/dist/types/core/utils/typed-array.d.ts +0 -6
  79. package/dist/types/core/utils/typed-array.d.ts.map +0 -1
  80. package/dist/types/core/utils/valid-properties.d.ts +0 -3
  81. package/dist/types/core/utils/valid-properties.d.ts.map +0 -1
  82. package/dist/types/index.d.ts +0 -18
  83. package/dist/types/index.d.ts.map +0 -1
  84. package/src/core/Serializer.ts +0 -119
  85. package/src/core/base-primitives.ts +0 -537
  86. package/src/core/compat.ts +0 -23
  87. package/src/core/constants.ts +0 -202
  88. package/src/core/constructors.ts +0 -265
  89. package/src/core/context/async-parser.ts +0 -666
  90. package/src/core/context/deserializer.ts +0 -832
  91. package/src/core/context/parser.ts +0 -335
  92. package/src/core/context/serializer.ts +0 -1524
  93. package/src/core/context/sync-parser.ts +0 -943
  94. package/src/core/cross/index.ts +0 -190
  95. package/src/core/errors.ts +0 -196
  96. package/src/core/function-string.ts +0 -31
  97. package/src/core/keys.ts +0 -17
  98. package/src/core/literals.ts +0 -43
  99. package/src/core/node.ts +0 -40
  100. package/src/core/opaque-reference.ts +0 -9
  101. package/src/core/plugin.ts +0 -105
  102. package/src/core/reference.ts +0 -66
  103. package/src/core/sequence.ts +0 -59
  104. package/src/core/special-reference.ts +0 -42
  105. package/src/core/stream.ts +0 -71
  106. package/src/core/string.ts +0 -86
  107. package/src/core/symbols.ts +0 -20
  108. package/src/core/tree/index.ts +0 -134
  109. package/src/core/types.ts +0 -377
  110. package/src/core/utils/error.ts +0 -73
  111. package/src/core/utils/get-identifier.ts +0 -18
  112. package/src/core/utils/get-object-flag.ts +0 -14
  113. package/src/core/utils/is-valid-identifier.ts +0 -12
  114. package/src/core/utils/promise-to-result.ts +0 -9
  115. package/src/core/utils/typed-array.ts +0 -56
  116. package/src/core/utils/valid-properties.ts +0 -34
  117. 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
- }