seroval 0.1.0 → 0.2.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.
@@ -34,73 +34,26 @@ function getIdentifier(index) {
34
34
  return ref;
35
35
  }
36
36
 
37
- // src/quote.ts
38
- function quote(str) {
39
- let result = "";
40
- let lastPos = 0;
41
- for (let i = 0, len = str.length; i < len; i++) {
42
- let replacement;
43
- switch (str[i]) {
44
- case '"':
45
- replacement = '\\"';
46
- break;
47
- case "\\":
48
- replacement = "\\\\";
49
- break;
50
- case "<":
51
- replacement = "\\x3C";
52
- break;
53
- case "\n":
54
- replacement = "\\n";
55
- break;
56
- case "\r":
57
- replacement = "\\r";
58
- break;
59
- case "\u2028":
60
- replacement = "\\u2028";
61
- break;
62
- case "\u2029":
63
- replacement = "\\u2029";
64
- break;
65
- default:
66
- continue;
67
- }
68
- result += str.slice(lastPos, i) + replacement;
69
- lastPos = i + 1;
70
- }
71
- if (lastPos === 0) {
72
- result = str;
73
- } else {
74
- result += str.slice(lastPos);
75
- }
76
- return `"${result}"`;
77
- }
78
-
79
- // src/index.ts
37
+ // src/context.ts
80
38
  var EMPTY_SET = "new Set";
81
39
  var EMPTY_MAP = "new Map";
82
40
  var EMPTY_ARRAY = "[]";
