seroval 1.3.2 → 1.4.1

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