seroval 0.4.0 → 0.5.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.
@@ -0,0 +1,288 @@
1
+ /* eslint-disable @typescript-eslint/no-use-before-define */
2
+ import {
3
+ SerializationContext,
4
+ } from '../context';
5
+ import { invQuote } from '../quote';
6
+ import { AsyncServerValue } from '../types';
7
+ import { getErrorConstructor, getTypedArrayConstructor } from './shared';
8
+ import { SYMBOL_REF } from './symbols';
9
+ import {
10
+ SerovalAggregateErrorNode,
11
+ SerovalArrayNode,
12
+ SerovalBigIntTypedArrayNode,
13
+ SerovalErrorNode,
14
+ SerovalIterableNode,
15
+ SerovalMapNode,
16
+ SerovalNode,
17
+ SerovalNodeType,
18
+ SerovalNullConstructorNode,
19
+ SerovalObjectNode,
20
+ SerovalObjectRecordNode,
21
+ SerovalPromiseNode,
22
+ SerovalSetNode,
23
+ SerovalTypedArrayNode,
24
+ } from './types';
25
+
26
+ function assignRef<T extends AsyncServerValue>(
27
+ ctx: SerializationContext,
28
+ index: number,
29
+ value: T,
30
+ ) {
31
+ ctx.valueMap.set(index, value);
32
+ return value;
33
+ }
34
+
35
+ function deserializeNodeList(
36
+ ctx: SerializationContext,
37
+ node: SerovalArrayNode | SerovalIterableNode | SerovalAggregateErrorNode,
38
+ result: AsyncServerValue[],
39
+ ) {
40
+ let item: SerovalNode;
41
+ for (let i = 0, len = node.a.length; i < len; i++) {
42
+ item = node.a[i];
43
+ if (item) {
44
+ result[i] = deserializeTree(ctx, item);
45
+ }
46
+ }
47
+ return result;
48
+ }
49
+
50
+ function deserializeArray(
51
+ ctx: SerializationContext,
52
+ node: SerovalArrayNode,
53
+ ) {
54
+ const result: AsyncServerValue[] = assignRef(
55
+ ctx,
56
+ node.i,
57
+ new Array<AsyncServerValue>(node.l),
58
+ );
59
+ ctx.stack.push(node.i);
60
+ deserializeNodeList(ctx, node, result);
61
+ ctx.stack.pop();
62
+ return result;
63
+ }
64
+
65
+ function deserializeProperties(
66
+ ctx: SerializationContext,
67
+ node: SerovalObjectRecordNode,
68
+ result: Record<string, AsyncServerValue>,
69
+ ) {
70
+ if (node.s === 0) {
71
+ return {};
72
+ }
73
+ for (let i = 0; i < node.s; i++) {
74
+ result[node.k[i]] = deserializeTree(ctx, node.v[i]);
75
+ }
76
+ return result;
77
+ }
78
+
79
+ function deserializeNullConstructor(
80
+ ctx: SerializationContext,
81
+ node: SerovalNullConstructorNode,
82
+ ) {
83
+ const result = assignRef(ctx, node.i, Object.create(null) as Record<string, AsyncServerValue>);
84
+ ctx.stack.push(node.i);
85
+ deserializeProperties(ctx, node.d, result);
86
+ ctx.stack.pop();
87
+ return result;
88
+ }
89
+
90
+ function deserializeObject(
91
+ ctx: SerializationContext,
92
+ node: SerovalObjectNode,
93
+ ) {
94
+ const result = assignRef(ctx, node.i, {} as Record<string, AsyncServerValue>);
95
+ ctx.stack.push(node.i);
96
+ deserializeProperties(ctx, node.d, result);
97
+ ctx.stack.pop();
98
+ return result;
99
+ }
100
+
101
+ function deserializeSet(
102
+ ctx: SerializationContext,
103
+ node: SerovalSetNode,
104
+ ) {
105
+ const result = assignRef(ctx, node.i, new Set<AsyncServerValue>());
106
+ ctx.stack.push(node.i);
107
+ for (let i = 0, len = node.a.length; i < len; i++) {
108
+ result.add(deserializeTree(ctx, node.a[i]));
109
+ }
110
+ ctx.stack.pop();
111
+ return result;
112
+ }
113
+
114
+ function deserializeMap(
115
+ ctx: SerializationContext,
116
+ node: SerovalMapNode,
117
+ ) {
118
+ const result = assignRef(
119
+ ctx,
120
+ node.i,
121
+ new Map<AsyncServerValue, AsyncServerValue>(),
122
+ );
123
+ ctx.stack.push(node.i);
124
+ for (let i = 0; i < node.d.s; i++) {
125
+ result.set(
126
+ deserializeTree(ctx, node.d.k[i]),
127
+ deserializeTree(ctx, node.d.v[i]),
128
+ );
129
+ }
130
+ ctx.stack.pop();
131
+ return result;
132
+ }
133
+
134
+ type AssignableValue = AggregateError | Error | Iterable<AsyncServerValue>
135
+ type AssignableNode = SerovalAggregateErrorNode | SerovalErrorNode | SerovalIterableNode;
136
+
137
+ function deserializeDictionary<T extends AssignableValue>(
138
+ ctx: SerializationContext,
139
+ node: AssignableNode,
140
+ result: T,
141
+ ) {
142
+ if (node.d) {
143
+ ctx.stack.push(node.i);
144
+ const fields = deserializeProperties(ctx, node.d, {});
145
+ ctx.stack.pop();
146
+ Object.assign(result, fields);
147
+ }
148
+ return result;
149
+ }
150
+
151
+ function deserializeAggregateError(
152
+ ctx: SerializationContext,
153
+ node: SerovalAggregateErrorNode,
154
+ ) {
155
+ // Serialize the required arguments
156
+ const result = assignRef(ctx, node.i, new AggregateError([], node.m));
157
+ ctx.stack.push(node.i);
158
+ result.errors = deserializeNodeList(ctx, node, new Array<AsyncServerValue>(node.l));
159
+ ctx.stack.pop();
160
+ // `AggregateError` might've been extended
161
+ // either through class or custom properties
162
+ // Make sure to assign extra properties
163
+ return deserializeDictionary(ctx, node, result);
164
+ }
165
+
166
+ function deserializeError(
167
+ ctx: SerializationContext,
168
+ node: SerovalErrorNode,
169
+ ) {
170
+ const ErrorConstructor = getErrorConstructor(node.c);
171
+ const result = assignRef(ctx, node.i, new ErrorConstructor(node.m));
172
+ return deserializeDictionary(ctx, node, result);
173
+ }
174
+
175
+ interface Deferred {
176
+ resolve(value: AsyncServerValue): void;
177
+ promise: Promise<AsyncServerValue>;
178
+ }
179
+
180
+ function createDeferred(): Deferred {
181
+ let resolver: Deferred['resolve'];
182
+ return {
183
+ resolve(v) {
184
+ resolver(v);
185
+ },
186
+ promise: new Promise((res) => {
187
+ resolver = res as Deferred['resolve'];
188
+ }),
189
+ };
190
+ }
191
+
192
+ function deserializePromise(
193
+ ctx: SerializationContext,
194
+ node: SerovalPromiseNode,
195
+ ) {
196
+ const deferred = createDeferred();
197
+ const result = assignRef(ctx, node.i, deferred.promise);
198
+ deferred.resolve(deserializeTree(ctx, node.n));
199
+ return result;
200
+ }
201
+
202
+ function deserializeTypedArray(
203
+ ctx: SerializationContext,
204
+ node: SerovalTypedArrayNode | SerovalBigIntTypedArrayNode,
205
+ ) {
206
+ const TypedArray = getTypedArrayConstructor(node.c);
207
+ const dummy = new TypedArray();
208
+ const result = assignRef(ctx, node.i, new TypedArray(
209
+ dummy.buffer,
210
+ node.l,
211
+ ));
212
+ for (let i = 0, len = node.s.length; i < len; i++) {
213
+ result[i] = node.t === SerovalNodeType.BigIntTypedArray
214
+ ? BigInt(node.s[i])
215
+ : Number(node.s[i]);
216
+ }
217
+ return result;
218
+ }
219
+
220
+ function deserializeIterable(
221
+ ctx: SerializationContext,
222
+ node: SerovalIterableNode,
223
+ ) {
224
+ const values: AsyncServerValue[] = [];
225
+ deserializeNodeList(ctx, node, values);
226
+ const result = assignRef(ctx, node.i, {
227
+ [Symbol.iterator]: () => values.values(),
228
+ });
229
+ return deserializeDictionary(ctx, node, result);
230
+ }
231
+
232
+ export default function deserializeTree(
233
+ ctx: SerializationContext,
234
+ node: SerovalNode,
235
+ ): AsyncServerValue {
236
+ switch (node.t) {
237
+ case SerovalNodeType.Number:
238
+ case SerovalNodeType.Boolean:
239
+ return node.s;
240
+ case SerovalNodeType.String:
241
+ return invQuote(node.s);
242
+ case SerovalNodeType.Undefined:
243
+ return undefined;
244
+ case SerovalNodeType.Null:
245
+ return null;
246
+ case SerovalNodeType.NegativeZero:
247
+ return -0;
248
+ case SerovalNodeType.Infinity:
249
+ return Infinity;
250
+ case SerovalNodeType.NegativeInfinity:
251
+ return -Infinity;
252
+ case SerovalNodeType.NaN:
253
+ return NaN;
254
+ case SerovalNodeType.BigInt:
255
+ return BigInt(node.s);
256
+ case SerovalNodeType.Reference:
257
+ return ctx.valueMap.get(node.i);
258
+ case SerovalNodeType.Array:
259
+ return deserializeArray(ctx, node);
260
+ case SerovalNodeType.Object:
261
+ return deserializeObject(ctx, node);
262
+ case SerovalNodeType.NullConstructor:
263
+ return deserializeNullConstructor(ctx, node);
264
+ case SerovalNodeType.Date:
265
+ return assignRef(ctx, node.i, new Date(node.s));
266
+ case SerovalNodeType.RegExp:
267
+ return assignRef(ctx, node.i, new RegExp(node.c, node.m));
268
+ case SerovalNodeType.Set:
269
+ return deserializeSet(ctx, node);
270
+ case SerovalNodeType.Map:
271
+ return deserializeMap(ctx, node);
272
+ case SerovalNodeType.BigIntTypedArray:
273
+ case SerovalNodeType.TypedArray:
274
+ return deserializeTypedArray(ctx, node);
275
+ case SerovalNodeType.AggregateError:
276
+ return deserializeAggregateError(ctx, node);
277
+ case SerovalNodeType.Error:
278
+ return deserializeError(ctx, node);
279
+ case SerovalNodeType.Iterable:
280
+ return deserializeIterable(ctx, node);
281
+ case SerovalNodeType.Promise:
282
+ return deserializePromise(ctx, node);
283
+ case SerovalNodeType.WKSymbol:
284
+ return SYMBOL_REF[node.s];
285
+ default:
286
+ throw new Error('Unsupported type');
287
+ }
288
+ }
@@ -0,0 +1,14 @@
1
+ export default function createIterator<T>(
2
+ values: Array<T>,
3
+ ): Iterator<T> {
4
+ let index = 0;
5
+ const len = values.length;
6
+ return {
7
+ next() {
8
+ return {
9
+ value: values[index++],
10
+ done: index >= len,
11
+ };
12
+ },
13
+ };
14
+ }
@@ -1,23 +1,121 @@
1
1
  import assert from '../assert';