83
- var REF_COUNT = /* @__PURE__ */ new Map();
84
- var STACK = /* @__PURE__ */ new Set();
85
- var REFS = /* @__PURE__ */ new Map();
86
- var ASSIGNED_REFS = /* @__PURE__ */ new Set();
87
- var VARS = [];
88
- var ASSIGNMENTS = [];
89
- var MAP_SETS = [];
90
- var SET_ADDS = [];
91
- function reset() {
92
- ASSIGNMENTS = [];
93
- MAP_SETS = [];
94
- SET_ADDS = [];
95
- VARS = [];
96
- REF_COUNT.clear();
97
- REFS.clear();
98
- ASSIGNED_REFS.clear();
41
+ function createSerializationContext() {
42
+ return {
43
+ refCount: /* @__PURE__ */ new Map(),
44
+ stack: /* @__PURE__ */ new Set(),
45
+ refs: /* @__PURE__ */ new Map(),
46
+ assignedRefs: /* @__PURE__ */ new Set(),
47
+ vars: [],
48
+ assignments: [],
49
+ mapSets: [],
50
+ setAdds: []
51
+ };
99
52
  }
100
- function resolveAssignments() {
101
- if (ASSIGNMENTS.length) {
53
+ function resolveAssignments(ctx) {
54
+ if (ctx.assignments.length) {
102
55
  const result = {};
103
- forEach(ASSIGNMENTS, ([source, value]) => {
56
+ forEach(ctx.assignments, ([source, value]) => {
104
57
  if (value in result) {
105
58
  result[value] = `${source}=${result[value]}`;
106
59
  } else {
@@ -111,10 +64,10 @@ function resolveAssignments() {
111
64
  }
112
65
  return "";
113
66
  }
114
- function resolveMapSets() {
115
- if (MAP_SETS.length) {
67
+ function resolveMapSets(ctx) {
68
+ if (ctx.mapSets.length) {
116
69
  const result = {};
117
- forEach(MAP_SETS, ([source, key, value]) => {
70
+ forEach(ctx.mapSets, ([source, key, value]) => {
118
71
  if (source in result) {
119
72
  result[source] = `${result[source]}.set(${key},${value})`;
120
73
  } else {
@@ -125,10 +78,10 @@ function resolveMapSets() {
125
78
  }
126
79
  return "";
127
80
  }
128
- function resolveSetAdds() {
129
- if (SET_ADDS.length) {
81
+ function resolveSetAdds(ctx) {
82
+ if (ctx.setAdds.length) {
130
83
  const result = {};
131
- forEach(SET_ADDS, ([source, value]) => {
84
+ forEach(ctx.setAdds, ([source, value]) => {
132
85
  if (source in result) {
133
86
  result[source] = `${result[source]}.add(${value})`;
134
87
  } else {
@@ -139,88 +92,114 @@ function resolveSetAdds() {
139
92
  }
140
93
  return "";
141
94
  }
142
- function resolvePatches() {
143
- return `${resolveAssignments()}${resolveMapSets()}${resolveSetAdds()}`;
95
+ function resolvePatches(ctx) {
96
+ return `${resolveAssignments(ctx)}${resolveMapSets(ctx)}${resolveSetAdds(ctx)}`;
144
97
  }
145
- function insertRef(current) {
146
- const count = REF_COUNT.get(current) || 0;
147
- REF_COUNT.set(current, count + 1);
98
+ function insertRef(ctx, current) {
99
+ const count = ctx.refCount.get(current) || 0;
100
+ ctx.refCount.set(current, count + 1);
148
101
  return count === 0;
149
102
  }
150
103
  function constructorCheck(value, constructor) {
151
104
  return value.constructor === constructor;
152
105
  }
153
- function isPrimitive(current) {
154
- if (!current || current === true) {
155
- return true;
156
- }
157
- const type = typeof current;
158
- const classConst = current.constructor;
159
- return type === "number" || type === "string" || type === "bigint" || classConst === Date || classConst === RegExp;
160
- }
161
- function lookupRefs(current) {
162
- if (isPrimitive(current)) {
163
- return;
164
- }
165
- if (Array.isArray(current)) {
166
- if (insertRef(current)) {
167
- forEach(current, lookupRefs);
168
- }
169
- } else if (constructorCheck(current, Set)) {
170
- if (insertRef(current)) {
171
- for (const item of current.keys()) {
172
- lookupRefs(item);
173
- }
174
- }
175
- } else if (constructorCheck(current, Map)) {
176
- if (insertRef(current)) {
177
- for (const [key, value] of current.entries()) {
178
- lookupRefs(key);
179
- lookupRefs(value);
180
- }
181
- }
182
- } else if (current.constructor === Object && insertRef(current)) {
183
- forEach(Object.values(current), lookupRefs);
184
- }
185
- }
186
- function createRef(value) {
187
- const current = REFS.get(value);
106
+ function createRef(ctx, value) {
107
+ const current = ctx.refs.get(value);
188
108
  if (current != null) {
189
109
  return current;
190
110
  }
191
- const id = REFS.size;
192
- REFS.set(value, id);
111
+ const id = ctx.refs.size;
112
+ ctx.refs.set(value, id);
193
113
  return id;
194
114
  }
195
- function getRefParam(index) {
196
- if (VARS[index]) {
197
- return VARS[index];
115
+ function getRefParam(ctx, index) {
116
+ if (ctx.vars[index]) {
117
+ return ctx.vars[index];
198
118
  }
199
119
  const result = getIdentifier(index);
200
- VARS[index] = result;
120
+ ctx.vars[index] = result;
201
121
  return result;
202
122
  }
203
- function assignRef(index, value) {
204
- return `${getRefParam(index)}=${value}`;
123
+ function assignRef(ctx, index, value) {
124
+ return `${getRefParam(ctx, index)}=${value}`;
125
+ }
126
+ function createAssignment(ctx, source, value) {
127
+ ctx.assignments.push([source, value]);
205
128
  }
206
- function createAssignment(source, value) {
207
- ASSIGNMENTS.push([source, value]);
129
+ function createSetAdd(ctx, ref, value) {
130
+ ctx.setAdds.push([getRefParam(ctx, ref), value]);
208
131
  }
209
- function createSetAdd(ref, value) {
210
- SET_ADDS.push([getRefParam(ref), value]);
132
+ function createMapSet(ctx, ref, key, value) {
133
+ ctx.mapSets.push([getRefParam(ctx, ref), key, value]);
211
134
  }
212
- function createMapSet(ref, key, value) {
213
- MAP_SETS.push([getRefParam(ref), key, value]);
135
+ function createArrayAssign(ctx, ref, index, value) {
136
+ createAssignment(ctx, `${getRefParam(ctx, ref)}[${index}]`, value);
214
137
  }
215
- function createArrayAssign(ref, index, value) {
216
- createAssignment(`${getRefParam(ref)}[${index}]`, value);
138
+ function createObjectIdentifierAssign(ctx, ref, key, value) {
139
+ createAssignment(ctx, `${getRefParam(ctx, ref)}.${key}`, value);
217
140
  }
218
- function createObjectIdentifierAssign(ref, key, value) {
219
- createAssignment(`${getRefParam(ref)}.${key}`, value);
141
+ function createObjectComputedAssign(ctx, ref, key, value) {
142
+ createAssignment(ctx, `${getRefParam(ctx, ref)}[${key}]`, value);
220
143
  }
221
- function createObjectStringAssign(ref, key, value) {
222
- createAssignment(`${getRefParam(ref)}[${quote(key)}]`, value);
144
+
145
+ // src/is-primitive.ts
146
+ function isPrimitive(current) {
147
+ if (!current || current === true) {
148
+ return true;
149
+ }
150
+ const type = typeof current;
151
+ const classConst = current.constructor;
152
+ return type === "number" || type === "string" || type === "bigint" || classConst === Date || classConst === RegExp;
223
153
  }
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";
158
+ }
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;
190
+ }
191
+ result += str.slice(lastPos, i) + replacement;
192
+ lastPos = i + 1;
193
+ }
194
+ if (lastPos === 0) {
195
+ result = str;
196
+ } else {
197
+ result += str.slice(lastPos);
198
+ }
199
+ return `"${result}"`;
200
+ }
201
+
202
+ // src/serialize-primitive.ts
224
203
  function serializePrimitive(value) {
225
204
  if (value === true) {
226
205
  return "!0";
@@ -248,122 +227,294 @@ function serializePrimitive(value) {
248
227
  }
249
228
  return String(value);
250
229
  }
251
- function traverse(current) {
230
+
231
+ // src/async.ts
232
+ async function lookupRefsAsync(ctx, current) {
233
+ if (isPrimitive(current)) {
234
+ return;
235
+ }
236
+ if (isPromise(current)) {
237
+ if (insertRef(ctx, current)) {
238
+ await current.then((value) => lookupRefsAsync(ctx, value));
239
+ }
240
+ } else if (Array.isArray(current)) {
241
+ if (insertRef(ctx, current)) {
242
+ for (const value of current) {
243
+ await lookupRefsAsync(ctx, value);
244
+ }
245
+ }
246
+ } else if (constructorCheck(current, Set)) {
247
+ if (insertRef(ctx, current)) {
248
+ for (const item of current.keys()) {
249
+ await lookupRefsAsync(ctx, item);
250
+ }
251
+ }
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);
257
+ }
258
+ }
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);
262
+ }
263
+ }
264
+ }
265
+ async function traverseAsync(ctx, current) {
252
266
  if (isPrimitive(current)) {
253
267
  return serializePrimitive(current);
254
268
  }
255
- let refResult = REFS.get(current);
269
+ let refResult = ctx.refs.get(current);
256
270
  if (refResult != null) {
257
- if (ASSIGNED_REFS.has(refResult)) {
258
- return { referred: getRefParam(refResult) };
271
+ if (ctx.assignedRefs.has(refResult)) {
272
+ return getRefParam(ctx, refResult);
259
273
  }
260
- ASSIGNED_REFS.add(refResult);
274
+ ctx.assignedRefs.add(refResult);
275
+ }
276
+ function getCurrentRef() {
277
+ if (refResult == null) {
278
+ refResult = createRef(ctx, current);
279
+ }
280
+ return refResult;
281
+ }
282
+ function processRef(value) {
283
+ if (refResult != null) {
284
+ return assignRef(ctx, refResult, value);
285
+ }
286
+ return value;
287
+ }
288
+ 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
+ });
261
301
  }
262
302
  if (constructorCheck(current, Set)) {
263
303
  if (current.size) {
264
304
  const values = [];
265
- STACK.add(current);
266
- for (const value2 of current.keys()) {
267
- if (STACK.has(value2)) {
268
- if (refResult == null) {
269
- refResult = createRef(current);
270
- }
271
- createSetAdd(refResult, getRefParam(createRef(value2)));
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)));
272
309
  } else {
273
- const result = traverse(value2);
274
- if (typeof result === "string") {
275
- values.push(result);
276
- } else {
277
- values.push(result.referred);
278
- }
310
+ values.push(await traverseAsync(ctx, value));
279
311
  }
280
312
  }
281
- STACK.delete(current);
282
- const value = values.length ? `new Set([${join(values, ",")}])` : EMPTY_SET;
283
- if (refResult != null) {
284
- return assignRef(refResult, value);
285
- }
286
- return value;
313
+ ctx.stack.delete(current);
314
+ return processRef(values.length ? `new Set([${join(values, ",")}])` : EMPTY_SET);
287
315
  }
288
316
  return EMPTY_SET;
289
317
  }
290
318
  if (constructorCheck(current, Map)) {
291
319
  if (current.size) {
292
320
  const values = [];
293
- STACK.add(current);
294
- for (const [key, value2] of current.entries()) {
295
- if (STACK.has(key)) {
296
- if (refResult == null) {
297
- refResult = createRef(current);
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);
298
332
  }
299
- const keyRef = getRefParam(createRef(key));
300
- if (STACK.has(value2)) {
301
- createMapSet(refResult, keyRef, getRefParam(createRef(value2)));
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
+ }
342
+ }
343
+ ctx.stack.delete(current);
344
+ return processRef(values.length ? `new Map([${join(values, ",")}])` : EMPTY_MAP);
345
+ }
346
+ return EMPTY_MAP;
347
+ }
348
+ 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 += ",";
302
359
  } else {
303
- const valueResult = traverse(value2);
304
- if (typeof valueResult === "string") {
305
- createMapSet(refResult, keyRef, valueResult);
306
- } else {
307
- createMapSet(refResult, keyRef, valueResult.referred);
360
+ values += await traverseAsync(ctx, item);
361
+ if (i < current.length - 1) {
362
+ values += ",";
308
363
  }
309
364
  }
310
- } else if (STACK.has(value2)) {
311
- if (refResult == null) {
312
- refResult = createRef(current);
313
- }
314
- const valueRef = getRefParam(createRef(value2));
315
- const keyResult = traverse(key);
316
- if (typeof keyResult === "string") {
317
- createMapSet(refResult, keyResult, valueRef);
365
+ } else {
366
+ values += ",";
367
+ }
368
+ }
369
+ ctx.stack.delete(current);
370
+ return processRef(`[${values}]`);
371
+ }
372
+ return EMPTY_ARRAY;
373
+ }
374
+ const empty = current.constructor == null;
375
+ 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);
318
386
  } else {
319
- createMapSet(refResult, keyResult.referred, valueRef);
387
+ createObjectComputedAssign(ctx, ref, key, refParam);
320
388
  }
321
389
  } else {
322
- const keyResult = traverse(key);
323
- const valueResult = traverse(value2);
324
- if (typeof keyResult === "string") {
325
- if (typeof valueResult === "string") {
326
- values.push(`[${keyResult},${valueResult}]`);
327
- } else {
328
- values.push(`[${keyResult},${valueResult.referred}]`);
329
- }
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);
396
+ } else {
397
+ const valueResult = await traverseAsync(ctx, value2);
398
+ values.push(`${quote(key)}:${valueResult}`);
399
+ }
400
+ }
401
+ ctx.stack.delete(current);
402
+ const value = `{${join(values, ",")}}`;
403
+ if (empty) {
404
+ return processRef(`Object.assign(Object.create(null),${value})`);
405
+ }
406
+ return processRef(value);
407
+ }
408
+ throw new Error("Unserializable value");
409
+ }
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);
426
+ }
427
+ }
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);
433
+ }
434
+ }
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));
473
+ }
474
+ }
475
+ ctx.stack.delete(current);
476
+ return processRef(values.length ? `new Set([${join(values, ",")}])` : EMPTY_SET);
477
+ }
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);
330
491
  } else {
331
- if (typeof valueResult === "string") {
332
- values.push(`[${keyResult.referred},${valueResult}]`);
333
- } else {
334
- values.push(`[${keyResult.referred},${valueResult.referred}]`);
335
- }
492
+ createMapSet(ctx, ref, keyRef, traverseSync(ctx, value));
336
493
  }
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)}]`);
337
499
  }
338
500
  }
339
- STACK.delete(current);
340
- const value = values.length ? `new Map([${join(values, ",")}])` : EMPTY_MAP;
341
- if (refResult != null) {
342
- return assignRef(refResult, value);
343
- }
344
- return value;
501
+ ctx.stack.delete(current);
502
+ return processRef(values.length ? `new Map([${join(values, ",")}])` : EMPTY_MAP);
345
503
  }
346
504
  return EMPTY_MAP;
347
505
  }
348
506
  if (Array.isArray(current)) {
349
507
  if (current.length) {
350
508
  let values = "";
351
- STACK.add(current);
509
+ ctx.stack.add(current);
352
510
  forEach(current, (item, i) => {
353
511
  if (i in current) {
354
- if (STACK.has(item)) {
355
- if (refResult == null) {
356
- refResult = createRef(current);
357
- }
358
- createArrayAssign(refResult, i, getRefParam(createRef(item)));
512
+ if (ctx.stack.has(item)) {
513
+ const refParam = getRefParam(ctx, createRef(ctx, item));
514
+ createArrayAssign(ctx, getCurrentRef(), i, refParam);
359
515
  values += ",";
360
516
  } else {
361
- const result = traverse(item);
362
- if (typeof result === "string") {
363
- values += result;
364
- } else {
365
- values += result.referred;
366
- }
517
+ values += traverseSync(ctx, item);
367
518
  if (i < current.length - 1) {
368
519
  values += ",";
369
520
  }
@@ -372,87 +523,104 @@ function traverse(current) {
372
523
  values += ",";
373
524
  }
374
525
  });
375
- STACK.delete(current);
376
- const value = `[${values}]`;
377
- if (refResult != null) {
378
- return assignRef(refResult, value);
379
- }
380
- return value;
526
+ ctx.stack.delete(current);
527
+ return processRef(`[${values}]`);
381
528
  }
382
529
  return EMPTY_ARRAY;
383
530
  }
384
- if (current.constructor === Object) {
531
+ const empty = current.constructor == null;
532
+ if (current.constructor === Object || empty) {
385
533
  const values = [];
386
- STACK.add(current);
534
+ ctx.stack.add(current);
387
535
  forEach(Object.entries(current), ([key, value2]) => {
388
536
  const check = Number(key);
389
- if (Number.isNaN(check) || /^([$A-Z_][0-9A-Z_$]*)$/i.test(key)) {
390
- if (STACK.has(value2)) {
391
- if (refResult == null) {
392
- refResult = createRef(current);
393
- }
394
- createObjectIdentifierAssign(refResult, key, getRefParam(createRef(value2)));
395
- } else {
396
- const result = traverse(value2);
397
- if (typeof result === "string") {
398
- values.push(`${key}:${result}`);
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);
399
543
  } else {
400
- values.push(`${key}:${result.referred}`);
544
+ createObjectIdentifierAssign(ctx, ref, key, refParam);
401
545
  }
402
- }
403
- } else if (STACK.has(value2)) {
404
- if (refResult == null) {
405
- refResult = createRef(current);
406
- }
407
- createObjectStringAssign(refResult, key, getRefParam(createRef(value2)));
408
- } else {
409
- const result = traverse(value2);
410
- if (typeof result === "string") {
411
- values.push(`${quote(key)}:${result}`);
412
546
  } else {
413
- values.push(`${quote(key)}:${result.referred}`);
547
+ values.push(`${key}:${traverseSync(ctx, value2)}`);
414
548
  }
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)}`);
415
554
  }
