seroval 0.8.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +4 -287
  2. package/dist/cjs/development/index.cjs +3858 -1385
  3. package/dist/cjs/development/index.cjs.map +4 -4
  4. package/dist/cjs/production/index.cjs +12 -3
  5. package/dist/esm/development/index.mjs +3611 -1136
  6. package/dist/esm/development/index.mjs.map +4 -4
  7. package/dist/esm/production/index.mjs +12 -3
  8. package/dist/types/core/Serializer.d.ts +14 -0
  9. package/dist/types/{tree → core}/UnsupportedTypeError.d.ts +4 -3
  10. package/dist/types/{assert.d.ts → core/assert.d.ts} +1 -1
  11. package/dist/types/core/assignments.d.ts +33 -0
  12. package/dist/types/core/base-primitives.d.ts +12 -0
  13. package/dist/types/{compat.d.ts → core/compat.d.ts} +22 -22
  14. package/dist/types/core/constants.d.ts +89 -0
  15. package/dist/types/core/context.d.ts +9 -0
  16. package/dist/types/core/cross/async.d.ts +3 -0
  17. package/dist/types/core/cross/context.d.ts +30 -0
  18. package/dist/types/core/cross/index.d.ts +7 -0
  19. package/dist/types/core/cross/primitives.d.ts +9 -0
  20. package/dist/types/core/cross/serialize.d.ts +5 -0
  21. package/dist/types/core/cross/stream.d.ts +3 -0
  22. package/dist/types/core/cross/sync.d.ts +3 -0
  23. package/dist/types/core/cross/web-api.d.ts +4 -0
  24. package/dist/types/{get-identifier.d.ts → core/get-identifier.d.ts} +1 -1
  25. package/dist/types/core/keys.d.ts +12 -0
  26. package/dist/types/{tree/constants.d.ts → core/literals.d.ts} +9 -11
  27. package/dist/types/core/promise-to-result.d.ts +1 -0
  28. package/dist/types/{tree → core}/reference.d.ts +5 -6
  29. package/dist/types/{tree → core}/shared.d.ts +13 -11
  30. package/dist/types/{string.d.ts → core/string.d.ts} +3 -3
  31. package/dist/types/core/tree/async.d.ts +3 -0
  32. package/dist/types/core/tree/context.d.ts +45 -0
  33. package/dist/types/core/tree/deserialize.d.ts +3 -0
  34. package/dist/types/core/tree/index.d.ts +15 -0
  35. package/dist/types/core/tree/primitives.d.ts +9 -0
  36. package/dist/types/core/tree/serialize.d.ts +4 -0
  37. package/dist/types/core/tree/sync.d.ts +3 -0
  38. package/dist/types/core/tree/web-api.d.ts +4 -0
  39. package/dist/types/{tree → core}/types.d.ts +228 -228
  40. package/dist/types/core/web-api.d.ts +4 -0
  41. package/dist/types/index.d.ts +9 -19
  42. package/dist/types/types.d.ts +20 -20
  43. package/package.json +7 -7
  44. package/src/core/Serializer.ts +46 -0
  45. package/src/{tree → core}/UnsupportedTypeError.ts +1 -1
  46. package/src/core/assignments.ts +159 -0
  47. package/src/{tree/primitives.ts → core/base-primitives.ts} +42 -133
  48. package/src/core/constants.ts +169 -0
  49. package/src/core/context.ts +15 -0
  50. package/src/core/cross/async.ts +614 -0
  51. package/src/core/cross/context.ts +79 -0
  52. package/src/core/cross/index.ts +154 -0
  53. package/src/core/cross/primitives.ts +137 -0
  54. package/src/core/cross/serialize.ts +846 -0
  55. package/src/core/cross/stream.ts +740 -0
  56. package/src/core/cross/sync.ts +561 -0
  57. package/src/core/cross/web-api.ts +55 -0
  58. package/src/core/header.js +65 -0
  59. package/src/core/keys.ts +33 -0
  60. package/src/core/literals.ts +28 -0
  61. package/src/core/promise-to-result.ts +9 -0
  62. package/src/{tree → core}/reference.ts +6 -8
  63. package/src/{tree → core}/shared.ts +17 -3
  64. package/src/{tree → core/tree}/async.ts +57 -34
  65. package/src/core/tree/context.ts +136 -0
  66. package/src/{tree → core/tree}/deserialize.ts +83 -54
  67. package/src/core/tree/index.ts +146 -0
  68. package/src/core/tree/primitives.ts +132 -0
  69. package/src/{tree → core/tree}/serialize.ts +124 -178
  70. package/src/{tree → core/tree}/sync.ts +60 -39
  71. package/src/{tree → core/tree}/web-api.ts +10 -50
  72. package/src/{tree → core}/types.ts +82 -54
  73. package/src/core/web-api.ts +51 -0
  74. package/src/index.ts +7 -141
  75. package/src/types.ts +1 -1
  76. package/dist/types/context.d.ts +0 -61
  77. package/dist/types/tree/async.d.ts +0 -3
  78. package/dist/types/tree/deserialize.d.ts +0 -3
  79. package/dist/types/tree/primitives.d.ts +0 -19
  80. package/dist/types/tree/serialize.d.ts +0 -4
  81. package/dist/types/tree/symbols.d.ts +0 -33
  82. package/dist/types/tree/sync.d.ts +0 -3
  83. package/dist/types/tree/web-api.d.ts +0 -6
  84. package/src/context.ts +0 -154
  85. package/src/tree/constants.ts +0 -72
  86. package/src/tree/iterator.ts +0 -14
  87. package/src/tree/symbols.ts +0 -65
  88. /package/src/{assert.ts → core/assert.ts} +0 -0
  89. /package/src/{compat.ts → core/compat.ts} +0 -0
  90. /package/src/{get-identifier.ts → core/get-identifier.ts} +0 -0
  91. /package/src/{string.ts → core/string.ts} +0 -0
