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