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