seroval 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -27,23 +27,99 @@ __export(src_exports, {
27
27
  });
28
28
  module.exports = __toCommonJS(src_exports);
29
29
 
30
- // src/array.ts
31
- function forEach(arr, callback) {
32
- for (let i = 0, len = arr.length; i < len; i++) {
33
- if (callback(arr[i], i)) {
34
- break;
35
- }
30
+ // src/checks.ts
31
+ function isPrimitive(current) {
32
+ if (!current || current === true) {
33
+ return true;
36
34
  }
35
+ const type = typeof current;
36
+ return type === "number" || type === "string" || type === "bigint";
37
37
  }
38
- function join(arr, joiner) {
38
+ function isPromise(obj) {
39
+ return !!obj && (typeof obj === "object" || typeof obj === "function") && "then" in obj && typeof obj.then === "function";
40
+ }
41
+ function constructorCheck(value, constructor) {
42
+ return value.constructor === constructor;
43
+ }
44
+ function isIterableBuiltin(obj) {
45
+ return Array.isArray(obj) || constructorCheck(obj, Set) || constructorCheck(obj, Map);
46
+ }
47
+ function isIterable(obj) {
48
+ return !!obj && typeof obj === "object" && !isIterableBuiltin(obj) && Symbol.iterator in obj && typeof obj[Symbol.iterator] === "function";
49
+ }
50
+
51
+ // src/quote.ts
52
+ function quote(str) {
39
53
  let result = "";
40
- forEach(arr, (value, index) => {
41
- result += value;
42
- if (index < arr.length - 1) {
43
- result += joiner;
54
+ let lastPos = 0;
55
+ for (let i = 0, len = str.length; i < len; i++) {
56
+ let replacement;
57
+ switch (str[i]) {
58
+ case '"':
59
+ replacement = '\\"';
60
+ break;
61
+ case "\\":
62
+ replacement = "\\\\";
63
+ break;
64
+ case "<":
65
+ replacement = "\\x3C";
66
+ break;
67
+ case "\n":
68
+ replacement = "\\n";
69
+ break;
70
+ case "\r":
71
+ replacement = "\\r";
72
+ break;
73
+ case "\u2028":
74
+ replacement = "\\u2028";
75
+ break;
76
+ case "\u2029":
77
+ replacement = "\\u2029";
78
+ break;
79
+ default:
80
+ continue;
44
81
  }
45
- });
46
- return result;
82
+ result += str.slice(lastPos, i) + replacement;
83
+ lastPos = i + 1;
84
+ }
85
+ if (lastPos === 0) {
86
+ result = str;
87
+ } else {
88
+ result += str.slice(lastPos);
89
+ }
90
+ return `"${result}"`;
91
+ }
92
+
93
+ // src/serialize-primitive.ts
94
+ function serializePrimitive(value) {
95
+ if (value === true) {
96
+ return "!0";
97
+ }
98
+ if (value === false) {
99
+ return "!1";
100
+ }
101
+ if (value === void 0) {
102
+ return "void 0";
103
+ }
104
+ if (value === null) {
105
+ return "null";
106
+ }
107
+ if (typeof value === "bigint") {
108
+ return `${value}n`;
109
+ }
110
+ if (typeof value === "string") {
111
+ return quote(value);
112
+ }
113
+ if (Object.is(value, -0)) {
114
+ return "-0";
115
+ }
116
+ if (Object.is(value, Infinity)) {
117
+ return "1/0";
118
+ }
119
+ if (Object.is(value, -Infinity)) {
120
+ return "-1/0";
121
+ }
122
+ return String(value);
47
123
  }
48
124
 
49
125
  // src/get-identifier.ts
@@ -63,533 +139,664 @@ function getIdentifier(index) {
63
139
  return ref;
64
140
  }
65
141
 
66
- // src/context.ts
67
- var EMPTY_SET = "new Set";
68
- var EMPTY_MAP = "new Map";
69
- var EMPTY_ARRAY = "[]";
142
+ // src/tree.ts
70
143
  function createSerializationContext() {
71
144
  return {
72
- refCount: /* @__PURE__ */ new Map(),
73
- stack: /* @__PURE__ */ new Set(),
145
+ markedRefs: [],
146
+ stack: [],
74
147
  refs: /* @__PURE__ */ new Map(),
75
- assignedRefs: /* @__PURE__ */ new Set(),
76
148
  vars: [],
77
149
  assignments: [],
78
- mapSets: [],
79
- setAdds: []
150
+ validRefs: /* @__PURE__ */ new Map()
80
151
  };
81
152
  }
82
- function resolveAssignments(ctx) {
83
- if (ctx.assignments.length) {
84
- const result = {};
85
- forEach(ctx.assignments, ([source, value]) => {
86
- if (value in result) {
87
- result[value] = `${source}=${result[value]}`;
88
- } else {
89
- result[value] = `${source}=${value}`;
90
- }
91
- });
92
- return `${join(Object.values(result), ",")},`;
153
+ function getAssignmentExpression(assignment) {
154
+ switch (assignment.type) {
155
+ case "index":
156
+ return `${assignment.source}=${assignment.value}`;
157
+ case "map":
158
+ return `${assignment.source}.set(${assignment.key},${assignment.value})`;
159
+ case "set":
160
+ return `${assignment.source}.add(${assignment.value})`;
161
+ default:
162
+ return "";
93
163
  }
94
- return "";
95
164
  }
96
- function resolveMapSets(ctx) {
97
- if (ctx.mapSets.length) {
98
- const result = {};
99
- forEach(ctx.mapSets, ([source, key, value]) => {
100
- if (source in result) {
101
- result[source] = `${result[source]}.set(${key},${value})`;
165
+ function mergeAssignments(ctx) {
166
+ const newAssignments = [];
167
+ let current = ctx.assignments[0];
168
+ let prev = current;
169
+ for (let i = 1, len = ctx.assignments.length; i < len; i += 1) {
170
+ const item = ctx.assignments[i];
171
+ if (item.type === prev.type) {
172
+ if (item.type === "index" && item.value === prev.value) {
173
+ current = {
174
+ type: "index",
175
+ source: item.source,
176
+ value: getAssignmentExpression(current)
177
+ };
178
+ } else if (item.type === "map" && item.source === prev.source) {
179
+ current = {
180
+ type: "map",
181
+ source: getAssignmentExpression(current),
182
+ key: item.key,
183
+ value: item.value
184
+ };
185
+ } else if (item.type === "set" && item.source === prev.source) {
186
+ current = {
187
+ type: "set",
188
+ source: getAssignmentExpression(current),
189
+ value: item.value
190
+ };
102
191
  } else {
103
- result[source] = `${source}.set(${key},${value})`;
192
+ newAssignments.push(current);
193
+ current = item;
104
194
  }
105
- });
106
- return `${join(Object.values(result), ",")},`;
195
+ } else {
196
+ newAssignments.push(current);
197
+ current = item;
198
+ }
199
+ prev = item;
107
200
  }
108
- return "";
201
+ newAssignments.push(current);
202
+ return newAssignments;
109
203
  }
110
- function resolveSetAdds(ctx) {
111
- if (ctx.setAdds.length) {
112
- const result = {};
113
- forEach(ctx.setAdds, ([source, value]) => {
114
- if (source in result) {
115
- result[source] = `${result[source]}.add(${value})`;
116
- } else {
117
- result[source] = `${source}.add(${value})`;
118
- }
119
- });
120
- return `${join(Object.values(result), ",")},`;
204
+ function resolvePatches(ctx) {
205
+ if (ctx.assignments.length) {
206
+ let result = "";
207
+ for (const assignment of mergeAssignments(ctx)) {
208
+ result += `${getAssignmentExpression(assignment)},`;
209
+ }
210
+ return result;
121
211
  }
122
212
  return "";
123
213
  }
124
- function resolvePatches(ctx) {
125
- return `${resolveAssignments(ctx)}${resolveMapSets(ctx)}${resolveSetAdds(ctx)}`;
126
- }
127
- function insertRef(ctx, current) {
128
- const count = ctx.refCount.get(current) || 0;
129
- ctx.refCount.set(current, count + 1);
130
- return count === 0;
131
- }
132
- function constructorCheck(value, constructor) {
133
- return value.constructor === constructor;
214
+ function markRef(ctx, current) {
215
+ ctx.markedRefs[current] = true;
134
216
  }
135
- function createRef(ctx, value) {
136
- const current = ctx.refs.get(value);
217
+ function createRef(ctx, index) {
218
+ const current = ctx.refs.get(index);
137
219
  if (current != null) {
138
220
  return current;
139
221
  }
140
222
  const id = ctx.refs.size;
141
- ctx.refs.set(value, id);
223
+ ctx.refs.set(index, id);
224
+ return id;
225
+ }
226
+ function createValidRef(ctx, index) {
227
+ const current = ctx.validRefs.get(index);
228
+ if (current != null) {
229
+ return current;
230
+ }
231
+ const id = ctx.validRefs.size;
232
+ ctx.validRefs.set(index, id);
142
233
  return id;
143
234
  }
144
235
  function getRefParam(ctx, index) {
145
- if (ctx.vars[index]) {
146
- return ctx.vars[index];
236
+ const actualIndex = createValidRef(ctx, index);
237
+ if (ctx.vars[actualIndex]) {
238
+ return ctx.vars[actualIndex];
147
239
  }
148
- const result = getIdentifier(index);
149
- ctx.vars[index] = result;
240
+ const result = getIdentifier(actualIndex);
241
+ ctx.vars[actualIndex] = result;
150
242
  return result;
151
243
  }
152
244
  function assignRef(ctx, index, value) {
153
- return `${getRefParam(ctx, index)}=${value}`;
245
+ if (ctx.markedRefs[index]) {
246
+ return `${getRefParam(ctx, index)}=${value}`;
247
+ }
248
+ return value;
154
249
  }
155
250
  function createAssignment(ctx, source, value) {
156
- ctx.assignments.push([source, value]);
251
+ ctx.assignments.push({
252
+ type: "index",
253
+ source,
254
+ value
255
+ });
157
256
  }
158
257
  function createSetAdd(ctx, ref, value) {
159
- ctx.setAdds.push([getRefParam(ctx, ref), value]);
258
+ markRef(ctx, ref);
259
+ ctx.assignments.push({
260
+ type: "set",
261
+ source: getRefParam(ctx, ref),
262
+ value
263
+ });
160
264
  }
161
265
  function createMapSet(ctx, ref, key, value) {
162
- ctx.mapSets.push([getRefParam(ctx, ref), key, value]);
266
+ markRef(ctx, ref);
267
+ ctx.assignments.push({
268
+ type: "map",
269
+ source: getRefParam(ctx, ref),
270
+ key,
271
+ value
272
+ });
163
273
  }
164
274
  function createArrayAssign(ctx, ref, index, value) {
275
+ markRef(ctx, ref);
165
276
  createAssignment(ctx, `${getRefParam(ctx, ref)}[${index}]`, value);
166
277
  }
167
278
  function createObjectIdentifierAssign(ctx, ref, key, value) {
279
+ markRef(ctx, ref);
168
280
  createAssignment(ctx, `${getRefParam(ctx, ref)}.${key}`, value);
169
281
  }
170
282
  function createObjectComputedAssign(ctx, ref, key, value) {
283
+ markRef(ctx, ref);
171
284
  createAssignment(ctx, `${getRefParam(ctx, ref)}[${key}]`, value);
172
285
  }
173
-
174
- // src/is-primitive.ts
175
- function isPrimitive(current) {
176
- if (!current || current === true) {
177
- return true;
286
+ function getErrorConstructor(error) {
287
+ if (error instanceof EvalError) {
288
+ return "EvalError";
178
289
  }
179
- const type = typeof current;
180
- const classConst = current.constructor;
181
- return type === "number" || type === "string" || type === "bigint" || classConst === Date || classConst === RegExp;
290
+ if (error instanceof RangeError) {
291
+ return "RangeError";
292
+ }
293
+ if (error instanceof ReferenceError) {
294
+ return "ReferenceError";
295
+ }
296
+ if (error instanceof SyntaxError) {
297
+ return "SyntaxError";
298
+ }
299
+ if (error instanceof TypeError) {
300
+ return "TypeError";
301
+ }
302
+ if (error instanceof URIError) {
303
+ return "URIError";
304
+ }
305
+ return "Error";
182
306
  }
183
-
184
- // src/is-promise.ts
185
- function isPromise(obj) {
186
- return !!obj && (typeof obj === "object" || typeof obj === "function") && "then" in obj && typeof obj.then === "function";
307
+ var EXCLUDED_ERROR_KEYS = {
308
+ name: true,
309
+ cause: true,
310
+ stack: true,
311
+ message: true
312
+ };
313
+ function getErrorOptions(error) {
314
+ let options;
315
+ const constructor = getErrorConstructor(error);
316
+ if (error.name !== constructor) {
317
+ options = { name: error.name };
318
+ } else if (error.constructor.name !== constructor) {
319
+ options = { name: error.constructor.name };
320
+ }
321
+ const names = Object.getOwnPropertyNames(error);
322
+ for (const name of names) {
323
+ if (!(name in EXCLUDED_ERROR_KEYS)) {
324
+ options = options || {};
325
+ options[name] = error[name];
326
+ }
327
+ }
328
+ return options;
187
329
  }
188
-
189
- // src/quote.ts
190
- function quote(str) {
191
- let result = "";
192
- let lastPos = 0;
193
- for (let i = 0, len = str.length; i < len; i++) {
194
- let replacement;
195
- switch (str[i]) {
196
- case '"':
197
- replacement = '\\"';
198
- break;
199
- case "\\":
200
- replacement = "\\\\";
201
- break;
202
- case "<":
203
- replacement = "\\x3C";
204
- break;
205
- case "\n":
206
- replacement = "\\n";
207
- break;
208
- case "\r":
209
- replacement = "\\r";
210
- break;
211
- case "\u2028":
212
- replacement = "\\u2028";
213
- break;
214
- case "\u2029":
215
- replacement = "\\u2029";
216
- break;
217
- default:
218
- continue;
330
+ function getIterableOptions(obj) {
331
+ const names = Object.getOwnPropertyNames(obj);
332
+ if (names.length) {
333
+ const options = {};
334
+ for (const name of names) {
335
+ options[name] = obj[name];
219
336
  }
220
- result += str.slice(lastPos, i) + replacement;
221
- lastPos = i + 1;
337
+ return options;
222
338
  }
223
- if (lastPos === 0) {
224
- result = str;
225
- } else {
226
- result += str.slice(lastPos);
339
+ return void 0;
340
+ }
341
+ function isReferenceInStack(ctx, node) {
342
+ return node[0] === 1 /* Reference */ && ctx.stack.includes(node[1]);
343
+ }
344
+ function generateRef(ctx, current) {
345
+ const ref = ctx.refs.has(current);
346
+ if (ref) {
347
+ const refID = ctx.refs.get(current) || 0;
348
+ markRef(ctx, refID);
349
+ return [1 /* Reference */, refID];
227
350
  }
228
- return `"${result}"`;
351
+ const id = ctx.refs.size;
352
+ ctx.refs.set(current, id);
353
+ return id;
229
354
  }
230
-
231
- // src/serialize-primitive.ts
232
- function serializePrimitive(value) {
233
- if (value === true) {
234
- return "!0";
355
+ function generateSemiPrimitiveValue(current, id) {
356
+ if (constructorCheck(current, Date)) {
357
+ return [2 /* Date */, current, id];
235
358
  }
236
- if (value === false) {
237
- return "!1";
359
+ if (constructorCheck(current, RegExp)) {
360
+ return [3 /* RegExp */, current, id];
238
361
  }
239
- if (value === void 0) {
240
- return "void 0";
362
+ if (constructorCheck(current, Int8Array)) {
363
+ return [13 /* TypedArray */, { constructor: "Int8Array", array: current }, id];
241
364
  }
242
- if (value === null) {
243
- return "null";
365
+ if (constructorCheck(current, Int16Array)) {
366
+ return [13 /* TypedArray */, { constructor: "Int16Array", array: current }, id];
244
367
  }
245
- if (Object.is(value, -0)) {
246
- return "-0";
368
+ if (constructorCheck(current, Int32Array)) {
369
+ return [13 /* TypedArray */, { constructor: "Int32Array", array: current }, id];
247
370
  }
248
- if (typeof value === "bigint") {
249
- return `BigInt("${value}")`;
371
+ if (constructorCheck(current, Uint8Array)) {
372
+ return [13 /* TypedArray */, { constructor: "Uint8Array", array: current }, id];
250
373
  }
251
- if (typeof value === "string") {
252
- return quote(value);
374
+ if (constructorCheck(current, Uint16Array)) {
375
+ return [13 /* TypedArray */, { constructor: "Uint16Array", array: current }, id];
253
376
  }
254
- if (value.constructor === Date) {
255
- return `new Date("${value.toISOString()}")`;
377
+ if (constructorCheck(current, Uint32Array)) {
378
+ return [13 /* TypedArray */, { constructor: "Uint32Array", array: current }, id];
256
379
  }
257
- return String(value);
380
+ if (constructorCheck(current, Uint8ClampedArray)) {
381
+ return [13 /* TypedArray */, { constructor: "Uint8ClampedArray", array: current }, id];
382
+ }
383
+ if (constructorCheck(current, Float32Array)) {
384
+ return [13 /* TypedArray */, { constructor: "Float32Array", array: current }, id];
385
+ }
386
+ if (constructorCheck(current, Float64Array)) {
387
+ return [13 /* TypedArray */, { constructor: "Float64Array", array: current }, id];
388
+ }
389
+ if (constructorCheck(current, BigInt64Array)) {
390
+ return [13 /* TypedArray */, { constructor: "BigInt64Array", array: current }, id];
391
+ }
392
+ if (constructorCheck(current, BigUint64Array)) {
393
+ return [13 /* TypedArray */, { constructor: "BigUint64Array", array: current }, id];
394
+ }
395
+ return void 0;
258
396
  }
259
-
260
- // src/async.ts
261
- async function lookupRefsAsync(ctx, current) {
397
+ function generateTreeSync(ctx, current) {
262
398
  if (isPrimitive(current)) {
263
- return;
399
+ return [0 /* Primitive */, current];
264
400
  }
265
- if (isPromise(current)) {
266
- if (insertRef(ctx, current)) {
267
- await current.then((value) => lookupRefsAsync(ctx, value));
401
+ const id = generateRef(ctx, current);
402
+ if (Array.isArray(id)) {
403
+ return id;
404
+ }
405
+ const semiPrimitive = generateSemiPrimitiveValue(current, id);
406
+ if (semiPrimitive) {
407
+ return semiPrimitive;
408
+ }
409
+ if (constructorCheck(current, Set)) {
410
+ const nodes = [];
411
+ const deferred = [];
412
+ for (const item of current.keys()) {
413
+ if (isIterable(item)) {
414
+ deferred.push(item);
415
+ } else {
416
+ nodes.push(generateTreeSync(ctx, item));
417
+ }
418
+ }
419
+ for (const item of deferred) {
420
+ nodes.push(generateTreeSync(ctx, item));
268
421
  }
269
- } else if (Array.isArray(current)) {
270
- if (insertRef(ctx, current)) {
271
- for (const value of current) {
272
- await lookupRefsAsync(ctx, value);
422
+ return [4 /* Set */, nodes, id];
423
+ }
424
+ if (constructorCheck(current, Map)) {
425
+ const nodes = [];
426
+ const deferred = [];
427
+ for (const [key, value] of current.entries()) {
428
+ if (isIterable(key) || isIterable(value)) {
429
+ deferred.push([key, value]);
430
+ } else {
431
+ const keyNode = generateTreeSync(ctx, key);
432
+ const valueNode = generateTreeSync(ctx, value);
433
+ nodes.push([keyNode, valueNode]);
273
434
  }
274
435
  }
275
- } else if (constructorCheck(current, Set)) {
276
- if (insertRef(ctx, current)) {
277
- for (const item of current.keys()) {
278
- await lookupRefsAsync(ctx, item);
436
+ for (const [key, value] of deferred) {
437
+ const keyNode = generateTreeSync(ctx, key);
438
+ const valueNode = generateTreeSync(ctx, value);
439
+ nodes.push([keyNode, valueNode]);
440
+ }
441
+ return [5 /* Map */, nodes, id];
442
+ }
443
+ if (Array.isArray(current)) {
444
+ const nodes = new Array(current.length);
445
+ const deferred = new Array(current.length);
446
+ for (const key in current) {
447
+ const item = current[key];
448
+ if (isIterable(item)) {
449
+ deferred[key] = item;
450
+ } else {
451
+ nodes[key] = generateTreeSync(ctx, item);
279
452
  }
280
453
  }
281
- } else if (constructorCheck(current, Map)) {
282
- if (insertRef(ctx, current)) {
283
- for (const [key, value] of current.entries()) {
284
- await lookupRefsAsync(ctx, key);
285
- await lookupRefsAsync(ctx, value);
454
+ for (const key in deferred) {
455
+ nodes[key] = generateTreeSync(ctx, deferred[key]);
456
+ }
457
+ return [6 /* Array */, nodes, id];
458
+ }
459
+ if (current instanceof AggregateError) {
460
+ const options = getErrorOptions(current);
461
+ return [11 /* AggregateError */, {
462
+ message: current.message,
463
+ options: options ? generateTreeSync(ctx, options) : void 0,
464
+ cause: "cause" in current ? generateTreeSync(ctx, { cause: current.cause }) : void 0,
465
+ errors: generateTreeSync(ctx, current.errors)
466
+ }, id];
467
+ }
468
+ if (current instanceof Error) {
469
+ const options = getErrorOptions(current);
470
+ return [10 /* Error */, {
471
+ constructor: getErrorConstructor(current),
472
+ message: current.message,
473
+ options: options ? generateTreeSync(ctx, options) : void 0,
474
+ cause: "cause" in current ? generateTreeSync(ctx, { cause: current.cause }) : void 0
475
+ }, id];
476
+ }
477
+ if (isIterable(current)) {
478
+ const options = getIterableOptions(current);
479
+ return [12 /* Iterable */, {
480
+ // Parse options first before the items
481
+ options: options ? generateTreeSync(ctx, options) : void 0,
482
+ items: generateTreeSync(ctx, Array.from(current))
483
+ }, id];
484
+ }
485
+ const empty = current.constructor == null;
486
+ if (current.constructor === Object || empty) {
487
+ const nodes = {};
488
+ const deferred = {};
489
+ for (const [key, item] of Object.entries(current)) {
490
+ if (isIterable(item)) {
491
+ deferred[key] = item;
492
+ } else {
493
+ nodes[key] = generateTreeSync(ctx, item);
286
494
  }
287
495
  }
288
- } else if ((current.constructor === Object || current.constructor == null) && insertRef(ctx, current)) {
289
- for (const value of Object.values(current)) {
290
- await lookupRefsAsync(ctx, value);
496
+ for (const [key, item] of Object.entries(deferred)) {
497
+ nodes[key] = generateTreeSync(ctx, item);
291
498
  }
499
+ return [
500
+ empty ? 8 /* NullConstructor */ : 7 /* Object */,
501
+ nodes,
502
+ id
503
+ ];
292
504
  }
505
+ throw new Error("Unsupported value");
293
506
  }
294
- async function traverseAsync(ctx, current) {
507
+ async function generateTreeAsync(ctx, current) {
295
508
  if (isPrimitive(current)) {
296
- return serializePrimitive(current);
509
+ return [0 /* Primitive */, current];
297
510
  }
298
- let refResult = ctx.refs.get(current);
299
- if (refResult != null) {
300
- if (ctx.assignedRefs.has(refResult)) {
301
- return getRefParam(ctx, refResult);
302
- }
303
- ctx.assignedRefs.add(refResult);
304
- }
305
- function getCurrentRef() {
306
- if (refResult == null) {
307
- refResult = createRef(ctx, current);
308
- }
309
- return refResult;
511
+ const id = generateRef(ctx, current);
512
+ if (Array.isArray(id)) {
513
+ return id;
310
514
  }
311
- function processRef(value) {
312
- if (refResult != null) {
313
- return assignRef(ctx, refResult, value);
314
- }
315
- return value;
515
+ const semiPrimitive = generateSemiPrimitiveValue(current, id);
516
+ if (semiPrimitive) {
517
+ return semiPrimitive;
316
518
  }
317
519
  if (isPromise(current)) {
318
- return current.then(async (value) => {
319
- ctx.stack.add(current);
320
- let result;
321
- if (ctx.stack.has(value)) {
322
- const refParam = getRefParam(ctx, createRef(ctx, value));
323
- result = `Promise.resolve().then(()=>${refParam})`;
324
- } else {
325
- result = `Promise.resolve(${await traverseAsync(ctx, value)})`;
326
- }
327
- ctx.stack.delete(current);
328
- return processRef(result);
329
- });
520
+ return current.then(async (value) => [
521
+ 9 /* Promise */,
522
+ await generateTreeAsync(ctx, value),
523
+ id
524
+ ]);
330
525
  }
331
526
  if (constructorCheck(current, Set)) {
332
- if (current.size) {
333
- const values = [];
334
- ctx.stack.add(current);
335
- for (const value of current.keys()) {
336
- if (ctx.stack.has(value)) {
337
- createSetAdd(ctx, getCurrentRef(), getRefParam(ctx, createRef(ctx, value)));
338
- } else {
339
- values.push(await traverseAsync(ctx, value));
340
- }
527
+ const nodes = [];
528
+ const deferred = [];
529
+ for (const item of current.keys()) {
530
+ if (isIterable(item)) {
531
+ deferred.push(item);
532
+ } else {
533
+ nodes.push(await generateTreeAsync(ctx, item));
341
534
  }
342
- ctx.stack.delete(current);
343
- return processRef(values.length ? `new Set([${join(values, ",")}])` : EMPTY_SET);
344
535
  }
345
- return EMPTY_SET;
536
+ for (const item of deferred) {
537
+ nodes.push(await generateTreeAsync(ctx, item));
538
+ }
539
+ return [4 /* Set */, nodes, id];
346
540
  }
347
541
  if (constructorCheck(current, Map)) {
348
- if (current.size) {
349
- const values = [];
350
- ctx.stack.add(current);
351
- for (const [key, value] of current.entries()) {
352
- if (ctx.stack.has(key)) {
353
- const ref = getCurrentRef();
354
- const keyRef = getRefParam(ctx, createRef(ctx, key));
355
- if (ctx.stack.has(value)) {
356
- const valueRef = getRefParam(ctx, createRef(ctx, value));
357
- createMapSet(ctx, ref, keyRef, valueRef);
358
- } else {
359
- const valueResult = await traverseAsync(ctx, value);
360
- createMapSet(ctx, ref, keyRef, valueResult);
361
- }
362
- } else if (ctx.stack.has(value)) {
363
- const valueRef = getRefParam(ctx, createRef(ctx, value));
364
- const keyResult = await traverseAsync(ctx, key);
365
- createMapSet(ctx, getCurrentRef(), keyResult, valueRef);
366
- } else {
367
- const keyResult = await traverseAsync(ctx, key);
368
- const valueResult = await traverseAsync(ctx, value);
369
- values.push(`[${keyResult},${valueResult}]`);
370
- }
542
+ const nodes = [];
543
+ const deferred = [];
544
+ for (const [key, value] of current.entries()) {
545
+ if (isIterable(key) || isIterable(value)) {
546
+ deferred.push([key, value]);
547
+ } else {
548
+ const keyNode = await generateTreeAsync(ctx, key);
549
+ const valueNode = await generateTreeAsync(ctx, value);
550
+ nodes.push([keyNode, valueNode]);
371
551
  }
372
- ctx.stack.delete(current);
373
- return processRef(values.length ? `new Map([${join(values, ",")}])` : EMPTY_MAP);
374
552
  }
375
- return EMPTY_MAP;
553
+ for (const [key, value] of deferred) {
554
+ const keyNode = await generateTreeAsync(ctx, key);
555
+ const valueNode = await generateTreeAsync(ctx, value);
556
+ nodes.push([keyNode, valueNode]);
557
+ }
558
+ return [5 /* Map */, nodes, id];
376
559
  }
377
560
  if (Array.isArray(current)) {
378
- if (current.length) {
379
- let values = "";
380
- ctx.stack.add(current);
381
- for (let i = 0, len = current.length; i < len; i += 1) {
382
- if (i in current) {
383
- const item = current[i];
384
- if (ctx.stack.has(item)) {
385
- const refParam = getRefParam(ctx, createRef(ctx, item));
386
- createArrayAssign(ctx, getCurrentRef(), i, refParam);
387
- values += ",";
388
- } else {
389
- values += await traverseAsync(ctx, item);
390
- if (i < current.length - 1) {
391
- values += ",";
392
- }
393
- }
394
- } else {
395
- values += ",";
396
- }
561
+ const nodes = new Array(current.length);
562
+ const deferred = new Array(current.length);
563
+ for (const key in current) {
564
+ const item = current[key];
565
+ if (isIterable(item)) {
566
+ deferred[key] = item;
567
+ } else {
568
+ nodes[key] = await generateTreeAsync(ctx, item);
397
569
  }
398
- ctx.stack.delete(current);
399
- return processRef(`[${values}]`);
400
570
  }
401
- return EMPTY_ARRAY;
571
+ for (const key in deferred) {
572
+ nodes[key] = await generateTreeAsync(ctx, deferred[key]);
573
+ }
574
+ return [6 /* Array */, nodes, id];
575
+ }
576
+ if (current instanceof AggregateError) {
577
+ const options = getErrorOptions(current);
578
+ return [11 /* AggregateError */, {
579
+ message: current.message,
580
+ options: options ? generateTreeSync(ctx, options) : void 0,
581
+ cause: "cause" in current ? await generateTreeAsync(ctx, { cause: current.cause }) : void 0,
582
+ errors: await generateTreeAsync(ctx, current.errors)
583
+ }, id];
584
+ }
585
+ if (current instanceof Error) {
586
+ const options = getErrorOptions(current);
587
+ return [10 /* Error */, {
588
+ constructor: getErrorConstructor(current),
589
+ message: current.message,
590
+ options: options ? await generateTreeAsync(ctx, options) : void 0,
591
+ cause: "cause" in current ? await generateTreeAsync(ctx, { cause: current.cause }) : void 0
592
+ }, id];
593
+ }
594
+ if (isIterable(current)) {
595
+ const options = getIterableOptions(current);
596
+ return [12 /* Iterable */, {
597
+ options: options ? await generateTreeAsync(ctx, options) : void 0,
598
+ items: await generateTreeAsync(ctx, Array.from(current))
599
+ }, id];
402
600
  }
403
601
  const empty = current.constructor == null;
404
602
  if (current.constructor === Object || empty) {
405
- const values = [];
406
- ctx.stack.add(current);
407
- for (const [key, value2] of Object.entries(current)) {
408
- const check = Number(key);
409
- if (check >= 0 || Number.isNaN(check) && /^([$A-Z_][0-9A-Z_$]*)$/i.test(key)) {
410
- if (ctx.stack.has(value2)) {
411
- const ref = getCurrentRef();
412
- const refParam = getRefParam(ctx, createRef(ctx, value2));
413
- if (Number.isNaN(check)) {
414
- createObjectIdentifierAssign(ctx, ref, key, refParam);
415
- } else {
416
- createObjectComputedAssign(ctx, ref, key, refParam);
417
- }
418
- } else {
419
- const valueResult = await traverseAsync(ctx, value2);
420
- values.push(`${key}:${valueResult}`);
421
- }
422
- } else if (ctx.stack.has(value2)) {
423
- const refParam = getRefParam(ctx, createRef(ctx, value2));
424
- createObjectComputedAssign(ctx, getCurrentRef(), quote(key), refParam);
603
+ const nodes = {};
604
+ const deferred = {};
605
+ for (const [key, item] of Object.entries(current)) {
606
+ if (isIterable(item)) {
607
+ deferred[key] = item;
425
608
  } else {
426
- const valueResult = await traverseAsync(ctx, value2);
427
- values.push(`${quote(key)}:${valueResult}`);
609
+ nodes[key] = await generateTreeAsync(ctx, item);
428
610
  }
429
611
  }
430
- ctx.stack.delete(current);
431
- const value = `{${join(values, ",")}}`;
432
- if (empty) {
433
- return processRef(`Object.assign(Object.create(null),${value})`);
612
+ for (const [key, item] of Object.entries(deferred)) {
613
+ nodes[key] = await generateTreeAsync(ctx, item);
434
614
  }
435
- return processRef(value);
615
+ return [
616
+ empty ? 8 /* NullConstructor */ : 7 /* Object */,
617
+ nodes,
618
+ id
619
+ ];
436
620
  }
437
- throw new Error("Unserializable value");
621
+ throw new Error("Unsupported value");
438
622
  }
439
-
440
- // src/sync.ts
441
- function lookupRefs(ctx, current) {
442
- if (isPrimitive(current)) {
443
- return;
444
- }
445
- if (Array.isArray(current)) {
446
- if (insertRef(ctx, current)) {
447
- forEach(current, (value) => {
448
- lookupRefs(ctx, value);
449
- });
450
- }
451
- } else if (constructorCheck(current, Set)) {
452
- if (insertRef(ctx, current)) {
453
- for (const item of current.keys()) {
454
- lookupRefs(ctx, item);
623
+ function serializeTree(ctx, [type, value, id]) {
624
+ switch (type) {
625
+ case 0 /* Primitive */:
626
+ return serializePrimitive(value);
627
+ case 1 /* Reference */:
628
+ return getRefParam(ctx, value);
629
+ case 9 /* Promise */: {
630
+ let serialized;
631
+ if (isReferenceInStack(ctx, value)) {
632
+ serialized = `Promise.resolve().then(()=>${getRefParam(ctx, value[1])})`;
633
+ } else {
634
+ ctx.stack.push(id);
635
+ const result = serializeTree(ctx, value);
636
+ ctx.stack.pop();
637
+ serialized = `Promise.resolve(${result})`;
455
638
  }
639
+ return assignRef(ctx, id, serialized);
456
640
  }
457
- } else if (constructorCheck(current, Map)) {
458
- if (insertRef(ctx, current)) {
459
- for (const [key, value] of current.entries()) {
460
- lookupRefs(ctx, key);
461
- lookupRefs(ctx, value);
641
+ case 2 /* Date */:
642
+ return assignRef(ctx, id, `new Date("${value.toISOString()}")`);
643
+ case 3 /* RegExp */:
644
+ return assignRef(ctx, id, String(value));
645
+ case 13 /* TypedArray */: {
646
+ const values = [...value.array].map(serializePrimitive).join(",");
647
+ let args = `[${values}]`;
648
+ if (value.array.byteOffset !== 0) {
649
+ args += `,${value.array.byteOffset}`;
462
650
  }
651
+ return assignRef(ctx, id, `new ${value.constructor}(${args})`);
463
652
  }
464
- } else if ((current.constructor === Object || current.constructor == null) && insertRef(ctx, current)) {
465
- forEach(Object.values(current), (value) => {
466
- lookupRefs(ctx, value);
467
- });
468
- }
469
- }
470
- function traverseSync(ctx, current) {
471
- if (isPrimitive(current)) {
472
- return serializePrimitive(current);
473
- }
474
- let refResult = ctx.refs.get(current);
475
- if (refResult != null) {
476
- if (ctx.assignedRefs.has(refResult)) {
477
- return getRefParam(ctx, refResult);
478
- }
479
- ctx.assignedRefs.add(refResult);
480
- }
481
- function getCurrentRef() {
482
- if (refResult == null) {
483
- refResult = createRef(ctx, current);
484
- }
485
- return refResult;
486
- }
487
- function processRef(value) {
488
- if (refResult != null) {
489
- return assignRef(ctx, refResult, value);
490
- }
491
- return value;
492
- }
493
- if (constructorCheck(current, Set)) {
494
- if (current.size) {
495
- const values = [];
496
- ctx.stack.add(current);
497
- for (const value of current.keys()) {
498
- if (ctx.stack.has(value)) {
499
- createSetAdd(ctx, getCurrentRef(), getRefParam(ctx, createRef(ctx, value)));
500
- } else {
501
- values.push(traverseSync(ctx, value));
653
+ case 4 /* Set */: {
654
+ let serialized = "new Set";
655
+ if (value.length) {
656
+ const values = [];
657
+ ctx.stack.push(id);
658
+ for (const item of value) {
659
+ if (isReferenceInStack(ctx, item)) {
660
+ createSetAdd(ctx, id, getRefParam(ctx, item[1]));
661
+ } else {
662
+ values.push(serializeTree(ctx, item));
663
+ }
664
+ }
665
+ ctx.stack.pop();
666
+ if (values.length) {
667
+ serialized += `([${values.join(",")}])`;
502
668
  }
503
669
  }
504
- ctx.stack.delete(current);
505
- return processRef(values.length ? `new Set([${join(values, ",")}])` : EMPTY_SET);
670
+ return assignRef(ctx, id, serialized);
506
671
  }
507
- return EMPTY_SET;
508
- }
509
- if (constructorCheck(current, Map)) {
510
- if (current.size) {
511
- const values = [];
512
- ctx.stack.add(current);
513
- for (const [key, value] of current.entries()) {
514
- if (ctx.stack.has(key)) {
515
- const ref = getCurrentRef();
516
- const keyRef = getRefParam(ctx, createRef(ctx, key));
517
- if (ctx.stack.has(value)) {
518
- const valueRef = getRefParam(ctx, createRef(ctx, value));
519
- createMapSet(ctx, ref, keyRef, valueRef);
672
+ case 5 /* Map */: {
673
+ let serialized = "new Map";
674
+ if (value.length) {
675
+ const values = [];
676
+ ctx.stack.push(id);
677
+ for (const [key, val] of value) {
678
+ if (isReferenceInStack(ctx, key)) {
679
+ const keyRef = getRefParam(ctx, key[1]);
680
+ if (isReferenceInStack(ctx, val)) {
681
+ const valueRef = getRefParam(ctx, val[1]);
682
+ createMapSet(ctx, id, keyRef, valueRef);
683
+ } else {
684
+ const parent = ctx.stack;
685
+ ctx.stack = [];
686
+ createMapSet(ctx, id, keyRef, serializeTree(ctx, val));
687
+ ctx.stack = parent;
688
+ }
689
+ } else if (isReferenceInStack(ctx, val)) {
690
+ const valueRef = getRefParam(ctx, val[1]);
691
+ const parent = ctx.stack;
692
+ ctx.stack = [];
693
+ createMapSet(ctx, id, serializeTree(ctx, key), valueRef);
694
+ ctx.stack = parent;
520
695
  } else {
521
- createMapSet(ctx, ref, keyRef, traverseSync(ctx, value));
696
+ values.push(`[${serializeTree(ctx, key)},${serializeTree(ctx, val)}]`);
522
697
  }
523
- } else if (ctx.stack.has(value)) {
524
- const valueRef = getRefParam(ctx, createRef(ctx, value));
525
- createMapSet(ctx, getCurrentRef(), traverseSync(ctx, key), valueRef);
526
- } else {
527
- values.push(`[${traverseSync(ctx, key)},${traverseSync(ctx, value)}]`);
698
+ }
699
+ ctx.stack.pop();
700
+ if (values.length) {
701
+ serialized += `([${values.join(",")}])`;
528
702
  }
529
703
  }
530
- ctx.stack.delete(current);
531
- return processRef(values.length ? `new Map([${join(values, ",")}])` : EMPTY_MAP);
704
+ return assignRef(ctx, id, serialized);
532
705
  }
533
- return EMPTY_MAP;
534
- }
535
- if (Array.isArray(current)) {
536
- if (current.length) {
706
+ case 6 /* Array */: {
537
707
  let values = "";
538
- ctx.stack.add(current);
539
- forEach(current, (item, i) => {
540
- if (i in current) {
541
- if (ctx.stack.has(item)) {
542
- const refParam = getRefParam(ctx, createRef(ctx, item));
543
- createArrayAssign(ctx, getCurrentRef(), i, refParam);
708
+ ctx.stack.push(id);
709
+ for (let i = 0, len = value.length; i < len; i++) {
710
+ const item = value[i];
711
+ if (i in value) {
712
+ if (isReferenceInStack(ctx, item)) {
713
+ createArrayAssign(ctx, id, i, getRefParam(ctx, item[1]));
544
714
  values += ",";
545
715
  } else {
546
- values += traverseSync(ctx, item);
547
- if (i < current.length - 1) {
716
+ values += serializeTree(ctx, item);
717
+ if (i < value.length - 1) {
548
718
  values += ",";
549
719
  }
550
720
  }
551
721
  } else {
552
722
  values += ",";
553
723
  }
554
- });
555
- ctx.stack.delete(current);
556
- return processRef(`[${values}]`);
724
+ }
725
+ ctx.stack.pop();
726
+ return assignRef(ctx, id, `[${values}]`);
557
727
  }
558
- return EMPTY_ARRAY;
559
- }
560
- const empty = current.constructor == null;
561
- if (current.constructor === Object || empty) {
562
- const values = [];
563
- ctx.stack.add(current);
564
- forEach(Object.entries(current), ([key, value2]) => {
565
- const check = Number(key);
566
- if (check >= 0 || Number.isNaN(check) && /^([$A-Z_][0-9A-Z_$]*)$/i.test(key)) {
567
- if (ctx.stack.has(value2)) {
568
- const ref = getCurrentRef();
569
- const refParam = getRefParam(ctx, createRef(ctx, value2));
570
- if (!Number.isNaN(check)) {
571
- createObjectComputedAssign(ctx, ref, key, refParam);
728
+ case 11 /* AggregateError */: {
729
+ const args = [serializeTree(ctx, value.errors), quote(value.message)];
730
+ if (value.cause) {
731
+ args.push(serializeTree(ctx, value.cause));
732
+ }
733
+ let serialized = `new AggregateError(${args.join(",")})`;
734
+ if (value.options) {
735
+ const options = serializeTree(ctx, value.options);
736
+ serialized = `Object.assign(${serialized},${options})`;
737
+ }
738
+ return assignRef(ctx, id, serialized);
739
+ }
740
+ case 10 /* Error */: {
741
+ const args = [quote(value.message)];
742
+ if (value.cause) {
743
+ args.push(serializeTree(ctx, value.cause));
744
+ }
745
+ let serialized = `new ${value.constructor}(${args.join(",")})`;
746
+ if (value.options) {
747
+ const options = serializeTree(ctx, value.options);
748
+ serialized = `Object.assign(${serialized},${options})`;
749
+ }
750
+ return assignRef(ctx, id, serialized);
751
+ }
752
+ case 12 /* Iterable */: {
753
+ const parent = ctx.stack;
754
+ ctx.stack = [];
755
+ const values = serializeTree(ctx, value.items);
756
+ ctx.stack = parent;
757
+ let serialized = `{[Symbol.iterator]:()=>${values}.values()}`;
758
+ if (value.options) {
759
+ ctx.stack.push(id);
760
+ const options = serializeTree(ctx, value.options);
761
+ ctx.stack.pop();
762
+ serialized = `Object.assign(${serialized},${options})`;
763
+ }
764
+ return assignRef(ctx, id, serialized);
765
+ }
766
+ case 8 /* NullConstructor */:
767
+ case 7 /* Object */: {
768
+ const values = [];
769
+ ctx.stack.push(id);
770
+ for (const [key, val] of Object.entries(value)) {
771
+ const check = Number(key);
772
+ if (check >= 0 || Number.isNaN(check) && /^([$A-Z_][0-9A-Z_$]*)$/i.test(key)) {
773
+ if (isReferenceInStack(ctx, val)) {
774
+ const refParam = getRefParam(ctx, val[1]);
775
+ if (!Number.isNaN(check)) {
776
+ createObjectComputedAssign(ctx, id, key, refParam);
777
+ } else {
778
+ createObjectIdentifierAssign(ctx, id, key, refParam);
779
+ }
572
780
  } else {
573
- createObjectIdentifierAssign(ctx, ref, key, refParam);
781
+ values.push(`${key}:${serializeTree(ctx, val)}`);
574
782
  }
783
+ } else if (isReferenceInStack(ctx, val)) {
784
+ const refParam = getRefParam(ctx, val[1]);
785
+ createObjectComputedAssign(ctx, id, quote(key), refParam);
575
786
  } else {
576
- values.push(`${key}:${traverseSync(ctx, value2)}`);
787
+ values.push(`${quote(key)}:${serializeTree(ctx, val)}`);
577
788
  }
578
- } else if (ctx.stack.has(value2)) {
579
- const refParam = getRefParam(ctx, createRef(ctx, value2));
580
- createObjectComputedAssign(ctx, getCurrentRef(), quote(key), refParam);
581
- } else {
582
- values.push(`${quote(key)}:${traverseSync(ctx, value2)}`);
583
789
  }
584
- });
585
- ctx.stack.delete(current);
586
- const value = `{${join(values, ",")}}`;
587
- if (empty) {
588
- return processRef(`Object.assign(Object.create(null),${value})`);
790
+ ctx.stack.pop();
791
+ let serialized = `{${values.join(",")}}`;
792
+ if (type === 8 /* NullConstructor */) {
793
+ serialized = `Object.assign(Object.create(null),${serialized})`;
794
+ }
795
+ return assignRef(ctx, id, serialized);
589
796
  }
590
- return processRef(value);
797
+ default:
798
+ throw new Error("Unsupported type");
591
799
  }
592
- throw new Error("Unserializable value");
593
800
  }
594
801
 
595
802
  // src/index.ts
@@ -597,7 +804,7 @@ function finalize(ctx, source, result) {
597
804
  if (ctx.vars.length) {
598
805
  const index = getRefParam(ctx, createRef(ctx, source));
599
806
  const patches = resolvePatches(ctx);
600
- const params = ctx.vars.length > 1 ? `(${join(ctx.vars, ",")})` : ctx.vars[0];
807
+ const params = ctx.vars.length > 1 ? `(${ctx.vars.join(",")})` : ctx.vars[0];
601
808
  if (result.startsWith(`${index}=`)) {
602
809
  return `(${params}=>(${result},${patches}${index}))()`;
603
810
  }
@@ -613,16 +820,8 @@ function serialize(source) {
613
820
  return serializePrimitive(source);
614
821
  }
615
822
  const ctx = createSerializationContext();
616
- lookupRefs(ctx, source);
617
- for (const [key, value] of ctx.refCount.entries()) {
618
- if (value > 1) {
619
- createRef(ctx, key);
620
- }
621
- }
622
- const result = traverseSync(ctx, source);
623
- if (typeof result !== "string") {
624
- throw new Error("Unreachable error");
625
- }
823
+ const tree = generateTreeSync(ctx, source);
824
+ const result = serializeTree(ctx, tree);
626
825
  return finalize(ctx, source, result);
627
826
  }
628
827
  async function serializeAsync(source) {
@@ -630,16 +829,8 @@ async function serializeAsync(source) {
630
829
  return serializePrimitive(source);
631
830
  }
632
831
  const ctx = createSerializationContext();
633
- await lookupRefsAsync(ctx, source);
634
- for (const [key, value] of ctx.refCount.entries()) {
635
- if (value > 1) {
636
- createRef(ctx, key);
637
- }
638
- }
639
- const result = await traverseAsync(ctx, source);
640
- if (typeof result !== "string") {
641
- throw new Error("Unreachable error");
642
- }
832
+ const tree = await generateTreeAsync(ctx, source);
833
+ const result = serializeTree(ctx, tree);
643
834
  return finalize(ctx, source, result);
644
835
  }
645
836
  function deserialize(source) {