seroval 0.11.6 → 0.12.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.
- package/README.md +29 -16
- package/dist/cjs/development/index.cjs +3072 -4875
- package/dist/cjs/development/index.cjs.map +4 -4
- package/dist/cjs/production/index.cjs +3 -3
- package/dist/esm/development/index.mjs +3069 -4874
- package/dist/esm/development/index.mjs.map +4 -4
- package/dist/esm/production/index.mjs +3 -3
- package/dist/types/core/Serializer.d.ts +2 -0
- package/dist/types/core/Serializer.d.ts.map +1 -0
- package/dist/types/core/UnsupportedTypeError.d.ts +1 -0
- package/dist/types/core/UnsupportedTypeError.d.ts.map +1 -0
- package/dist/types/core/assert.d.ts +1 -0
- package/dist/types/core/assert.d.ts.map +1 -0
- package/dist/types/core/base/async.d.ts +30 -0
- package/dist/types/core/base/async.d.ts.map +1 -0
- package/dist/types/core/base/stream.d.ts +40 -0
- package/dist/types/core/base/stream.d.ts.map +1 -0
- package/dist/types/core/base/sync.d.ts +32 -0
- package/dist/types/core/base/sync.d.ts.map +1 -0
- package/dist/types/core/base-primitives.d.ts +3 -1
- package/dist/types/core/base-primitives.d.ts.map +1 -0
- package/dist/types/core/compat.d.ts +1 -0
- package/dist/types/core/compat.d.ts.map +1 -0
- package/dist/types/core/constants.d.ts +19 -4
- package/dist/types/core/constants.d.ts.map +1 -0
- package/dist/types/core/constructors.d.ts +1 -0
- package/dist/types/core/constructors.d.ts.map +1 -0
- package/dist/types/core/cross/async.d.ts +8 -3
- package/dist/types/core/cross/async.d.ts.map +1 -0
- package/dist/types/core/cross/cross-parser.d.ts +8 -0
- package/dist/types/core/cross/cross-parser.d.ts.map +1 -0
- package/dist/types/core/cross/index.d.ts +12 -5
- package/dist/types/core/cross/index.d.ts.map +1 -0
- package/dist/types/core/cross/serialize.d.ts +23 -5
- package/dist/types/core/cross/serialize.d.ts.map +1 -0
- package/dist/types/core/cross/stream.d.ts +8 -3
- package/dist/types/core/cross/stream.d.ts.map +1 -0
- package/dist/types/core/cross/sync.d.ts +8 -3
- package/dist/types/core/cross/sync.d.ts.map +1 -0
- package/dist/types/core/get-identifier.d.ts +1 -0
- package/dist/types/core/get-identifier.d.ts.map +1 -0
- package/dist/types/core/keys.d.ts +1 -0
- package/dist/types/core/keys.d.ts.map +1 -0
- package/dist/types/core/literals.d.ts +1 -0
- package/dist/types/core/literals.d.ts.map +1 -0
- package/dist/types/core/parser-context.d.ts +23 -0
- package/dist/types/core/parser-context.d.ts.map +1 -0
- package/dist/types/core/plugin.d.ts +26 -0
- package/dist/types/core/plugin.d.ts.map +1 -0
- package/dist/types/core/promise-to-result.d.ts +1 -0
- package/dist/types/core/promise-to-result.d.ts.map +1 -0
- package/dist/types/core/reference.d.ts +1 -0
- package/dist/types/core/reference.d.ts.map +1 -0
- package/dist/types/core/serializer-context.old.d.ts +165 -0
- package/dist/types/core/serializer-context.old.d.ts.map +1 -0
- package/dist/types/core/shared.d.ts +4 -7
- package/dist/types/core/shared.d.ts.map +1 -0
- package/dist/types/core/string.d.ts +1 -0
- package/dist/types/core/string.d.ts.map +1 -0
- package/dist/types/core/tree/async.d.ts +8 -3
- package/dist/types/core/tree/async.d.ts.map +1 -0
- package/dist/types/core/tree/deserialize.d.ts +49 -2
- package/dist/types/core/tree/deserialize.d.ts.map +1 -0
- package/dist/types/core/tree/index.d.ts +10 -7
- package/dist/types/core/tree/index.d.ts.map +1 -0
- package/dist/types/core/tree/serialize.d.ts +37 -4
- package/dist/types/core/tree/serialize.d.ts.map +1 -0
- package/dist/types/core/tree/sync.d.ts +8 -3
- package/dist/types/core/tree/sync.d.ts.map +1 -0
- package/dist/types/core/types.d.ts +10 -3
- package/dist/types/core/types.d.ts.map +1 -0
- package/dist/types/core/web-api.d.ts +1 -0
- package/dist/types/core/web-api.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/types.d.ts +1 -0
- package/dist/types/types.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/core/Serializer.ts +2 -0
- package/src/core/base/async.ts +804 -0
- package/src/core/base/stream.ts +496 -0
- package/src/core/base/sync.ts +675 -0
- package/src/core/base-primitives.ts +22 -0
- package/src/core/constants.ts +61 -45
- package/src/core/cross/async.ts +6 -751
- package/src/core/cross/cross-parser.ts +9 -0
- package/src/core/cross/index.ts +62 -84
- package/src/core/cross/serialize.ts +71 -862
- package/src/core/cross/stream.ts +6 -873
- package/src/core/cross/sync.ts +6 -624
- package/src/core/is-serializable.new.ts +208 -0
- package/src/core/keys.ts +1 -1
- package/src/core/parser-context.ts +131 -0
- package/src/core/plugin.ts +55 -0
- package/src/core/serializer-context.new.ts +1168 -0
- package/src/core/serializer-context.old.ts +1126 -0
- package/src/core/shared.ts +46 -123
- package/src/core/tree/async.ts +6 -750
- package/src/core/tree/deserialize.ts +423 -420
- package/src/core/tree/index.ts +49 -91
- package/src/core/tree/parser.ts +45 -0
- package/src/core/tree/serialize.ts +122 -828
- package/src/core/tree/sync.ts +6 -624
- package/src/core/types.ts +13 -2
- package/src/example.ts +28 -0
- package/src/index.ts +3 -0
- package/dist/types/core/assignments.d.ts +0 -33
- package/dist/types/core/context.d.ts +0 -9
- package/dist/types/core/cross/context.d.ts +0 -37
- package/dist/types/core/cross/primitives.d.ts +0 -9
- package/dist/types/core/cross/web-api.d.ts +0 -4
- package/dist/types/core/tree/context.d.ts +0 -44
- package/dist/types/core/tree/primitives.d.ts +0 -9
- package/dist/types/core/tree/web-api.d.ts +0 -4
- package/src/core/assignments.ts +0 -159
- package/src/core/context.ts +0 -15
- package/src/core/cross/context.ts +0 -102
- package/src/core/cross/primitives.ts +0 -128
- package/src/core/cross/web-api.ts +0 -50
- package/src/core/tree/context.ts +0 -125
- package/src/core/tree/primitives.ts +0 -123
- package/src/core/tree/web-api.ts +0 -50
|
@@ -0,0 +1,804 @@
|
|
|
1
|
+
/* eslint-disable prefer-destructuring */
|
|
2
|
+
/* eslint-disable no-await-in-loop */
|
|
3
|
+
import type { BigIntTypedArrayValue, TypedArrayValue } from '../../types';
|
|
4
|
+
import UnsupportedTypeError from '../UnsupportedTypeError';
|
|
5
|
+
import assert from '../assert';
|
|
6
|
+
import {
|
|
7
|
+
createPluginNode,
|
|
8
|
+
createDateNode,
|
|
9
|
+
createRegExpNode,
|
|
10
|
+
createArrayBufferNode,
|
|
11
|
+
createWKSymbolNode,
|
|
12
|
+
createBigIntNode,
|
|
13
|
+
createStringNode,
|
|
14
|
+
createNumberNode,
|
|
15
|
+
} from '../base-primitives';
|
|
16
|
+
import { BIGINT_FLAG, Feature } from '../compat';
|
|
17
|
+
import type { WellKnownSymbols } from '../constants';
|
|
18
|
+
import { SerovalNodeType, UNIVERSAL_SENTINEL } from '../constants';
|
|
19
|
+
import {
|
|
20
|
+
createRequestOptions,
|
|
21
|
+
createResponseOptions,
|
|
22
|
+
createEventOptions,
|
|
23
|
+
createCustomEventOptions,
|
|
24
|
+
} from '../constructors';
|
|
25
|
+
import {
|
|
26
|
+
NULL_NODE,
|
|
27
|
+
TRUE_NODE,
|
|
28
|
+
FALSE_NODE,
|
|
29
|
+
UNDEFINED_NODE,
|
|
30
|
+
} from '../literals';
|
|
31
|
+
import { BaseParserContext } from '../parser-context';
|
|
32
|
+
import promiseToResult from '../promise-to-result';
|
|
33
|
+
import { hasReferenceID } from '../reference';
|
|
34
|
+
import { getErrorConstructor, getErrorOptions, getObjectFlag } from '../shared';
|
|
35
|
+
import { serializeString } from '../string';
|
|
36
|
+
import { SerovalObjectRecordSpecialKey } from '../types';
|
|
37
|
+
import type {
|
|
38
|
+
SerovalErrorNode,
|
|
39
|
+
SerovalArrayNode,
|
|
40
|
+
SerovalBigIntTypedArrayNode,
|
|
41
|
+
SerovalBoxedNode,
|
|
42
|
+
SerovalNode,
|
|
43
|
+
SerovalNullConstructorNode,
|
|
44
|
+
SerovalObjectNode,
|
|
45
|
+
SerovalObjectRecordKey,
|
|
46
|
+
SerovalObjectRecordNode,
|
|
47
|
+
SerovalPromiseNode,
|
|
48
|
+
SerovalTypedArrayNode,
|
|
49
|
+
SerovalAggregateErrorNode,
|
|
50
|
+
SerovalBlobNode,
|
|
51
|
+
SerovalCustomEventNode,
|
|
52
|
+
SerovalEventNode,
|
|
53
|
+
SerovalFileNode,
|
|
54
|
+
SerovalFormDataNode,
|
|
55
|
+
SerovalHeadersNode,
|
|
56
|
+
SerovalMapNode,
|
|
57
|
+
SerovalPlainRecordNode,
|
|
58
|
+
SerovalPluginNode,
|
|
59
|
+
SerovalRequestNode,
|
|
60
|
+
SerovalResponseNode,
|
|
61
|
+
SerovalSetNode,
|
|
62
|
+
SerovalDataViewNode,
|
|
63
|
+
} from '../types';
|
|
64
|
+
import { createURLNode, createURLSearchParamsNode, createDOMExceptionNode } from '../web-api';
|
|
65
|
+
|
|
66
|
+
type ObjectLikeNode =
|
|
67
|
+
| SerovalObjectNode
|
|
68
|
+
| SerovalNullConstructorNode
|
|
69
|
+
| SerovalPromiseNode;
|
|
70
|
+
|
|
71
|
+
export default abstract class BaseAsyncParserContext extends BaseParserContext {
|
|
72
|
+
private async parseItems(
|
|
73
|
+
current: unknown[],
|
|
74
|
+
): Promise<SerovalNode[]> {
|
|
75
|
+
const size = current.length;
|
|
76
|
+
const nodes = [];
|
|
77
|
+
const deferred = [];
|
|
78
|
+
for (let i = 0, item: unknown; i < size; i++) {
|
|
79
|
+
if (i in current) {
|
|
80
|
+
item = current[i];
|
|
81
|
+
if (this.isIterable(item)) {
|
|
82
|
+
deferred[i] = item;
|
|
83
|
+
} else {
|
|
84
|
+
nodes[i] = await this.parse(item);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (let i = 0; i < size; i++) {
|
|
89
|
+
if (i in deferred) {
|
|
90
|
+
nodes[i] = await this.parse(deferred[i]);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return nodes;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private async parseArray(
|
|
97
|
+
id: number,
|
|
98
|
+
current: unknown[],
|
|
99
|
+
): Promise<SerovalArrayNode> {
|
|
100
|
+
return {
|
|
101
|
+
t: SerovalNodeType.Array,
|
|
102
|
+
i: id,
|
|
103
|
+
s: undefined,
|
|
104
|
+
l: current.length,
|
|
105
|
+
c: undefined,
|
|
106
|
+
m: undefined,
|
|
107
|
+
p: undefined,
|
|
108
|
+
e: undefined,
|
|
109
|
+
a: await this.parseItems(current),
|
|
110
|
+
f: undefined,
|
|
111
|
+
b: undefined,
|
|
112
|
+
o: getObjectFlag(current),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private async parseBoxed(
|
|
117
|
+
id: number,
|
|
118
|
+
current: object,
|
|
119
|
+
): Promise<SerovalBoxedNode> {
|
|
120
|
+
return {
|
|
121
|
+
t: SerovalNodeType.Boxed,
|
|
122
|
+
i: id,
|
|
123
|
+
s: undefined,
|
|
124
|
+
l: undefined,
|
|
125
|
+
c: undefined,
|
|
126
|
+
m: undefined,
|
|
127
|
+
p: undefined,
|
|
128
|
+
e: undefined,
|
|
129
|
+
a: undefined,
|
|
130
|
+
f: await this.parse(current.valueOf()),
|
|
131
|
+
b: undefined,
|
|
132
|
+
o: undefined,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private async parseTypedArray(
|
|
137
|
+
id: number,
|
|
138
|
+
current: TypedArrayValue,
|
|
139
|
+
): Promise<SerovalTypedArrayNode> {
|
|
140
|
+
return {
|
|
141
|
+
t: SerovalNodeType.TypedArray,
|
|
142
|
+
i: id,
|
|
143
|
+
s: undefined,
|
|
144
|
+
l: current.length,
|
|
145
|
+
c: current.constructor.name,
|
|
146
|
+
m: undefined,
|
|
147
|
+
p: undefined,
|
|
148
|
+
e: undefined,
|
|
149
|
+
a: undefined,
|
|
150
|
+
f: await this.parse(current.buffer),
|
|
151
|
+
b: current.byteOffset,
|
|
152
|
+
o: undefined,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private async parseBigIntTypedArray(
|
|
157
|
+
id: number,
|
|
158
|
+
current: BigIntTypedArrayValue,
|
|
159
|
+
): Promise<SerovalBigIntTypedArrayNode> {
|
|
160
|
+
return {
|
|
161
|
+
t: SerovalNodeType.BigIntTypedArray,
|
|
162
|
+
i: id,
|
|
163
|
+
s: undefined,
|
|
164
|
+
l: current.length,
|
|
165
|
+
c: current.constructor.name,
|
|
166
|
+
m: undefined,
|
|
167
|
+
p: undefined,
|
|
168
|
+
e: undefined,
|
|
169
|
+
a: undefined,
|
|
170
|
+
f: await this.parse(current.buffer),
|
|
171
|
+
b: current.byteOffset,
|
|
172
|
+
o: undefined,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private async parseDataView(
|
|
177
|
+
id: number,
|
|
178
|
+
current: DataView,
|
|
179
|
+
): Promise<SerovalDataViewNode> {
|
|
180
|
+
return {
|
|
181
|
+
t: SerovalNodeType.DataView,
|
|
182
|
+
i: id,
|
|
183
|
+
s: undefined,
|
|
184
|
+
l: current.byteLength,
|
|
185
|
+
c: undefined,
|
|
186
|
+
m: undefined,
|
|
187
|
+
p: undefined,
|
|
188
|
+
e: undefined,
|
|
189
|
+
a: undefined,
|
|
190
|
+
f: await this.parse(current.buffer),
|
|
191
|
+
b: current.byteOffset,
|
|
192
|
+
o: undefined,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private async parseProperties(
|
|
197
|
+
properties: Record<string, unknown>,
|
|
198
|
+
): Promise<SerovalObjectRecordNode> {
|
|
199
|
+
const entries = Object.entries(properties);
|
|
200
|
+
const keyNodes: SerovalObjectRecordKey[] = [];
|
|
201
|
+
const valueNodes: SerovalNode[] = [];
|
|
202
|
+
const deferredKeys: string[] = [];
|
|
203
|
+
const deferredValues: unknown[] = [];
|
|
204
|
+
for (
|
|
205
|
+
let i = 0, len = entries.length, key: string, item: unknown;
|
|
206
|
+
i < len;
|
|
207
|
+
i++
|
|
208
|
+
) {
|
|
209
|
+
key = serializeString(entries[i][0]);
|
|
210
|
+
item = entries[i][1];
|
|
211
|
+
// Defer iterables since iterables have lazy evaluation.
|
|
212
|
+
// Of course this doesn't include types seroval supports.
|
|
213
|
+
if (this.isIterable(item)) {
|
|
214
|
+
deferredKeys.push(key);
|
|
215
|
+
deferredValues.push(item);
|
|
216
|
+
} else {
|
|
217
|
+
keyNodes.push(key);
|
|
218
|
+
valueNodes.push(await this.parse(item));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
for (let i = 0, len = deferredKeys.length; i < len; i++) {
|
|
222
|
+
keyNodes.push(deferredKeys[i]);
|
|
223
|
+
valueNodes.push(await this.parse(deferredValues[i]));
|
|
224
|
+
}
|
|
225
|
+
// Check special properties
|
|
226
|
+
if (this.features & Feature.Symbol) {
|
|
227
|
+
if (Symbol.iterator in properties) {
|
|
228
|
+
keyNodes.push(SerovalObjectRecordSpecialKey.SymbolIterator);
|
|
229
|
+
valueNodes.push(await this.parse(Array.from(properties as Iterable<unknown>)));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
k: keyNodes,
|
|
234
|
+
v: valueNodes,
|
|
235
|
+
s: keyNodes.length,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private async parsePlainObject(
|
|
240
|
+
id: number,
|
|
241
|
+
current: Record<string, unknown>,
|
|
242
|
+
empty: boolean,
|
|
243
|
+
): Promise<ObjectLikeNode> {
|
|
244
|
+
return {
|
|
245
|
+
t: empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,
|
|
246
|
+
i: id,
|
|
247
|
+
s: undefined,
|
|
248
|
+
l: undefined,
|
|
249
|
+
c: undefined,
|
|
250
|
+
m: undefined,
|
|
251
|
+
p: await this.parseProperties(current),
|
|
252
|
+
e: undefined,
|
|
253
|
+
a: undefined,
|
|
254
|
+
f: undefined,
|
|
255
|
+
b: undefined,
|
|
256
|
+
o: getObjectFlag(current),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private async parseError(
|
|
261
|
+
id: number,
|
|
262
|
+
current: Error,
|
|
263
|
+
): Promise<SerovalErrorNode> {
|
|
264
|
+
const options = getErrorOptions(current, this.features);
|
|
265
|
+
const optionsNode = options
|
|
266
|
+
? await this.parseProperties(options)
|
|
267
|
+
: undefined;
|
|
268
|
+
return {
|
|
269
|
+
t: SerovalNodeType.Error,
|
|
270
|
+
i: id,
|
|
271
|
+
s: getErrorConstructor(current),
|
|
272
|
+
l: undefined,
|
|
273
|
+
c: undefined,
|
|
274
|
+
m: serializeString(current.message),
|
|
275
|
+
p: optionsNode,
|
|
276
|
+
e: undefined,
|
|
277
|
+
a: undefined,
|
|
278
|
+
f: undefined,
|
|
279
|
+
b: undefined,
|
|
280
|
+
o: undefined,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
private async parseMap(
|
|
285
|
+
id: number,
|
|
286
|
+
current: Map<unknown, unknown>,
|
|
287
|
+
): Promise<SerovalMapNode> {
|
|
288
|
+
const keyNodes: SerovalNode[] = [];
|
|
289
|
+
const valueNodes: SerovalNode[] = [];
|
|
290
|
+
const deferredKey: unknown[] = [];
|
|
291
|
+
const deferredValue: unknown[] = [];
|
|
292
|
+
for (const [key, value] of current.entries()) {
|
|
293
|
+
// Either key or value might be an iterable
|
|
294
|
+
if (this.isIterable(key) || this.isIterable(value)) {
|
|
295
|
+
deferredKey.push(key);
|
|
296
|
+
deferredValue.push(value);
|
|
297
|
+
} else {
|
|
298
|
+
keyNodes.push(await this.parse(key));
|
|
299
|
+
valueNodes.push(await this.parse(value));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
for (let i = 0, len = deferredKey.length; i < len; i++) {
|
|
303
|
+
keyNodes.push(await this.parse(deferredKey[i]));
|
|
304
|
+
valueNodes.push(await this.parse(deferredValue[i]));
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
t: SerovalNodeType.Map,
|
|
308
|
+
i: id,
|
|
309
|
+
s: undefined,
|
|
310
|
+
l: undefined,
|
|
311
|
+
c: undefined,
|
|
312
|
+
m: undefined,
|
|
313
|
+
p: undefined,
|
|
314
|
+
e: { k: keyNodes, v: valueNodes, s: current.size },
|
|
315
|
+
a: undefined,
|
|
316
|
+
f: undefined,
|
|
317
|
+
b: undefined,
|
|
318
|
+
o: undefined,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private async parseSet(
|
|
323
|
+
id: number,
|
|
324
|
+
current: Set<unknown>,
|
|
325
|
+
): Promise<SerovalSetNode> {
|
|
326
|
+
const nodes: SerovalNode[] = [];
|
|
327
|
+
const deferred: unknown[] = [];
|
|
328
|
+
for (const item of current.keys()) {
|
|
329
|
+
// Iterables are lazy, so the evaluation must be deferred
|
|
330
|
+
if (this.isIterable(item)) {
|
|
331
|
+
deferred.push(item);
|
|
332
|
+
} else {
|
|
333
|
+
nodes.push(await this.parse(item));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
// Parse deferred items
|
|
337
|
+
for (let i = 0, len = deferred.length; i < len; i++) {
|
|
338
|
+
nodes.push(await this.parse(deferred[i]));
|
|
339
|
+
}
|
|
340
|
+
return {
|
|
341
|
+
t: SerovalNodeType.Set,
|
|
342
|
+
i: id,
|
|
343
|
+
s: undefined,
|
|
344
|
+
l: current.size,
|
|
345
|
+
c: undefined,
|
|
346
|
+
m: undefined,
|
|
347
|
+
p: undefined,
|
|
348
|
+
e: undefined,
|
|
349
|
+
a: nodes,
|
|
350
|
+
f: undefined,
|
|
351
|
+
b: undefined,
|
|
352
|
+
o: undefined,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private async parseBlob(
|
|
357
|
+
id: number,
|
|
358
|
+
current: Blob,
|
|
359
|
+
): Promise<SerovalBlobNode> {
|
|
360
|
+
return {
|
|
361
|
+
t: SerovalNodeType.Blob,
|
|
362
|
+
i: id,
|
|
363
|
+
s: undefined,
|
|
364
|
+
l: undefined,
|
|
365
|
+
c: serializeString(current.type),
|
|
366
|
+
m: undefined,
|
|
367
|
+
p: undefined,
|
|
368
|
+
e: undefined,
|
|
369
|
+
f: await this.parse(await current.arrayBuffer()),
|
|
370
|
+
a: undefined,
|
|
371
|
+
b: undefined,
|
|
372
|
+
o: undefined,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
private async parseFile(
|
|
377
|
+
id: number,
|
|
378
|
+
current: File,
|
|
379
|
+
): Promise<SerovalFileNode> {
|
|
380
|
+
return {
|
|
381
|
+
t: SerovalNodeType.File,
|
|
382
|
+
i: id,
|
|
383
|
+
s: undefined,
|
|
384
|
+
l: undefined,
|
|
385
|
+
c: serializeString(current.type),
|
|
386
|
+
m: serializeString(current.name),
|
|
387
|
+
p: undefined,
|
|
388
|
+
e: undefined,
|
|
389
|
+
f: await this.parse(await current.arrayBuffer()),
|
|
390
|
+
a: undefined,
|
|
391
|
+
b: current.lastModified,
|
|
392
|
+
o: undefined,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
protected async parsePlainProperties(
|
|
397
|
+
entries: [key: string, value: unknown][],
|
|
398
|
+
): Promise<SerovalPlainRecordNode> {
|
|
399
|
+
const size = entries.length;
|
|
400
|
+
const keyNodes: string[] = [];
|
|
401
|
+
const valueNodes: SerovalNode[] = [];
|
|
402
|
+
const deferredKeys: string[] = [];
|
|
403
|
+
const deferredValues: unknown[] = [];
|
|
404
|
+
for (let i = 0, key: string, item: unknown; i < size; i++) {
|
|
405
|
+
key = serializeString(entries[i][0]);
|
|
406
|
+
item = entries[i][1];
|
|
407
|
+
if (this.isIterable(item)) {
|
|
408
|
+
deferredKeys.push(key);
|
|
409
|
+
deferredValues.push(item);
|
|
410
|
+
} else {
|
|
411
|
+
keyNodes.push(key);
|
|
412
|
+
valueNodes.push(await this.parse(item));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
for (let i = 0, len = deferredKeys.length; i < len; i++) {
|
|
416
|
+
keyNodes.push(deferredKeys[i]);
|
|
417
|
+
valueNodes.push(await this.parse(deferredValues[i]));
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
k: keyNodes,
|
|
421
|
+
v: valueNodes,
|
|
422
|
+
s: size,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
private async parseHeaders(
|
|
427
|
+
id: number,
|
|
428
|
+
current: Headers,
|
|
429
|
+
): Promise<SerovalHeadersNode> {
|
|
430
|
+
const items: [key: string, value: unknown][] = [];
|
|
431
|
+
current.forEach((value, key) => {
|
|
432
|
+
items.push([key, value]);
|
|
433
|
+
});
|
|
434
|
+
return {
|
|
435
|
+
t: SerovalNodeType.Headers,
|
|
436
|
+
i: id,
|
|
437
|
+
s: undefined,
|
|
438
|
+
l: undefined,
|
|
439
|
+
c: undefined,
|
|
440
|
+
m: undefined,
|
|
441
|
+
p: undefined,
|
|
442
|
+
e: await this.parsePlainProperties(items),
|
|
443
|
+
a: undefined,
|
|
444
|
+
f: undefined,
|
|
445
|
+
b: undefined,
|
|
446
|
+
o: undefined,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
private async parseFormData(
|
|
451
|
+
id: number,
|
|
452
|
+
current: FormData,
|
|
453
|
+
): Promise<SerovalFormDataNode> {
|
|
454
|
+
const items: [key: string, value: FormDataEntryValue][] = [];
|
|
455
|
+
current.forEach((value, key) => {
|
|
456
|
+
items.push([key, value]);
|
|
457
|
+
});
|
|
458
|
+
return {
|
|
459
|
+
t: SerovalNodeType.FormData,
|
|
460
|
+
i: id,
|
|
461
|
+
s: undefined,
|
|
462
|
+
l: undefined,
|
|
463
|
+
c: undefined,
|
|
464
|
+
m: undefined,
|
|
465
|
+
p: undefined,
|
|
466
|
+
e: await this.parsePlainProperties(items),
|
|
467
|
+
a: undefined,
|
|
468
|
+
f: undefined,
|
|
469
|
+
b: undefined,
|
|
470
|
+
o: undefined,
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
private async parseRequest(
|
|
475
|
+
id: number,
|
|
476
|
+
current: Request,
|
|
477
|
+
): Promise<SerovalRequestNode> {
|
|
478
|
+
return {
|
|
479
|
+
t: SerovalNodeType.Request,
|
|
480
|
+
i: id,
|
|
481
|
+
s: serializeString(current.url),
|
|
482
|
+
l: undefined,
|
|
483
|
+
c: undefined,
|
|
484
|
+
m: undefined,
|
|
485
|
+
p: undefined,
|
|
486
|
+
e: undefined,
|
|
487
|
+
f: await this.parse(
|
|
488
|
+
createRequestOptions(current, current.body ? await current.clone().arrayBuffer() : null),
|
|
489
|
+
),
|
|
490
|
+
a: undefined,
|
|
491
|
+
b: undefined,
|
|
492
|
+
o: undefined,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
private async parseResponse(
|
|
497
|
+
id: number,
|
|
498
|
+
current: Response,
|
|
499
|
+
): Promise<SerovalResponseNode> {
|
|
500
|
+
return {
|
|
501
|
+
t: SerovalNodeType.Response,
|
|
502
|
+
i: id,
|
|
503
|
+
s: undefined,
|
|
504
|
+
l: undefined,
|
|
505
|
+
c: undefined,
|
|
506
|
+
m: undefined,
|
|
507
|
+
p: undefined,
|
|
508
|
+
e: undefined,
|
|
509
|
+
f: undefined,
|
|
510
|
+
a: [
|
|
511
|
+
current.body
|
|
512
|
+
? await this.parse(await current.clone().arrayBuffer())
|
|
513
|
+
: NULL_NODE,
|
|
514
|
+
await this.parse(createResponseOptions(current)),
|
|
515
|
+
],
|
|
516
|
+
b: undefined,
|
|
517
|
+
o: undefined,
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
private async parseEvent(
|
|
522
|
+
id: number,
|
|
523
|
+
current: Event,
|
|
524
|
+
): Promise<SerovalEventNode> {
|
|
525
|
+
return {
|
|
526
|
+
t: SerovalNodeType.Event,
|
|
527
|
+
i: id,
|
|
528
|
+
s: serializeString(current.type),
|
|
529
|
+
l: undefined,
|
|
530
|
+
c: undefined,
|
|
531
|
+
m: undefined,
|
|
532
|
+
p: undefined,
|
|
533
|
+
e: undefined,
|
|
534
|
+
a: undefined,
|
|
535
|
+
f: await this.parse(createEventOptions(current)),
|
|
536
|
+
b: undefined,
|
|
537
|
+
o: undefined,
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
private async parseCustomEvent(
|
|
542
|
+
id: number,
|
|
543
|
+
current: CustomEvent,
|
|
544
|
+
): Promise<SerovalCustomEventNode> {
|
|
545
|
+
return {
|
|
546
|
+
t: SerovalNodeType.CustomEvent,
|
|
547
|
+
i: id,
|
|
548
|
+
s: serializeString(current.type),
|
|
549
|
+
l: undefined,
|
|
550
|
+
c: undefined,
|
|
551
|
+
m: undefined,
|
|
552
|
+
p: undefined,
|
|
553
|
+
e: undefined,
|
|
554
|
+
a: undefined,
|
|
555
|
+
f: await this.parse(createCustomEventOptions(current)),
|
|
556
|
+
b: undefined,
|
|
557
|
+
o: undefined,
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
private async parseAggregateError(
|
|
562
|
+
id: number,
|
|
563
|
+
current: AggregateError,
|
|
564
|
+
): Promise<SerovalAggregateErrorNode> {
|
|
565
|
+
const options = getErrorOptions(current, this.features);
|
|
566
|
+
const optionsNode = options
|
|
567
|
+
? await this.parseProperties(options)
|
|
568
|
+
: undefined;
|
|
569
|
+
return {
|
|
570
|
+
t: SerovalNodeType.AggregateError,
|
|
571
|
+
i: id,
|
|
572
|
+
s: undefined,
|
|
573
|
+
l: undefined,
|
|
574
|
+
c: undefined,
|
|
575
|
+
m: serializeString(current.message),
|
|
576
|
+
p: optionsNode,
|
|
577
|
+
e: undefined,
|
|
578
|
+
a: undefined,
|
|
579
|
+
f: undefined,
|
|
580
|
+
b: undefined,
|
|
581
|
+
o: undefined,
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
private async parsePromise(
|
|
586
|
+
id: number,
|
|
587
|
+
current: Promise<unknown>,
|
|
588
|
+
): Promise<SerovalPromiseNode> {
|
|
589
|
+
const [status, result] = await promiseToResult(current);
|
|
590
|
+
return {
|
|
591
|
+
t: SerovalNodeType.Promise,
|
|
592
|
+
i: id,
|
|
593
|
+
s: status,
|
|
594
|
+
l: undefined,
|
|
595
|
+
c: undefined,
|
|
596
|
+
m: undefined,
|
|
597
|
+
p: undefined,
|
|
598
|
+
e: undefined,
|
|
599
|
+
a: undefined,
|
|
600
|
+
f: await this.parse(result),
|
|
601
|
+
b: undefined,
|
|
602
|
+
o: undefined,
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
private async parsePlugin(
|
|
607
|
+
id: number,
|
|
608
|
+
current: unknown,
|
|
609
|
+
): Promise<SerovalPluginNode | undefined> {
|
|
610
|
+
const currentPlugins = this.plugins;
|
|
611
|
+
if (currentPlugins) {
|
|
612
|
+
for (let i = 0, len = currentPlugins.length; i < len; i++) {
|
|
613
|
+
const plugin = currentPlugins[i];
|
|
614
|
+
if (plugin.parse.async && plugin.test(current)) {
|
|
615
|
+
return createPluginNode(
|
|
616
|
+
id,
|
|
617
|
+
plugin.tag,
|
|
618
|
+
await plugin.parse.async(current, this, {
|
|
619
|
+
id,
|
|
620
|
+
}),
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return undefined;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
private async parseObject(
|
|
629
|
+
id: number,
|
|
630
|
+
current: object,
|
|
631
|
+
): Promise<SerovalNode> {
|
|
632
|
+
if (Array.isArray(current)) {
|
|
633
|
+
return this.parseArray(id, current);
|
|
634
|
+
}
|
|
635
|
+
const currentClass = current.constructor;
|
|
636
|
+
switch (currentClass) {
|
|
637
|
+
case Object:
|
|
638
|
+
return this.parsePlainObject(
|
|
639
|
+
id,
|
|
640
|
+
current as Record<string, unknown>,
|
|
641
|
+
false,
|
|
642
|
+
);
|
|
643
|
+
case undefined:
|
|
644
|
+
return this.parsePlainObject(
|
|
645
|
+
id,
|
|
646
|
+
current as Record<string, unknown>,
|
|
647
|
+
true,
|
|
648
|
+
);
|
|
649
|
+
case Date:
|
|
650
|
+
return createDateNode(id, current as unknown as Date);
|
|
651
|
+
case RegExp:
|
|
652
|
+
return createRegExpNode(id, current as unknown as RegExp);
|
|
653
|
+
case Error:
|
|
654
|
+
case EvalError:
|
|
655
|
+
case RangeError:
|
|
656
|
+
case ReferenceError:
|
|
657
|
+
case SyntaxError:
|
|
658
|
+
case TypeError:
|
|
659
|
+
case URIError:
|
|
660
|
+
return this.parseError(id, current as unknown as Error);
|
|
661
|
+
case Number:
|
|
662
|
+
case Boolean:
|
|
663
|
+
case String:
|
|
664
|
+
case BigInt:
|
|
665
|
+
return this.parseBoxed(id, current);
|
|
666
|
+
default:
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
const currentFeatures = this.features;
|
|
670
|
+
// Promises
|
|
671
|
+
if (
|
|
672
|
+
(currentFeatures & Feature.Promise)
|
|
673
|
+
&& (currentClass === Promise || current instanceof Promise)
|
|
674
|
+
) {
|
|
675
|
+
return this.parsePromise(id, current as unknown as Promise<unknown>);
|
|
676
|
+
}
|
|
677
|
+
// Typed Arrays
|
|
678
|
+
if (currentFeatures & Feature.TypedArray) {
|
|
679
|
+
switch (currentClass) {
|
|
680
|
+
case ArrayBuffer:
|
|
681
|
+
return createArrayBufferNode(id, current as unknown as ArrayBuffer);
|
|
682
|
+
case Int8Array:
|
|
683
|
+
case Int16Array:
|
|
684
|
+
case Int32Array:
|
|
685
|
+
case Uint8Array:
|
|
686
|
+
case Uint16Array:
|
|
687
|
+
case Uint32Array:
|
|
688
|
+
case Uint8ClampedArray:
|
|
689
|
+
case Float32Array:
|
|
690
|
+
case Float64Array:
|
|
691
|
+
return this.parseTypedArray(id, current as unknown as TypedArrayValue);
|
|
692
|
+
case DataView:
|
|
693
|
+
return this.parseDataView(id, current as unknown as DataView);
|
|
694
|
+
default:
|
|
695
|
+
break;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
// BigInt Typed Arrays
|
|
699
|
+
if ((currentFeatures & BIGINT_FLAG) === BIGINT_FLAG) {
|
|
700
|
+
switch (currentClass) {
|
|
701
|
+
case BigInt64Array:
|
|
702
|
+
case BigUint64Array:
|
|
703
|
+
return this.parseBigIntTypedArray(id, current as unknown as BigIntTypedArrayValue);
|
|
704
|
+
default:
|
|
705
|
+
break;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
// ES Collection
|
|
709
|
+
if (currentFeatures & Feature.Map && currentClass === Map) {
|
|
710
|
+
return this.parseMap(
|
|
711
|
+
id,
|
|
712
|
+
current as unknown as Map<unknown, unknown>,
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
if (currentFeatures & Feature.Set && currentClass === Set) {
|
|
716
|
+
return this.parseSet(
|
|
717
|
+
id,
|
|
718
|
+
current as unknown as Set<unknown>,
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
// Web APIs
|
|
722
|
+
if (currentFeatures & Feature.WebAPI) {
|
|
723
|
+
switch (currentClass) {
|
|
724
|
+
case (typeof URL !== 'undefined' ? URL : UNIVERSAL_SENTINEL):
|
|
725
|
+
return createURLNode(id, current as unknown as URL);
|
|
726
|
+
case (typeof URLSearchParams !== 'undefined' ? URLSearchParams : UNIVERSAL_SENTINEL):
|
|
727
|
+
return createURLSearchParamsNode(id, current as unknown as URLSearchParams);
|
|
728
|
+
case (typeof Blob !== 'undefined' ? Blob : UNIVERSAL_SENTINEL):
|
|
729
|
+
return this.parseBlob(id, current as unknown as Blob);
|
|
730
|
+
case (typeof File !== 'undefined' ? File : UNIVERSAL_SENTINEL):
|
|
731
|
+
return this.parseFile(id, current as unknown as File);
|
|
732
|
+
case (typeof Headers !== 'undefined' ? Headers : UNIVERSAL_SENTINEL):
|
|
733
|
+
return this.parseHeaders(id, current as unknown as Headers);
|
|
734
|
+
case (typeof FormData !== 'undefined' ? FormData : UNIVERSAL_SENTINEL):
|
|
735
|
+
return this.parseFormData(id, current as unknown as FormData);
|
|
736
|
+
case (typeof Request !== 'undefined' ? Request : UNIVERSAL_SENTINEL):
|
|
737
|
+
return this.parseRequest(id, current as unknown as Request);
|
|
738
|
+
case (typeof Response !== 'undefined' ? Response : UNIVERSAL_SENTINEL):
|
|
739
|
+
return this.parseResponse(id, current as unknown as Response);
|
|
740
|
+
case (typeof Event !== 'undefined' ? Event : UNIVERSAL_SENTINEL):
|
|
741
|
+
return this.parseEvent(id, current as unknown as Event);
|
|
742
|
+
case (typeof CustomEvent !== 'undefined' ? CustomEvent : UNIVERSAL_SENTINEL):
|
|
743
|
+
return this.parseCustomEvent(id, current as unknown as CustomEvent);
|
|
744
|
+
case (typeof DOMException !== 'undefined' ? DOMException : UNIVERSAL_SENTINEL):
|
|
745
|
+
return createDOMExceptionNode(id, current as unknown as DOMException);
|
|
746
|
+
default:
|
|
747
|
+
break;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
const parsed = await this.parsePlugin(id, current);
|
|
751
|
+
if (parsed) {
|
|
752
|
+
return parsed;
|
|
753
|
+
}
|
|
754
|
+
if (
|
|
755
|
+
(currentFeatures & Feature.AggregateError)
|
|
756
|
+
&& typeof AggregateError !== 'undefined'
|
|
757
|
+
&& (currentClass === AggregateError || current instanceof AggregateError)
|
|
758
|
+
) {
|
|
759
|
+
return this.parseAggregateError(id, current as unknown as AggregateError);
|
|
760
|
+
}
|
|
761
|
+
// Slow path. We only need to handle Errors and Iterators
|
|
762
|
+
// since they have very broad implementations.
|
|
763
|
+
if (current instanceof Error) {
|
|
764
|
+
return this.parseError(id, current);
|
|
765
|
+
}
|
|
766
|
+
// Generator functions don't have a global constructor
|
|
767
|
+
// despite existing
|
|
768
|
+
if (currentFeatures & Feature.Symbol && Symbol.iterator in current) {
|
|
769
|
+
return this.parsePlainObject(id, current, !!currentClass);
|
|
770
|
+
}
|
|
771
|
+
throw new UnsupportedTypeError(current);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
async parse<T>(current: T): Promise<SerovalNode> {
|
|
775
|
+
switch (current) {
|
|
776
|
+
case true: return TRUE_NODE;
|
|
777
|
+
case false: return FALSE_NODE;
|
|
778
|
+
case undefined: return UNDEFINED_NODE;
|
|
779
|
+
case null: return NULL_NODE;
|
|
780
|
+
default: break;
|
|
781
|
+
}
|
|
782
|
+
switch (typeof current) {
|
|
783
|
+
case 'string': return createStringNode(current as string);
|
|
784
|
+
case 'number': return createNumberNode(current as number);
|
|
785
|
+
case 'bigint':
|
|
786
|
+
assert(this.features & Feature.BigInt, new UnsupportedTypeError(current));
|
|
787
|
+
return createBigIntNode(current as bigint);
|
|
788
|
+
case 'object': {
|
|
789
|
+
const id = this.getReference(current);
|
|
790
|
+
return typeof id === 'number' ? this.parseObject(id, current as object) : id;
|
|
791
|
+
}
|
|
792
|
+
case 'symbol': {
|
|
793
|
+
assert(this.features & Feature.Symbol, new UnsupportedTypeError(current));
|
|
794
|
+
const id = this.getReference(current);
|
|
795
|
+
return typeof id === 'number' ? createWKSymbolNode(id, current as WellKnownSymbols) : id;
|
|
796
|
+
}
|
|
797
|
+
case 'function':
|
|
798
|
+
assert(hasReferenceID(current), new Error('Cannot serialize function without reference ID.'));
|
|
799
|
+
return this.getStrictReference(current);
|
|
800
|
+
default:
|
|
801
|
+
throw new UnsupportedTypeError(current);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
}
|