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