seroval 0.7.0 → 0.9.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.
Files changed (42) hide show
  1. package/dist/cjs/development/index.cjs +1247 -1069
  2. package/dist/cjs/development/index.cjs.map +4 -4
  3. package/dist/cjs/production/index.cjs +3 -3
  4. package/dist/esm/development/index.mjs +1247 -1069
  5. package/dist/esm/development/index.mjs.map +4 -4
  6. package/dist/esm/production/index.mjs +3 -3
  7. package/dist/types/assert.d.ts +1 -1
  8. package/dist/types/context.d.ts +8 -2
  9. package/dist/types/index.d.ts +3 -4
  10. package/dist/types/string.d.ts +1 -1
  11. package/dist/types/tree/UnsupportedTypeError.d.ts +3 -0
  12. package/dist/types/tree/async.d.ts +3 -3
  13. package/dist/types/tree/constants.d.ts +11 -0
  14. package/dist/types/tree/deserialize.d.ts +2 -2
  15. package/dist/types/tree/primitives.d.ts +9 -15
  16. package/dist/types/tree/serialize.d.ts +2 -2
  17. package/dist/types/tree/shared.d.ts +12 -8
  18. package/dist/types/tree/sync.d.ts +3 -3
  19. package/dist/types/tree/types.d.ts +74 -71
  20. package/dist/types/tree/web-api.d.ts +2 -2
  21. package/dist/types/types.d.ts +4 -4
  22. package/package.json +11 -9
  23. package/src/assert.ts +2 -2
  24. package/src/compat.ts +0 -1
  25. package/src/context.ts +20 -7
  26. package/src/get-identifier.ts +1 -1
  27. package/src/index.ts +35 -26
  28. package/src/string.ts +2 -2
  29. package/src/tree/UnsupportedTypeError.ts +8 -0
  30. package/src/tree/async.ts +256 -233
  31. package/src/tree/constants.ts +73 -0
  32. package/src/tree/deserialize.ts +112 -93
  33. package/src/tree/primitives.ts +93 -134
  34. package/src/tree/reference.ts +3 -3
  35. package/src/tree/serialize.ts +307 -201
  36. package/src/tree/shared.ts +45 -22
  37. package/src/tree/symbols.ts +13 -13
  38. package/src/tree/sync.ts +236 -198
  39. package/src/tree/types.ts +87 -94
  40. package/src/tree/web-api.ts +14 -7
  41. package/src/types.ts +7 -3
  42. package/src/tree/iterator.ts +0 -14
@@ -0,0 +1,73 @@
1
+ import type { SerovalConstantNode } from './types';
2
+ import { SerovalConstant, SerovalNodeType } from './types';
3
+
4
+ function createConstantNode(value: SerovalConstant): SerovalConstantNode {
5
+ return {
6
+ t: SerovalNodeType.Constant,
7
+ i: undefined,
8
+ s: value,
9
+ l: undefined,
10
+ c: undefined,
11
+ m: undefined,
12
+ d: undefined,
13
+ a: undefined,
14
+ f: undefined,
15
+ b: undefined,
16
+ o: undefined,
17
+ };
18
+ }
19
+
20
+ export const TRUE_NODE = createConstantNode(SerovalConstant.True);
21
+ export const FALSE_NODE = createConstantNode(SerovalConstant.False);
22
+ export const UNDEFINED_NODE = createConstantNode(SerovalConstant.Undefined);
23
+ export const NULL_NODE = createConstantNode(SerovalConstant.Null);
24
+ export const NEG_ZERO_NODE = createConstantNode(SerovalConstant.NegativeZero);
25
+ export const INFINITY_NODE = createConstantNode(SerovalConstant.Infinity);
26
+ export const NEG_INFINITY_NODE = createConstantNode(SerovalConstant.NegativeInfinity);
27
+ export const NAN_NODE = createConstantNode(SerovalConstant.NaN);
28
+
29
+ export function serializeConstant(node: SerovalConstantNode): string {
30
+ switch (node.s) {
31
+ case SerovalConstant.True:
32
+ return '!0';
33
+ case SerovalConstant.False:
34
+ return '!1';
35
+ case SerovalConstant.Undefined:
36
+ return 'void 0';
37
+ case SerovalConstant.Null:
38
+ return 'null';
39
+ case SerovalConstant.NegativeZero:
40
+ return '-0';
41
+ case SerovalConstant.Infinity:
42
+ return '1/0';
43
+ case SerovalConstant.NegativeInfinity:
44
+ return '-1/0';
45
+ case SerovalConstant.NaN:
46
+ return 'NaN';
47
+ default:
48
+ throw new Error('invariant');
49
+ }
50
+ }
51
+
52
+ export function deserializeConstant(node: SerovalConstantNode): unknown {
53
+ switch (node.s) {
54
+ case SerovalConstant.True:
55
+ return true;
56
+ case SerovalConstant.False:
57
+ return false;
58
+ case SerovalConstant.Undefined:
59
+ return undefined;
60
+ case SerovalConstant.Null:
61
+ return null;
62
+ case SerovalConstant.NegativeZero:
63
+ return -0;
64
+ case SerovalConstant.Infinity:
65
+ return Infinity;
66
+ case SerovalConstant.NegativeInfinity:
67
+ return -Infinity;
68
+ case SerovalConstant.NaN:
69
+ return NaN;
70
+ default:
71
+ throw new Error('invariant');
72
+ }
73
+ }
@@ -1,30 +1,32 @@
1
1
  /* eslint-disable prefer-spread */