@@ -0,0 +1,28 @@
1
+ import { SerovalConstant, SerovalNodeType } from './constants';
2
+ import type { SerovalConstantNode } 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
+ p: undefined,
13
+ e: undefined,
14
+ a: undefined,
15
+ f: undefined,
16
+ b: undefined,
17
+ o: undefined,
18
+ };
19
+ }
20
+
21
+ export const TRUE_NODE = createConstantNode(SerovalConstant.True);
22
+ export const FALSE_NODE = createConstantNode(SerovalConstant.False);
23
+ export const UNDEFINED_NODE = createConstantNode(SerovalConstant.Undefined);
24
+ export const NULL_NODE = createConstantNode(SerovalConstant.Null);
25
+ export const NEG_ZERO_NODE = createConstantNode(SerovalConstant.NegativeZero);
26
+ export const INFINITY_NODE = createConstantNode(SerovalConstant.Infinity);
27
+ export const NEG_INFINITY_NODE = createConstantNode(SerovalConstant.NegativeInfinity);
28
+ export const NAN_NODE = createConstantNode(SerovalConstant.NaN);
@@ -0,0 +1,9 @@
1
+ export default async function promiseToResult(
2
+ current: Promise<unknown>,
3
+ ): Promise<[0 | 1, unknown]> {
4
+ try {
5
+ return [1, await current];
6
+ } catch (e) {
7
+ return [0, e];
8
+ }
9
+ }
@@ -1,6 +1,6 @@
1
- /* eslint-disable @typescript-eslint/no-unnecessary-condition */
2
1
  /* eslint-disable no-restricted-globals */
3
- import assert from '../assert';
2
+ import assert from './assert';
3
+ import { REFERENCES_KEY } from './keys';
4
4
 
5
5
  const REFERENCE = new Map<unknown, string>();
6
6
  const INV_REFERENCE = new Map<string, unknown>();
@@ -29,31 +29,29 @@ export function getReference<T>(id: string): T {
29
29
  return INV_REFERENCE.get(id) as T;
30
30
  }
31
31
 
