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