seroval 0.4.0-alpha.4 → 0.4.0-alpha.6

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.
@@ -0,0 +1,177 @@
1
+ import assert from '../assert';
2
+ import { constructorCheck } from '../checks';
3
+ import { Feature } from '../compat';
4
+ import { SerializationContext, ParserContext, markRef } from '../context';
5
+ import quote from '../quote';
6
+ import { ErrorValue, PrimitiveValue } from '../types';
7
+ import { SerovalNode, SerovalReferenceNode, SerovalNodeType } from './types';
8
+
9
+ export function getErrorConstructor(error: ErrorValue) {
10
+ if (error instanceof EvalError) {
11
+ return 'EvalError';
12
+ }
13
+ if (error instanceof RangeError) {
14
+ return 'RangeError';
15
+ }
16
+ if (error instanceof ReferenceError) {
17
+ return 'ReferenceError';
18
+ }
19
+ if (error instanceof SyntaxError) {
20
+ return 'SyntaxError';
21
+ }
22
+ if (error instanceof TypeError) {
23
+ return 'TypeError';
24
+ }
25
+ if (error instanceof URIError) {
26
+ return 'URIError';
27
+ }
28
+ return 'Error';
29
+ }
30
+
31
+ export function getErrorOptions(
32
+ error: Error,
33
+ ) {
34
+ let options: Record<string, any> | undefined;
35
+ const constructor = getErrorConstructor(error);
36
+ // Name has been modified
37
+ if (error.name !== constructor) {
38
+ options = { name: error.name };
39
+ } else if (error.constructor.name !== constructor) {
40
+ // Otherwise, name is overriden because
41
+ // the Error class is extended
42
+ options = { name: error.constructor.name };
43
+ }
44
+ const names = Object.getOwnPropertyNames(error);
45
+ for (const name of names) {
46
+ if (name !== 'name' && name !== 'message') {
47
+ options = options || {};
48
+ options[name] = error[name as keyof Error];
49
+ }
50
+ }
51
+ return options;
52
+ }
53
+
54
+ export function getIterableOptions(obj: Iterable<any>) {
55
+ const names = Object.getOwnPropertyNames(obj);
56
+ if (names.length) {
57
+ const options: Record<string, unknown> = {};
58
+ for (const name of names) {
59
+ options[name] = obj[name as unknown as keyof typeof obj];
60
+ }
61
+ return options;
62
+ }
63
+ return undefined;
64
+ }
65
+
66
+ export function isReferenceInStack(
67
+ ctx: SerializationContext,
68
+ node: SerovalNode,
69
+ ): node is SerovalReferenceNode {
70
+ return node[0] === SerovalNodeType.Reference && ctx.stack.includes(node[1]);
71
+ }
72
+
73
+ export function generateRef(
74
+ ctx: ParserContext,
75
+ current: unknown,
76
+ ): number | SerovalReferenceNode {
77
+ // Check if reference number already exists
78
+ const ref = ctx.refs.has(current);
79
+ if (ref) {
80
+ // Exists, means this value is currently
81
+ // being referenced
82
+ const refID = ctx.refs.get(current) || 0;
83
+ // Mark reference
84
+ markRef(ctx, refID);
85
+ return [SerovalNodeType.Reference, refID];
86
+ }
87
+ // Create a new reference ID
88
+ const id = ctx.refs.size;
89
+ ctx.refs.set(current, id);
90
+ return id;
91
+ }
92
+
93
+ export function generateSemiPrimitiveValue(
94
+ ctx: ParserContext,
95
+ current: unknown,
96
+ id: number,
97
+ ): SerovalNode | undefined {
98
+ if (typeof current === 'bigint') {
99
+ assert(ctx.features & Feature.BigInt, 'Unsupported type "BigInt"');
100
+ return [SerovalNodeType.BigInt, `${current}n`];
101
+ }
102
+ if (constructorCheck<Date>(current, Date)) {
103
+ return [SerovalNodeType.Date, current.toISOString(), id];
104
+ }
105
+ if (constructorCheck<RegExp>(current, RegExp)) {
106
+ return [SerovalNodeType.RegExp, String(current), id];
107
+ }
108
+ if (
109
+ constructorCheck<Int8Array>(current, Int8Array)
110
+ || constructorCheck<Int16Array>(current, Int16Array)
111
+ || constructorCheck<Int32Array>(current, Int32Array)
112
+ || constructorCheck<Uint8Array>(current, Uint8Array)
113
+ || constructorCheck<Uint16Array>(current, Uint16Array)
114
+ || constructorCheck<Uint32Array>(current, Uint32Array)
115
+ || constructorCheck<Uint8ClampedArray>(current, Uint8ClampedArray)
116
+ || constructorCheck<Float32Array>(current, Float32Array)
117
+ || constructorCheck<Float64Array>(current, Float64Array)
118
+ ) {
119
+ const constructor = current.constructor.name;
120
+ assert(ctx.features & Feature.TypedArray, `Unsupported value type "${constructor}"`);
121
+ return [SerovalNodeType.TypedArray, [constructor, current.toString(), current.byteOffset], id];
122
+ }
123
+ if (
124
+ constructorCheck<BigInt64Array>(current, BigInt64Array)
125
+ || constructorCheck<BigUint64Array>(current, BigUint64Array)
126
+ ) {
127
+ const constructor = current.constructor.name;
128
+ assert(
129
+ ctx.features & (Feature.BigIntTypedArray),
130
+ `Unsupported value type "${constructor}"`,
131
+ );
132
+ let result = '';
133
+ const cap = current.length - 1;
134
+ for (let i = 0; i < cap; i++) {
135
+ result += `${current[i]}n,`;
136
+ }
137
+ result += `"${current[cap]}"`;
138
+ return [
139
+ SerovalNodeType.BigIntTypedArray,
140
+ [constructor, result, current.byteOffset],
141
+ id,
142
+ ];
143
+ }
144
+ return undefined;
145
+ }
146
+
147
+ export function serializePrimitive(
148
+ value: PrimitiveValue,
149
+ ): string | number | null {
150
+ // Shortened forms
151
+ if (value === true) {
152
+ return '!0';
153
+ }
154
+ if (value === false) {
155
+ return '!1';
156
+ }
157
+ if (value === undefined) {
158
+ return 'void 0';
159
+ }
160
+ if (value === null) {
161
+ return null;
162
+ }
163
+ if (typeof value === 'string') {
164
+ return quote(value);
165
+ }
166
+ // negative 0 isn't the same as 0
167
+ if (Object.is(value, -0)) {
168
+ return '-0';
169
+ }
170
+ if (Object.is(value, Infinity)) {
171
+ return '1/0';
172
+ }
173
+ if (Object.is(value, -Infinity)) {
174
+ return '-1/0';
175
+ }
176
+ return value;
177
+ }
@@ -0,0 +1,234 @@
1
+ /* eslint-disable @typescript-eslint/no-use-before-define */
2
+ import assert from '../assert';
3
+ import { isIterable, isPrimitive, constructorCheck } from '../checks';
4
+ import { Feature } from '../compat';
5
+ import { createRef, ParserContext } from '../context';
6
+ import { ServerValue } from '../types';
7
+ import {
8
+ generateRef,
9
+ generateSemiPrimitiveValue,
10
+ getErrorConstructor,
11
+ getErrorOptions,
12
+ getIterableOptions,
13
+ serializePrimitive,
14
+ } from './shared';
15
+ import {
16
+ SerovalAggregateErrorNode,
17
+ SerovalArrayNode,
18
+ SerovalDictionaryNode,
19
+ SerovalErrorNode,
20
+ SerovalIterableNode,
21
+ SerovalMapNode,
22
+ SerovalNode,
23
+ SerovalNodeType,
24
+ SerovalSetNode,
25
+ } from './types';
26
+
27
+ function generateDictionary(
28
+ ctx: ParserContext,
29
+ properties: Record<string, ServerValue>,
30
+ ): SerovalDictionaryNode {
31
+ const keys = Object.keys(properties);
32
+ const nodes: SerovalDictionaryNode = {};
33
+ const deferred: Record<string, ServerValue> = {};
34
+ for (const key of keys) {
35
+ if (isIterable(properties[key])) {
36
+ deferred[key] = properties[key];
37
+ } else {
38
+ nodes[key] = generateTreeSync(ctx, properties[key]);
39
+ }
40
+ }
41
+ for (const key of Object.keys(deferred)) {
42
+ nodes[key] = generateTreeSync(ctx, deferred[key]);
43
+ }
44
+ return nodes;
45
+ }
46
+
47
+ function generateSetNode(
48
+ ctx: ParserContext,
49
+ current: Set<ServerValue>,
50
+ id: number,
51
+ ): SerovalSetNode {
52
+ assert(ctx.features & Feature.Set, 'Unsupported type "Set"');
53
+ const len = current.size;
54
+ const nodes = new Array<SerovalNode>(len);
55
+ const deferred = new Array<ServerValue>(len);
56
+ let deferredSize = 0;
57
+ let nodeSize = 0;
58
+ for (const item of current.keys()) {
59
+ // Iterables are lazy, so the evaluation must be deferred
60
+ if (isIterable(item)) {
61
+ deferred[deferredSize++] = item;
62
+ } else {
63
+ nodes[nodeSize++] = generateTreeSync(ctx, item);
64
+ }
65
+ }
66
+ // Parse deferred items
67
+ for (let i = 0; i < deferredSize; i++) {
68
+ nodes[nodeSize + i] = generateTreeSync(ctx, deferred[i]);
69
+ }
70
+ return [SerovalNodeType.Set, nodes, id];
71
+ }
72
+
73
+ function generateMapNode(
74
+ ctx: ParserContext,
75
+ current: Map<ServerValue, ServerValue>,
76
+ id: number,
77
+ ): SerovalMapNode {
78
+ assert(ctx.features & Feature.Map, 'Unsupported type "Map"');
79
+ const len = current.size;
80
+ const keyNodes = new Array<SerovalNode>(len);
81
+ const valueNodes = new Array<SerovalNode>(len);
82
+ const deferredKey = new Array<ServerValue>(len);
83
+ const deferredValue = new Array<ServerValue>(len);
84
+ let deferredSize = 0;
85
+ let nodeSize = 0;
86
+ for (const [key, value] of current.entries()) {
87
+ // Either key or value might be an iterable
88
+ if (isIterable(key) || isIterable(value)) {
89
+ deferredKey[deferredSize] = key;
90
+ deferredValue[deferredSize] = value;
91
+ deferredSize++;
92
+ } else {
93
+ keyNodes[nodeSize] = generateTreeSync(ctx, key);
94
+ valueNodes[nodeSize] = generateTreeSync(ctx, value);
95
+ nodeSize++;
96
+ }
97
+ }
98
+ for (let i = 0; i < deferredSize; i++) {
99
+ keyNodes[nodeSize + i] = generateTreeSync(ctx, deferredKey[i]);
100
+ valueNodes[nodeSize + i] = generateTreeSync(ctx, deferredValue[i]);
101
+ }
102
+ return [SerovalNodeType.Map, [keyNodes, valueNodes, len], id];
103
+ }
104
+
105
+ function generateNodeList(
106
+ ctx: ParserContext,
107
+ current: ServerValue[],
108
+ ) {
109
+ const size = current.length;
110
+ const nodes = new Array<SerovalNode>(size);
111
+ const deferred = new Array<ServerValue>(size);
112
+ for (let i = 0; i < size; i++) {
113
+ if (i in current) {
114
+ if (isIterable(current[i])) {
115
+ deferred[i] = current[i];
116
+ } else {
117
+ nodes[i] = generateTreeSync(ctx, current[i]);
118
+ }
119
+ }
120
+ }
121
+ for (let i = 0; i < size; i++) {
122
+ if (i in deferred) {
123
+ nodes[i] = generateTreeSync(ctx, deferred[i]);
124
+ }
125
+ }
126
+ return nodes;
127
+ }
128
+
129
+ function generateArrayNode(
130
+ ctx: ParserContext,
131
+ current: ServerValue[],
132
+ id: number,
133
+ ): SerovalArrayNode {
134
+ return [SerovalNodeType.Array, generateNodeList(ctx, current), id];
135
+ }
136
+
137
+ function generateAggregateErrorNode(
138
+ ctx: ParserContext,
139
+ current: AggregateError,
140
+ id: number,
141
+ ): SerovalAggregateErrorNode {
142
+ const options = getErrorOptions(current);
143
+ const optionsNode = options
144
+ ? generateDictionary(ctx, options)
145
+ : undefined;
146
+ const errorsNode = generateTreeSync(ctx, current.errors as ServerValue);
147
+ return [SerovalNodeType.AggregateError, [current.message, optionsNode, errorsNode], id];
148
+ }
149
+
150
+ function generateErrorNode(
151
+ ctx: ParserContext,
152
+ current: Error,
153
+ id: number,
154
+ ): SerovalErrorNode {
155
+ const options = getErrorOptions(current);
156
+ const optionsNode = options
157
+ ? generateDictionary(ctx, options)
158
+ : undefined;
159
+ return [
160
+ SerovalNodeType.Error,
161
+ [getErrorConstructor(current), current.message, optionsNode],
162
+ id,
163
+ ];
164
+ }
165
+
166
+ function generateIterableNode(
167
+ ctx: ParserContext,
168
+ current: Iterable<ServerValue>,
169
+ id: number,
170
+ ): SerovalIterableNode {
171
+ assert(ctx.features & Feature.SymbolIterator, 'Unsupported type "Iterable"');
172
+ const options = getIterableOptions(current);
173
+ return [SerovalNodeType.Iterable, [
174
+ // Parse options first before the items
175
+ options
176
+ ? generateDictionary(ctx, options as Record<string, ServerValue>)
177
+ : undefined,
178
+ generateNodeList(ctx, Array.from(current)),
179
+ ], id];
180
+ }
181
+
182
+ function generateTreeSync(
183
+ ctx: ParserContext,
184
+ current: ServerValue,
185
+ ): SerovalNode {
186
+ if (isPrimitive(current)) {
187
+ return [SerovalNodeType.Primitive, serializePrimitive(current)];
188
+ }
189
+ // Non-primitive values needs a reference ID
190
+ // mostly because the values themselves are stateful
191
+ const id = generateRef(ctx, current);
192
+ if (Array.isArray(id)) {
193
+ return id;
194
+ }
195
+ const semiPrimitive = generateSemiPrimitiveValue(ctx, current, id);
196
+ if (semiPrimitive) {
197
+ return semiPrimitive;
198
+ }
199
+ if (constructorCheck<Set<ServerValue>>(current, Set)) {
200
+ return generateSetNode(ctx, current, id);
201
+ }
202
+ if (constructorCheck<Map<ServerValue, ServerValue>>(current, Map)) {
203
+ return generateMapNode(ctx, current, id);
204
+ }
205
+ if (Array.isArray(current)) {
206
+ return generateArrayNode(ctx, current, id);
207
+ }
208
+ if (current instanceof AggregateError && ctx.features & Feature.AggregateError) {
209
+ return generateAggregateErrorNode(ctx, current, id);
210
+ }
211
+ if (current instanceof Error) {
212
+ return generateErrorNode(ctx, current, id);
213
+ }
214
+ if (isIterable(current)) {
215
+ return generateIterableNode(ctx, current, id);
216
+ }
217
+ const empty = current.constructor == null;
218
+ if (current.constructor === Object || empty) {
219
+ return [
220
+ empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,
221
+ generateDictionary(ctx, current as Record<string, ServerValue>),
222
+ id,
223
+ ];
224
+ }
225
+ throw new Error('Unsupported value');
226
+ }
227
+
228
+ export default function parseSync(
229
+ ctx: ParserContext,
230
+ current: ServerValue,
231
+ ) {
232
+ const result = generateTreeSync(ctx, current);
233
+ return [result, createRef(ctx, current), result[0] === SerovalNodeType.Object] as const;
234
+ }
@@ -0,0 +1,101 @@
1
+ import { PrimitiveValue } from '../types';
2
+
3
+ export const enum SerovalNodeType {
4
+ Primitive,
5
+ BigInt,
6
+ Reference,
7
+ Date,
8
+ RegExp,
9
+ Set,
10
+ Map,
11
+ Array,
12
+ Object,
13
+ NullConstructor,
14
+ Promise,
15
+ Error,
16
+ AggregateError,
17
+ Iterable,
18
+ TypedArray,
19
+ BigIntTypedArray,
20
+ }
21
+
22
+ export type SerovalPrimitiveNode = [
23
+ type: SerovalNodeType.Primitive,
24
+ value: PrimitiveValue,
25
+ ];
26
+ export type SerovalReferenceNode = [type: SerovalNodeType.Reference, value: number];
27
+ export type SerovalSemiPrimitiveNode =
28
+ | [type: SerovalNodeType.BigInt, value: string]
29
+ | [type: SerovalNodeType.Date, value: string, id: number]
30
+ | [type: SerovalNodeType.RegExp, value: string, id: number]
31
+ | [
32
+ type: SerovalNodeType.TypedArray,
33
+ value: [constructor: string, array: string, byteOffset: number],
34
+ id: number
35
+ ]
36
+ | [
37
+ type: SerovalNodeType.BigIntTypedArray,
38
+ value: [constructor: string, array: string, byteOffset: number],
39
+ id: number
40
+ ];
41
+
42
+ export type SerovalDictionaryNode = Record<string, SerovalNode>;
43
+ export type SerovalSetNode = [type: SerovalNodeType.Set, value: SerovalNode[], id: number];
44
+ export type SerovalMapNode = [
45
+ type: SerovalNodeType.Map,
46
+ value: [key: SerovalNode[], value: SerovalNode[], size: number],
47
+ id: number
48
+ ];
49
+ export type SerovalArrayNode = [type: SerovalNodeType.Array, value: SerovalNode[], id: number];
50
+ export type SerovalObjectNode = [
51
+ type: SerovalNodeType.Object,
52
+ value: SerovalDictionaryNode,
53
+ id: number
54
+ ];
55
+ export type SerovalNullConstructorNode = [
56
+ type: SerovalNodeType.NullConstructor,
57
+ value: SerovalDictionaryNode,
58
+ id: number,
59
+ ];
60
+ export type SerovalPromiseNode = [type: SerovalNodeType.Promise, value: SerovalNode, id: number];
61
+ export type SerovalErrorNode = [
62
+ type: SerovalNodeType.Error,
63
+ value: [
64
+ constructor: string,
65
+ message: string,
66
+ options?: SerovalDictionaryNode,
67
+ ],
68
+ id: number
69
+ ];
70
+ export type SerovalAggregateErrorNode = [
71
+ type: SerovalNodeType.AggregateError,
72
+ value: [
73
+ message: string,
74
+ options: SerovalDictionaryNode | undefined,
75
+ errors: SerovalNode,
76
+ ],
77
+ id: number
78
+ ];
79
+
80
+ export type SerovalIterableNode = [
81
+ type: SerovalNodeType.Iterable,
82
+ value: [
83
+ options: SerovalDictionaryNode | undefined,
84
+ items: SerovalNode[],
85
+ ],
86
+ id: number,
87
+ ];
88
+
89
+ export type SerovalNode =
90
+ | SerovalPrimitiveNode
91
+ | SerovalReferenceNode
92
+ | SerovalSemiPrimitiveNode
93
+ | SerovalSetNode
94
+ | SerovalMapNode
95
+ | SerovalArrayNode
96
+ | SerovalObjectNode
97
+ | SerovalNullConstructorNode
98
+ | SerovalPromiseNode
99
+ | SerovalErrorNode
100
+ | SerovalAggregateErrorNode
101
+ | SerovalIterableNode;
@@ -1,122 +0,0 @@
1
- import { AsyncServerValue, PrimitiveValue, ServerValue } from './types';
2
- interface IndexAssignment {
3
- type: 'index';
4
- source: string;
5
- value: string;
6
- }
7
- interface MapAssignment {
8
- type: 'map';
9
- source: string;
10
- key: string;
11
- value: string;
12
- }
13
- interface SetAssignment {
14
- type: 'set';
15
- source: string;
16
- value: string;
17
- }
18
- export type Assignment = IndexAssignment | MapAssignment | SetAssignment;
19
- export interface ParserContext {
20
- refs: Map<unknown, number>;
21
- markedRefs: Set<number>;
22
- features: number;
23
- }
24
- export interface SerializationContext {
25
- stack: number[];
26
- validRefs: Map<number, number>;
27
- markedRefs: Set<number>;
28
- vars: string[];
29
- assignments: Assignment[];
30
- features: number;
31
- }
32
- export interface Options {
33
- target: string | string[];
34
- }
35
- export declare function createParserContext(options?: Partial<Options>): ParserContext;
36
- export interface SerializationOptions {
37
- markedRefs: number[] | Set<number>;
38
- features: number;
39
- }
40
- export declare function createSerializationContext(options: SerializationOptions): SerializationContext;
41
- export declare function resolvePatches(ctx: SerializationContext): string | undefined;
42
- /**
43
- * Creates the reference param (identifier) from the given reference ID
44
- * Calling this function means the value has been referenced somewhere
45
- */
46
- export declare function getRefParam(ctx: SerializationContext, index: number): string;
47
- declare const enum SerovalNodeType {
48
- Primitive = 0,
49
- BigInt = 1,
50
- Reference = 2,
51
- Date = 3,
52
- RegExp = 4,
53
- Set = 5,
54
- Map = 6,
55
- Array = 7,
56
- Object = 8,
57
- NullConstructor = 9,
58
- Promise = 10,
59
- Error = 11,
60
- AggregateError = 12,
61
- Iterable = 13,
62
- TypedArray = 14,
63
- BigIntTypedArray = 15
64
- }
65
- type SerovalPrimitiveNode = [type: SerovalNodeType.Primitive, value: PrimitiveValue];
66
- type SerovalReferenceNode = [type: SerovalNodeType.Reference, value: number];
67
- type SerovalSemiPrimitiveNode = [type: SerovalNodeType.BigInt, value: string] | [type: SerovalNodeType.Date, value: string, id: number] | [type: SerovalNodeType.RegExp, value: string, id: number] | [
68
- type: SerovalNodeType.TypedArray,
69
- value: [constructor: string, array: string, byteOffset: number],
70
- id: number
71
- ] | [
72
- type: SerovalNodeType.BigIntTypedArray,
73
- value: [constructor: string, array: string, byteOffset: number],
74
- id: number
75
- ];
76
- type SerovalDictionaryNode = [key: string[], value: SerovalNode[], size: number];
77
- type SerovalSetNode = [type: SerovalNodeType.Set, value: SerovalNode[], id: number];
78
- type SerovalMapNode = [
79
- type: SerovalNodeType.Map,
80
- value: [key: SerovalNode[], value: SerovalNode[], size: number],
81
- id: number
82
- ];
83
- type SerovalArrayNode = [type: SerovalNodeType.Array, value: SerovalNode[], id: number];
84
- type SerovalObjectNode = [type: SerovalNodeType.Object, value: SerovalDictionaryNode, id: number];
85
- type SerovalNullConstructorNode = [
86
- type: SerovalNodeType.NullConstructor,
87
- value: SerovalDictionaryNode,
88
- id: number
89
- ];
90
- type SerovalPromiseNode = [type: SerovalNodeType.Promise, value: SerovalNode, id: number];
91
- type SerovalErrorNode = [
92
- type: SerovalNodeType.Error,
93
- value: [
94
- constructor: string,
95
- message: string,
96
- options?: SerovalDictionaryNode
97
- ],
98
- id: number
99
- ];
100
- type SerovalAggregateErrorNode = [
101
- type: SerovalNodeType.AggregateError,
102
- value: [
103
- message: string,
104
- options: SerovalDictionaryNode | undefined,
105
- errors: SerovalNode
106
- ],
107
- id: number
108
- ];
109
- type SerovalIterableNode = [
110
- type: SerovalNodeType.Iterable,
111
- value: [
112
- options: SerovalDictionaryNode | undefined,
113
- items: SerovalNode
114
- ],
115
- id: number
116
- ];
117
- export type SerovalNode = SerovalPrimitiveNode | SerovalReferenceNode | SerovalSemiPrimitiveNode | SerovalSetNode | SerovalMapNode | SerovalArrayNode | SerovalObjectNode | SerovalNullConstructorNode | SerovalPromiseNode | SerovalErrorNode | SerovalAggregateErrorNode | SerovalIterableNode;
118
- export declare function parseSync(ctx: ParserContext, current: ServerValue): readonly [SerovalNode, number, boolean];
119
- export declare function parseAsync(ctx: ParserContext, current: AsyncServerValue): Promise<readonly [SerovalNode, number, boolean]>;
120
- export declare function serializePrimitive(value: PrimitiveValue): string | number | null;
121
- export declare function serializeTree(ctx: SerializationContext, [type, value, id]: SerovalNode): string;
122
- export {};