32
- export const GLOBAL_KEY = '__SEROVAL__';
33
-
34
32
  if (typeof globalThis !== undefined) {
35
- Object.defineProperty(globalThis, GLOBAL_KEY, {
33
+ Object.defineProperty(globalThis, REFERENCES_KEY, {
36
34
  value: INV_REFERENCE,
37
35
  configurable: true,
38
36
  writable: false,
39
37
  enumerable: false,
40
38
  });
41
39
  } else if (typeof window !== undefined) {
42
- Object.defineProperty(window, GLOBAL_KEY, {
40
+ Object.defineProperty(window, REFERENCES_KEY, {
43
41
  value: INV_REFERENCE,
44
42
  configurable: true,
45
43
  writable: false,
46
44
  enumerable: false,
47
45
  });
48
46
  } else if (typeof self !== undefined) {
49
- Object.defineProperty(self, GLOBAL_KEY, {
47
+ Object.defineProperty(self, REFERENCES_KEY, {
50
48
  value: INV_REFERENCE,
51
49
  configurable: true,
52
50
  writable: false,
53
51
  enumerable: false,
54
52
  });
55
53
  } else if (typeof global !== undefined) {
56
- Object.defineProperty(global, GLOBAL_KEY, {
54
+ Object.defineProperty(global, REFERENCES_KEY, {
57
55
  value: INV_REFERENCE,
58
56
  configurable: true,
59
57
  writable: false,
@@ -1,8 +1,9 @@
1
- import { Feature } from '../compat';
2
- import type { ParserContext } from '../context';
1
+ import { Feature } from './compat';
3
2
  import type {
4
3
  ErrorValue,
5
4
  } from '../types';
5
+ import { SerovalObjectFlags } from './constants';
6
+ import type { BaseParserContext } from './context';
6
7
 
7
8
  export function getErrorConstructorName(error: ErrorValue): string {
8
9
  if (error instanceof EvalError) {
@@ -50,7 +51,7 @@ export function getErrorConstructor(errorName: string): ErrorConstructors {
50
51
  }
51
52
 
52
53
  export function getErrorOptions(
53
- ctx: ParserContext,
54
+ ctx: BaseParserContext,
54
55
  error: Error,
55
56
  ): Record<string, unknown> | undefined {
56
57
  let options: Record<string, unknown> | undefined;
@@ -152,3 +153,16 @@ export function isValidIdentifier(name: string): boolean {
152
153
  || (char >= 'a' && char <= 'z')
153
154
  ) && IDENTIFIER_CHECK.test(name);
154
155
  }
156
+
157
+ export function getObjectFlag(obj: unknown): SerovalObjectFlags {
158
+ if (Object.isFrozen(obj)) {
159
+ return SerovalObjectFlags.Frozen;
160
+ }
161
+ if (Object.isSealed(obj)) {
162
+ return SerovalObjectFlags.Sealed;
163
+ }
164
+ if (Object.isExtensible(obj)) {
165
+ return SerovalObjectFlags.None;
166
+ }
167
+ return SerovalObjectFlags.NonExtensible;
168
+ }
@@ -2,43 +2,36 @@
2
2
  /* eslint-disable @typescript-eslint/no-use-before-define */
3
3
  import assert from '../assert';
4
4
  import { Feature } from '../compat';
5
- import type { ParserContext } from '../context';
5
+ import type { ParserContext } from './context';
6
6
  import {
7
7
  createIndexedValue,
8
- } from '../context';
8
+ } from './context';
9
9
  import { serializeString } from '../string';
10
10
  import type {
11
11
  BigIntTypedArrayValue,
12
12
  TypedArrayValue,
13
- } from '../types';
14
- import UnsupportedTypeError from './UnsupportedTypeError';
13
+ } from '../../types';
14
+ import UnsupportedTypeError from '../UnsupportedTypeError';
15
15
  import {
16
16
  TRUE_NODE,
17
17
  FALSE_NODE,
18
18
  UNDEFINED_NODE,
19
19
  NULL_NODE,
20
- } from './constants';
20
+ } from '../literals';
21
21
  import {
22
- createBigIntNode,
23
22
  createBigIntTypedArrayNode,
24
- createDateNode,
25
- createNumberNode,
26
- createIndexedValueNode,
27
- createRegExpNode,
28
- createStringNode,
29
23
  createTypedArrayNode,
30
- createReferenceNode,
31
- createArrayBufferNode,
32
24
  createDataViewNode,
33
25
  createSymbolNode,
34
26
  createFunctionNode,
35
27
  } from './primitives';
36
- import { hasReferenceID } from './reference';
28
+ import { hasReferenceID } from '../reference';
37
29
  import {
38
30
  getErrorConstructorName,
39
31
  getErrorOptions,
32
+ getObjectFlag,
40
33
  isIterable,
41
- } from './shared';
34
+ } from '../shared';
42
35
  import type {
43
36
  SerovalAggregateErrorNode,
44
37
  SerovalArrayNode,
@@ -55,17 +48,27 @@ import type {
55
48
  SerovalPlainRecordNode,
56
49
  SerovalPromiseNode,
57
50
  SerovalSetNode,
58
- } from './types';
51
+ } from '../types';
59
52
  import {
60
- SerovalNodeType,
61
53
  SerovalObjectRecordSpecialKey,
62
- } from './types';
54
+ } from '../types';
63
55
  import {
64
56
  createBlobNode,
65
57
  createFileNode,
66
- createURLNode,
67
- createURLSearchParamsNode,
68
58
  } from './web-api';
59
+ import { SerovalNodeType } from '../constants';
60
+ import {
61
+ createArrayBufferNode,
62
+ createBigIntNode,
63
+ createDateNode,
64
+ createIndexedValueNode,
65
+ createNumberNode,
66
+ createReferenceNode,
67
+ createRegExpNode,
68
+ createStringNode,
69
+ } from '../base-primitives';
70
+ import { createURLNode, createURLSearchParamsNode } from '../web-api';
71
+ import promiseToResult from '../promise-to-result';
69
72
 
70
73
  type ObjectLikeNode =
71
74
  | SerovalObjectNode
@@ -110,10 +113,12 @@ async function generateArrayNode(
110
113
  l: current.length,
111
114
  c: undefined,
112
115
  m: undefined,
113
- d: undefined,
116
+ p: undefined,
117
+ e: undefined,
114
118
  a: await generateNodeList(ctx, current),
115
119
  f: undefined,
116
120
  b: undefined,
121
+ o: getObjectFlag(current),
117
122
  };
118
123
  }
119
124
 
@@ -153,10 +158,12 @@ async function generateMapNode(
153
158
  l: undefined,
154
159
  c: undefined,
155
160
  m: undefined,
156
- d: { k: keyNodes, v: valueNodes, s: len },
161
+ p: undefined,
162
+ e: { k: keyNodes, v: valueNodes, s: len },
157
163
  a: undefined,
158
164
  f: undefined,
159
165
  b: undefined,
166
+ o: undefined,
160
167
  };
161
168
  }
162
169
 
@@ -190,10 +197,12 @@ async function generateSetNode(
190
197
  l: len,
191
198
  c: undefined,
192
199
  m: undefined,
193
- d: undefined,
200
+ p: undefined,
201
+ e: undefined,
194
202
  a: nodes,
195
203
  f: undefined,
196
204
  b: undefined,
205
+ o: undefined,
197
206
  };
198
207
  }
199
208
 
@@ -291,18 +300,20 @@ async function generatePromiseNode(
291
300
  current: Promise<unknown>,
292
301
  ): Promise<SerovalPromiseNode> {
293
302
  assert(ctx.features & Feature.Promise, new UnsupportedTypeError(current));
303
+ const [status, result] = await promiseToResult(current);
294
304
  return {
295
305
  t: SerovalNodeType.Promise,
296
306
  i: id,
297
- s: undefined,
307
+ s: status,
298
308
  l: undefined,
299
309
  c: undefined,
300
310
  m: undefined,
301
- // Parse options first before the items
302
- d: undefined,
311
+ p: undefined,
312
+ e: undefined,
303
313
  a: undefined,
304
- f: await parseAsync(ctx, await current),
314
+ f: await parseAsync(ctx, result),
305
315
  b: undefined,
316
+ o: undefined,
306
317
  };
307
318
  }
308
319
 
@@ -319,10 +330,12 @@ async function generateObjectNode(
319
330
  l: undefined,
320
331
  c: undefined,
321
332
  m: undefined,
322
- d: await generateProperties(ctx, current),
333
+ p: await generateProperties(ctx, current),
334
+ e: undefined,
323
335
  a: undefined,
324
336
  f: undefined,
325
337
  b: undefined,
338
+ o: getObjectFlag(current),
326
339
  };
327
340
  }
328
341
 
@@ -342,10 +355,12 @@ async function generateAggregateErrorNode(
342
355
  l: undefined,
343
356
  c: undefined,
344
357
  m: serializeString(current.message),
345
- d: optionsNode,
358
+ p: optionsNode,
359
+ e: undefined,
346
360
  a: undefined,
347
361
  f: undefined,
348
362
  b: undefined,
363
+ o: undefined,
349
364
  };
350
365
  }
351
366
 
@@ -365,10 +380,12 @@ async function generateErrorNode(
365
380
  l: undefined,
366
381
  c: getErrorConstructorName(current),
367
382
  m: serializeString(current.message),
368
- d: optionsNode,
383
+ p: optionsNode,
384
+ e: undefined,
369
385
  a: undefined,
370
386
  f: undefined,
371
387
  b: undefined,
388
+ o: undefined,
372
389
  };
373
390
  }
374
391
 
@@ -389,10 +406,12 @@ async function generateHeadersNode(
389
406
  l: undefined,
390
407
  c: undefined,
391
408
  m: undefined,
392
- d: await generatePlainProperties(ctx, items),
409
+ p: undefined,
410
+ e: await generatePlainProperties(ctx, items),
393
411
  a: undefined,
394
412
  f: undefined,
395
413
  b: undefined,
414
+ o: undefined,
396
415
  };
397
416
  }
398
417
 
@@ -413,10 +432,12 @@ async function generateFormDataNode(
413
432
  l: undefined,
414
433
  c: undefined,
415
434
  m: undefined,
416
- d: await generatePlainProperties(ctx, items),
435
+ p: undefined,
436
+ e: await generatePlainProperties(ctx, items),
417
437
  a: undefined,
418
438
  f: undefined,
419
439
  b: undefined,
440
+ o: undefined,
420
441
  };
421
442
  }