2
2
  /* eslint-disable @typescript-eslint/no-use-before-define */
3
- import {
3
+ import type {
4
4
  SerializationContext,
5
5
  } from '../context';
6
6
  import { deserializeString } from '../string';
7
+ import type { BigIntTypedArrayValue, TypedArrayValue } from '../types';
8
+ import { deserializeConstant } from './constants';
7
9
  import { getReference } from './reference';
8
10
  import { getErrorConstructor, getTypedArrayConstructor } from './shared';
9
11
  import { SYMBOL_REF } from './symbols';
10
- import {
12
+ import type {
11
13
  SerovalAggregateErrorNode,
12
14
  SerovalArrayBufferNode,
13
15
  SerovalArrayNode,
14
16
  SerovalBigIntTypedArrayNode,
15
17
  SerovalBlobNode,
18
+ SerovalBoxedNode,
16
19
  SerovalDataViewNode,
17
20
  SerovalDateNode,
18
21
  SerovalErrorNode,
19
22
  SerovalFileNode,
20
23
  SerovalFormDataNode,
21
24
  SerovalHeadersNode,
22
- SerovalIterableNode,
23
25
  SerovalMapNode,
24
26
  SerovalNode,
25
- SerovalNodeType,
26
27
  SerovalNullConstructorNode,
27
28
  SerovalObjectNode,
29
+ SerovalObjectRecordKey,
28
30
  SerovalObjectRecordNode,
29
31
  SerovalPromiseNode,
30
32
  SerovalReferenceNode,
@@ -34,12 +36,30 @@ import {
34
36
  SerovalURLNode,
35
37
  SerovalURLSearchParamsNode,
36
38
  } from './types';
39
+ import {
40
+ SerovalObjectFlags,
41
+ SerovalNodeType,
42
+ SerovalObjectRecordSpecialKey,
43
+ } from './types';
44
+
45
+ function applyObjectFlag(obj: unknown, flag: SerovalObjectFlags): unknown {
46
+ switch (flag) {
47
+ case SerovalObjectFlags.Frozen:
48
+ return Object.freeze(obj);
49
+ case SerovalObjectFlags.NonExtensible:
50
+ return Object.preventExtensions(obj);
51
+ case SerovalObjectFlags.Sealed:
52
+ return Object.seal(obj);
53
+ default:
54
+ return obj;
55
+ }
56
+ }
37
57
 
38
58
  function assignIndexedValue<T>(
39
59
  ctx: SerializationContext,
40
60
  index: number,
41
61
  value: T,
42
- ) {
62
+ ): T {
43
63
  if (ctx.markedRefs.has(index)) {
44
64
  ctx.valueMap.set(index, value);
45
65
  }
@@ -49,65 +69,77 @@ function assignIndexedValue<T>(
49
69
  function deserializeArray(
50
70
  ctx: SerializationContext,
51
71
  node: SerovalArrayNode,
52
- ) {
72
+ ): unknown[] {
73
+ const len = node.l;
53
74
  const result: unknown[] = assignIndexedValue(
54
75
  ctx,
55
76
  node.i,
56
- new Array<unknown>(node.l),
77
+ new Array<unknown>(len),
57
78
  );
58
- let item: SerovalNode;
59
- for (let i = 0, len = node.l; i < len; i++) {
79
+ let item: SerovalNode | undefined;
80
+ for (let i = 0; i < len; i++) {
60
81
  item = node.a[i];
61
82
  if (item) {
62
83
  result[i] = deserializeTree(ctx, item);
63
84
  }
64
85
  }
86
+ applyObjectFlag(result, node.o);
65
87
  return result;
66
88
  }
67
89
 
68
90
  function deserializeProperties(
69
91
  ctx: SerializationContext,
70
92
  node: SerovalObjectRecordNode,
71
- result: Record<string, unknown>,
72
- ) {
73
- if (node.s === 0) {
74
- return {};
75
- }
76
- for (let i = 0; i < node.s; i++) {
77
- result[deserializeString(node.k[i])] = deserializeTree(ctx, node.v[i]);
93
+ result: Record<string | symbol, unknown>,
94
+ ): Record<string | symbol, unknown> {
95
+ const len = node.s;
96
+ if (len) {
97
+ let key: SerovalObjectRecordKey;
98
+ let value: unknown;
99
+ const keys = node.k;
100
+ const vals = node.v;
101
+ for (let i = 0; i < len; i++) {
102
+ key = keys[i];
103
+ value = deserializeTree(ctx, vals[i]);
104
+ switch (key) {
105
+ case SerovalObjectRecordSpecialKey.SymbolIterator: {
106
+ const current = value as unknown[];
107
+ result[Symbol.iterator] = (): IterableIterator<unknown> => current.values();
108
+ }
109
+ break;
110
+ default:
111
+ result[deserializeString(key)] = value;
112
+ break;
113
+ }
114
+ }
78
115
  }
79
116
  return result;
80
117
  }
81
118
 
82
- function deserializeNullConstructor(
119
+ function deserializeObject(
83
120
  ctx: SerializationContext,
84
- node: SerovalNullConstructorNode,
85
- ) {
121
+ node: SerovalObjectNode | SerovalNullConstructorNode,
122
+ ): Record<string, unknown> {
86
123
  const result = assignIndexedValue(
87
124
  ctx,
88
125
  node.i,
89
- Object.create(null) as Record<string, unknown>,
126
+ (node.t === SerovalNodeType.Object
127
+ ? {}
128
+ : Object.create(null)) as Record<string, unknown>,
90
129
  );
91
130
  deserializeProperties(ctx, node.d, result);
92
- return result;
93
- }
94
-
95
- function deserializeObject(
96
- ctx: SerializationContext,
97
- node: SerovalObjectNode,
98
- ) {
99
- const result = assignIndexedValue(ctx, node.i, {} as Record<string, unknown>);
100
- deserializeProperties(ctx, node.d, result);
131
+ applyObjectFlag(result, node.o);
101
132
  return result;
102
133
  }
103
134
 
104
135
  function deserializeSet(
105
136
  ctx: SerializationContext,
106
137
  node: SerovalSetNode,
107
- ) {
138
+ ): Set<unknown> {
108
139
  const result = assignIndexedValue(ctx, node.i, new Set<unknown>());
140
+ const items = node.a;
109
141
  for (let i = 0, len = node.l; i < len; i++) {
110
- result.add(deserializeTree(ctx, node.a[i]));
142
+ result.add(deserializeTree(ctx, items[i]));
111
143
  }
112
144
  return result;
113
145
  }
@@ -115,29 +147,31 @@ function deserializeSet(
115
147
  function deserializeMap(
116
148
  ctx: SerializationContext,
117
149
  node: SerovalMapNode,
118
- ) {
150
+ ): Map<unknown, unknown> {
119
151
  const result = assignIndexedValue(
120
152
  ctx,
121
153
  node.i,
122
154
  new Map<unknown, unknown>(),
123
155
  );
156
+ const keys = node.d.k;
157
+ const vals = node.d.v;
124
158
  for (let i = 0, len = node.d.s; i < len; i++) {
125
159
  result.set(
126
- deserializeTree(ctx, node.d.k[i]),
127
- deserializeTree(ctx, node.d.v[i]),
160
+ deserializeTree(ctx, keys[i]),
161
+ deserializeTree(ctx, vals[i]),
128
162
  );
129
163
  }
130
164
  return result;
131
165
  }
132
166
 
133
167
  type AssignableValue = AggregateError | Error | Iterable<unknown>
134
- type AssignableNode = SerovalAggregateErrorNode | SerovalErrorNode | SerovalIterableNode;
168
+ type AssignableNode = SerovalAggregateErrorNode | SerovalErrorNode;
135
169
 
136
170
  function deserializeDictionary<T extends AssignableValue>(
137
171
  ctx: SerializationContext,
138
172
  node: AssignableNode,
139
173
  result: T,
140
- ) {
174
+ ): T {
141
175
  if (node.d) {
142
176
  const fields = deserializeProperties(ctx, node.d, {});
143
177
  Object.assign(result, fields);
@@ -148,7 +182,7 @@ function deserializeDictionary<T extends AssignableValue>(
148
182
  function deserializeAggregateError(
149
183
  ctx: SerializationContext,
150
184
  node: SerovalAggregateErrorNode,
151
- ) {
185
+ ): AggregateError {
152
186
  // Serialize the required arguments
153
187
  const result = assignIndexedValue(
154
188
  ctx,
@@ -164,7 +198,7 @@ function deserializeAggregateError(
164
198
  function deserializeError(
165
199
  ctx: SerializationContext,
166
200
  node: SerovalErrorNode,
167
- ) {
201
+ ): Error {
168
202
  const ErrorConstructor = getErrorConstructor(node.c);
169
203
  const result = assignIndexedValue(ctx, node.i, new ErrorConstructor(deserializeString(node.m)));
170
204
  return deserializeDictionary(ctx, node, result);
@@ -178,7 +212,7 @@ interface Deferred {
178
212
  function createDeferred(): Deferred {
179
213
  let resolver: Deferred['resolve'];
180
214
  return {
181
- resolve(v) {
215
+ resolve(v): void {
182
216
  resolver(v);
183
217
  },
184
218
  promise: new Promise((res) => {
@@ -187,10 +221,10 @@ function createDeferred(): Deferred {
187
221
  };
188
222
  }
189
223
 
190
- function deserializePromise(
224
+ async function deserializePromise(
191
225
  ctx: SerializationContext,
192
226
  node: SerovalPromiseNode,
193
- ) {
227
+ ): Promise<unknown> {
194
228
  const deferred = createDeferred();
195
229
  const result = assignIndexedValue(ctx, node.i, deferred.promise);
196
230
  deferred.resolve(deserializeTree(ctx, node.f));
@@ -200,7 +234,7 @@ function deserializePromise(
200
234
  function deserializeArrayBuffer(
201
235
  ctx: SerializationContext,
202
236
  node: SerovalArrayBufferNode,
203
- ) {
237
+ ): ArrayBuffer {
204
238
  const bytes = new Uint8Array(node.s);
205
239
  const result = assignIndexedValue(ctx, node.i, bytes.buffer);
206
240
  return result;
@@ -209,7 +243,7 @@ function deserializeArrayBuffer(
209
243
  function deserializeTypedArray(
210
244
  ctx: SerializationContext,
211
245
  node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
212
- ) {
246
+ ): TypedArrayValue | BigIntTypedArrayValue {
213
247
  const TypedArray = getTypedArrayConstructor(node.c);
214
248
  const source = deserializeTree(ctx, node.f) as ArrayBuffer;
215
249
  const result = assignIndexedValue(ctx, node.i, new TypedArray(
@@ -220,63 +254,45 @@ function deserializeTypedArray(
220
254
  return result;
221
255
  }
222
256
 
223
- function deserializeIterable(
224
- ctx: SerializationContext,
225
- node: SerovalIterableNode,
226
- ) {
227
- const values: unknown[] = [];
228
- let item: SerovalNode;
229
- for (let i = 0, len = node.l; i < len; i++) {
230
- item = node.a[i];
231
- if (item) {
232
- values[i] = deserializeTree(ctx, item);
233
- }
234
- }
235
- const result: Iterable<unknown> = assignIndexedValue(ctx, node.i, {
236
- [Symbol.iterator]: () => values.values(),
237
- });
238
- return deserializeDictionary(ctx, node, result);
239
- }
240
-
241
257
  function deserializeDate(
242
258
  ctx: SerializationContext,
243
259
  node: SerovalDateNode,
244
- ) {
260
+ ): Date {
245
261
  return assignIndexedValue(ctx, node.i, new Date(node.s));
246
262
  }
247
263
 
248
264
  function deserializeRegExp(
249
265
  ctx: SerializationContext,
250
266
  node: SerovalRegExpNode,
251
- ) {
267
+ ): RegExp {
252
268
  return assignIndexedValue(ctx, node.i, new RegExp(node.c, node.m));
253
269
  }
254
270
 
255
271
  function deserializeURL(
256
272
  ctx: SerializationContext,
257
273
  node: SerovalURLNode,
258
- ) {
274
+ ): URL {
259
275
  return assignIndexedValue(ctx, node.i, new URL(deserializeString(node.s)));
260
276
  }
261
277
 
262
278
  function deserializeURLSearchParams(
263
279
  ctx: SerializationContext,
264
280
  node: SerovalURLSearchParamsNode,
265
- ) {
281
+ ): URLSearchParams {
266
282
  return assignIndexedValue(ctx, node.i, new URLSearchParams(deserializeString(node.s)));
267
283
  }
268
284
 
269
285
  function deserializeReference(
270
286
  ctx: SerializationContext,
271
287
  node: SerovalReferenceNode,
272
- ) {
288
+ ): unknown {
273
289
  return assignIndexedValue(ctx, node.i, getReference(deserializeString(node.s)));
274
290
  }
275
291
 
276
292
  function deserializeDataView(
277
293
  ctx: SerializationContext,
278
294
  node: SerovalDataViewNode,
279
- ) {
295
+ ): DataView {
280
296
  const source = deserializeTree(ctx, node.f) as ArrayBuffer;
281
297
  const result = assignIndexedValue(ctx, node.i, new DataView(
282
298
  source,
@@ -289,7 +305,7 @@ function deserializeDataView(
289
305
  function deserializeBlob(
290
306
  ctx: SerializationContext,
291
307
  node: SerovalBlobNode,
292
- ) {
308
+ ): Blob {
293
309
  const source = deserializeTree(ctx, node.f) as ArrayBuffer;
294
310
  const result = assignIndexedValue(ctx, node.i, new Blob(
295
311
  [source],
@@ -301,7 +317,7 @@ function deserializeBlob(
301
317
  function deserializeFile(
302
318
  ctx: SerializationContext,
303
319
  node: SerovalFileNode,
304
- ) {
320
+ ): File {
305
321
  const source = deserializeTree(ctx, node.f) as ArrayBuffer;
306
322
  const result = assignIndexedValue(ctx, node.i, new File(
307
323
  [source],
@@ -314,12 +330,14 @@ function deserializeFile(
314
330
  function deserializeHeaders(
315
331
  ctx: SerializationContext,
316
332
  node: SerovalHeadersNode,
317
- ) {
333
+ ): Headers {
318
334
  const result = assignIndexedValue(ctx, node.i, new Headers());
335
+ const keys = node.d.k;
336
+ const vals = node.d.v;
319
337
  for (let i = 0, len = node.d.s; i < len; i++) {
320
338
  result.set(
321
- deserializeString(node.d.k[i]),
322
- deserializeTree(ctx, node.d.v[i]) as string,
339
+ deserializeString(keys[i]),
340
+ deserializeTree(ctx, vals[i]) as string,
323
341
  );
324
342
  }
325
343
  return result;
@@ -328,39 +346,41 @@ function deserializeHeaders(
328
346
  function deserializeFormData(
329
347
  ctx: SerializationContext,
330
348
  node: SerovalFormDataNode,
331
- ) {
349
+ ): FormData {
332
350
  const result = assignIndexedValue(ctx, node.i, new FormData());
351
+ const keys = node.d.k;
352
+ const vals = node.d.v;
333
353
  for (let i = 0, len = node.d.s; i < len; i++) {
334
354
  result.set(
335
- deserializeString(node.d.k[i]),
336
- deserializeTree(ctx, node.d.v[i]) as FormDataEntryValue,
355
+ deserializeString(keys[i]),
356
+ deserializeTree(ctx, vals[i]) as FormDataEntryValue,
337
357
  );
338
358
  }
339
359
  return result;
340
360
  }
341
361
 
362
+ function deserializeBoxed(
363
+ ctx: SerializationContext,
364
+ node: SerovalBoxedNode,
365
+ ): unknown {
366
+ return assignIndexedValue(
367
+ ctx,
368
+ node.i,
369
+ Object(deserializeTree(ctx, node.f)),
370
+ );
371
+ }
372
+
342
373
  export default function deserializeTree(
343
374
  ctx: SerializationContext,
344
375
  node: SerovalNode,
345
376
  ): unknown {
346
377
  switch (node.t) {
378
+ case SerovalNodeType.Constant:
379
+ return deserializeConstant(node);
347
380
  case SerovalNodeType.Number:
348
- case SerovalNodeType.Boolean:
349
381
  return node.s;
350
382
  case SerovalNodeType.String:
351
383
  return deserializeString(node.s);
352
- case SerovalNodeType.Undefined:
353
- return undefined;
354
- case SerovalNodeType.Null:
355
- return null;
356
- case SerovalNodeType.NegativeZero:
357
- return -0;
358
- case SerovalNodeType.Infinity:
359
- return Infinity;
360
- case SerovalNodeType.NegativeInfinity:
361
- return -Infinity;
362
- case SerovalNodeType.NaN:
363
- return NaN;
364
384
  case SerovalNodeType.BigInt:
365
385
  return BigInt(node.s);
366
386
  case SerovalNodeType.IndexedValue:
@@ -368,9 +388,8 @@ export default function deserializeTree(
368
388
  case SerovalNodeType.Array:
369
389
  return deserializeArray(ctx, node);
370
390
  case SerovalNodeType.Object:
371
- return deserializeObject(ctx, node);
372
391
  case SerovalNodeType.NullConstructor:
373
- return deserializeNullConstructor(ctx, node);
392
+ return deserializeObject(ctx, node);
374
393
  case SerovalNodeType.Date:
375
394
  return deserializeDate(ctx, node);
376
395
  case SerovalNodeType.RegExp:
@@ -390,8 +409,6 @@ export default function deserializeTree(
390
409
  return deserializeAggregateError(ctx, node);
391
410
  case SerovalNodeType.Error:
392
411
  return deserializeError(ctx, node);
393
- case SerovalNodeType.Iterable:
394
- return deserializeIterable(ctx, node);
395
412
  case SerovalNodeType.Promise:
396
413
  return deserializePromise(ctx, node);
397
414
  case SerovalNodeType.WKSymbol:
@@ -410,7 +427,9 @@ export default function deserializeTree(
410
427
  return deserializeHeaders(ctx, node);
411
428
  case SerovalNodeType.FormData:
412
429
  return deserializeFormData(ctx, node);
430
+ case SerovalNodeType.Boxed:
431
+ return deserializeBoxed(ctx, node);
413
432
  default:
414
- throw new Error('Unsupported type');
433
+ throw new Error('invariant');
415
434
  }
416
435
  }