seroval 0.4.1 → 0.5.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.
@@ -5,7 +5,7 @@ import {
5
5
  ErrorValue,
6
6
  } from '../types';
7
7
 
8
- export function getErrorConstructor(error: ErrorValue) {
8
+ export function getErrorConstructorName(error: ErrorValue) {
9
9
  if (error instanceof EvalError) {
10
10
  return 'EvalError';
11
11
  }
@@ -27,12 +27,26 @@ export function getErrorConstructor(error: ErrorValue) {
27
27
  return 'Error';
28
28
  }
29
29
 
30
+ export function getErrorConstructor(errorName: string) {
31
+ switch (errorName) {
32
+ case 'Error': return Error;
33
+ case 'EvalError': return EvalError;
34
+ case 'RangeError': return RangeError;
35
+ case 'ReferenceError': return ReferenceError;
36
+ case 'SyntaxError': return SyntaxError;
37
+ case 'TypeError': return TypeError;
38
+ case 'URIError': return URIError;
39
+ default:
40
+ throw new Error(`Unknown Error constructor "${errorName}"`);
41
+ }
42
+ }
43
+
30
44
  export function getErrorOptions(
31
45
  ctx: ParserContext,
32
46
  error: Error,
33
47
  ) {
34
48
  let options: Record<string, any> | undefined;
35
- const constructor = getErrorConstructor(error);
49
+ const constructor = getErrorConstructorName(error);
36
50
  // Name has been modified
37
51
  if (error.name !== constructor) {
38
52
  options = { name: error.name };
@@ -99,3 +113,33 @@ export function isIterable(
99
113
  }
100
114
  return Symbol.iterator in value;
101
115
  }
116
+
117
+ export function getTypedArrayConstructor(name: string) {
118
+ switch (name) {
119
+ case 'Int8Array': return Int8Array;
120
+ case 'Int16Array': return Int16Array;
121
+ case 'Int32Array': return Int32Array;
122
+ case 'Uint8Array': return Uint8Array;
123
+ case 'Uint16Array': return Uint16Array;
124
+ case 'Uint32Array': return Uint32Array;
125
+ case 'Uint8ClampedArray': return Uint8ClampedArray;
126
+ case 'Float32Array': return Float32Array;
127
+ case 'Float64Array': return Float64Array;
128
+ case 'BigInt64Array': return BigInt64Array;
129
+ case 'BigUint64Array': return BigUint64Array;
130
+ default:
131
+ throw new Error(`Unknown TypedArray "${name}"`);
132
+ }
133
+ }
134
+
135
+ const IDENTIFIER_CHECK = /^[$A-Z_][0-9A-Z_$]*$/i;
136
+
137
+ export function isValidIdentifier(name: string) {
138
+ const char = name[0];
139
+ return (
140
+ char === '$'
141
+ || char === '_'
142
+ || (char >= 'A' && char <= 'Z')
143
+ || (char >= 'a' && char <= 'z')
144
+ ) && IDENTIFIER_CHECK.test(name);
145
+ }
@@ -0,0 +1,65 @@
1
+ export const enum Symbols {
2
+ AsyncIterator,
3
+ HasInstance,
4
+ IsConcatSpreadable,
5
+ Iterator,
6
+ Match,
7
+ MatchAll,
8
+ Replace,
9
+ Search,
10
+ Species,
11
+ Split,
12
+ ToPrimitive,
13
+ ToStringTag,
14
+ Unscopables
15
+ }
16
+
17
+ export const SYMBOL_STRING: Record<Symbols, string> = {
18
+ [Symbols.AsyncIterator]: 'Symbol.asyncIterator',
19
+ [Symbols.HasInstance]: 'Symbol.hasInstance',
20
+ [Symbols.IsConcatSpreadable]: 'Symbol.isConcatSpreadable',
21
+ [Symbols.Iterator]: 'Symbol.iterator',
22
+ [Symbols.Match]: 'Symbol.match',
23
+ [Symbols.MatchAll]: 'Symbol.matchAll',
24
+ [Symbols.Replace]: 'Symbol.replace',
25
+ [Symbols.Search]: 'Symbol.search',
26
+ [Symbols.Species]: 'Symbol.species',
27
+ [Symbols.Split]: 'Symbol.split',
28
+ [Symbols.ToPrimitive]: 'Symbol.toPrimitive',
29
+ [Symbols.ToStringTag]: 'Symbol.toStringTag',
30
+ [Symbols.Unscopables]: 'Symbol.unscopables',
31
+ };
32
+
33
+ export const INV_SYMBOL_REF = {
34
+ [Symbol.asyncIterator]: Symbols.AsyncIterator,
35
+ [Symbol.hasInstance]: Symbols.HasInstance,
36
+ [Symbol.isConcatSpreadable]: Symbols.IsConcatSpreadable,
37
+ [Symbol.iterator]: Symbols.Iterator,
38
+ [Symbol.match]: Symbols.Match,
39
+ [Symbol.matchAll]: Symbols.MatchAll,
40
+ [Symbol.replace]: Symbols.Replace,
41
+ [Symbol.search]: Symbols.Search,
42
+ [Symbol.species]: Symbols.Species,
43
+ [Symbol.split]: Symbols.Split,
44
+ [Symbol.toPrimitive]: Symbols.ToPrimitive,
45
+ [Symbol.toStringTag]: Symbols.ToStringTag,
46
+ [Symbol.unscopables]: Symbols.Unscopables,
47
+ };
48
+
49
+ export type WellKnownSymbols = keyof typeof INV_SYMBOL_REF;
50
+
51
+ export const SYMBOL_REF: Record<Symbols, WellKnownSymbols> = {
52
+ [Symbols.AsyncIterator]: Symbol.asyncIterator,
53
+ [Symbols.HasInstance]: Symbol.hasInstance,
54
+ [Symbols.IsConcatSpreadable]: Symbol.isConcatSpreadable,
55
+ [Symbols.Iterator]: Symbol.iterator,
56
+ [Symbols.Match]: Symbol.match,
57
+ [Symbols.MatchAll]: Symbol.matchAll,
58
+ [Symbols.Replace]: Symbol.replace,
59
+ [Symbols.Search]: Symbol.search,
60
+ [Symbols.Species]: Symbol.species,
61
+ [Symbols.Split]: Symbol.split,
62
+ [Symbols.ToPrimitive]: Symbol.toPrimitive,
63
+ [Symbols.ToStringTag]: Symbol.toStringTag,
64
+ [Symbols.Unscopables]: Symbol.unscopables,
65
+ };
package/src/tree/sync.ts CHANGED
@@ -1,29 +1,34 @@
1
1
  /* eslint-disable @typescript-eslint/no-use-before-define */
2
2
  import assert from '../assert';
3
3
  import { Feature } from '../compat';
4
- import { createRef, ParserContext } from '../context';
5
- import quote from '../quote';
4
+ import { createRef, getRootID, ParserContext } from '../context';
6
5
  import { BigIntTypedArrayValue, ServerValue, TypedArrayValue } from '../types';
7
6
  import {
8
7
  createBigIntNode,
9
8
  createBigIntTypedArrayNode,
10
9
  createDateNode,
11
- createPrimitiveNode,
10
+ createNumberNode,
12
11
  createReferenceNode,
13
12
  createRegExpNode,
13
+ createStringNode,
14
14
  createTypedArrayNode,
15
+ createWKSymbolNode,
15
16
  FALSE_NODE,
17
+ INFINITY_NODE,
18
+ NAN_NODE,
19
+ NEG_INFINITY_NODE,
16
20
  NEG_ZERO_NODE,
17
21
  NULL_NODE,
18
22
  TRUE_NODE,
19
23
  UNDEFINED_NODE,
20
24
  } from './primitives';
21
25
  import {
22
- getErrorConstructor,
26
+ getErrorConstructorName,
23
27
  getErrorOptions,
24
28
  getIterableOptions,
25
29
  isIterable,
26
30
  } from './shared';
31
+ import { INV_SYMBOL_REF } from './symbols';
27
32
  import {
28
33
  SerovalAggregateErrorNode,
29
34
  SerovalArrayNode,
@@ -72,12 +77,12 @@ function generateArrayNode(
72
77
  t: SerovalNodeType.Array,
73
78
  i: id,
74
79
  s: undefined,
75
- l: undefined,
80
+ l: current.length,
76
81
  c: undefined,
77
82
  m: undefined,
78
83
  d: undefined,
79
84
  a: generateNodeList(ctx, current),
80
- n: undefined,
85
+ f: undefined,
81
86
  };
82
87
  }
83
88
 
@@ -119,7 +124,7 @@ function generateMapNode(
119
124
  m: undefined,
120
125
  d: { k: keyNodes, v: valueNodes, s: len },
121
126
  a: undefined,
122
- n: undefined,
127
+ f: undefined,
123
128
  };
124
129
  }
125
130
 
@@ -150,12 +155,12 @@ function generateSetNode(
150
155
  t: SerovalNodeType.Set,
151
156
  i: id,
152
157
  s: undefined,
153
- l: undefined,
158
+ l: len,
154
159
  c: undefined,
155
160
  m: undefined,
156
161
  d: undefined,
157
162
  a: nodes,
158
- n: undefined,
163
+ f: undefined,
159
164
  };
160
165
  }
161
166
 
@@ -200,21 +205,22 @@ function generateIterableNode(
200
205
  id: number,
201
206
  current: Iterable<ServerValue>,
202
207
  ): SerovalIterableNode {
203
- assert(ctx.features & Feature.SymbolIterator, 'Unsupported type "Iterable"');
208
+ assert(ctx.features & Feature.Symbol, 'Unsupported type "Iterable"');
204
209
  const options = getIterableOptions(current);
210
+ const array = Array.from(current);
205
211
  return {
206
212
  t: SerovalNodeType.Iterable,
207
213
  i: id,
208
214
  s: undefined,
209
- l: undefined,
215
+ l: array.length,
210
216
  c: undefined,
211
217
  m: undefined,
212
218
  // Parse options first before the items
213
219
  d: options
214
220
  ? generateProperties(ctx, options as Record<string, ServerValue>)
215
221
  : undefined,
216
- a: generateNodeList(ctx, Array.from(current)),
217
- n: undefined,
222
+ a: generateNodeList(ctx, array),
223
+ f: undefined,
218
224
  };
219
225
  }
220
226
 
@@ -236,7 +242,7 @@ function generateObjectNode(
236
242
  m: undefined,
237
243
  d: generateProperties(ctx, current),
238
244
  a: undefined,
239
- n: undefined,
245
+ f: undefined,
240
246
  };
241
247
  }
