seroval 0.6.0 → 0.8.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 +15 -3
- package/dist/cjs/development/index.cjs +1431 -991
- package/dist/cjs/development/index.cjs.map +4 -4
- package/dist/cjs/production/index.cjs +3 -3
- package/dist/esm/development/index.mjs +1431 -991
- package/dist/esm/development/index.mjs.map +4 -4
- package/dist/esm/production/index.mjs +3 -3
- package/dist/types/assert.d.ts +1 -1
- package/dist/types/compat.d.ts +1 -1
- package/dist/types/context.d.ts +13 -7
- package/dist/types/index.d.ts +3 -4
- package/dist/types/string.d.ts +3 -0
- package/dist/types/tree/UnsupportedTypeError.d.ts +3 -0
- package/dist/types/tree/async.d.ts +3 -3
- package/dist/types/tree/constants.d.ts +11 -0
- package/dist/types/tree/deserialize.d.ts +2 -2
- package/dist/types/tree/primitives.d.ts +11 -14
- package/dist/types/tree/serialize.d.ts +2 -2
- package/dist/types/tree/shared.d.ts +10 -8
- package/dist/types/tree/sync.d.ts +3 -3
- package/dist/types/tree/types.d.ts +106 -70
- package/dist/types/tree/web-api.d.ts +4 -2
- package/dist/types/types.d.ts +4 -4
- package/package.json +11 -8
- package/src/assert.ts +2 -2
- package/src/compat.ts +1 -2
- package/src/context.ts +24 -13
- package/src/get-identifier.ts +1 -1
- package/src/index.ts +35 -26
- package/src/string.ts +53 -0
- package/src/tree/UnsupportedTypeError.ts +8 -0
- package/src/tree/async.ts +313 -222
- package/src/tree/constants.ts +72 -0
- package/src/tree/deserialize.ts +239 -119
- package/src/tree/primitives.ts +154 -143
- package/src/tree/reference.ts +4 -3
- package/src/tree/serialize.ts +394 -170
- package/src/tree/shared.ts +31 -22
- package/src/tree/symbols.ts +13 -13
- package/src/tree/sync.ts +288 -191
- package/src/tree/types.ts +173 -91
- package/src/tree/web-api.ts +59 -6
- package/src/types.ts +7 -3
- package/dist/types/quote.d.ts +0 -2
- package/src/quote.ts +0 -56
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "seroval",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
7
7
|
"src"
|
|
@@ -15,12 +15,14 @@
|
|
|
15
15
|
],
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@types/node": "^18.15.3",
|
|
18
|
-
"
|
|
19
|
-
"eslint
|
|
20
|
-
"
|
|
21
|
-
"
|
|
18
|
+
"@vitest/ui": "^0.30.1",
|
|
19
|
+
"eslint": "^8.39.0",
|
|
20
|
+
"eslint-config-lxsmnsyc": "^0.6.4",
|
|
21
|
+
"node-fetch-native": "^1.1.0",
|
|
22
|
+
"pridepack": "2.4.4",
|
|
23
|
+
"tslib": "^2.5.0",
|
|
22
24
|
"typescript": "^4.9.4",
|
|
23
|
-
"vitest": "^0.
|
|
25
|
+
"vitest": "^0.30.1"
|
|
24
26
|
},
|
|
25
27
|
"scripts": {
|
|
26
28
|
"prepublishOnly": "pridepack clean && pridepack build",
|
|
@@ -31,7 +33,8 @@
|
|
|
31
33
|
"watch": "pridepack watch",
|
|
32
34
|
"start": "pridepack start",
|
|
33
35
|
"dev": "pridepack dev",
|
|
34
|
-
"test": "vitest"
|
|
36
|
+
"test": "vitest",
|
|
37
|
+
"test:ui": "vitest --ui"
|
|
35
38
|
},
|
|
36
39
|
"private": false,
|
|
37
40
|
"description": "Stringify JS values",
|
|
@@ -64,5 +67,5 @@
|
|
|
64
67
|
"typesVersions": {
|
|
65
68
|
"*": {}
|
|
66
69
|
},
|
|
67
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "f7fe3305e0295499989d9f675ff54f9305db23b0"
|
|
68
71
|
}
|
package/src/assert.ts
CHANGED
package/src/compat.ts
CHANGED
package/src/context.ts
CHANGED
|
@@ -8,25 +8,33 @@ interface IndexAssignment {
|
|
|
8
8
|
v: string;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
interface
|
|
12
|
-
t: '
|
|
11
|
+
interface SetAssignment {
|
|
12
|
+
t: 'set';
|
|
13
13
|
s: string;
|
|
14
14
|
k: string;
|
|
15
15
|
v: string;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
interface
|
|
19
|
-
t: '
|
|
18
|
+
interface AddAssignment {
|
|
19
|
+
t: 'add';
|
|
20
20
|
s: string;
|
|
21
21
|
k: undefined;
|
|
22
22
|
v: string;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
interface AppendAssignment {
|
|
26
|
+
t: 'append';
|
|
27
|
+
s: string;
|
|
28
|
+
k: string;
|
|
29
|
+
v: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
25
32
|
// Array of assignments to be done (used for recursion)
|
|
26
33
|
export type Assignment =
|
|
27
34
|
| IndexAssignment
|
|
28
|
-
|
|
|
29
|
-
| SetAssignment
|
|
35
|
+
| AddAssignment
|
|
36
|
+
| SetAssignment
|
|
37
|
+
| AppendAssignment;
|
|
30
38
|
|
|
31
39
|
export interface ParserContext {
|
|
32
40
|
refs: Map<unknown, number>;
|
|
@@ -37,12 +45,12 @@ export interface ParserContext {
|
|
|
37
45
|
export interface SerializationContext {
|
|
38
46
|
stack: number[];
|
|
39
47
|
// Map tree refs to actual refs
|
|
40
|
-
validRefs: number[];
|
|
48
|
+
validRefs: (number | undefined)[];
|
|
41
49
|
refSize: number;
|
|
42
50
|
// Refs that are...referenced
|
|
43
51
|
markedRefs: Set<number>;
|
|
44
52
|
// Variables
|
|
45
|
-
vars: string[];
|
|
53
|
+
vars: (string | undefined)[];
|
|
46
54
|
// Array of assignments to be done (used for recursion)
|
|
47
55
|
assignments: Assignment[];
|
|
48
56
|
// Supported features
|
|
@@ -61,7 +69,7 @@ const DEFAULT_OPTIONS: Options = {
|
|
|
61
69
|
|
|
62
70
|
export function createParserContext(options: Partial<Options> = {}): ParserContext {
|
|
63
71
|
// eslint-disable-next-line prefer-object-spread
|
|
64
|
-
const result = Object.assign({}, DEFAULT_OPTIONS, options
|
|
72
|
+
const result = Object.assign({}, DEFAULT_OPTIONS, options);
|
|
65
73
|
return {
|
|
66
74
|
markedRefs: new Set(),
|
|
67
75
|
refs: new Map(),
|
|
@@ -90,14 +98,17 @@ export function createSerializationContext(options: SerializationOptions): Seria
|
|
|
90
98
|
/**
|
|
91
99
|
* Increments the number of references the referenced value has
|
|
92
100
|
*/
|
|
93
|
-
export function markRef(
|
|
101
|
+
export function markRef(
|
|
102
|
+
ctx: ParserContext | SerializationContext,
|
|
103
|
+
current: number,
|
|
104
|
+
): void {
|
|
94
105
|
ctx.markedRefs.add(current);
|
|
95
106
|
}
|
|
96
107
|
/**
|
|
97
108
|
* Creates the reference param (identifier) from the given reference ID
|
|
98
109
|
* Calling this function means the value has been referenced somewhere
|
|
99
110
|
*/
|
|
100
|
-
export function getRefParam(ctx: SerializationContext, index: number) {
|
|
111
|
+
export function getRefParam(ctx: SerializationContext, index: number): string {
|
|
101
112
|
/**
|
|
102
113
|
* Creates a new reference ID from a given reference ID
|
|
103
114
|
* This new reference ID means that the reference itself
|
|
@@ -120,7 +131,7 @@ export function getRefParam(ctx: SerializationContext, index: number) {
|
|
|
120
131
|
export function getRootID<T>(
|
|
121
132
|
ctx: ParserContext,
|
|
122
133
|
current: T,
|
|
123
|
-
) {
|
|
134
|
+
): number {
|
|
124
135
|
const ref = ctx.refs.get(current);
|
|
125
136
|
if (ref == null) {
|
|
126
137
|
return ctx.refs.size;
|
|
@@ -131,7 +142,7 @@ export function getRootID<T>(
|
|
|
131
142
|
export function createIndexedValue<T>(
|
|
132
143
|
ctx: ParserContext,
|
|
133
144
|
current: T,
|
|
134
|
-
) {
|
|
145
|
+
): number {
|
|
135
146
|
const ref = ctx.refs.get(current);
|
|
136
147
|
if (ref == null) {
|
|
137
148
|
const id = ctx.refs.size;
|
package/src/get-identifier.ts
CHANGED
|
@@ -4,7 +4,7 @@ const REF_START_CHARS_LEN = REF_START_CHARS.length;
|
|
|
4
4
|
const REF_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$_';
|
|
5
5
|
const REF_CHARS_LEN = REF_CHARS.length;
|
|
6
6
|
|
|
7
|
-
export default function getIdentifier(index: number) {
|
|
7
|
+
export default function getIdentifier(index: number): string {
|
|
8
8
|
let mod = index % REF_START_CHARS_LEN;
|
|
9
9
|
let ref = REF_START_CHARS[mod];
|
|
10
10
|
index = (index - mod) / REF_START_CHARS_LEN;
|
package/src/index.ts
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
/* eslint-disable no-await-in-loop */
|
|
2
2
|
import { Feature } from './compat';
|
|
3
|
-
import {
|
|
3
|
+
import type {
|
|
4
4
|
SerializationContext,
|
|
5
|
-
getRefParam,
|
|
6
5
|
Options,
|
|
6
|
+
} from './context';
|
|
7
|
+
import {
|
|
8
|
+
getRefParam,
|
|
7
9
|
createParserContext,
|
|
8
10
|
createSerializationContext,
|
|
11
|
+
getRootID,
|
|
9
12
|
} from './context';
|
|
13
|
+
import parseSync from './tree/sync';
|
|
10
14
|
import parseAsync from './tree/async';
|
|
11
15
|
import deserializeTree from './tree/deserialize';
|
|
12
16
|
import serializeTree, { resolvePatches } from './tree/serialize';
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
17
|
+
import type { SerovalNode } from './tree/types';
|
|
18
|
+
import { SerovalNodeType } from './tree/types';
|
|
15
19
|
|
|
16
|
-
export {
|
|
20
|
+
export type {
|
|
17
21
|
AsyncServerValue,
|
|
18
22
|
ServerValue,
|
|
19
23
|
PrimitiveValue,
|
|
@@ -28,7 +32,7 @@ function finalize(
|
|
|
28
32
|
rootID: number,
|
|
29
33
|
isObject: boolean,
|
|
30
34
|
result: string,
|
|
31
|
-
) {
|
|
35
|
+
): string {
|
|
32
36
|
// Shared references detected
|
|
33
37
|
if (ctx.vars.length) {
|
|
34
38
|
const patches = resolvePatches(ctx);
|
|
@@ -62,23 +66,33 @@ function finalize(
|
|
|
62
66
|
export function serialize<T>(
|
|
63
67
|
source: T,
|
|
64
68
|
options?: Partial<Options>,
|
|
65
|
-
) {
|
|
69
|
+
): string {
|
|
66
70
|
const ctx = createParserContext(options);
|
|
67
|
-
const
|
|
71
|
+
const tree = parseSync(ctx, source);
|
|
68
72
|
const serial = createSerializationContext(ctx);
|
|
69
73
|
const result = serializeTree(serial, tree);
|
|
70
|
-
return finalize(
|
|
74
|
+
return finalize(
|
|
75
|
+
serial,
|
|
76
|
+
getRootID(ctx, source),
|
|
77
|
+
tree.t === SerovalNodeType.Object,
|
|
78
|
+
result,
|
|
79
|
+
);
|
|
71
80
|
}
|
|
72
81
|
|
|
73
82
|
export async function serializeAsync<T>(
|
|
74
83
|
source: T,
|
|
75
84
|
options?: Partial<Options>,
|
|
76
|
-
) {
|
|
85
|
+
): Promise<string> {
|
|
77
86
|
const ctx = createParserContext(options);
|
|
78
|
-
const
|
|
87
|
+
const tree = await parseAsync(ctx, source);
|
|
79
88
|
const serial = createSerializationContext(ctx);
|
|
80
89
|
const result = serializeTree(serial, tree);
|
|
81
|
-
return finalize(
|
|
90
|
+
return finalize(
|
|
91
|
+
serial,
|
|
92
|
+
getRootID(ctx, source),
|
|
93
|
+
tree.t === SerovalNodeType.Object,
|
|
94
|
+
result,
|
|
95
|
+
);
|
|
82
96
|
}
|
|
83
97
|
|
|
84
98
|
export function deserialize<T>(source: string): T {
|
|
@@ -87,11 +101,10 @@ export function deserialize<T>(source: string): T {
|
|
|
87
101
|
}
|
|
88
102
|
|
|
89
103
|
export interface SerovalJSON {
|
|
90
|
-
t: SerovalNode
|
|
91
|
-
r: number
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
m: number[],
|
|
104
|
+
t: SerovalNode;
|
|
105
|
+
r: number;
|
|
106
|
+
f: number;
|
|
107
|
+
m: number[];
|
|
95
108
|
}
|
|
96
109
|
|
|
97
110
|
export function toJSON<T>(
|
|
@@ -99,11 +112,9 @@ export function toJSON<T>(
|
|
|
99
112
|
options?: Partial<Options>,
|
|
100
113
|
): SerovalJSON {
|
|
101
114
|
const ctx = createParserContext(options);
|
|
102
|
-
const [tree, root, isObject] = parseSync(ctx, source);
|
|
103
115
|
return {
|
|
104
|
-
t:
|
|
105
|
-
r:
|
|
106
|
-
i: isObject,
|
|
116
|
+
t: parseSync(ctx, source),
|
|
117
|
+
r: getRootID(ctx, source),
|
|
107
118
|
f: ctx.features,
|
|
108
119
|
m: Array.from(ctx.markedRefs),
|
|
109
120
|
};
|
|
@@ -114,11 +125,9 @@ export async function toJSONAsync<T>(
|
|
|
114
125
|
options?: Partial<Options>,
|
|
115
126
|
): Promise<SerovalJSON> {
|
|
116
127
|
const ctx = createParserContext(options);
|
|
117
|
-
const [tree, root, isObject] = await parseAsync(ctx, source);
|
|
118
128
|
return {
|
|
119
|
-
t:
|
|
120
|
-
r:
|
|
121
|
-
i: isObject,
|
|
129
|
+
t: await parseAsync(ctx, source),
|
|
130
|
+
r: getRootID(ctx, source),
|
|
122
131
|
f: ctx.features,
|
|
123
132
|
m: Array.from(ctx.markedRefs),
|
|
124
133
|
};
|
|
@@ -130,7 +139,7 @@ export function compileJSON(source: SerovalJSON): string {
|
|
|
130
139
|
markedRefs: source.m,
|
|
131
140
|
});
|
|
132
141
|
const result = serializeTree(serial, source.t);
|
|
133
|
-
return finalize(serial, source.r, source.i, result);
|
|
142
|
+
return finalize(serial, source.r, source.t.i === SerovalNodeType.Object, result);
|
|
134
143
|
}
|
|
135
144
|
|
|
136
145
|
export function fromJSON<T>(source: SerovalJSON): T {
|
package/src/string.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export function serializeChar(str: string): string | undefined {
|
|
2
|
+
switch (str) {
|
|
3
|
+
case '"': return '\\"';
|
|
4
|
+
case '\\': return '\\\\';
|
|
5
|
+
case '\n': return '\\n';
|
|
6
|
+
case '\r': return '\\r';
|
|
7
|
+
case '\b': return '\\b';
|
|
8
|
+
case '\t': return '\\t';
|
|
9
|
+
case '\f': return '\\f';
|
|
10
|
+
case '<': return '\\x3C';
|
|
11
|
+
case '\u2028': return '\\u2028';
|
|
12
|
+
case '\u2029': return '\\u2029';
|
|
13
|
+
default: return undefined;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Written by https://github.com/DylanPiercey and is distributed under the MIT license.
|
|
18
|
+
// Creates a JavaScript double quoted string and escapes all characters
|
|
19
|
+
// not listed as DoubleStringCharacters on
|
|
20
|
+
// Also includes "<" to escape "</script>" and "\" to avoid invalid escapes in the output.
|
|
21
|
+
// http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
|
|
22
|
+
export function serializeString(str: string): string {
|
|
23
|
+
let result = '';
|
|
24
|
+
let lastPos = 0;
|
|
25
|
+
let replacement: string | undefined;
|
|
26
|
+
for (let i = 0, len = str.length; i < len; i++) {
|
|
27
|
+
replacement = serializeChar(str[i]);
|
|
28
|
+
if (replacement) {
|
|
29
|
+
result += str.slice(lastPos, i) + replacement;
|
|
30
|
+
lastPos = i + 1;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (lastPos === 0) {
|
|
34
|
+
result = str;
|
|
35
|
+
} else {
|
|
36
|
+
result += str.slice(lastPos);
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function deserializeString(str: string): string {
|
|
42
|
+
return str
|
|
43
|
+
.replace(/\\"/g, '"')
|
|
44
|
+
.replace(/\\\\/g, '\\')
|
|
45
|
+
.replace(/\\n/g, '\n')
|
|
46
|
+
.replace(/\\r/g, '\r')
|
|
47
|
+
.replace(/\\b/g, '\b')
|
|
48
|
+
.replace(/\\t/g, '\t')
|
|
49
|
+
.replace(/\\f/g, '\f')
|
|
50
|
+
.replace(/\\x3C/g, '<')
|
|
51
|
+
.replace(/\\u2028/g, '\u2028')
|
|
52
|
+
.replace(/\\u2029/g, '\u2029');
|
|
53
|
+
}
|