422
443
 
@@ -432,10 +453,12 @@ async function generateBoxedNode(
432
453
  l: undefined,
433
454
  c: undefined,
434
455
  m: undefined,
435
- d: undefined,
456
+ p: undefined,
457
+ e: undefined,
436
458
  a: undefined,
437
459
  f: await parseAsync(ctx, current.valueOf()),
438
460
  b: undefined,
461
+ o: undefined,
439
462
  };
440
463
  }
441
464
 
@@ -449,7 +472,7 @@ async function parseObject(
449
472
  // Non-primitive values needs a reference ID
450
473
  // mostly because the values themselves are stateful
451
474
  const id = createIndexedValue(ctx, current);
452
- if (ctx.markedRefs.has(id)) {
475
+ if (ctx.reference.marked.has(id)) {
453
476
  return createIndexedValueNode(id);
454
477
  }
455
478
  if (hasReferenceID(current)) {
@@ -0,0 +1,136 @@
1
+ import { ALL_ENABLED } from '../compat';
2
+ import type { BaseParserContext, BaseSerializerContext } from '../context';
3
+ import getIdentifier from '../get-identifier';
4
+
5
+ export interface ParserReference {
6
+ ids: Map<unknown, number>;
7
+ marked: Set<number>;
8
+ }
9
+
10
+ export interface ParserContext extends BaseParserContext {
11
+ reference: ParserReference;
12
+ }
13
+
14
+ export interface ParserOptions {
15
+ disabledFeatures: number;
16
+ }
17
+
18
+ export function createParserContext(options: Partial<ParserOptions> = {}): ParserContext {
19
+ return {
20
+ reference: {
21
+ ids: new Map(),
22
+ marked: new Set(),
23
+ },
24
+ features: ALL_ENABLED ^ (options.disabledFeatures || 0),
25
+ };
26
+ }
27
+
28
+ export interface SerializerReference {
29
+ size: number;
30
+ // Map tree refs to actual refs
31
+ valid: (number | undefined)[];
32
+ // Refs that are...referenced
33
+ marked: Set<number>;
34
+ }
35
+
36
+ export interface SerializerContext extends BaseSerializerContext {
37
+ reference: SerializerReference;
38
+ // Variables
39
+ vars: (string | undefined)[];
40
+ }
41
+
42
+ export interface SerializerOptions {
43
+ markedRefs: number[] | Set<number>;
44
+ features: number;
45
+ }
46
+
47
+ export function createSerializerContext(options: SerializerOptions): SerializerContext {
48
+ return {
49
+ stack: [],
50
+ vars: [],
51
+ assignments: [],
52
+ reference: {
53
+ valid: [],
54
+ size: 0,
55
+ marked: new Set(options.markedRefs),
56
+ },
57
+ features: options.features,
58
+ flags: [],
59
+ };
60
+ }
61
+
62
+ /**
63
+ * Increments the number of references the referenced value has
64
+ */
65
+ export function markRef(
66
+ ctx: ParserContext | SerializerContext,
67
+ current: number,
68
+ ): void {
69
+ ctx.reference.marked.add(current);
70
+ }
71
+ /**
72
+ * Creates the reference param (identifier) from the given reference ID
73
+ * Calling this function means the value has been referenced somewhere
74
+ */
75
+ export function getRefParam(ctx: SerializerContext, index: number): string {
76
+ /**
77
+ * Creates a new reference ID from a given reference ID
78
+ * This new reference ID means that the reference itself
79
+ * has been referenced at least once, and is used to generate
80
+ * the variables
81
+ */
82
+ let actualIndex = ctx.reference.valid[index];
83
+ if (actualIndex == null) {
84
+ actualIndex = ctx.reference.size++;
85
+ ctx.reference.valid[index] = actualIndex;
86
+ }
87
+ let identifier = ctx.vars[actualIndex];
88
+ if (identifier == null) {
89
+ identifier = getIdentifier(actualIndex);
90
+ ctx.vars[actualIndex] = identifier;
91
+ }
92
+ return identifier;
93
+ }
94
+
95
+ export function getRootID<T>(
96
+ ctx: ParserContext,
97
+ current: T,
98
+ ): number {
99
+ const ref = ctx.reference.ids.get(current);
100
+ if (ref == null) {
101
+ return ctx.reference.ids.size;
102
+ }
103
+ return ref;
104
+ }
105
+
106
+ export function createIndexedValue<T>(
107
+ ctx: ParserContext,
108
+ current: T,
109
+ ): number {
110
+ const ref = ctx.reference.ids.get(current);
111
+ if (ref == null) {
112
+ const id = ctx.reference.ids.size;
113
+ ctx.reference.ids.set(current, id);
114
+ return id;
115
+ }
116
+ markRef(ctx, ref);
117
+ return ref;
118
+ }
119
+
120
+ export interface DeserializerContext {
121
+ values: Map<number, unknown>;
122
+ refs: Set<number>;
123
+ }
124
+
125
+ export interface DeserializerOptions {
126
+ markedRefs: number[] | Set<number>;
127
+ }
128
+
129
+ export function createDeserializerContext(
130
+ options: DeserializerOptions,
131
+ ): DeserializerContext {
132
+ return {
133
+ values: new Map(),
134
+ refs: new Set(options.markedRefs),
135
+ };
136
+ }