seroval 0.4.0-alpha.6 → 0.4.0-alpha.8
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 +84 -64
- package/dist/cjs/development/index.cjs.map +3 -3
- package/dist/cjs/production/index.cjs +2 -2
- package/dist/esm/development/index.mjs +84 -64
- package/dist/esm/development/index.mjs.map +3 -3
- package/dist/esm/production/index.mjs +2 -2
- package/dist/types/context.d.ts +5 -4
- package/dist/types/tree/types.d.ts +1 -1
- package/package.json +2 -2
- package/src/context.ts +16 -14
- package/src/index.ts +3 -3
- package/src/tree/async.ts +23 -15
- package/src/tree/serialize.ts +28 -30
- package/src/tree/sync.ts +23 -15
- package/src/tree/types.ts +1 -1
package/src/context.ts
CHANGED
|
@@ -28,16 +28,17 @@ export type Assignment =
|
|
|
28
28
|
|
|
29
29
|
export interface ParserContext {
|
|
30
30
|
refs: Map<unknown, number>;
|
|
31
|
-
markedRefs:
|
|
31
|
+
markedRefs: Record<number, number>;
|
|
32
32
|
features: number;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export interface SerializationContext {
|
|
36
36
|
stack: number[];
|
|
37
37
|
// Map tree refs to actual refs
|
|
38
|
-
validRefs:
|
|
38
|
+
validRefs: number[];
|
|
39
|
+
refSize: number;
|
|
39
40
|
// Refs that are...referenced
|
|
40
|
-
markedRefs:
|
|
41
|
+
markedRefs: Record<number, number>;
|
|
41
42
|
// Variables
|
|
42
43
|
vars: string[];
|
|
43
44
|
// Array of assignments to be done (used for recursion)
|
|
@@ -58,14 +59,14 @@ export function createParserContext(options: Partial<Options> = {}): ParserConte
|
|
|
58
59
|
// eslint-disable-next-line prefer-object-spread
|
|
59
60
|
const result = Object.assign({}, DEFAULT_OPTIONS, options || {});
|
|
60
61
|
return {
|
|
61
|
-
markedRefs:
|
|
62
|
+
markedRefs: {},
|
|
62
63
|
refs: new Map(),
|
|
63
64
|
features: parseTargets(result.target),
|
|
64
65
|
};
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
export interface SerializationOptions {
|
|
68
|
-
markedRefs: number
|
|
69
|
+
markedRefs: Record<number, number>;
|
|
69
70
|
features: number;
|
|
70
71
|
}
|
|
71
72
|
|
|
@@ -74,9 +75,10 @@ export function createSerializationContext(options: SerializationOptions): Seria
|
|
|
74
75
|
stack: [],
|
|
75
76
|
vars: [],
|
|
76
77
|
assignments: [],
|
|
77
|
-
validRefs:
|
|
78
|
+
validRefs: [],
|
|
79
|
+
refSize: 0,
|
|
78
80
|
features: options.features,
|
|
79
|
-
markedRefs:
|
|
81
|
+
markedRefs: options.markedRefs,
|
|
80
82
|
};
|
|
81
83
|
}
|
|
82
84
|
|
|
@@ -84,7 +86,7 @@ export function createSerializationContext(options: SerializationOptions): Seria
|
|
|
84
86
|
* Increments the number of references the referenced value has
|
|
85
87
|
*/
|
|
86
88
|
export function markRef(ctx: ParserContext | SerializationContext, current: number) {
|
|
87
|
-
ctx.markedRefs
|
|
89
|
+
ctx.markedRefs[current] = 1;
|
|
88
90
|
}
|
|
89
91
|
|
|
90
92
|
/**
|
|
@@ -97,13 +99,13 @@ function createValidRef(
|
|
|
97
99
|
ctx: SerializationContext,
|
|
98
100
|
index: number,
|
|
99
101
|
) {
|
|
100
|
-
const current = ctx.validRefs
|
|
101
|
-
if (current
|
|
102
|
-
|
|
102
|
+
const current = ctx.validRefs[index];
|
|
103
|
+
if (current == null) {
|
|
104
|
+
const value = ctx.refSize++;
|
|
105
|
+
ctx.validRefs[index] = value;
|
|
106
|
+
return value;
|
|
103
107
|
}
|
|
104
|
-
|
|
105
|
-
ctx.validRefs.set(index, id);
|
|
106
|
-
return id;
|
|
108
|
+
return current;
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
/**
|
package/src/index.ts
CHANGED
|
@@ -106,7 +106,7 @@ type SerovalJSON = [
|
|
|
106
106
|
root: number,
|
|
107
107
|
isObject: boolean,
|
|
108
108
|
feature: number,
|
|
109
|
-
markedRefs: number
|
|
109
|
+
markedRefs: Record<number, number>,
|
|
110
110
|
];
|
|
111
111
|
|
|
112
112
|
export function toJSON<T extends ServerValue>(
|
|
@@ -120,7 +120,7 @@ export function toJSON<T extends ServerValue>(
|
|
|
120
120
|
root,
|
|
121
121
|
isObject,
|
|
122
122
|
ctx.features,
|
|
123
|
-
|
|
123
|
+
ctx.markedRefs,
|
|
124
124
|
]);
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -135,7 +135,7 @@ export async function toJSONAsync<T extends AsyncServerValue>(
|
|
|
135
135
|
root,
|
|
136
136
|
isObject,
|
|
137
137
|
ctx.features,
|
|
138
|
-
|
|
138
|
+
ctx.markedRefs,
|
|
139
139
|
]);
|
|
140
140
|
}
|
|
141
141
|
|
package/src/tree/async.ts
CHANGED
|
@@ -30,24 +30,34 @@ import {
|
|
|
30
30
|
SerovalSetNode,
|
|
31
31
|
} from './types';
|
|
32
32
|
|
|
33
|
-
async function
|
|
33
|
+
async function serializePropertiesAsync(
|
|
34
34
|
ctx: ParserContext,
|
|
35
|
-
properties: Record<string,
|
|
35
|
+
properties: Record<string, unknown>,
|
|
36
36
|
): Promise<SerovalDictionaryNode> {
|
|
37
37
|
const keys = Object.keys(properties);
|
|
38
|
-
const
|
|
39
|
-
const
|
|
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;
|
|
40
45
|
for (const key of keys) {
|
|
41
46
|
if (isIterable(properties[key])) {
|
|
42
|
-
|
|
47
|
+
deferredKeys[deferredSize] = key;
|
|
48
|
+
deferredValues[deferredSize] = properties[key] as AsyncServerValue;
|
|
49
|
+
deferredSize++;
|
|
43
50
|
} else {
|
|
44
|
-
|
|
51
|
+
keyNodes[nodesSize] = key;
|
|
52
|
+
valueNodes[nodesSize] = await generateTreeAsync(ctx, properties[key] as AsyncServerValue);
|
|
53
|
+
nodesSize++;
|
|
45
54
|
}
|
|
46
55
|
}
|
|
47
|
-
for (
|
|
48
|
-
|
|
56
|
+
for (let i = 0; i < deferredSize; i++) {
|
|
57
|
+
keyNodes[nodesSize + i] = deferredKeys[i];
|
|
58
|
+
valueNodes[nodesSize + i] = await generateTreeAsync(ctx, deferredValues[i]);
|
|
49
59
|
}
|
|
50
|
-
return
|
|
60
|
+
return [keyNodes, valueNodes, size];
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
async function generateSetNode(
|
|
@@ -147,7 +157,7 @@ async function generateAggregateErrorNode(
|
|
|
147
157
|
): Promise<SerovalAggregateErrorNode> {
|
|
148
158
|
const options = getErrorOptions(current);
|
|
149
159
|
const optionsNode = options
|
|
150
|
-
? await
|
|
160
|
+
? await serializePropertiesAsync(ctx, options)
|
|
151
161
|
: undefined;
|
|
152
162
|
const errorsNode = await generateTreeAsync(ctx, current.errors as AsyncServerValue);
|
|
153
163
|
return [
|
|
@@ -164,7 +174,7 @@ async function generateErrorNode(
|
|
|
164
174
|
): Promise<SerovalErrorNode> {
|
|
165
175
|
const options = getErrorOptions(current);
|
|
166
176
|
const optionsNode = options
|
|
167
|
-
? await
|
|
177
|
+
? await serializePropertiesAsync(ctx, options)
|
|
168
178
|
: undefined;
|
|
169
179
|
return [
|
|
170
180
|
SerovalNodeType.Error,
|
|
@@ -182,9 +192,7 @@ async function generateIterableNode(
|
|
|
182
192
|
const options = getIterableOptions(current);
|
|
183
193
|
return [SerovalNodeType.Iterable, [
|
|
184
194
|
// Parse options first before the items
|
|
185
|
-
options
|
|
186
|
-
? await generateDictionary(ctx, options as Record<string, AsyncServerValue>)
|
|
187
|
-
: undefined,
|
|
195
|
+
options ? await serializePropertiesAsync(ctx, options) : undefined,
|
|
188
196
|
await generateNodeList(ctx, Array.from(current)),
|
|
189
197
|
], id];
|
|
190
198
|
}
|
|
@@ -236,7 +244,7 @@ async function generateTreeAsync(
|
|
|
236
244
|
if (current.constructor === Object || empty) {
|
|
237
245
|
return [
|
|
238
246
|
empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,
|
|
239
|
-
await
|
|
247
|
+
await serializePropertiesAsync(ctx, current as Record<string, unknown>),
|
|
240
248
|
id,
|
|
241
249
|
];
|
|
242
250
|
}
|
package/src/tree/serialize.ts
CHANGED
|
@@ -96,7 +96,7 @@ function assignRef(
|
|
|
96
96
|
index: number,
|
|
97
97
|
value: string,
|
|
98
98
|
) {
|
|
99
|
-
if (ctx.markedRefs
|
|
99
|
+
if (ctx.markedRefs[index]) {
|
|
100
100
|
return `${getRefParam(ctx, index)}=${value}`;
|
|
101
101
|
}
|
|
102
102
|
return value;
|
|
@@ -145,7 +145,7 @@ function createMapSet(
|
|
|
145
145
|
function createArrayAssign(
|
|
146
146
|
ctx: SerializationContext,
|
|
147
147
|
ref: number,
|
|
148
|
-
index: number,
|
|
148
|
+
index: number | string,
|
|
149
149
|
value: string,
|
|
150
150
|
) {
|
|
151
151
|
markRef(ctx, ref);
|
|
@@ -157,11 +157,9 @@ function createObjectAssign(
|
|
|
157
157
|
ref: number,
|
|
158
158
|
key: string,
|
|
159
159
|
value: string,
|
|
160
|
-
computed: boolean,
|
|
161
160
|
) {
|
|
162
161
|
markRef(ctx, ref);
|
|
163
|
-
|
|
164
|
-
createAssignment(ctx, `${getRefParam(ctx, ref)}${member}`, value);
|
|
162
|
+
createAssignment(ctx, `${getRefParam(ctx, ref)}.${key}`, value);
|
|
165
163
|
}
|
|
166
164
|
|
|
167
165
|
const IDENTIFIER_CHECK = /^([$A-Z_][0-9A-Z_$]*)$/i;
|
|
@@ -169,59 +167,59 @@ const IDENTIFIER_CHECK = /^([$A-Z_][0-9A-Z_$]*)$/i;
|
|
|
169
167
|
function serializeAssignments(
|
|
170
168
|
ctx: SerializationContext,
|
|
171
169
|
targetRef: number,
|
|
172
|
-
|
|
170
|
+
[keys, values, size]: SerovalDictionaryNode,
|
|
173
171
|
) {
|
|
174
172
|
ctx.stack.push(targetRef);
|
|
175
173
|
const mainAssignments: Assignment[] = [];
|
|
176
|
-
for (
|
|
174
|
+
for (let i = 0; i < size; i++) {
|
|
177
175
|
const parentStack = ctx.stack;
|
|
178
176
|
ctx.stack = [];
|
|
179
|
-
const refParam = serializeTree(ctx,
|
|
177
|
+
const refParam = serializeTree(ctx, values[i]);
|
|
180
178
|
ctx.stack = parentStack;
|
|
179
|
+
const key = keys[i];
|
|
181
180
|
const check = Number(key);
|
|
182
181
|
const parentAssignment = ctx.assignments;
|
|
183
182
|
ctx.assignments = mainAssignments;
|
|
184
183
|
// Test if key is a valid number or JS identifier
|
|
185
184
|
// so that we don't have to serialize the key and wrap with brackets
|
|
186
185
|
const isIdentifier = check >= 0 || IDENTIFIER_CHECK.test(key);
|
|
187
|
-
|
|
188
|
-
ctx,
|
|
189
|
-
|
|
190
|
-
isIdentifier ? key : quote(key),
|
|
191
|
-
|
|
192
|
-
!(isIdentifier && Number.isNaN(check)),
|
|
193
|
-
);
|
|
186
|
+
if (isIdentifier && Number.isNaN(check)) {
|
|
187
|
+
createObjectAssign(ctx, targetRef, key, refParam);
|
|
188
|
+
} else {
|
|
189
|
+
createArrayAssign(ctx, targetRef, isIdentifier ? key : quote(key), refParam);
|
|
190
|
+
}
|
|
194
191
|
ctx.assignments = parentAssignment;
|
|
195
192
|
}
|
|
196
193
|
ctx.stack.pop();
|
|
197
194
|
return resolveAssignments(mainAssignments);
|
|
198
195
|
}
|
|
199
196
|
|
|
200
|
-
function
|
|
197
|
+
function serializeObject(
|
|
201
198
|
ctx: SerializationContext,
|
|
202
199
|
sourceID: number,
|
|
203
|
-
|
|
200
|
+
[keys, values, size]: SerovalDictionaryNode,
|
|
204
201
|
) {
|
|
202
|
+
if (size === 0) {
|
|
203
|
+
return '{}';
|
|
204
|
+
}
|
|
205
205
|
let result = '';
|
|
206
206
|
ctx.stack.push(sourceID);
|
|
207
|
-
for (
|
|
208
|
-
const
|
|
207
|
+
for (let i = 0; i < size; i++) {
|
|
208
|
+
const key = keys[i];
|
|
209
|
+
const val = values[i];
|
|
209
210
|
const check = Number(key);
|
|
210
211
|
// Test if key is a valid number or JS identifier
|
|
211
212
|
// so that we don't have to serialize the key and wrap with brackets
|
|
212
213
|
const isIdentifier = check >= 0 || IDENTIFIER_CHECK.test(key);
|
|
213
|
-
const validKey = isIdentifier ? key : quote(key);
|
|
214
214
|
if (isReferenceInStack(ctx, val)) {
|
|
215
215
|
const refParam = getRefParam(ctx, val[1]);
|
|
216
|
-
|
|
217
|
-
ctx,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
!(isIdentifier && Number.isNaN(check)),
|
|
222
|
-
);
|
|
216
|
+
if (isIdentifier && Number.isNaN(check)) {
|
|
217
|
+
createObjectAssign(ctx, sourceID, key, refParam);
|
|
218
|
+
} else {
|
|
219
|
+
createArrayAssign(ctx, sourceID, isIdentifier ? key : quote(key), refParam);
|
|
220
|
+
}
|
|
223
221
|
} else {
|
|
224
|
-
result += `${
|
|
222
|
+
result += `${isIdentifier ? key : quote(key)}:${serializeTree(ctx, val)},`;
|
|
225
223
|
}
|
|
226
224
|
}
|
|
227
225
|
ctx.stack.pop();
|
|
@@ -400,7 +398,7 @@ function serializeWithObjectAssign(
|
|
|
400
398
|
id: number,
|
|
401
399
|
serialized: string,
|
|
402
400
|
) {
|
|
403
|
-
const fields =
|
|
401
|
+
const fields = serializeObject(ctx, id, value);
|
|
404
402
|
if (fields !== '{}') {
|
|
405
403
|
return `Object.assign(${serialized},${fields})`;
|
|
406
404
|
}
|
|
@@ -551,7 +549,7 @@ export default function serializeTree(
|
|
|
551
549
|
case SerovalNodeType.NullConstructor:
|
|
552
550
|
return serializeNullConstructor(ctx, value, id);
|
|
553
551
|
case SerovalNodeType.Object:
|
|
554
|
-
return assignRef(ctx, id,
|
|
552
|
+
return assignRef(ctx, id, serializeObject(ctx, id, value));
|
|
555
553
|
default:
|
|
556
554
|
throw new Error('Unsupported type');
|
|
557
555
|
}
|
package/src/tree/sync.ts
CHANGED
|
@@ -24,24 +24,34 @@ import {
|
|
|
24
24
|
SerovalSetNode,
|
|
25
25
|
} from './types';
|
|
26
26
|
|
|
27
|
-
function
|
|
27
|
+
function serializePropertiesSync(
|
|
28
28
|
ctx: ParserContext,
|
|
29
|
-
properties: Record<string,
|
|
29
|
+
properties: Record<string, unknown>,
|
|
30
30
|
): SerovalDictionaryNode {
|
|
31
31
|
const keys = Object.keys(properties);
|
|
32
|
-
const
|
|
33
|
-
const
|
|
32
|
+
const size = keys.length;
|
|
33
|
+
const keyNodes = new Array<string>(size);
|
|
34
|
+
const valueNodes = new Array<SerovalNode>(size);
|
|
35
|
+
const deferredKeys = new Array<string>(size);
|
|
36
|
+
const deferredValues = new Array<ServerValue>(size);
|
|
37
|
+
let deferredSize = 0;
|
|
38
|
+
let nodesSize = 0;
|
|
34
39
|
for (const key of keys) {
|
|
35
40
|
if (isIterable(properties[key])) {
|
|
36
|
-
|
|
41
|
+
deferredKeys[deferredSize] = key;
|
|
42
|
+
deferredValues[deferredSize] = properties[key] as ServerValue;
|
|
43
|
+
deferredSize++;
|
|
37
44
|
} else {
|
|
38
|
-
|
|
45
|
+
keyNodes[nodesSize] = key;
|
|
46
|
+
valueNodes[nodesSize] = generateTreeSync(ctx, properties[key] as ServerValue);
|
|
47
|
+
nodesSize++;
|
|
39
48
|
}
|
|
40
49
|
}
|
|
41
|
-
for (
|
|
42
|
-
|
|
50
|
+
for (let i = 0; i < deferredSize; i++) {
|
|
51
|
+
keyNodes[nodesSize + i] = deferredKeys[i];
|
|
52
|
+
valueNodes[nodesSize + i] = generateTreeSync(ctx, deferredValues[i]);
|
|
43
53
|
}
|
|
44
|
-
return
|
|
54
|
+
return [keyNodes, valueNodes, size];
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
function generateSetNode(
|
|
@@ -141,7 +151,7 @@ function generateAggregateErrorNode(
|
|
|
141
151
|
): SerovalAggregateErrorNode {
|
|
142
152
|
const options = getErrorOptions(current);
|
|
143
153
|
const optionsNode = options
|
|
144
|
-
?
|
|
154
|
+
? serializePropertiesSync(ctx, options)
|
|
145
155
|
: undefined;
|
|
146
156
|
const errorsNode = generateTreeSync(ctx, current.errors as ServerValue);
|
|
147
157
|
return [SerovalNodeType.AggregateError, [current.message, optionsNode, errorsNode], id];
|
|
@@ -154,7 +164,7 @@ function generateErrorNode(
|
|
|
154
164
|
): SerovalErrorNode {
|
|
155
165
|
const options = getErrorOptions(current);
|
|
156
166
|
const optionsNode = options
|
|
157
|
-
?
|
|
167
|
+
? serializePropertiesSync(ctx, options)
|
|
158
168
|
: undefined;
|
|
159
169
|
return [
|
|
160
170
|
SerovalNodeType.Error,
|
|
@@ -172,9 +182,7 @@ function generateIterableNode(
|
|
|
172
182
|
const options = getIterableOptions(current);
|
|
173
183
|
return [SerovalNodeType.Iterable, [
|
|
174
184
|
// Parse options first before the items
|
|
175
|
-
options
|
|
176
|
-
? generateDictionary(ctx, options as Record<string, ServerValue>)
|
|
177
|
-
: undefined,
|
|
185
|
+
options ? serializePropertiesSync(ctx, options) : undefined,
|
|
178
186
|
generateNodeList(ctx, Array.from(current)),
|
|
179
187
|
], id];
|
|
180
188
|
}
|
|
@@ -218,7 +226,7 @@ function generateTreeSync(
|
|
|
218
226
|
if (current.constructor === Object || empty) {
|
|
219
227
|
return [
|
|
220
228
|
empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,
|
|
221
|
-
|
|
229
|
+
serializePropertiesSync(ctx, current as Record<string, unknown>),
|
|
222
230
|
id,
|
|
223
231
|
];
|
|
224
232
|
}
|
package/src/tree/types.ts
CHANGED
|
@@ -39,7 +39,7 @@ export type SerovalSemiPrimitiveNode =
|
|
|
39
39
|
id: number
|
|
40
40
|
];
|
|
41
41
|
|
|
42
|
-
export type SerovalDictionaryNode =
|
|
42
|
+
export type SerovalDictionaryNode = [key: string[], value: SerovalNode[], size: number];
|
|
43
43
|
export type SerovalSetNode = [type: SerovalNodeType.Set, value: SerovalNode[], id: number];
|
|
44
44
|
export type SerovalMapNode = [
|
|
45
45
|
type: SerovalNodeType.Map,
|