seroval 0.4.0-alpha.13 → 0.4.0-alpha.15

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,13 +1,7 @@
1
- import { SerializationContext } from '../context';
2
1
  import {
3
2
  AsyncServerValue,
4
3
  ErrorValue,
5
4
  } from '../types';
6
- import {
7
- SerovalNode,
8
- SerovalReferenceNode,
9
- SerovalNodeType,
10
- } from './types';
11
5
 
12
6
  export function getErrorConstructor(error: ErrorValue) {
13
7
  if (error instanceof EvalError) {
@@ -66,13 +60,6 @@ export function getIterableOptions(obj: Iterable<any>) {
66
60
  return undefined;
67
61
  }
68
62
 
69
- export function isReferenceInStack(
70
- ctx: SerializationContext,
71
- node: SerovalNode,
72
- ): node is SerovalReferenceNode {
73
- return node.t === SerovalNodeType.Reference && ctx.stack.includes(node.i);
74
- }
75
-
76
63
  export function isIterable(
77
64
  value: unknown,
78
65
  ): value is Iterable<AsyncServerValue> {
package/src/tree/sync.ts CHANGED
@@ -5,9 +5,14 @@ import { createRef, ParserContext } from '../context';
5
5
  import quote from '../quote';
6
6
  import { BigIntTypedArrayValue, ServerValue, TypedArrayValue } from '../types';
7
7
  import {
8
+ createBigIntNode,
9
+ createBigIntTypedArrayNode,
10
+ createDateNode,
11
+ createPrimitiveNode,
12
+ createReferenceNode,
13
+ createRegExpNode,
14
+ createTypedArrayNode,
8
15
  FALSE_NODE,
9
- INFINITY_NODE,
10
- NEG_INFINITY_NODE,
11
16
  NEG_ZERO_NODE,
12
17
  NULL_NODE,
13
18
  TRUE_NODE,
@@ -22,35 +27,21 @@ import {
22
27
  import {
23
28
  SerovalAggregateErrorNode,
24
29
  SerovalArrayNode,
25
- SerovalBigIntNode,
26
- SerovalBigIntTypedArrayNode,
27
- SerovalDateNode,
28
30
  SerovalErrorNode,
29
31
  SerovalIterableNode,
30
32
  SerovalMapNode,
31
- SerovalMapRecordNode,
32
33
  SerovalNode,
33
34
  SerovalNodeType,
34
35
  SerovalNullConstructorNode,
35
36
  SerovalObjectNode,
36
37
  SerovalObjectRecordNode,
37
- SerovalPrimitiveNode,
38
- SerovalReferenceNode,
39
- SerovalRegExpNode,
40
38
  SerovalSetNode,
41
- SerovalTypedArrayNode,
42
39
  } from './types';
43
40
 
44
41
  type ObjectLikeNode = SerovalObjectNode | SerovalNullConstructorNode | SerovalIterableNode;
45
42
 
46
43
  class SyncParser {
47
- ctx: ParserContext;
48
-
49
- constructor(ctx: ParserContext) {
50
- this.ctx = ctx;
51
- }
52
-
53
- generateNodeList(current: ServerValue[]) {
44
+ static generateNodeList(ctx: ParserContext, current: ServerValue[]) {
54
45
  const size = current.length;
55
46
  const nodes = new Array<SerovalNode>(size);
56
47
  const deferred = new Array<ServerValue>(size);
@@ -61,27 +52,42 @@ class SyncParser {
61
52
  if (isIterable(item)) {
62
53
  deferred[i] = item;
63
54
  } else {
64
- nodes[i] = this.parse(item);
55
+ nodes[i] = this.parse(ctx, item);
65
56
  }
66
57
  }
67
58
  }
68
59
  for (let i = 0; i < size; i++) {
69
60
  if (i in deferred) {
70
- nodes[i] = this.parse(deferred[i]);
61
+ nodes[i] = this.parse(ctx, deferred[i]);
71
62
  }
72
63
  }
73
64
  return nodes;
74
65
  }
75
66
 
76
- generateArrayNode(id: number, current: ServerValue[]): SerovalArrayNode {
77
- return new SerovalArrayNode(id, this.generateNodeList(current));
67
+ static generateArrayNode(
68
+ ctx: ParserContext,
69
+ id: number,
70
+ current: ServerValue[],
71
+ ): SerovalArrayNode {
72
+ return {
73
+ t: SerovalNodeType.Array,
74
+ i: id,
75
+ s: undefined,
76
+ l: undefined,
77
+ c: undefined,
78
+ m: undefined,
79
+ d: undefined,
80
+ a: this.generateNodeList(ctx, current),
81
+ n: undefined,
82
+ };
78
83
  }
79
84
 
80
- generateMapNode(
85
+ static generateMapNode(
86
+ ctx: ParserContext,
81
87
  id: number,
82
88
  current: Map<ServerValue, ServerValue>,
83
89
  ): SerovalMapNode {
84
- assert(this.ctx.features & Feature.Map, 'Unsupported type "Map"');
90
+ assert(ctx.features & Feature.Map, 'Unsupported type "Map"');
85
91
  const len = current.size;
86
92
  const keyNodes = new Array<SerovalNode>(len);
87
93
  const valueNodes = new Array<SerovalNode>(len);
@@ -96,23 +102,34 @@ class SyncParser {
96
102
  deferredValue[deferredSize] = value;
97
103
  deferredSize++;
98
104
  } else {
99
- keyNodes[nodeSize] = this.parse(key);
100
- valueNodes[nodeSize] = this.parse(value);
105
+ keyNodes[nodeSize] = this.parse(ctx, key);
106
+ valueNodes[nodeSize] = this.parse(ctx, value);
101
107
  nodeSize++;
102
108
  }
103
109
  }
104
110
  for (let i = 0; i < deferredSize; i++) {
105
- keyNodes[nodeSize + i] = this.parse(deferredKey[i]);
106
- valueNodes[nodeSize + i] = this.parse(deferredValue[i]);
111
+ keyNodes[nodeSize + i] = this.parse(ctx, deferredKey[i]);
112
+ valueNodes[nodeSize + i] = this.parse(ctx, deferredValue[i]);
107
113
  }
108
- return new SerovalMapNode(id, new SerovalMapRecordNode(keyNodes, valueNodes, len));
114
+ return {
115
+ t: SerovalNodeType.Map,
116
+ i: id,
117
+ s: undefined,
118
+ l: undefined,
119
+ c: undefined,
120
+ m: undefined,
121
+ d: { k: keyNodes, v: valueNodes, s: len },
122
+ a: undefined,
123
+ n: undefined,
124
+ };
109
125
  }
110
126
 
111
- generateSetNode(
127
+ static generateSetNode(
128
+ ctx: ParserContext,
112
129
  id: number,
113
130
  current: Set<ServerValue>,
114
131
  ): SerovalSetNode {
115
- assert(this.ctx.features & Feature.Set, 'Unsupported type "Set"');
132
+ assert(ctx.features & Feature.Set, 'Unsupported type "Set"');
116
133
  const len = current.size;
117
134
  const nodes = new Array<SerovalNode>(len);
118
135
  const deferred = new Array<ServerValue>(len);
@@ -123,17 +140,30 @@ class SyncParser {
123
140
  if (isIterable(item)) {
124
141
  deferred[deferredSize++] = item;
125
142
  } else {
126
- nodes[nodeSize++] = this.parse(item);
143
+ nodes[nodeSize++] = this.parse(ctx, item);
127
144
  }
128
145
  }
129
146
  // Parse deferred items
130
147
  for (let i = 0; i < deferredSize; i++) {
131
- nodes[nodeSize + i] = this.parse(deferred[i]);
148
+ nodes[nodeSize + i] = this.parse(ctx, deferred[i]);
132
149
  }
133
- return new SerovalSetNode(id, nodes);
150
+ return {
151
+ t: SerovalNodeType.Set,
152
+ i: id,
153
+ s: undefined,
154
+ l: undefined,
155
+ c: undefined,
156
+ m: undefined,
157
+ d: undefined,
158
+ a: nodes,
159
+ n: undefined,
160
+ };
134
161
  }
135
162
 
136
- generateProperties(properties: Record<string, ServerValue>): SerovalObjectRecordNode {
163
+ static generateProperties(
164
+ ctx: ParserContext,
165
+ properties: Record<string, ServerValue>,
166
+ ): SerovalObjectRecordNode {
137
167
  const keys = Object.keys(properties);
138
168
  const size = keys.length;
139
169
  const keyNodes = new Array<string>(size);
@@ -151,13 +181,13 @@ class SyncParser {
151
181
  deferredSize++;
152
182
  } else {
153
183
  keyNodes[nodesSize] = key;
154
- valueNodes[nodesSize] = this.parse(item);
184
+ valueNodes[nodesSize] = this.parse(ctx, item);
155
185
  nodesSize++;
156
186
  }
157
187
  }
158
188
  for (let i = 0; i < deferredSize; i++) {
159
189
  keyNodes[nodesSize + i] = deferredKeys[i];
160
- valueNodes[nodesSize + i] = this.parse(deferredValues[i]);
190
+ valueNodes[nodesSize + i] = this.parse(ctx, deferredValues[i]);
161
191
  }
162
192
  return {
163
193
  k: keyNodes,
@@ -166,103 +196,137 @@ class SyncParser {
166
196
  };
167
197
  }
168
198
 
169
- generateIterableNode(
199
+ static generateIterableNode(
200
+ ctx: ParserContext,
170
201
  id: number,
171
202
  current: Iterable<ServerValue>,
172
203
  ): SerovalIterableNode {
173
- assert(this.ctx.features & Feature.SymbolIterator, 'Unsupported type "Iterable"');
204
+ assert(ctx.features & Feature.SymbolIterator, 'Unsupported type "Iterable"');
174
205
  const options = getIterableOptions(current);
175
- return new SerovalIterableNode(
176
- id,
206
+ return {
207
+ t: SerovalNodeType.Iterable,
208
+ i: id,
209
+ s: undefined,
210
+ l: undefined,
211
+ c: undefined,
212
+ m: undefined,
177
213
  // Parse options first before the items
178
- options
179
- ? this.generateProperties(options as Record<string, ServerValue>)
214
+ d: options
215
+ ? this.generateProperties(ctx, options as Record<string, ServerValue>)
180
216
  : undefined,
181
- this.generateNodeList(Array.from(current)),
182
- );
217
+ a: this.generateNodeList(ctx, Array.from(current)),
218
+ n: undefined,
219
+ };
183
220
  }
184
221
 
185
- generateObjectNode(
222
+ static generateObjectNode(
223
+ ctx: ParserContext,
186
224
  id: number,
187
225
  current: Record<string, ServerValue> | Iterable<ServerValue>,
188
226
  empty: boolean,
189
227
  ): ObjectLikeNode {
190
228
  if (Symbol.iterator in current) {
191
- return this.generateIterableNode(id, current);
192
- }
193
- if (empty) {
194
- return new SerovalNullConstructorNode(id, this.generateProperties(current));
229
+ return this.generateIterableNode(ctx, id, current);
195
230
  }
196
- return new SerovalObjectNode(id, this.generateProperties(current));
231
+ return {
232
+ t: empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,
233
+ i: id,
234
+ s: undefined,
235
+ l: undefined,
236
+ c: undefined,
237
+ m: undefined,
238
+ d: this.generateProperties(ctx, current),
239
+ a: undefined,
240
+ n: undefined,
241
+ };
197
242
  }
198
243
 
199
- generateAggregateErrorNode(
244
+ static generateAggregateErrorNode(
245
+ ctx: ParserContext,
200
246
  id: number,
201
247
  current: AggregateError,
202
248
  ): SerovalAggregateErrorNode {
203
249
  const options = getErrorOptions(current);
204
250
  const optionsNode = options
205
- ? this.generateProperties(options)
251
+ ? this.generateProperties(ctx, options)
206
252
  : undefined;
207
- return new SerovalAggregateErrorNode(
208
- id,
209
- current.message,
210
- optionsNode,
211
- this.parse(current.errors),
212
- );
253
+ return {
254
+ t: SerovalNodeType.AggregateError,
255
+ i: id,
256
+ s: undefined,
257
+ l: undefined,
258
+ c: undefined,
259
+ m: current.message,
260
+ d: optionsNode,
261
+ a: undefined,
262
+ n: this.parse(ctx, current.errors),
263
+ };
213
264
  }
214
265
 
215
- generateErrorNode(
266
+ static generateErrorNode(
267
+ ctx: ParserContext,
216
268
  id: number,
217
269
  current: Error,
218
270
  ): SerovalErrorNode {
219
271
  const options = getErrorOptions(current);
220
272
  const optionsNode = options
221
- ? this.generateProperties(options)
273
+ ? this.generateProperties(ctx, options)
222
274
  : undefined;
223
- return new SerovalErrorNode(id, getErrorConstructor(current), current.message, optionsNode);
275
+ return {
276
+ t: SerovalNodeType.Error,
277
+ i: id,
278
+ s: undefined,
279
+ l: undefined,
280
+ c: getErrorConstructor(current),
281
+ m: current.message,
282
+ d: optionsNode,
283
+ a: undefined,
284
+ n: undefined,
285
+ };
224
286
  }
225
287
 
226
- parse(current: ServerValue): SerovalNode {
288
+ static parse(
289
+ ctx: ParserContext,
290
+ current: ServerValue,
291
+ ): SerovalNode {
227
292
  switch (typeof current) {
228
293
  case 'boolean':
229
294
  return current ? TRUE_NODE : FALSE_NODE;
230
295
  case 'undefined':
231
296
  return UNDEFINED_NODE;
232
297
  case 'string':
233
- return new SerovalPrimitiveNode(quote(current));
298
+ return createPrimitiveNode(quote(current));
234
299
  case 'number':
235
300
  if (Object.is(current, -0)) {
236
301
  return NEG_ZERO_NODE;
237
302
  }
238
303
  if (Object.is(current, Infinity)) {
239
- return INFINITY_NODE;
304
+ return createPrimitiveNode('1/0');
240
305
  }
241
306
  if (Object.is(current, -Infinity)) {
242
- return NEG_INFINITY_NODE;
307
+ return createPrimitiveNode('-1/0');
243
308
  }
244
- return new SerovalPrimitiveNode(current);
309
+ return createPrimitiveNode(current);
245
310
  case 'bigint':
246
- assert(this.ctx.features & Feature.BigInt, 'Unsupported type "BigInt"');
247
- return new SerovalBigIntNode(current);
311
+ return createBigIntNode(ctx, current);
248
312
  case 'object': {
249
313
  if (!current) {
250
314
  return NULL_NODE;
251
315
  }
252
316
  // Non-primitive values needs a reference ID
253
317
  // mostly because the values themselves are stateful
254
- const id = createRef(this.ctx, current, true);
255
- if (this.ctx.markedRefs[id]) {
256
- return new SerovalReferenceNode(id);
318
+ const id = createRef(ctx, current, true);
319
+ if (ctx.markedRefs.has(id)) {
320
+ return createReferenceNode(id);
257
321
  }
258
322
  if (Array.isArray(current)) {
259
- return this.generateArrayNode(id, current);
323
+ return this.generateArrayNode(ctx, id, current);
260
324
  }
261
325
  switch (current.constructor) {
262
326
  case Date:
263
- return new SerovalDateNode(id, current as Date);
327
+ return createDateNode(id, current as Date);
264
328
  case RegExp:
265
- return new SerovalRegExpNode(id, current as RegExp);
329
+ return createRegExpNode(id, current as RegExp);
266
330
  case Int8Array:
267
331
  case Int16Array:
268
332
  case Int32Array:
@@ -272,28 +336,23 @@ class SyncParser {
272
336
  case Uint8ClampedArray:
273
337
  case Float32Array:
274
338
  case Float64Array:
275
- assert(this.ctx.features & Feature.TypedArray, `Unsupported value type "${current.constructor.name}"`);
276
- return new SerovalTypedArrayNode(id, current as TypedArrayValue);
339
+ return createTypedArrayNode(ctx, id, current as TypedArrayValue);
277
340
  case BigInt64Array:
278
341
  case BigUint64Array:
279
- assert(
280
- this.ctx.features & (Feature.BigIntTypedArray),
281
- `Unsupported value type "${current.constructor.name}"`,
282
- );
283
- return new SerovalBigIntTypedArrayNode(id, current as BigIntTypedArrayValue);
342
+ return createBigIntTypedArrayNode(ctx, id, current as BigIntTypedArrayValue);
284
343
  case Map:
285
- return this.generateMapNode(id, current as Map<ServerValue, ServerValue>);
344
+ return this.generateMapNode(ctx, id, current as Map<ServerValue, ServerValue>);
286
345
  case Set:
287
- return this.generateSetNode(id, current as Set<ServerValue>);
346
+ return this.generateSetNode(ctx, id, current as Set<ServerValue>);
288
347
  case Object:
289
- return this.generateObjectNode(id, current as Record<string, ServerValue>, false);
348
+ return this.generateObjectNode(ctx, id, current as Record<string, ServerValue>, false);
290
349
  case undefined:
291
- return this.generateObjectNode(id, current as Record<string, ServerValue>, true);
350
+ return this.generateObjectNode(ctx, id, current as Record<string, ServerValue>, true);
292
351
  case AggregateError:
293
- if (this.ctx.features & Feature.AggregateError) {
294
- return this.generateAggregateErrorNode(id, current as AggregateError);
352
+ if (ctx.features & Feature.AggregateError) {
353
+ return this.generateAggregateErrorNode(ctx, id, current as AggregateError);
295
354
  }
296
- return this.generateErrorNode(id, current as AggregateError);
355
+ return this.generateErrorNode(ctx, id, current as AggregateError);
297
356
  case Error:
298
357
  case EvalError:
299
358
  case RangeError:
@@ -301,19 +360,19 @@ class SyncParser {
301
360
  case SyntaxError:
302
361
  case TypeError:
303
362
  case URIError:
304
- return this.generateErrorNode(id, current as Error);
363
+ return this.generateErrorNode(ctx, id, current as Error);
305
364
  default:
306
365
  break;
307
366
  }
308
- if (current instanceof AggregateError && this.ctx.features & Feature.AggregateError) {
309
- return this.generateAggregateErrorNode(id, current);
367
+ if (current instanceof AggregateError && ctx.features & Feature.AggregateError) {
368
+ return this.generateAggregateErrorNode(ctx, id, current);
310
369
  }
311
370
  if (current instanceof Error) {
312
- return this.generateErrorNode(id, current);
371
+ return this.generateErrorNode(ctx, id, current);
313
372
  }
314
373
  // Generator functions don't have a global constructor
315
374
  if (Symbol.iterator in current) {
316
- return this.generateIterableNode(id, current);
375
+ return this.generateIterableNode(ctx, id, current);
317
376
  }
318
377
  throw new Error('Unsupported type');
319
378
  }
@@ -327,7 +386,7 @@ export default function parseSync(
327
386
  ctx: ParserContext,
328
387
  current: ServerValue,
329
388
  ) {
330
- const result = new SyncParser(ctx).parse(current);
389
+ const result = SyncParser.parse(ctx, current);
331
390
  const isObject = result.t === SerovalNodeType.Object
332
391
  || result.t === SerovalNodeType.Iterable;
333
392
  return [result, createRef(ctx, current, false), isObject] as const;