seroval 0.4.0-alpha.3 → 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 +786 -675
- package/dist/cjs/development/index.cjs.map +4 -4
- package/dist/cjs/production/index.cjs +2 -2
- package/dist/esm/development/index.mjs +786 -675
- package/dist/esm/development/index.mjs.map +4 -4
- package/dist/esm/production/index.mjs +2 -2
- package/dist/types/compat.d.ts +13 -12
- package/dist/types/context.d.ts +53 -0
- package/dist/types/index.d.ts +5 -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/dist/types/types.d.ts +2 -2
- package/package.json +2 -2
- package/src/checks.ts +1 -2
- package/src/compat.ts +28 -14
- package/src/context.ts +137 -0
- package/src/index.ts +79 -25
- 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/src/types.ts +3 -3
- package/dist/types/tree.d.ts +0 -112
- package/src/tree.ts +0 -1204
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SerializationContext, ParserContext } from '../context';
|
|
2
|
+
import { ErrorValue, PrimitiveValue } from '../types';
|
|
3
|
+
import { SerovalNode, SerovalReferenceNode } from './types';
|
|
4
|
+
export declare function getErrorConstructor(error: ErrorValue): "EvalError" | "RangeError" | "ReferenceError" | "SyntaxError" | "TypeError" | "URIError" | "Error";
|
|
5
|
+
export declare function getErrorOptions(error: Error): Record<string, any> | undefined;
|
|
6
|
+
export declare function getIterableOptions(obj: Iterable<any>): Record<string, unknown> | undefined;
|
|
7
|
+
export declare function isReferenceInStack(ctx: SerializationContext, node: SerovalNode): node is SerovalReferenceNode;
|
|
8
|
+
export declare function generateRef(ctx: ParserContext, current: unknown): number | SerovalReferenceNode;
|
|
9
|
+
export declare function generateSemiPrimitiveValue(ctx: ParserContext, current: unknown, id: number): SerovalNode | undefined;
|
|
10
|
+
export declare function serializePrimitive(value: PrimitiveValue): string | number | null;
|
|
@@ -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/dist/types/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export type PrimitiveValue = boolean | string | number | undefined | null
|
|
1
|
+
export type PrimitiveValue = boolean | string | number | undefined | null;
|
|
2
2
|
export type ErrorValue = Error | AggregateError | EvalError | RangeError | ReferenceError | TypeError | SyntaxError | URIError;
|
|
3
3
|
export type TypedArrayValue = Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | BigInt64Array | BigUint64Array;
|
|
4
|
-
export type SemiPrimitiveValue = RegExp | Date | TypedArrayValue;
|
|
4
|
+
export type SemiPrimitiveValue = RegExp | Date | TypedArrayValue | bigint;
|
|
5
5
|
export type CommonServerValue = PrimitiveValue | SemiPrimitiveValue | ErrorValue;
|
|
6
6
|
export type ServerValue = CommonServerValue | Array<ServerValue> | readonly ServerValue[] | Iterable<ServerValue> | {
|
|
7
7
|
[key: string | number]: ServerValue;
|
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/checks.ts
CHANGED
|
@@ -6,8 +6,7 @@ export function isPrimitive(current: unknown): current is PrimitiveValue {
|
|
|
6
6
|
}
|
|
7
7
|
const type = typeof current;
|
|
8
8
|
return type === 'number'
|
|
9
|
-
|| type === 'string'
|
|
10
|
-
|| type === 'bigint';
|
|
9
|
+
|| type === 'string';
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
export function isPromise<T>(obj: unknown): obj is PromiseLike<T> {
|
package/src/compat.ts
CHANGED
|
@@ -40,17 +40,18 @@ export interface PlatformVersion {
|
|
|
40
40
|
export type Platform = keyof PlatformVersion;
|
|
41
41
|
|
|
42
42
|
export const enum Feature {
|
|
43
|
-
AggregateError,
|
|
44
|
-
ArrayPrototypeValues,
|
|
45
|
-
ArrowFunction,
|
|
46
|
-
BigInt,
|
|
47
|
-
Map,
|
|
48
|
-
MethodShorthand,
|
|
49
|
-
ObjectAssign,
|
|
50
|
-
Promise,
|
|
51
|
-
Set,
|
|
52
|
-
SymbolIterator,
|
|
53
|
-
TypedArray,
|
|
43
|
+
AggregateError = 0x01,
|
|
44
|
+
ArrayPrototypeValues = 0x02,
|
|
45
|
+
ArrowFunction = 0x04,
|
|
46
|
+
BigInt = 0x08,
|
|
47
|
+
Map = 0x10,
|
|
48
|
+
MethodShorthand = 0x20,
|
|
49
|
+
ObjectAssign = 0x40,
|
|
50
|
+
Promise = 0x80,
|
|
51
|
+
Set = 0x100,
|
|
52
|
+
SymbolIterator = 0x200,
|
|
53
|
+
TypedArray = 0x400,
|
|
54
|
+
BigIntTypedArray = 0x800,
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
type VersionTable = {
|
|
@@ -201,6 +202,19 @@ const VERSION_TABLE: VersionTable = {
|
|
|
201
202
|
deno: [1, 0, 0],
|
|
202
203
|
node: [0, 10, 0],
|
|
203
204
|
},
|
|
205
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array#browser_compatibility
|
|
206
|
+
[Feature.BigIntTypedArray]: {
|
|
207
|
+
es: [2020, 0, 0],
|
|
208
|
+
chrome: [67, 0, 0],
|
|
209
|
+
edge: [79, 0, 0],
|
|
210
|
+
firefox: [68, 0, 0],
|
|
211
|
+
opera: [54, 6, 0],
|
|
212
|
+
safari: [15, 1, 0],
|
|
213
|
+
ios: [15, 2, 0],
|
|
214
|
+
samsung: [9, 0, 0],
|
|
215
|
+
deno: [1, 0, 0],
|
|
216
|
+
node: [10, 4, 0],
|
|
217
|
+
},
|
|
204
218
|
};
|
|
205
219
|
|
|
206
220
|
const TARGET_REGEX = /^(es|chrome|edge|safari|firefox|opera|ios|samsung|deno|node)([0-9]+(\.[0-9]+(\.[0-9]+)?)?)$/i;
|
|
@@ -226,9 +240,9 @@ function getTargetVersions(targets: string | string[]): Target[] {
|
|
|
226
240
|
return [parseTarget(targets)];
|
|
227
241
|
}
|
|
228
242
|
|
|
229
|
-
export function parseTargets(targets: string | string[]):
|
|
243
|
+
export function parseTargets(targets: string | string[]): number {
|
|
230
244
|
const parsed = getTargetVersions(targets);
|
|
231
|
-
|
|
245
|
+
let flags = 0;
|
|
232
246
|
|
|
233
247
|
for (const key in VERSION_TABLE) {
|
|
234
248
|
const base = VERSION_TABLE[key as unknown as Feature];
|
|
@@ -238,7 +252,7 @@ export function parseTargets(targets: string | string[]): Set<Feature> {
|
|
|
238
252
|
flag = flag && !!baseVersion && (compareVersion(baseVersion, version) <= 0);
|
|
239
253
|
}
|
|
240
254
|
if (flag) {
|
|
241
|
-
flags
|
|
255
|
+
flags |= Number(key);
|
|
242
256
|
}
|
|
243
257
|
}
|
|
244
258
|
|
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,20 +2,19 @@
|
|
|
2
2
|
import { isPrimitive } from './checks';
|
|
3
3
|
import { Feature } from './compat';
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
createSerializationContext,
|
|
7
|
-
generateTreeAsync,
|
|
8
|
-
generateTreeSync,
|
|
5
|
+
SerializationContext,
|
|
9
6
|
getRefParam,
|
|
10
7
|
Options,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} 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';
|
|
16
16
|
import {
|
|
17
17
|
AsyncServerValue,
|
|
18
|
-
NonPrimitiveServerValue,
|
|
19
18
|
PrimitiveValue,
|
|
20
19
|
ServerValue,
|
|
21
20
|
CommonServerValue,
|
|
@@ -32,9 +31,10 @@ export {
|
|
|
32
31
|
ErrorValue,
|
|
33
32
|
};
|
|
34
33
|
|
|
35
|
-
function finalize
|
|
34
|
+
function finalize(
|
|
36
35
|
ctx: SerializationContext,
|
|
37
|
-
|
|
36
|
+
rootID: number,
|
|
37
|
+
isObject: boolean,
|
|
38
38
|
result: string,
|
|
39
39
|
) {
|
|
40
40
|
// Shared references detected
|
|
@@ -43,7 +43,7 @@ function finalize<T extends NonPrimitiveServerValue<ServerValue | AsyncServerVal
|
|
|
43
43
|
let body = result;
|
|
44
44
|
if (patches) {
|
|
45
45
|
// Get (or create) a ref from the source
|
|
46
|
-
const index = getRefParam(ctx,
|
|
46
|
+
const index = getRefParam(ctx, rootID);
|
|
47
47
|
if (result.startsWith(`${index}=`)) {
|
|
48
48
|
body = `${result},${patches}${index}`;
|
|
49
49
|
} else {
|
|
@@ -54,7 +54,7 @@ function finalize<T extends NonPrimitiveServerValue<ServerValue | AsyncServerVal
|
|
|
54
54
|
? ctx.vars.join(',')
|
|
55
55
|
: ctx.vars[0];
|
|
56
56
|
// Source is probably already assigned
|
|
57
|
-
if (ctx.features
|
|
57
|
+
if (ctx.features & Feature.ArrowFunction) {
|
|
58
58
|
params = ctx.vars.length > 1 || ctx.vars.length === 0
|
|
59
59
|
? `(${params})`
|
|
60
60
|
: params;
|
|
@@ -62,7 +62,7 @@ function finalize<T extends NonPrimitiveServerValue<ServerValue | AsyncServerVal
|
|
|
62
62
|
}
|
|
63
63
|
return `(function(${params}){return ${body}})()`;
|
|
64
64
|
}
|
|
65
|
-
if (
|
|
65
|
+
if (isObject) {
|
|
66
66
|
return `(${result})`;
|
|
67
67
|
}
|
|
68
68
|
return result;
|
|
@@ -72,26 +72,28 @@ export function serialize<T extends ServerValue>(
|
|
|
72
72
|
source: T,
|
|
73
73
|
options?: Partial<Options>,
|
|
74
74
|
) {
|
|
75
|
-
const ctx =
|
|
75
|
+
const ctx = createParserContext(options);
|
|
76
76
|
if (isPrimitive(source)) {
|
|
77
|
-
return serializePrimitive(
|
|
77
|
+
return String(serializePrimitive(source));
|
|
78
78
|
}
|
|
79
|
-
const tree =
|
|
80
|
-
const
|
|
81
|
-
|
|
79
|
+
const [tree, rootID, isObject] = parseSync(ctx, source);
|
|
80
|
+
const serial = createSerializationContext(ctx);
|
|
81
|
+
const result = serializeTree(serial, tree);
|
|
82
|
+
return finalize(serial, rootID, isObject, result);
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
export async function serializeAsync<T extends AsyncServerValue>(
|
|
85
86
|
source: T,
|
|
86
87
|
options?: Partial<Options>,
|
|
87
88
|
) {
|
|
88
|
-
const ctx =
|
|
89
|
+
const ctx = createParserContext(options);
|
|
89
90
|
if (isPrimitive(source)) {
|
|
90
|
-
return serializePrimitive(
|
|
91
|
+
return String(serializePrimitive(source));
|
|
91
92
|
}
|
|
92
|
-
const tree = await
|
|
93
|
-
const
|
|
94
|
-
|
|
93
|
+
const [tree, rootID, isObject] = await parseAsync(ctx, source);
|
|
94
|
+
const serial = createSerializationContext(ctx);
|
|
95
|
+
const result = serializeTree(serial, tree);
|
|
96
|
+
return finalize(serial, rootID, isObject, result);
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
export function deserialize<T extends AsyncServerValue>(source: string): T {
|
|
@@ -99,4 +101,56 @@ export function deserialize<T extends AsyncServerValue>(source: string): T {
|
|
|
99
101
|
return (0, eval)(source) as T;
|
|
100
102
|
}
|
|
101
103
|
|
|
104
|
+
type SerovalJSON = [
|
|
105
|
+
tree: SerovalNode,
|
|
106
|
+
root: number,
|
|
107
|
+
isObject: boolean,
|
|
108
|
+
feature: number,
|
|
109
|
+
markedRefs: number[],
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
export function toJSON<T extends ServerValue>(
|
|
113
|
+
source: T,
|
|
114
|
+
options?: Partial<Options>,
|
|
115
|
+
) {
|
|
116
|
+
const ctx = createParserContext(options);
|
|
117
|
+
const [tree, root, isObject] = parseSync(ctx, source);
|
|
118
|
+
return JSON.stringify([
|
|
119
|
+
tree,
|
|
120
|
+
root,
|
|
121
|
+
isObject,
|
|
122
|
+
ctx.features,
|
|
123
|
+
[...ctx.markedRefs],
|
|
124
|
+
]);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export async function toJSONAsync<T extends AsyncServerValue>(
|
|
128
|
+
source: T,
|
|
129
|
+
options?: Partial<Options>,
|
|
130
|
+
) {
|
|
131
|
+
const ctx = createParserContext(options);
|
|
132
|
+
const [tree, root, isObject] = await parseAsync(ctx, source);
|
|
133
|
+
return JSON.stringify([
|
|
134
|
+
tree,
|
|
135
|
+
root,
|
|
136
|
+
isObject,
|
|
137
|
+
ctx.features,
|
|
138
|
+
[...ctx.markedRefs],
|
|
139
|
+
]);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function compileJSON(source: string): string {
|
|
143
|
+
const parsed = JSON.parse(source) as SerovalJSON;
|
|
144
|
+
const serial = createSerializationContext({
|
|
145
|
+
features: parsed[3],
|
|
146
|
+
markedRefs: parsed[4],
|
|
147
|
+
});
|
|
148
|
+
const result = serializeTree(serial, parsed[0]);
|
|
149
|
+
return finalize(serial, parsed[1], parsed[2], result);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function fromJSON<T extends AsyncServerValue>(source: string): T {
|
|
153
|
+
return deserialize<T>(compileJSON(source));
|
|
154
|
+
}
|
|
155
|
+
|
|
102
156
|
export default serialize;
|