416
555
  });
417
- STACK.delete(current);
556
+ ctx.stack.delete(current);
418
557
  const value = `{${join(values, ",")}}`;
419
- if (refResult != null) {
420
- return assignRef(refResult, value);
558
+ if (empty) {
559
+ return processRef(`Object.assign(Object.create(null),${value})`);
421
560
  }
422
- return value;
561
+ return processRef(value);
423
562
  }
424
563
  throw new Error("Unserializable value");
425
564
  }
565
+
566
+ // src/index.ts
567
+ function finalize(ctx, source, result) {
568
+ if (ctx.vars.length) {
569
+ const index = getRefParam(ctx, createRef(ctx, source));
570
+ const patches = resolvePatches(ctx);
571
+ const params = ctx.vars.length > 1 ? `(${join(ctx.vars, ",")})` : ctx.vars[0];
572
+ if (result.startsWith(`${index}=`)) {
573
+ return `(${params}=>(${result},${patches}${index}))()`;
574
+ }
575
+ return `(${params}=>(${index}=${result},${patches}${index}))()`;
576
+ }
577
+ if (source.constructor === Object) {
578
+ return `(${result})`;
579
+ }
580
+ return result;
581
+ }
426
582
  function serialize(source) {
427
583
  if (isPrimitive(source)) {
428
584
  return serializePrimitive(source);
429
585
  }
430
- reset();
431
- lookupRefs(source);
432
- for (const [key, value] of REF_COUNT.entries()) {
586
+ const ctx = createSerializationContext();
587
+ lookupRefs(ctx, source);
588
+ for (const [key, value] of ctx.refCount.entries()) {
433
589
  if (value > 1) {
434
- createRef(key);
590
+ createRef(ctx, key);
435
591
  }
436
592
  }
437
- const result = traverse(source);
593
+ const result = traverseSync(ctx, source);
438
594
  if (typeof result !== "string") {
439
595
  throw new Error("Unreachable error");
440
596
  }
441
- if (VARS.length) {
442
- const index = getRefParam(createRef(source));
443
- const patches = resolvePatches();
444
- const params = VARS.length > 1 ? `(${join(VARS, ",")})` : VARS[0];
445
- if (result.startsWith(index)) {
446
- return `(${params}=>(${result},${patches}${index}))()`;
597
+ return finalize(ctx, source, result);
598
+ }
599
+ async function serializeAsync(source) {
600
+ if (isPrimitive(source)) {
601
+ return serializePrimitive(source);
602
+ }
603
+ 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);
447
608
  }
448
- return `(${params}=>(${index}=${result},${patches}${index}))()`;
449
609
  }
450
- if (source.constructor === Object) {
451
- return `(${result})`;
610
+ const result = await traverseAsync(ctx, source);
611
+ if (typeof result !== "string") {
612
+ throw new Error("Unreachable error");
452
613
  }
453
- return result;
614
+ return finalize(ctx, source, result);
615
+ }
616
+ function deserialize(source) {
617
+ return (0, eval)(source);
454
618
  }
619
+ var src_default = serialize;
455
620
  export {
456
- serialize as default
621
+ src_default as default,
622
+ deserialize,
623
+ serialize,
624
+ serializeAsync
457
625
  };
458
626
  //# sourceMappingURL=index.mjs.map