seroval 0.4.0-alpha.4 → 0.4.0-alpha.5
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 +642 -610
- package/dist/cjs/development/index.cjs.map +4 -4
- package/dist/cjs/production/index.cjs +2 -2
- package/dist/esm/development/index.mjs +642 -610
- package/dist/esm/development/index.mjs.map +4 -4
- package/dist/esm/production/index.mjs +2 -2
- package/dist/types/context.d.ts +53 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/tree/async.d.ts +4 -0
- package/dist/types/tree/serialize.d.ts +4 -0
- package/dist/types/tree/shared.d.ts +10 -0
- package/dist/types/tree/sync.d.ts +4 -0
- package/dist/types/tree/types.d.ts +79 -0
- package/package.json +2 -2
- package/src/context.ts +137 -0
- package/src/index.ts +9 -10
- package/src/tree/async.ts +260 -0
- package/src/tree/serialize.ts +563 -0
- package/src/tree/shared.ts +177 -0
- package/src/tree/sync.ts +242 -0
- package/src/tree/types.ts +101 -0
- package/dist/types/tree.d.ts +0 -122
- package/src/tree.ts +0 -1246
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { PrimitiveValue } from '../types';
|
|
2
|
+
export declare const enum SerovalNodeType {
|
|
3
|
+
Primitive = 0,
|
|
4
|
+
BigInt = 1,
|
|
5
|
+
Reference = 2,
|
|
6
|
+
Date = 3,
|
|
7
|
+
RegExp = 4,
|
|
8
|
+
Set = 5,
|
|
9
|
+
Map = 6,
|
|
10
|
+
Array = 7,
|
|
11
|
+
Object = 8,
|
|
12
|
+
NullConstructor = 9,
|
|
13
|
+
Promise = 10,
|
|
14
|
+
Error = 11,
|
|
15
|
+
AggregateError = 12,
|
|
16
|
+
Iterable = 13,
|
|
17
|
+
TypedArray = 14,
|
|
18
|
+
BigIntTypedArray = 15
|
|
19
|
+
}
|
|
20
|
+
export type SerovalPrimitiveNode = [
|
|
21
|
+
type: SerovalNodeType.Primitive,
|
|
22
|
+
value: PrimitiveValue
|
|
23
|
+
];
|
|
24
|
+
export type SerovalReferenceNode = [type: SerovalNodeType.Reference, value: number];
|
|
25
|
+
export type SerovalSemiPrimitiveNode = [type: SerovalNodeType.BigInt, value: string] | [type: SerovalNodeType.Date, value: string, id: number] | [type: SerovalNodeType.RegExp, value: string, id: number] | [
|
|
26
|
+
type: SerovalNodeType.TypedArray,
|
|
27
|
+
value: [constructor: string, array: string, byteOffset: number],
|
|
28
|
+
id: number
|
|
29
|
+
] | [
|
|
30
|
+
type: SerovalNodeType.BigIntTypedArray,
|
|
31
|
+
value: [constructor: string, array: string, byteOffset: number],
|
|
32
|
+
id: number
|
|
33
|
+
];
|
|
34
|
+
export type SerovalDictionaryNode = [key: string[], value: SerovalNode[], size: number];
|
|
35
|
+
export type SerovalSetNode = [type: SerovalNodeType.Set, value: SerovalNode[], id: number];
|
|
36
|
+
export type SerovalMapNode = [
|
|
37
|
+
type: SerovalNodeType.Map,
|
|
38
|
+
value: [key: SerovalNode[], value: SerovalNode[], size: number],
|
|
39
|
+
id: number
|
|
40
|
+
];
|
|
41
|
+
export type SerovalArrayNode = [type: SerovalNodeType.Array, value: SerovalNode[], id: number];
|
|
42
|
+
export type SerovalObjectNode = [
|
|
43
|
+
type: SerovalNodeType.Object,
|
|
44
|
+
value: SerovalDictionaryNode,
|
|
45
|
+
id: number
|
|
46
|
+
];
|
|
47
|
+
export type SerovalNullConstructorNode = [
|
|
48
|
+
type: SerovalNodeType.NullConstructor,
|
|
49
|
+
value: SerovalDictionaryNode,
|
|
50
|
+
id: number
|
|
51
|
+
];
|
|
52
|
+
export type SerovalPromiseNode = [type: SerovalNodeType.Promise, value: SerovalNode, id: number];
|
|
53
|
+
export type SerovalErrorNode = [
|
|
54
|
+
type: SerovalNodeType.Error,
|
|
55
|
+
value: [
|
|
56
|
+
constructor: string,
|
|
57
|
+
message: string,
|
|
58
|
+
options?: SerovalDictionaryNode
|
|
59
|
+
],
|
|
60
|
+
id: number
|
|
61
|
+
];
|
|
62
|
+
export type SerovalAggregateErrorNode = [
|
|
63
|
+
type: SerovalNodeType.AggregateError,
|
|
64
|
+
value: [
|
|
65
|
+
message: string,
|
|
66
|
+
options: SerovalDictionaryNode | undefined,
|
|
67
|
+
errors: SerovalNode
|
|
68
|
+
],
|
|
69
|
+
id: number
|
|
70
|
+
];
|
|
71
|
+
export type SerovalIterableNode = [
|
|
72
|
+
type: SerovalNodeType.Iterable,
|
|
73
|
+
value: [
|
|
74
|
+
options: SerovalDictionaryNode | undefined,
|
|
75
|
+
items: SerovalNode[]
|
|
76
|
+
],
|
|
77
|
+
id: number
|
|
78
|
+
];
|
|
79
|
+
export type SerovalNode = SerovalPrimitiveNode | SerovalReferenceNode | SerovalSemiPrimitiveNode | SerovalSetNode | SerovalMapNode | SerovalArrayNode | SerovalObjectNode | SerovalNullConstructorNode | SerovalPromiseNode | SerovalErrorNode | SerovalAggregateErrorNode | SerovalIterableNode;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "seroval",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.4.0-alpha.
|
|
4
|
+
"version": "0.4.0-alpha.5",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
7
7
|
"src"
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"typesVersions": {
|
|
65
65
|
"*": {}
|
|
66
66
|
},
|
|
67
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "b6e4a61b67d1ba6e6e209dd5ba81cd94fb33d021"
|
|
68
68
|
}
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { parseTargets } from './compat';
|
|
2
|
+
import getIdentifier from './get-identifier';
|
|
3
|
+
|
|
4
|
+
interface IndexAssignment {
|
|
5
|
+
type: 'index';
|
|
6
|
+
source: string;
|
|
7
|
+
value: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface MapAssignment {
|
|
11
|
+
type: 'map';
|
|
12
|
+
source: string;
|
|
13
|
+
key: string;
|
|
14
|
+
value: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface SetAssignment {
|
|
18
|
+
type: 'set';
|
|
19
|
+
source: string;
|
|
20
|
+
value: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Array of assignments to be done (used for recursion)
|
|
24
|
+
export type Assignment =
|
|
25
|
+
| IndexAssignment
|
|
26
|
+
| MapAssignment
|
|
27
|
+
| SetAssignment;
|
|
28
|
+
|
|
29
|
+
export interface ParserContext {
|
|
30
|
+
refs: Map<unknown, number>;
|
|
31
|
+
markedRefs: Set<number>;
|
|
32
|
+
features: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface SerializationContext {
|
|
36
|
+
stack: number[];
|
|
37
|
+
// Map tree refs to actual refs
|
|
38
|
+
validRefs: Map<number, number>;
|
|
39
|
+
// Refs that are...referenced
|
|
40
|
+
markedRefs: Set<number>;
|
|
41
|
+
// Variables
|
|
42
|
+
vars: string[];
|
|
43
|
+
// Array of assignments to be done (used for recursion)
|
|
44
|
+
assignments: Assignment[];
|
|
45
|
+
// Supported features
|
|
46
|
+
features: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface Options {
|
|
50
|
+
target: string | string[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const DEFAULT_OPTIONS: Options = {
|
|
54
|
+
target: 'es2023',
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export function createParserContext(options: Partial<Options> = {}): ParserContext {
|
|
58
|
+
// eslint-disable-next-line prefer-object-spread
|
|
59
|
+
const result = Object.assign({}, DEFAULT_OPTIONS, options || {});
|
|
60
|
+
return {
|
|
61
|
+
markedRefs: new Set(),
|
|
62
|
+
refs: new Map(),
|
|
63
|
+
features: parseTargets(result.target),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface SerializationOptions {
|
|
68
|
+
markedRefs: number[] | Set<number>;
|
|
69
|
+
features: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function createSerializationContext(options: SerializationOptions): SerializationContext {
|
|
73
|
+
return {
|
|
74
|
+
stack: [],
|
|
75
|
+
vars: [],
|
|
76
|
+
assignments: [],
|
|
77
|
+
validRefs: new Map(),
|
|
78
|
+
features: options.features,
|
|
79
|
+
markedRefs: new Set(options.markedRefs),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Increments the number of references the referenced value has
|
|
85
|
+
*/
|
|
86
|
+
export function markRef(ctx: ParserContext | SerializationContext, current: number) {
|
|
87
|
+
ctx.markedRefs.add(current);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Creates a new reference ID from a given reference ID
|
|
92
|
+
* This new reference ID means that the reference itself
|
|
93
|
+
* has been referenced at least once, and is used to generate
|
|
94
|
+
* the variables
|
|
95
|
+
*/
|
|
96
|
+
function createValidRef(
|
|
97
|
+
ctx: SerializationContext,
|
|
98
|
+
index: number,
|
|
99
|
+
) {
|
|
100
|
+
const current = ctx.validRefs.get(index);
|
|
101
|
+
if (current != null) {
|
|
102
|
+
return current;
|
|
103
|
+
}
|
|
104
|
+
const id = ctx.validRefs.size;
|
|
105
|
+
ctx.validRefs.set(index, id);
|
|
106
|
+
return id;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Creates the reference param (identifier) from the given reference ID
|
|
111
|
+
* Calling this function means the value has been referenced somewhere
|
|
112
|
+
*/
|
|
113
|
+
export function getRefParam(ctx: SerializationContext, index: number) {
|
|
114
|
+
const actualIndex = createValidRef(ctx, index);
|
|
115
|
+
if (ctx.vars[actualIndex]) {
|
|
116
|
+
return ctx.vars[actualIndex];
|
|
117
|
+
}
|
|
118
|
+
const result = getIdentifier(actualIndex);
|
|
119
|
+
ctx.vars[actualIndex] = result;
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Creates a reference ID from the given values
|
|
125
|
+
*/
|
|
126
|
+
export function createRef(
|
|
127
|
+
ctx: ParserContext,
|
|
128
|
+
index: unknown,
|
|
129
|
+
) {
|
|
130
|
+
const current = ctx.refs.get(index);
|
|
131
|
+
if (current != null) {
|
|
132
|
+
return current;
|
|
133
|
+
}
|
|
134
|
+
const id = ctx.refs.size;
|
|
135
|
+
ctx.refs.set(index, id);
|
|
136
|
+
return id;
|
|
137
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -2,18 +2,17 @@
|
|
|
2
2
|
import { isPrimitive } from './checks';
|
|
3
3
|
import { Feature } from './compat';
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
createSerializationContext,
|
|
5
|
+
SerializationContext,
|
|
7
6
|
getRefParam,
|
|
8
7
|
Options,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} from './tree';
|
|
8
|
+
createParserContext,
|
|
9
|
+
createSerializationContext,
|
|
10
|
+
} from './context';
|
|
11
|
+
import parseAsync from './tree/async';
|
|
12
|
+
import serializeTree, { resolvePatches } from './tree/serialize';
|
|
13
|
+
import { serializePrimitive } from './tree/shared';
|
|
14
|
+
import parseSync from './tree/sync';
|
|
15
|
+
import { SerovalNode } from './tree/types';
|
|
17
16
|
import {
|
|
18
17
|
AsyncServerValue,
|
|
19
18
|
PrimitiveValue,
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/* eslint-disable no-await-in-loop */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-use-before-define */
|
|
3
|
+
import assert from '../assert';
|
|
4
|
+
import {
|
|
5
|
+
isIterable,
|
|
6
|
+
isPrimitive,
|
|
7
|
+
constructorCheck,
|
|
8
|
+
isPromise,
|
|
9
|
+
} from '../checks';
|
|
10
|
+
import { Feature } from '../compat';
|
|
11
|
+
import { createRef, ParserContext } from '../context';
|
|
12
|
+
import { AsyncServerValue } from '../types';
|
|
13
|
+
import {
|
|
14
|
+
generateRef,
|
|
15
|
+
generateSemiPrimitiveValue,
|
|
16
|
+
getErrorConstructor,
|
|
17
|
+
getErrorOptions,
|
|
18
|
+
getIterableOptions,
|
|
19
|
+
serializePrimitive,
|
|
20
|
+
} from './shared';
|
|
21
|
+
import {
|
|
22
|
+
SerovalAggregateErrorNode,
|
|
23
|
+
SerovalArrayNode,
|
|
24
|
+
SerovalDictionaryNode,
|
|
25
|
+
SerovalErrorNode,
|
|
26
|
+
SerovalIterableNode,
|
|
27
|
+
SerovalMapNode,
|
|
28
|
+
SerovalNode,
|
|
29
|
+
SerovalNodeType,
|
|
30
|
+
SerovalSetNode,
|
|
31
|
+
} from './types';
|
|
32
|
+
|
|
33
|
+
async function serializePropertiesAsync(
|
|
34
|
+
ctx: ParserContext,
|
|
35
|
+
properties: Record<string, unknown>,
|
|
36
|
+
): Promise<SerovalDictionaryNode> {
|
|
37
|
+
const keys = Object.keys(properties);
|
|
38
|
+
const size = keys.length;
|
|
39
|
+
const keyNodes = new Array<string>(size);
|
|
40
|
+
const valueNodes = new Array<SerovalNode>(size);
|
|
41
|
+
const deferredKeys = new Array<string>(size);
|
|
42
|
+
const deferredValues = new Array<AsyncServerValue>(size);
|
|
43
|
+
let deferredSize = 0;
|
|
44
|
+
let nodesSize = 0;
|
|
45
|
+
for (const key of keys) {
|
|
46
|
+
if (isIterable(properties[key])) {
|
|
47
|
+
deferredKeys[deferredSize] = key;
|
|
48
|
+
deferredValues[deferredSize] = properties[key] as AsyncServerValue;
|
|
49
|
+
deferredSize++;
|
|
50
|
+
} else {
|
|
51
|
+
keyNodes[nodesSize] = key;
|
|
52
|
+
valueNodes[nodesSize] = await generateTreeAsync(ctx, properties[key] as AsyncServerValue);
|
|
53
|
+
nodesSize++;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
for (let i = 0; i < deferredSize; i++) {
|
|
57
|
+
keyNodes[nodesSize + i] = deferredKeys[i];
|
|
58
|
+
valueNodes[nodesSize + i] = await generateTreeAsync(ctx, deferredValues[i]);
|
|
59
|
+
}
|
|
60
|
+
return [keyNodes, valueNodes, size];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function generateSetNode(
|
|
64
|
+
ctx: ParserContext,
|
|
65
|
+
current: Set<AsyncServerValue>,
|
|
66
|
+
id: number,
|
|
67
|
+
): Promise<SerovalSetNode> {
|
|
68
|
+
assert(ctx.features & Feature.Set, 'Unsupported type "Set"');
|
|
69
|
+
const len = current.size;
|
|
70
|
+
const nodes = new Array<SerovalNode>(len);
|
|
71
|
+
const deferred = new Array<AsyncServerValue>(len);
|
|
72
|
+
let deferredSize = 0;
|
|
73
|
+
let nodeSize = 0;
|
|
74
|
+
for (const item of current.keys()) {
|
|
75
|
+
// Iterables are lazy, so the evaluation must be deferred
|
|
76
|
+
if (isIterable(item)) {
|
|
77
|
+
deferred[deferredSize++] = item;
|
|
78
|
+
} else {
|
|
79
|
+
nodes[nodeSize++] = await generateTreeAsync(ctx, item);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Parse deferred items
|
|
83
|
+
for (let i = 0; i < deferredSize; i++) {
|
|
84
|
+
nodes[nodeSize + i] = await generateTreeAsync(ctx, deferred[i]);
|
|
85
|
+
}
|
|
86
|
+
return [SerovalNodeType.Set, nodes, id];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function generateMapNode(
|
|
90
|
+
ctx: ParserContext,
|
|
91
|
+
current: Map<AsyncServerValue, AsyncServerValue>,
|
|
92
|
+
id: number,
|
|
93
|
+
): Promise<SerovalMapNode> {
|
|
94
|
+
assert(ctx.features & Feature.Map, 'Unsupported type "Map"');
|
|
95
|
+
const len = current.size;
|
|
96
|
+
const keyNodes = new Array<SerovalNode>(len);
|
|
97
|
+
const valueNodes = new Array<SerovalNode>(len);
|
|
98
|
+
const deferredKey = new Array<AsyncServerValue>(len);
|
|
99
|
+
const deferredValue = new Array<AsyncServerValue>(len);
|
|
100
|
+
let deferredSize = 0;
|
|
101
|
+
let nodeSize = 0;
|
|
102
|
+
for (const [key, value] of current.entries()) {
|
|
103
|
+
// Either key or value might be an iterable
|
|
104
|
+
if (isIterable(key) || isIterable(value)) {
|
|
105
|
+
deferredKey[deferredSize] = key;
|
|
106
|
+
deferredValue[deferredSize] = value;
|
|
107
|
+
deferredSize++;
|
|
108
|
+
} else {
|
|
109
|
+
keyNodes[nodeSize] = await generateTreeAsync(ctx, key);
|
|
110
|
+
valueNodes[nodeSize] = await generateTreeAsync(ctx, value);
|
|
111
|
+
nodeSize++;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (let i = 0; i < deferredSize; i++) {
|
|
115
|
+
keyNodes[nodeSize + i] = await generateTreeAsync(ctx, deferredKey[i]);
|
|
116
|
+
valueNodes[nodeSize + i] = await generateTreeAsync(ctx, deferredValue[i]);
|
|
117
|
+
}
|
|
118
|
+
return [SerovalNodeType.Map, [keyNodes, valueNodes, len], id];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function generateNodeList(
|
|
122
|
+
ctx: ParserContext,
|
|
123
|
+
current: AsyncServerValue[],
|
|
124
|
+
) {
|
|
125
|
+
const size = current.length;
|
|
126
|
+
const nodes = new Array<SerovalNode>(size);
|
|
127
|
+
const deferred = new Array<AsyncServerValue>(size);
|
|
128
|
+
for (let i = 0; i < size; i++) {
|
|
129
|
+
if (i in current) {
|
|
130
|
+
if (isIterable(current[i])) {
|
|
131
|
+
deferred[i] = current[i];
|
|
132
|
+
} else {
|
|
133
|
+
nodes[i] = await generateTreeAsync(ctx, current[i]);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
for (let i = 0; i < size; i++) {
|
|
138
|
+
if (i in deferred) {
|
|
139
|
+
nodes[i] = await generateTreeAsync(ctx, deferred[i]);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return nodes;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function generateArrayNode(
|
|
146
|
+
ctx: ParserContext,
|
|
147
|
+
current: AsyncServerValue[],
|
|
148
|
+
id: number,
|
|
149
|
+
): Promise<SerovalArrayNode> {
|
|
150
|
+
return [SerovalNodeType.Array, await generateNodeList(ctx, current), id];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function generateAggregateErrorNode(
|
|
154
|
+
ctx: ParserContext,
|
|
155
|
+
current: AggregateError,
|
|
156
|
+
id: number,
|
|
157
|
+
): Promise<SerovalAggregateErrorNode> {
|
|
158
|
+
const options = getErrorOptions(current);
|
|
159
|
+
const optionsNode = options
|
|
160
|
+
? await serializePropertiesAsync(ctx, options)
|
|
161
|
+
: undefined;
|
|
162
|
+
const errorsNode = await generateTreeAsync(ctx, current.errors as AsyncServerValue);
|
|
163
|
+
return [
|
|
164
|
+
SerovalNodeType.AggregateError,
|
|
165
|
+
[current.message, optionsNode, errorsNode],
|
|
166
|
+
id,
|
|
167
|
+
];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function generateErrorNode(
|
|
171
|
+
ctx: ParserContext,
|
|
172
|
+
current: Error,
|
|
173
|
+
id: number,
|
|
174
|
+
): Promise<SerovalErrorNode> {
|
|
175
|
+
const options = getErrorOptions(current);
|
|
176
|
+
const optionsNode = options
|
|
177
|
+
? await serializePropertiesAsync(ctx, options)
|
|
178
|
+
: undefined;
|
|
179
|
+
return [
|
|
180
|
+
SerovalNodeType.Error,
|
|
181
|
+
[getErrorConstructor(current), current.message, optionsNode],
|
|
182
|
+
id,
|
|
183
|
+
];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function generateIterableNode(
|
|
187
|
+
ctx: ParserContext,
|
|
188
|
+
current: Iterable<AsyncServerValue>,
|
|
189
|
+
id: number,
|
|
190
|
+
): Promise<SerovalIterableNode> {
|
|
191
|
+
assert(ctx.features & Feature.SymbolIterator, 'Unsupported type "Iterable"');
|
|
192
|
+
const options = getIterableOptions(current);
|
|
193
|
+
return [SerovalNodeType.Iterable, [
|
|
194
|
+
// Parse options first before the items
|
|
195
|
+
options ? await serializePropertiesAsync(ctx, options) : undefined,
|
|
196
|
+
await generateNodeList(ctx, Array.from(current)),
|
|
197
|
+
], id];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function generateTreeAsync(
|
|
201
|
+
ctx: ParserContext,
|
|
202
|
+
current: AsyncServerValue,
|
|
203
|
+
): Promise<SerovalNode> {
|
|
204
|
+
if (isPrimitive(current)) {
|
|
205
|
+
return [SerovalNodeType.Primitive, serializePrimitive(current)];
|
|
206
|
+
}
|
|
207
|
+
// Non-primitive values needs a reference ID
|
|
208
|
+
// mostly because the values themselves are stateful
|
|
209
|
+
const id = generateRef(ctx, current);
|
|
210
|
+
if (Array.isArray(id)) {
|
|
211
|
+
return id;
|
|
212
|
+
}
|
|
213
|
+
const semiPrimitive = generateSemiPrimitiveValue(ctx, current, id);
|
|
214
|
+
if (semiPrimitive) {
|
|
215
|
+
return semiPrimitive;
|
|
216
|
+
}
|
|
217
|
+
if (isPromise(current)) {
|
|
218
|
+
assert(ctx.features & Feature.Promise, 'Unsupported type "Promise"');
|
|
219
|
+
return current.then(async (value) => [
|
|
220
|
+
SerovalNodeType.Promise,
|
|
221
|
+
await generateTreeAsync(ctx, value),
|
|
222
|
+
id,
|
|
223
|
+
]);
|
|
224
|
+
}
|
|
225
|
+
if (constructorCheck<Set<AsyncServerValue>>(current, Set)) {
|
|
226
|
+
return generateSetNode(ctx, current, id);
|
|
227
|
+
}
|
|
228
|
+
if (constructorCheck<Map<AsyncServerValue, AsyncServerValue>>(current, Map)) {
|
|
229
|
+
return generateMapNode(ctx, current, id);
|
|
230
|
+
}
|
|
231
|
+
if (Array.isArray(current)) {
|
|
232
|
+
return generateArrayNode(ctx, current, id);
|
|
233
|
+
}
|
|
234
|
+
if (current instanceof AggregateError && ctx.features & Feature.AggregateError) {
|
|
235
|
+
return generateAggregateErrorNode(ctx, current, id);
|
|
236
|
+
}
|
|
237
|
+
if (current instanceof Error) {
|
|
238
|
+
return generateErrorNode(ctx, current, id);
|
|
239
|
+
}
|
|
240
|
+
if (isIterable(current)) {
|
|
241
|
+
return generateIterableNode(ctx, current, id);
|
|
242
|
+
}
|
|
243
|
+
const empty = current.constructor == null;
|
|
244
|
+
if (current.constructor === Object || empty) {
|
|
245
|
+
return [
|
|
246
|
+
empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,
|
|
247
|
+
await serializePropertiesAsync(ctx, current as Record<string, unknown>),
|
|
248
|
+
id,
|
|
249
|
+
];
|
|
250
|
+
}
|
|
251
|
+
throw new Error('Unsupported value');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export default async function parseAsync(
|
|
255
|
+
ctx: ParserContext,
|
|
256
|
+
current: AsyncServerValue,
|
|
257
|
+
) {
|
|
258
|
+
const result = await generateTreeAsync(ctx, current);
|
|
259
|
+
return [result, createRef(ctx, current), result[0] === SerovalNodeType.Object] as const;
|
|
260
|
+
}
|