json-as 0.9.17 → 0.9.18
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/.github/FUNDING.yml +1 -1
- package/.github/workflows/nodejs.yml +4 -5
- package/.github/workflows/release-package.yml +2 -2
- package/CHANGELOG +1 -0
- package/README.md +27 -67
- package/as-test.config.json +3 -5
- package/assembly/__tests__/test.spec.ts +201 -311
- package/assembly/__tests__/types.ts +9 -10
- package/assembly/custom/sink.ts +264 -263
- package/assembly/custom/types.ts +1 -1
- package/assembly/deserialize/array.ts +30 -26
- package/assembly/index.d.ts +1 -2
- package/assembly/serialize/object.ts +2 -1
- package/assembly/test.ts +4 -3
- package/assembly/tsconfig.json +8 -10
- package/bench/bench-node.js +6 -6
- package/bench/benchmark.ts +18 -18
- package/bench/tsconfig.json +96 -98
- package/bench.js +9 -9
- package/index.ts +1 -1
- package/package.json +7 -5
- package/transform/lib/index.js +475 -421
- package/transform/package.json +1 -1
- package/transform/src/index.ts +242 -140
- package/transform/tsconfig.json +2 -2
package/transform/package.json
CHANGED
package/transform/src/index.ts
CHANGED
|
@@ -2,25 +2,24 @@ import {
|
|
|
2
2
|
ClassDeclaration,
|
|
3
3
|
FieldDeclaration,
|
|
4
4
|
IdentifierExpression,
|
|
5
|
-
NamedTypeNode,
|
|
6
5
|
StringLiteralExpression,
|
|
7
6
|
Parser,
|
|
8
7
|
Source,
|
|
9
|
-
NodeKind
|
|
8
|
+
NodeKind,
|
|
9
|
+
Expression,
|
|
10
|
+
CommonFlags,
|
|
10
11
|
} from "assemblyscript/dist/assemblyscript.js";
|
|
11
12
|
|
|
12
13
|
import { toString, isStdlib } from "visitor-as/dist/utils.js";
|
|
13
14
|
import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
|
|
14
15
|
import { Transform } from "assemblyscript/dist/transform.js";
|
|
15
|
-
import { CommonFlags } from "types:assemblyscript/src/common";
|
|
16
|
-
import { DecoratorNode } from "types:assemblyscript/src/ast";
|
|
17
16
|
|
|
18
17
|
class JSONTransform extends BaseVisitor {
|
|
19
18
|
public schemasList: SchemaData[] = [];
|
|
20
19
|
public currentClass!: SchemaData;
|
|
21
20
|
public sources = new Set<Source>();
|
|
22
21
|
|
|
23
|
-
visitMethodDeclaration(): void {
|
|
22
|
+
visitMethodDeclaration(): void {}
|
|
24
23
|
visitClassDeclaration(node: ClassDeclaration): void {
|
|
25
24
|
if (!node.decorators?.length) return;
|
|
26
25
|
|
|
@@ -39,21 +38,20 @@ class JSONTransform extends BaseVisitor {
|
|
|
39
38
|
schema.name = node.name.text;
|
|
40
39
|
|
|
41
40
|
const members = [
|
|
42
|
-
...node.members.filter(v => v.kind === NodeKind.FieldDeclaration)
|
|
41
|
+
...node.members.filter((v) => v.kind === NodeKind.FieldDeclaration),
|
|
43
42
|
];
|
|
44
43
|
|
|
45
44
|
if (node.extendsType) {
|
|
46
45
|
schema.parent = this.schemasList.find(
|
|
47
|
-
(v) => v.name == node.extendsType?.name.identifier.text
|
|
46
|
+
(v) => v.name == node.extendsType?.name.identifier.text,
|
|
48
47
|
) as SchemaData | null;
|
|
49
48
|
|
|
50
49
|
if (schema.parent?.members) {
|
|
51
50
|
for (let i = schema.parent.members.length - 1; i >= 0; i--) {
|
|
52
51
|
const replace = schema.members.find(
|
|
53
|
-
(v) => v.name == schema.parent?.members[i]?.name
|
|
52
|
+
(v) => v.name == schema.parent?.members[i]?.name,
|
|
54
53
|
);
|
|
55
54
|
if (!replace) {
|
|
56
|
-
//schema.members.unshift(schema.parent?.members[i]!);
|
|
57
55
|
members.unshift(schema.parent?.members[i]!.node);
|
|
58
56
|
}
|
|
59
57
|
}
|
|
@@ -61,12 +59,13 @@ class JSONTransform extends BaseVisitor {
|
|
|
61
59
|
}
|
|
62
60
|
|
|
63
61
|
if (!members.length) {
|
|
64
|
-
let SERIALIZE_RAW_EMPTY =
|
|
62
|
+
let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}';
|
|
65
63
|
//let SERIALIZE_PRETTY_EMPTY = "__SERIALIZE_PRETTY(): string {\n return \"{}\";\n}";
|
|
66
64
|
|
|
67
65
|
let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}";
|
|
68
66
|
|
|
69
|
-
let DESERIALIZE_EMPTY =
|
|
67
|
+
let DESERIALIZE_EMPTY =
|
|
68
|
+
"__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}";
|
|
70
69
|
|
|
71
70
|
if (process.env["JSON_DEBUG"]) {
|
|
72
71
|
console.log(SERIALIZE_RAW_EMPTY);
|
|
@@ -75,14 +74,26 @@ class JSONTransform extends BaseVisitor {
|
|
|
75
74
|
console.log(DESERIALIZE_EMPTY);
|
|
76
75
|
}
|
|
77
76
|
|
|
78
|
-
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(
|
|
77
|
+
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(
|
|
78
|
+
SERIALIZE_RAW_EMPTY,
|
|
79
|
+
node,
|
|
80
|
+
);
|
|
79
81
|
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
|
|
80
|
-
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(
|
|
83
|
+
INITIALIZE_EMPTY,
|
|
84
|
+
node,
|
|
85
|
+
);
|
|
86
|
+
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(
|
|
87
|
+
DESERIALIZE_EMPTY,
|
|
88
|
+
node,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
|
|
92
|
+
node.members.push(SERIALIZE_RAW_METHOD_EMPTY);
|
|
93
|
+
if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
|
|
94
|
+
node.members.push(INITIALIZE_METHOD_EMPTY);
|
|
95
|
+
if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
|
|
96
|
+
node.members.push(DESERIALIZE_METHOD_EMPTY);
|
|
86
97
|
|
|
87
98
|
this.schemasList.push(schema);
|
|
88
99
|
}
|
|
@@ -91,7 +102,12 @@ class JSONTransform extends BaseVisitor {
|
|
|
91
102
|
const name = member.name;
|
|
92
103
|
if (!(member instanceof FieldDeclaration)) continue;
|
|
93
104
|
if (!member.type) {
|
|
94
|
-
throw new Error(
|
|
105
|
+
throw new Error(
|
|
106
|
+
"Fields must be strongly typed! Found " +
|
|
107
|
+
toString(member) +
|
|
108
|
+
" at " +
|
|
109
|
+
node.range.source.normalizedPath,
|
|
110
|
+
);
|
|
95
111
|
}
|
|
96
112
|
const type = toString(member.type!);
|
|
97
113
|
if (type.startsWith("(") && type.includes("=>")) continue;
|
|
@@ -100,7 +116,6 @@ class JSONTransform extends BaseVisitor {
|
|
|
100
116
|
if (member.flags == CommonFlags.Static) continue;
|
|
101
117
|
if (member.flags === CommonFlags.Private) continue;
|
|
102
118
|
if (member.flags === CommonFlags.Protected) continue;
|
|
103
|
-
if (member.decorators && member.decorators.find((v) => (<IdentifierExpression>v.name).text == "omit")) continue;
|
|
104
119
|
|
|
105
120
|
const mem = new Property();
|
|
106
121
|
mem.name = name.text;
|
|
@@ -108,95 +123,90 @@ class JSONTransform extends BaseVisitor {
|
|
|
108
123
|
mem.value = value;
|
|
109
124
|
mem.node = member;
|
|
110
125
|
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
if (decorator = member.decorators.find(v => (<IdentifierExpression>v.name).text == "alias") as DecoratorNode | null) {
|
|
114
|
-
if ((<IdentifierExpression>decorator.name).text == "alias") {
|
|
115
|
-
if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath);
|
|
116
|
-
mem.flags.push(PropertyFlags.Alias);
|
|
117
|
-
mem.alias = (decorator.args[0] as StringLiteralExpression).value;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
for (let i = 0; i < (member.decorators).length; i++) {
|
|
122
|
-
const decorator = member.decorators[i]!;
|
|
123
|
-
if ((<IdentifierExpression>decorator.name).text == "omitnull") {
|
|
124
|
-
mem.flags.push(PropertyFlags.OmitNull);
|
|
125
|
-
} else if ((<IdentifierExpression>decorator.name).text == "omitif") {
|
|
126
|
-
if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath);
|
|
127
|
-
mem.args?.push((decorator.args[0] as StringLiteralExpression).value);
|
|
128
|
-
mem.flags.push(PropertyFlags.OmitIf);
|
|
129
|
-
} else if ((<IdentifierExpression>decorator.name).text == "flatten") {
|
|
130
|
-
if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @flatten in " + node.range.source.normalizedPath);
|
|
131
|
-
mem.flags.push(PropertyFlags.Flatten);
|
|
132
|
-
mem.args = [(decorator.args[0] as StringLiteralExpression).value];
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (!mem.flags.length) {
|
|
138
|
-
mem.flags = [PropertyFlags.None];
|
|
139
|
-
if (type == "JSON.Raw") {
|
|
140
|
-
mem.serialize = escapeString(JSON.stringify(mem.alias || mem.name)) + ":${this." + name.text + "}";
|
|
141
|
-
mem.deserialize = "this." + name.text + " = " + "data.substring(value_start, value_end);"
|
|
142
|
-
} else {
|
|
143
|
-
mem.serialize = escapeString(JSON.stringify(mem.alias || mem.name)) + ":${__SERIALIZE<" + type + ">(this." + name.text + ")}";
|
|
144
|
-
mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));"
|
|
145
|
-
}
|
|
126
|
+
if (type == "JSON.Raw") {
|
|
127
|
+
mem.flags.set(PropertyFlags.JSON_Raw, []);
|
|
146
128
|
}
|
|
147
129
|
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
130
|
+
if (member.decorators) {
|
|
131
|
+
for (const decorator of member.decorators) {
|
|
132
|
+
const decoratorName = (decorator.name as IdentifierExpression).text;
|
|
133
|
+
|
|
134
|
+
const args = getArgs(decorator.args);
|
|
135
|
+
|
|
136
|
+
switch (decoratorName) {
|
|
137
|
+
case "alias": {
|
|
138
|
+
if (!args.length)
|
|
139
|
+
throw new Error(
|
|
140
|
+
"Expected 1 argument but got zero at @alias in " +
|
|
141
|
+
node.range.source.normalizedPath,
|
|
142
|
+
);
|
|
143
|
+
mem.alias = args[0]!;
|
|
144
|
+
mem.flags.set(PropertyFlags.Alias, args);
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
case "omit": {
|
|
148
|
+
mem.flags.set(PropertyFlags.Omit, args);
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
case "omitif": {
|
|
152
|
+
if (!decorator.args?.length)
|
|
153
|
+
throw new Error(
|
|
154
|
+
"Expected 1 argument but got zero at @omitif in " +
|
|
155
|
+
node.range.source.normalizedPath,
|
|
156
|
+
);
|
|
157
|
+
mem.flags.set(PropertyFlags.OmitIf, args);
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
case "omitnull": {
|
|
161
|
+
mem.flags.set(PropertyFlags.OmitNull, args);
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
166
165
|
}
|
|
167
|
-
mem.name = name.text;
|
|
168
166
|
}
|
|
169
167
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
168
|
+
mem.generate();
|
|
169
|
+
|
|
170
|
+
if (this.schemasList.find((v) => v.name == type)) {
|
|
171
|
+
mem.initialize =
|
|
172
|
+
"this." +
|
|
173
|
+
name.text +
|
|
174
|
+
" = changetype<nonnull<" +
|
|
175
|
+
mem.type +
|
|
176
|
+
">>(__new(offsetof<nonnull<" +
|
|
177
|
+
mem.type +
|
|
178
|
+
">>(), idof<nonnull<" +
|
|
179
|
+
mem.type +
|
|
180
|
+
">>()));\n changetype<nonnull<" +
|
|
181
|
+
mem.type +
|
|
182
|
+
">>(this." +
|
|
183
|
+
name.text +
|
|
184
|
+
").__INITIALIZE()";
|
|
173
185
|
} else if (mem.value) {
|
|
174
186
|
mem.initialize = "this." + name.text + " = " + mem.value;
|
|
175
|
-
} else if (
|
|
176
|
-
mem.initialize = "this." + name.text + " = new " + mem.type + "()"
|
|
177
|
-
} else if (
|
|
178
|
-
mem.initialize = "this." + name.text +
|
|
179
|
-
} else if (
|
|
180
|
-
mem.initialize =
|
|
181
|
-
|
|
187
|
+
} else if (type === "Map") {
|
|
188
|
+
mem.initialize = "this." + name.text + " = new " + mem.type + "()";
|
|
189
|
+
} else if (type === "string") {
|
|
190
|
+
mem.initialize = "this." + name.text + ' = ""';
|
|
191
|
+
} else if (type === "Array") {
|
|
192
|
+
mem.initialize =
|
|
193
|
+
"this." + name.text + " = instantiate<" + mem.type + ">()";
|
|
194
|
+
} else if (type === "bool" || type === "boolean") {
|
|
182
195
|
mem.initialize = "this." + name.text + " = false";
|
|
183
|
-
} else if (
|
|
184
|
-
mem.initialize = "this." + name.text +
|
|
196
|
+
} else if (type === "JSON.Raw") {
|
|
197
|
+
mem.initialize = "this." + name.text + ' = ""';
|
|
185
198
|
} else if (
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
199
|
+
type === "u8" ||
|
|
200
|
+
type === "u16" ||
|
|
201
|
+
type === "u32" ||
|
|
202
|
+
type === "u64" ||
|
|
203
|
+
type === "i8" ||
|
|
204
|
+
type === "i16" ||
|
|
205
|
+
type === "i32" ||
|
|
206
|
+
type === "i64"
|
|
194
207
|
) {
|
|
195
208
|
mem.initialize = "this." + name.text + " = 0";
|
|
196
|
-
} else if (
|
|
197
|
-
t === "f32" ||
|
|
198
|
-
t === "f64"
|
|
199
|
-
) {
|
|
209
|
+
} else if (type === "f32" || type === "f64") {
|
|
200
210
|
mem.initialize = "this." + name.text + " = 0.0";
|
|
201
211
|
}
|
|
202
212
|
|
|
@@ -208,7 +218,8 @@ class JSONTransform extends BaseVisitor {
|
|
|
208
218
|
|
|
209
219
|
let INITIALIZE = "__INITIALIZE(): this {\n";
|
|
210
220
|
|
|
211
|
-
let DESERIALIZE =
|
|
221
|
+
let DESERIALIZE =
|
|
222
|
+
"__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n const len = key_end - key_start;\n";
|
|
212
223
|
let indent = " ";
|
|
213
224
|
|
|
214
225
|
if (!schema.members.length) return;
|
|
@@ -216,8 +227,8 @@ class JSONTransform extends BaseVisitor {
|
|
|
216
227
|
found = false;
|
|
217
228
|
|
|
218
229
|
if (
|
|
219
|
-
schema.members[0]?.flags.
|
|
220
|
-
|
|
230
|
+
schema.members[0]?.flags.has(PropertyFlags.OmitNull) ||
|
|
231
|
+
schema.members[0]?.flags.has(PropertyFlags.OmitIf)
|
|
221
232
|
) {
|
|
222
233
|
SERIALIZE_RAW += schema.members[0]?.serialize;
|
|
223
234
|
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize;
|
|
@@ -227,14 +238,15 @@ class JSONTransform extends BaseVisitor {
|
|
|
227
238
|
found = true;
|
|
228
239
|
}
|
|
229
240
|
|
|
230
|
-
if (schema.members[0]?.initialize)
|
|
241
|
+
if (schema.members[0]?.initialize)
|
|
242
|
+
INITIALIZE += " " + schema.members[0]?.initialize + ";\n";
|
|
231
243
|
|
|
232
244
|
for (let i = 1; i < schema.members.length; i++) {
|
|
233
245
|
const member = schema.members[i]!;
|
|
234
246
|
if (member.initialize) INITIALIZE += " " + member.initialize + ";\n";
|
|
235
247
|
if (
|
|
236
|
-
member.flags.
|
|
237
|
-
|
|
248
|
+
member.flags.has(PropertyFlags.OmitNull) ||
|
|
249
|
+
member.flags.has(PropertyFlags.OmitIf)
|
|
238
250
|
) {
|
|
239
251
|
SERIALIZE_RAW += member.serialize;
|
|
240
252
|
SERIALIZE_PRETTY += member.serialize;
|
|
@@ -246,17 +258,21 @@ class JSONTransform extends BaseVisitor {
|
|
|
246
258
|
}
|
|
247
259
|
|
|
248
260
|
if (found) {
|
|
249
|
-
SERIALIZE_RAW +=
|
|
250
|
-
|
|
261
|
+
SERIALIZE_RAW +=
|
|
262
|
+
"`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}";
|
|
263
|
+
SERIALIZE_PRETTY +=
|
|
264
|
+
"`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}";
|
|
251
265
|
} else {
|
|
252
266
|
SERIALIZE_RAW += "`;\n};";
|
|
253
267
|
SERIALIZE_PRETTY += "`;\n};";
|
|
254
268
|
}
|
|
255
269
|
|
|
256
|
-
INITIALIZE += " return this;\n}"
|
|
270
|
+
INITIALIZE += " return this;\n}";
|
|
257
271
|
|
|
258
272
|
const sortedMembers: Property[][] = [];
|
|
259
|
-
const _sorted = schema.members.sort(
|
|
273
|
+
const _sorted = schema.members.sort(
|
|
274
|
+
(a, b) => a.name.length - b.name.length,
|
|
275
|
+
);
|
|
260
276
|
let len = 0;
|
|
261
277
|
let offset = 0;
|
|
262
278
|
sortedMembers.push([_sorted[0]!]);
|
|
@@ -265,7 +281,7 @@ class JSONTransform extends BaseVisitor {
|
|
|
265
281
|
const member = _sorted[i]!;
|
|
266
282
|
if (member.alias?.length || member.name.length > len) {
|
|
267
283
|
sortedMembers.push([member]);
|
|
268
|
-
len = member.alias?.length || member.name.length
|
|
284
|
+
len = member.alias?.length || member.name.length;
|
|
269
285
|
offset++;
|
|
270
286
|
} else {
|
|
271
287
|
sortedMembers[offset]!.push(member);
|
|
@@ -278,24 +294,30 @@ class JSONTransform extends BaseVisitor {
|
|
|
278
294
|
const name = encodeKey(firstMember.alias || firstMember.name);
|
|
279
295
|
if (name.length === 1) {
|
|
280
296
|
if (first) {
|
|
281
|
-
DESERIALIZE +=
|
|
297
|
+
DESERIALIZE +=
|
|
298
|
+
" if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
282
299
|
first = false;
|
|
283
300
|
} else {
|
|
284
|
-
DESERIALIZE +=
|
|
301
|
+
DESERIALIZE +=
|
|
302
|
+
"else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
285
303
|
}
|
|
286
304
|
} else if (name.length === 2) {
|
|
287
305
|
if (first) {
|
|
288
|
-
DESERIALIZE +=
|
|
306
|
+
DESERIALIZE +=
|
|
307
|
+
" if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
289
308
|
first = false;
|
|
290
309
|
} else {
|
|
291
|
-
DESERIALIZE +=
|
|
310
|
+
DESERIALIZE +=
|
|
311
|
+
"else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
292
312
|
}
|
|
293
313
|
} else if (name.length === 4) {
|
|
294
314
|
if (first) {
|
|
295
|
-
DESERIALIZE +=
|
|
315
|
+
DESERIALIZE +=
|
|
316
|
+
" if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
|
|
296
317
|
first = false;
|
|
297
318
|
} else {
|
|
298
|
-
DESERIALIZE +=
|
|
319
|
+
DESERIALIZE +=
|
|
320
|
+
"else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
|
|
299
321
|
}
|
|
300
322
|
} else {
|
|
301
323
|
if (first) {
|
|
@@ -319,28 +341,36 @@ class JSONTransform extends BaseVisitor {
|
|
|
319
341
|
f = false;
|
|
320
342
|
DESERIALIZE += ` if (${charCodeAt64(name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
|
|
321
343
|
} else {
|
|
322
|
-
DESERIALIZE =
|
|
344
|
+
DESERIALIZE =
|
|
345
|
+
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
346
|
+
`else if (${charCodeAt64(name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
|
|
323
347
|
}
|
|
324
348
|
} else {
|
|
325
349
|
if (f) {
|
|
326
350
|
f = false;
|
|
327
|
-
DESERIALIZE += ` if (0 == memory.compare(changetype<usize>("${escapeQuote(escapeSlash(name))}"), changetype<usize>(data) + (key_start << 1), ${name.length << 1})) {\n ${member.deserialize}\n return true;\n }\n
|
|
351
|
+
DESERIALIZE += ` if (0 == memory.compare(changetype<usize>("${escapeQuote(escapeSlash(name))}"), changetype<usize>(data) + (key_start << 1), ${name.length << 1})) {\n ${member.deserialize}\n return true;\n }\n`;
|
|
328
352
|
} else {
|
|
329
|
-
DESERIALIZE =
|
|
353
|
+
DESERIALIZE =
|
|
354
|
+
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
355
|
+
` else if (0 == memory.compare(changetype<usize>("${escapeQuote(escapeSlash(name))}"), changetype<usize>(data) + (key_start << 1), ${name.length << 1})) {\n ${member.deserialize}\n return true;\n }\n`;
|
|
330
356
|
}
|
|
331
357
|
}
|
|
332
358
|
}
|
|
333
359
|
if (name.length < 3) {
|
|
334
|
-
DESERIALIZE += ` default: {\n return false;\n }\n }\n
|
|
360
|
+
DESERIALIZE += ` default: {\n return false;\n }\n }\n`;
|
|
335
361
|
} else if (name.length == 4) {
|
|
336
|
-
DESERIALIZE =
|
|
362
|
+
DESERIALIZE =
|
|
363
|
+
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
364
|
+
` else {\n return false;\n }\n`;
|
|
337
365
|
} else {
|
|
338
|
-
DESERIALIZE =
|
|
366
|
+
DESERIALIZE =
|
|
367
|
+
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
368
|
+
` else {\n return false;\n }\n`;
|
|
339
369
|
}
|
|
340
370
|
DESERIALIZE += " } ";
|
|
341
371
|
}
|
|
342
372
|
|
|
343
|
-
DESERIALIZE += "\n return false;\n}"
|
|
373
|
+
DESERIALIZE += "\n return false;\n}";
|
|
344
374
|
|
|
345
375
|
//console.log(sortedMembers);
|
|
346
376
|
|
|
@@ -351,14 +381,20 @@ class JSONTransform extends BaseVisitor {
|
|
|
351
381
|
console.log(DESERIALIZE);
|
|
352
382
|
}
|
|
353
383
|
|
|
354
|
-
const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(
|
|
384
|
+
const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(
|
|
385
|
+
SERIALIZE_RAW,
|
|
386
|
+
node,
|
|
387
|
+
);
|
|
355
388
|
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
|
|
356
389
|
const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
|
|
357
390
|
const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
|
|
358
391
|
|
|
359
|
-
if (!node.members.find(v => v.name.text == "__SERIALIZE"))
|
|
360
|
-
|
|
361
|
-
if (!node.members.find(v => v.name.text == "
|
|
392
|
+
if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
|
|
393
|
+
node.members.push(SERIALIZE_RAW_METHOD);
|
|
394
|
+
if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
|
|
395
|
+
node.members.push(INITIALIZE_METHOD);
|
|
396
|
+
if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
|
|
397
|
+
node.members.push(DESERIALIZE_METHOD);
|
|
362
398
|
|
|
363
399
|
this.schemasList.push(schema);
|
|
364
400
|
}
|
|
@@ -405,27 +441,32 @@ export default class Transformer extends Transform {
|
|
|
405
441
|
for (const schema of schemas) {
|
|
406
442
|
if (schema.parent) {
|
|
407
443
|
const parent = schemas.find((v) => v.name === schema.parent?.name);
|
|
408
|
-
if (!parent)
|
|
444
|
+
if (!parent)
|
|
445
|
+
throw new Error(
|
|
446
|
+
`Class ${schema.name} extends its parent class ${schema.parent}, but ${schema.parent} does not include a @json or @serializable decorator! Add the decorator and rebuild.`,
|
|
447
|
+
);
|
|
409
448
|
}
|
|
410
449
|
}
|
|
411
450
|
}
|
|
412
451
|
}
|
|
413
452
|
|
|
414
453
|
enum PropertyFlags {
|
|
415
|
-
None,
|
|
416
454
|
Omit,
|
|
417
455
|
OmitNull,
|
|
418
456
|
OmitIf,
|
|
419
457
|
Alias,
|
|
420
|
-
|
|
458
|
+
JSON_Raw,
|
|
421
459
|
}
|
|
422
460
|
|
|
423
461
|
class Property {
|
|
424
|
-
public name: string = ""
|
|
462
|
+
public name: string = "";
|
|
425
463
|
public alias: string | null = null;
|
|
426
464
|
public type: string = "";
|
|
427
465
|
public value: string | null = null;
|
|
428
|
-
public flags: PropertyFlags[] =
|
|
466
|
+
public flags: Map<PropertyFlags, string[]> = new Map<
|
|
467
|
+
PropertyFlags,
|
|
468
|
+
string[]
|
|
469
|
+
>();
|
|
429
470
|
public args: string[] | null = [];
|
|
430
471
|
|
|
431
472
|
public serialize: string | null = null;
|
|
@@ -433,11 +474,57 @@ class Property {
|
|
|
433
474
|
public initialize: string | null = null;
|
|
434
475
|
|
|
435
476
|
public node!: FieldDeclaration;
|
|
477
|
+
|
|
478
|
+
private right_s: string = "";
|
|
479
|
+
private right_d: string = "";
|
|
480
|
+
|
|
481
|
+
public generate(): void {
|
|
482
|
+
const name = this.name;
|
|
483
|
+
const escapedName = escapeString(JSON.stringify(this.alias || this.name));
|
|
484
|
+
const type = this.type;
|
|
485
|
+
if (this.flags.has(PropertyFlags.Omit)) return;
|
|
486
|
+
|
|
487
|
+
if (this.flags.has(PropertyFlags.JSON_Raw)) {
|
|
488
|
+
this.right_s = "this." + name;
|
|
489
|
+
this.right_d = "data.substring(value_start, value_end);";
|
|
490
|
+
} else {
|
|
491
|
+
this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")";
|
|
492
|
+
this.right_d =
|
|
493
|
+
"__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (this.flags.has(PropertyFlags.OmitIf)) {
|
|
497
|
+
const condition = this.args![0];
|
|
498
|
+
this.serialize =
|
|
499
|
+
"${" +
|
|
500
|
+
condition +
|
|
501
|
+
' ? "" : \'' +
|
|
502
|
+
escapedName +
|
|
503
|
+
":' + " +
|
|
504
|
+
this.right_s +
|
|
505
|
+
' + ","}';
|
|
506
|
+
this.deserialize = "this." + name + " = " + this.right_d + ";";
|
|
507
|
+
} else if (this.flags.has(PropertyFlags.OmitNull)) {
|
|
508
|
+
this.serialize =
|
|
509
|
+
"${changetype<usize>(this." +
|
|
510
|
+
name +
|
|
511
|
+
") == <usize>0" +
|
|
512
|
+
' ? "" : \'' +
|
|
513
|
+
escapedName +
|
|
514
|
+
":' + " +
|
|
515
|
+
this.right_s +
|
|
516
|
+
' + ","}';
|
|
517
|
+
this.deserialize = "this." + name + " = " + this.right_d + ";";
|
|
518
|
+
} else {
|
|
519
|
+
this.serialize = escapedName + ":${" + this.right_s + "}";
|
|
520
|
+
this.deserialize = "this." + name + " = " + this.right_d + ";";
|
|
521
|
+
}
|
|
522
|
+
}
|
|
436
523
|
}
|
|
437
524
|
|
|
438
525
|
class SchemaData {
|
|
439
526
|
public name: string = "";
|
|
440
|
-
public members: Property[] = []
|
|
527
|
+
public members: Property[] = [];
|
|
441
528
|
public parent: SchemaData | null = null;
|
|
442
529
|
public node!: ClassDeclaration;
|
|
443
530
|
}
|
|
@@ -448,7 +535,9 @@ function charCodeAt32(data: string, offset: number): number {
|
|
|
448
535
|
|
|
449
536
|
function charCodeAt64(data: string, offset: number): bigint {
|
|
450
537
|
if (offset + 3 >= data.length) {
|
|
451
|
-
throw new Error(
|
|
538
|
+
throw new Error(
|
|
539
|
+
"The string must have at least 4 characters from the specified offset.",
|
|
540
|
+
);
|
|
452
541
|
}
|
|
453
542
|
|
|
454
543
|
const firstCharCode = BigInt(data.charCodeAt(offset));
|
|
@@ -456,7 +545,11 @@ function charCodeAt64(data: string, offset: number): bigint {
|
|
|
456
545
|
const thirdCharCode = BigInt(data.charCodeAt(offset + 2));
|
|
457
546
|
const fourthCharCode = BigInt(data.charCodeAt(offset + 3));
|
|
458
547
|
|
|
459
|
-
const u64Value =
|
|
548
|
+
const u64Value =
|
|
549
|
+
(fourthCharCode << 48n) |
|
|
550
|
+
(thirdCharCode << 32n) |
|
|
551
|
+
(secondCharCode << 16n) |
|
|
552
|
+
firstCharCode;
|
|
460
553
|
|
|
461
554
|
return u64Value;
|
|
462
555
|
}
|
|
@@ -467,15 +560,24 @@ function encodeKey(key: string): string {
|
|
|
467
560
|
}
|
|
468
561
|
|
|
469
562
|
function escapeString(data: string): string {
|
|
470
|
-
return data.replace(/\\/g, "\\\\")
|
|
471
|
-
.replace(/\`/g, '\\`');
|
|
563
|
+
return data.replace(/\\/g, "\\\\").replace(/\`/g, "\\`");
|
|
472
564
|
}
|
|
473
565
|
|
|
474
566
|
function escapeSlash(data: string): string {
|
|
475
|
-
return data.replace(/\\/g, "\\\\")
|
|
476
|
-
.replace(/\`/g, '\\`');
|
|
567
|
+
return data.replace(/\\/g, "\\\\").replace(/\`/g, "\\`");
|
|
477
568
|
}
|
|
478
569
|
|
|
479
570
|
function escapeQuote(data: string): string {
|
|
480
|
-
return data.replace(/\"/g, "
|
|
481
|
-
}
|
|
571
|
+
return data.replace(/\"/g, '\\"');
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function getArgs(args: Expression[] | null): string[] {
|
|
575
|
+
if (!args) return [];
|
|
576
|
+
let out: string[] = [];
|
|
577
|
+
for (const arg of args) {
|
|
578
|
+
if (arg instanceof StringLiteralExpression) {
|
|
579
|
+
out.push(arg.value);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
return out;
|
|
583
|
+
}
|
package/transform/tsconfig.json
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
"module": "ES2015",
|
|
5
5
|
"downlevelIteration": true,
|
|
6
6
|
"outDir": "./lib/",
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
"strict": true,
|
|
9
9
|
"noImplicitAny": true,
|
|
10
10
|
"strictNullChecks": true,
|
|
11
11
|
"strictFunctionTypes": true,
|
|
12
|
-
"strictBindCallApply": true
|
|
12
|
+
"strictBindCallApply": true,
|
|
13
13
|
"strictPropertyInitialization": true,
|
|
14
14
|
"noImplicitThis": true,
|
|
15
15
|
"alwaysStrict": true,
|