242
248
 
@@ -253,12 +259,12 @@ function generateAggregateErrorNode(
253
259
  t: SerovalNodeType.AggregateError,
254
260
  i: id,
255
261
  s: undefined,
256
- l: undefined,
262
+ l: current.errors.length,
257
263
  c: undefined,
258
264
  m: current.message,
259
265
  d: optionsNode,
260
- a: undefined,
261
- n: parse(ctx, current.errors),
266
+ a: generateNodeList(ctx, current.errors as ServerValue[]),
267
+ f: undefined,
262
268
  };
263
269
  }
264
270
 
@@ -276,11 +282,11 @@ function generateErrorNode(
276
282
  i: id,
277
283
  s: undefined,
278
284
  l: undefined,
279
- c: getErrorConstructor(current),
285
+ c: getErrorConstructorName(current),
280
286
  m: current.message,
281
287
  d: optionsNode,
282
288
  a: undefined,
283
- n: undefined,
289
+ f: undefined,
284
290
  };
285
291
  }
286
292
 
@@ -294,18 +300,21 @@ function parse(
294
300
  case 'undefined':
295
301
  return UNDEFINED_NODE;
296
302
  case 'string':
297
- return createPrimitiveNode(quote(current));
303
+ return createStringNode(current);
298
304
  case 'number':
299
- if (Object.is(current, -0)) {
300
- return NEG_ZERO_NODE;
305
+ switch (current) {
306
+ case Infinity: return INFINITY_NODE;
307
+ case -Infinity: return NEG_INFINITY_NODE;
308
+ default: break;
301
309
  }
302
- if (Object.is(current, Infinity)) {
303
- return createPrimitiveNode('1/0');
310
+ // eslint-disable-next-line no-self-compare
311
+ if (current !== current) {
312
+ return NAN_NODE;
304
313
  }
305
- if (Object.is(current, -Infinity)) {
306
- return createPrimitiveNode('-1/0');
314
+ if (Object.is(current, -0)) {
315
+ return NEG_ZERO_NODE;
307
316
  }
308
- return createPrimitiveNode(current);
317
+ return createNumberNode(current);
309
318
  case 'bigint':
310
319
  return createBigIntNode(ctx, current);
311
320
  case 'object': {
@@ -314,7 +323,7 @@ function parse(
314
323
  }
315
324
  // Non-primitive values needs a reference ID
316
325
  // mostly because the values themselves are stateful
317
- const id = createRef(ctx, current, true);
326
+ const id = createRef(ctx, current);
318
327
  if (ctx.markedRefs.has(id)) {
319
328
  return createReferenceNode(id);
320
329
  }
@@ -363,8 +372,11 @@ function parse(
363
372
  default:
364
373
  break;
365
374
  }
366
- if (current instanceof AggregateError && ctx.features & Feature.AggregateError) {
367
- return generateAggregateErrorNode(ctx, id, current);
375
+ if (current instanceof AggregateError) {
376
+ if (ctx.features & Feature.AggregateError) {
377
+ return generateAggregateErrorNode(ctx, id, current);
378
+ }
379
+ return generateErrorNode(ctx, id, current);
368
380
  }
369
381
  if (current instanceof Error) {
370
382
  return generateErrorNode(ctx, id, current);
@@ -375,6 +387,10 @@ function parse(
375
387
  }
376
388
  throw new Error('Unsupported type');
377
389
  }
390
+ case 'symbol':
391
+ assert(ctx.features & Feature.Symbol, 'Unsupported type "symbol"');
392
+ assert(current in INV_SYMBOL_REF, 'seroval only supports well-known symbols');
393
+ return createWKSymbolNode(current);
378
394
  default:
379
395
  throw new Error('Unsupported type');
380
396
  }
@@ -387,5 +403,5 @@ export default function parseSync(
387
403
  const result = parse(ctx, current);
388
404
  const isObject = result.t === SerovalNodeType.Object
389
405
  || result.t === SerovalNodeType.Iterable;
390
- return [result, createRef(ctx, current, false), isObject] as const;
406
+ return [result, getRootID(ctx, current), isObject] as const;
391
407
  }
package/src/tree/types.ts CHANGED
@@ -1,7 +1,15 @@
1
- import { PrimitiveValue } from '../types';
1
+ import { Symbols } from './symbols';
2
2
 
3
3
  export const enum SerovalNodeType {
4
- Primitive,
4
+ Number,
5
+ String,
6
+ Boolean,
7
+ Null,
8
+ Undefined,
9
+ NegativeZero,
10
+ Infinity,
11
+ NegativeInfinity,
12
+ NaN,
5
13
  BigInt,
6
14
  Reference,
7
15
  Date,
@@ -17,27 +25,28 @@ export const enum SerovalNodeType {
17
25
  Iterable,
18
26
  TypedArray,
19
27
  BigIntTypedArray,
28
+ WKSymbol,
20
29
  }
21
30
 
22
31
  export interface SerovalBaseNode {
23
32
  // Type of the node
24
33
  t: SerovalNodeType;
25
- // Serialized value
26
- s: PrimitiveValue | undefined;
27
34
  // Reference ID
28
35
  i: number | undefined;
36
+ // Serialized value
37
+ s: any;
29
38
  // Size/Byte offset
30
39
  l: number | undefined;
31
- // Constructor name
40
+ // Constructor name / RegExp source
32
41
  c: string | undefined;
42
+ // message /flags
43
+ m: string | undefined;
33
44
  // dictionary
34
45
  d: SerovalDictionaryNode | undefined;
35
- // message
36
- m: string | undefined;
37
- // next node
38
- n: SerovalNode | undefined;
39
46
  // array of nodes
40
47
  a: SerovalNode[] | undefined;
48
+ // fulfilled node
49
+ f: SerovalNode | undefined;
41
50
  }
42
51
 
43
52
  export interface SerovalObjectRecordNode {
@@ -56,10 +65,56 @@ export type SerovalDictionaryNode =
56
65
  | SerovalObjectRecordNode
57
66
  | SerovalMapRecordNode;
58
67
 
59
- export interface SerovalPrimitiveNode extends SerovalBaseNode {
60
- t: SerovalNodeType.Primitive;
68
+ export interface SerovalNumberNode extends SerovalBaseNode {
69
+ t: SerovalNodeType.Number;
70
+ s: number;
71
+ }
72
+
73
+ export interface SerovalStringNode extends SerovalBaseNode {
74
+ t: SerovalNodeType.String;
75
+ s: string;
76
+ }
77
+
78
+ export interface SerovalBooleanNode extends SerovalBaseNode {
79
+ t: SerovalNodeType.Boolean;
80
+ s: boolean;
81
+ }
82
+
83
+ export interface SerovalNullNode extends SerovalBaseNode {
84
+ t: SerovalNodeType.Null;
85
+ }
86
+
87
+ export interface SerovalUndefinedNode extends SerovalBaseNode {
88
+ t: SerovalNodeType.Undefined;
89
+ }
90
+
91
+ export interface SerovalNegativeZeroNode extends SerovalBaseNode {
92
+ t: SerovalNodeType.NegativeZero;
93
+ }
94
+
95
+ export interface SerovalInfinityNode extends SerovalBaseNode {
96
+ t: SerovalNodeType.Infinity;
61
97
  }
62
98
 
99
+ export interface SerovalNegativeInfinityNode extends SerovalBaseNode {
100
+ t: SerovalNodeType.NegativeInfinity;
101
+ }
102
+
103
+ export interface SerovalNaNNode extends SerovalBaseNode {
104
+ t: SerovalNodeType.NaN;
105
+ }
106
+
107
+ export type SerovalPrimitiveNode =
108
+ | SerovalNumberNode
109
+ | SerovalStringNode
110
+ | SerovalBooleanNode
111
+ | SerovalNullNode
112
+ | SerovalUndefinedNode
113
+ | SerovalNegativeZeroNode
114
+ | SerovalNegativeInfinityNode
115
+ | SerovalInfinityNode
116
+ | SerovalNaNNode;
117
+
63
118
  export interface SerovalReferenceNode extends SerovalBaseNode {
64
119
  t: SerovalNodeType.Reference;
65
120
  i: number;
@@ -79,13 +134,16 @@ export interface SerovalDateNode extends SerovalBaseNode {
79
134
  export interface SerovalRegExpNode extends SerovalBaseNode {
80
135
  t: SerovalNodeType.RegExp;
81
136
  i: number;
82
- s: string;
137
+ // source
138
+ c: string;
139
+ // flags
140
+ m: string;
83
141
  }
84
142
 
85
143
  export interface SerovalTypedArrayNode extends SerovalBaseNode {
86
144
  t: SerovalNodeType.TypedArray;
87
145
  i: number;
88
- s: string;
146
+ s: string[];
89
147
  l: number;
90
148
  c: string;
91
149
  }
@@ -93,7 +151,7 @@ export interface SerovalTypedArrayNode extends SerovalBaseNode {
93
151
  export interface SerovalBigIntTypedArrayNode extends SerovalBaseNode {
94
152
  t: SerovalNodeType.BigIntTypedArray;
95
153
  i: number;
96
- s: string;
154
+ s: string[];
97
155
  l: number;
98
156
  c: string;
99
157
  }
@@ -107,6 +165,7 @@ export type SerovalSemiPrimitiveNode =
107
165
 
108
166
  export interface SerovalSetNode extends SerovalBaseNode {
109
167
  t: SerovalNodeType.Set;
168
+ l: number;
110
169
  a: SerovalNode[];
111
170
  i: number;
112
171
  }
@@ -119,6 +178,7 @@ export interface SerovalMapNode extends SerovalBaseNode {
119
178
 
120
179
  export interface SerovalArrayNode extends SerovalBaseNode {
121
180
  t: SerovalNodeType.Array;
181
+ l: number;
122
182
  a: SerovalNode[];
123
183
  i: number;
124
184
  }
@@ -137,7 +197,7 @@ export interface SerovalNullConstructorNode extends SerovalBaseNode {
137
197
 
138
198
  export interface SerovalPromiseNode extends SerovalBaseNode {
139
199
  t: SerovalNodeType.Promise;
140
- n: SerovalNode;
200
+ f: SerovalNode;
141
201
  i: number;
142
202
  }
143
203
 
@@ -153,17 +213,24 @@ export interface SerovalAggregateErrorNode extends SerovalBaseNode {
153
213
  t: SerovalNodeType.AggregateError;
154
214
  m: string;
155
215
  d: SerovalObjectRecordNode | undefined;
156
- n: SerovalNode;
216
+ l: number;
217
+ a: SerovalNode[];
157
218
  i: number;
158
219
  }
159
220
 
160
221
  export interface SerovalIterableNode extends SerovalBaseNode {
161
222
  t: SerovalNodeType.Iterable;
162
223
  d: SerovalObjectRecordNode | undefined;
224
+ l: number;
163
225
  a: SerovalNode[];
164
226
  i: number;
165
227
  }
166
228
 
229
+ export interface SerovalWKSymbolNode extends SerovalBaseNode {
230
+ t: SerovalNodeType.WKSymbol;
231
+ s: Symbols;
232
+ }
233
+
167
234
  export type SerovalNode =
168
235
  | SerovalPrimitiveNode
169
236
  | SerovalReferenceNode
@@ -176,4 +243,5 @@ export type SerovalNode =
176
243
  | SerovalPromiseNode
177
244
  | SerovalErrorNode
178
245
  | SerovalAggregateErrorNode
179
- | SerovalIterableNode;
246
+ | SerovalIterableNode
247
+ | SerovalWKSymbolNode;
package/src/types.ts CHANGED
@@ -1,10 +1,13 @@
1
+ import { WellKnownSymbols } from './tree/symbols';
2
+
1
3
  // Values that are non-recursive
2
4
  export type PrimitiveValue =
3
5
  | boolean
4
6
  | string
5
7
  | number
6
8
  | undefined
7
- | null;
9
+ | null
10
+ | WellKnownSymbols;
8
11
 
9
12
  export type ErrorValue =
10
13
  | Error