2
2
  import { Feature } from '../compat';
3
3
  import { ParserContext } from '../context';
4
+ import quote from '../quote';
4
5
  import { BigIntTypedArrayValue, TypedArrayValue } from '../types';
6
+ import { INV_SYMBOL_REF, WellKnownSymbols } from './symbols';
5
7
  import {
6
8
  SerovalBigIntNode,
7
9
  SerovalBigIntTypedArrayNode,
10
+ SerovalBooleanNode,
8
11
  SerovalDateNode,
12
+ SerovalInfinityNode,
13
+ SerovalNaNNode,
14
+ SerovalNegativeInfinityNode,
15
+ SerovalNegativeZeroNode,
9
16
  SerovalNodeType,
10
- SerovalPrimitiveNode,
17
+ SerovalNullNode,
18
+ SerovalNumberNode,
11
19
  SerovalReferenceNode,
12
20
  SerovalRegExpNode,
21
+ SerovalStringNode,
13
22
  SerovalTypedArrayNode,
23
+ SerovalUndefinedNode,
24
+ SerovalWKSymbolNode,
14
25
  } from './types';
15
26
 
16
- export function createPrimitiveNode(
17
- value: string | number | null,
18
- ): SerovalPrimitiveNode {
27
+ export const TRUE_NODE: SerovalBooleanNode = {
28
+ t: SerovalNodeType.Boolean,
29
+ i: undefined,
30
+ s: true,
31
+ l: undefined,
32
+ c: undefined,
33
+ m: undefined,
34
+ d: undefined,
35
+ a: undefined,
36
+ n: undefined,
37
+ };
38
+ export const FALSE_NODE: SerovalBooleanNode = {
39
+ t: SerovalNodeType.Boolean,
40
+ i: undefined,
41
+ s: false,
42
+ l: undefined,
43
+ c: undefined,
44
+ m: undefined,
45
+ d: undefined,
46
+ a: undefined,
47
+ n: undefined,
48
+ };
49
+ export const UNDEFINED_NODE: SerovalUndefinedNode = {
50
+ t: SerovalNodeType.Undefined,
51
+ i: undefined,
52
+ s: undefined,
53
+ l: undefined,
54
+ c: undefined,
55
+ m: undefined,
56
+ d: undefined,
57
+ a: undefined,
58
+ n: undefined,
59
+ };
60
+ export const NULL_NODE: SerovalNullNode = {
61
+ t: SerovalNodeType.Null,
62
+ i: undefined,
63
+ s: undefined,
64
+ l: undefined,
65
+ c: undefined,
66
+ m: undefined,
67
+ d: undefined,
68
+ a: undefined,
69
+ n: undefined,
70
+ };
71
+ export const NEG_ZERO_NODE: SerovalNegativeZeroNode = {
72
+ t: SerovalNodeType.NegativeZero,
73
+ i: undefined,
74
+ s: undefined,
75
+ l: undefined,
76
+ c: undefined,
77
+ m: undefined,
78
+ d: undefined,
79
+ a: undefined,
80
+ n: undefined,
81
+ };
82
+ export const INFINITY_NODE: SerovalInfinityNode = {
83
+ t: SerovalNodeType.Infinity,
84
+ i: undefined,
85
+ s: undefined,
86
+ l: undefined,
87
+ c: undefined,
88
+ m: undefined,
89
+ d: undefined,
90
+ a: undefined,
91
+ n: undefined,
92
+ };
93
+ export const NEG_INFINITY_NODE: SerovalNegativeInfinityNode = {
94
+ t: SerovalNodeType.NegativeInfinity,
95
+ i: undefined,
96
+ s: undefined,
97
+ l: undefined,
98
+ c: undefined,
99
+ m: undefined,
100
+ d: undefined,
101
+ a: undefined,
102
+ n: undefined,
103
+ };
104
+ export const NAN_NODE: SerovalNaNNode = {
105
+ t: SerovalNodeType.NaN,
106
+ i: undefined,
107
+ s: undefined,
108
+ l: undefined,
109
+ c: undefined,
110
+ m: undefined,
111
+ d: undefined,
112
+ a: undefined,
113
+ n: undefined,
114
+ };
115
+
116
+ export function createNumberNode(value: number): SerovalNumberNode {
19
117
  return {
20
- t: SerovalNodeType.Primitive,
118
+ t: SerovalNodeType.Number,
21
119
  i: undefined,
22
120
  s: value,
23
121
  l: undefined,
@@ -29,13 +127,19 @@ export function createPrimitiveNode(
29
127
  };
30
128
  }
31
129
 
32
- export const TRUE_NODE = createPrimitiveNode('!0');
33
- export const FALSE_NODE = createPrimitiveNode('!1');
34
- export const UNDEFINED_NODE = createPrimitiveNode('void 0');
35
- export const NULL_NODE = createPrimitiveNode(null);
36
- export const NEG_ZERO_NODE = createPrimitiveNode('-0');
37
- export const INFINITY_NODE = createPrimitiveNode('1/0');
38
- export const NEG_INFINITY_NODE = createPrimitiveNode('-1/0');
130
+ export function createStringNode(value: string): SerovalStringNode {
131
+ return {
132
+ t: SerovalNodeType.String,
133
+ i: undefined,
134
+ s: quote(value),
135
+ l: undefined,
136
+ c: undefined,
137
+ m: undefined,
138
+ d: undefined,
139
+ a: undefined,
140
+ n: undefined,
141
+ };
142
+ }
39
143
 
40
144
  export function createBigIntNode(
41
145
  ctx: ParserContext,
@@ -45,7 +149,7 @@ export function createBigIntNode(
45
149
  return {
46
150
  t: SerovalNodeType.BigInt,
47
151
  i: undefined,
48
- s: current.toString() + 'n',
152
+ s: current.toString(),
49
153
  l: undefined,
50
154
  c: undefined,
51
155
  m: undefined,
@@ -87,10 +191,10 @@ export function createRegExpNode(id: number, current: RegExp): SerovalRegExpNode
87
191
  return {
88
192
  t: SerovalNodeType.RegExp,
89
193
  i: id,
90
- s: String(current),
194
+ s: undefined,
91
195
  l: undefined,
92
- c: undefined,
93
- m: undefined,
196
+ c: current.source,
197
+ m: current.flags,
94
198
  d: undefined,
95
199
  a: undefined,
96
200
  n: undefined,
@@ -104,10 +208,15 @@ export function createTypedArrayNode(
104
208
  ): SerovalTypedArrayNode {
105
209
  const constructor = current.constructor.name;
106
210
  assert(ctx.features & Feature.TypedArray, `Unsupported value type "${constructor}"`);
211
+ const len = current.length;
212
+ const values = new Array<string>(len);
213
+ for (let i = 0; i < len; i++) {
214
+ values[i] = current[i].toString();
215
+ }
107
216
  return {
108
217
  t: SerovalNodeType.TypedArray,
109
218
  i: id,
110
- s: current.toString(),
219
+ s: values,
111
220
  l: current.byteOffset,
112
221
  c: constructor,
113
222
  m: undefined,
@@ -129,17 +238,15 @@ export function createBigIntTypedArrayNode(
129
238
  (ctx.features & BIGINT_FLAG) === BIGINT_FLAG,
130
239
  `Unsupported value type "${constructor}"`,
131
240
  );
132
- let result = '';
133
- for (let i = 0, len = current.length; i < len; i++) {
134
- if (i !== 0) {
135
- result += ',';
136
- }
137
- result += current[i].toString() + 'n';
241
+ const len = current.length;
242
+ const values = new Array<string>(len);
243
+ for (let i = 0; i < len; i++) {
244
+ values[i] = current[i].toString();
138
245
  }
139
246
  return {
140
247
  t: SerovalNodeType.BigIntTypedArray,
141
248
  i: id,
142
- s: result,
249
+ s: values,
143
250
  l: (current as BigInt64Array).byteOffset,
144
251
  c: constructor,
145
252
  m: undefined,
@@ -148,3 +255,19 @@ export function createBigIntTypedArrayNode(
148
255
  n: undefined,
149
256
  };
150
257
  }
258
+
259
+ export function createWKSymbolNode(
260
+ current: WellKnownSymbols,
261
+ ): SerovalWKSymbolNode {
262
+ return {
263
+ t: SerovalNodeType.WKSymbol,
264
+ i: undefined,
265
+ s: INV_SYMBOL_REF[current],
266
+ l: undefined,
267
+ c: undefined,
268
+ m: undefined,
269
+ d: undefined,
270
+ a: undefined,
271
+ n: undefined,
272
+ };
273
+ }