json-as 0.9.21 → 0.9.22
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/.prettierrc.json +4 -0
- package/CHANGELOG +1 -1
- package/README.md +2 -2
- package/assembly/__benches__/as-tral.d.ts +1 -0
- package/assembly/__benches__/bool.bench.ts +14 -0
- package/assembly/__benches__/simd.bench.ts +36 -0
- package/assembly/__benches__/string.bench.ts +21 -0
- package/assembly/__tests__/bool.spec.ts +7 -7
- package/assembly/__tests__/float.spec.ts +23 -23
- package/assembly/__tests__/integer.spec.ts +11 -11
- package/assembly/__tests__/obj.spec.ts +1 -2
- package/assembly/__tests__/string.spec.ts +17 -41
- package/assembly/__tests__/test.spec.ts +28 -130
- package/assembly/custom/bs.ts +57 -1
- package/assembly/custom/sink.ts +19 -75
- package/assembly/deserialize/array.ts +1 -5
- package/assembly/deserialize/string.ts +71 -1
- package/assembly/index.ts +16 -178
- package/assembly/serialize/bool.ts +13 -0
- package/assembly/serialize/object.ts +5 -0
- package/assembly/serialize/string.ts +218 -6
- package/assembly/test.ts +28 -8
- package/assembly/util/strings.ts +0 -0
- package/bench.js +1 -1
- package/package.json +8 -7
- package/transform/lib/index.js +177 -172
- package/transform/lib/visitor.js +448 -0
- package/transform/package.json +1 -1
- package/transform/src/index.ts +188 -229
- package/transform/tsconfig.json +2 -2
- package/bench/bench-node.js +0 -17
- package/bench/benchmark.ts +0 -77
- package/bench/benchmark.wasm +0 -0
- package/bench/tsconfig.json +0 -97
package/transform/lib/index.js
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
import { FieldDeclaration, IdentifierExpression, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, } from "assemblyscript/dist/assemblyscript.js";
|
|
1
|
+
import { FieldDeclaration, IdentifierExpression, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, NamedTypeNode } from "assemblyscript/dist/assemblyscript.js";
|
|
2
2
|
import { toString, isStdlib } from "visitor-as/dist/utils.js";
|
|
3
3
|
import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
|
|
4
4
|
import { Transform } from "assemblyscript/dist/transform.js";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
const json_types = ["Array", "string", "String", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean", "Map", "Date"];
|
|
5
7
|
class JSONTransform extends BaseVisitor {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
types = json_types;
|
|
9
|
+
schemasList = [];
|
|
10
|
+
currentClass;
|
|
11
|
+
sources = new Set();
|
|
12
|
+
appendParentFields(node, schema, members) {
|
|
13
|
+
if (node.extendsType) {
|
|
14
|
+
if (schema.parent?.members) {
|
|
15
|
+
for (let i = schema.parent.members.length - 1; i >= 0; i--) {
|
|
16
|
+
const replace = schema.members.find((v) => v.name == schema.parent?.members[i]?.name);
|
|
17
|
+
if (!replace) {
|
|
18
|
+
members.unshift(schema.parent?.members[i].node);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
this.appendParentFields(schema.parent.node, schema, members);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
handleEmptyClass(node, schema, members) {
|
|
26
|
+
let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}';
|
|
27
|
+
let SERIALIZE_PRETTY_EMPTY = '__SERIALIZE_PRETTY(): string {\n return "{}";\n}';
|
|
28
|
+
let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}";
|
|
29
|
+
let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}";
|
|
30
|
+
if (process.env["JSON_DEBUG"]) {
|
|
31
|
+
console.log(SERIALIZE_RAW_EMPTY);
|
|
32
|
+
console.log(SERIALIZE_PRETTY_EMPTY);
|
|
33
|
+
console.log(INITIALIZE_EMPTY);
|
|
34
|
+
console.log(DESERIALIZE_EMPTY);
|
|
35
|
+
}
|
|
36
|
+
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node);
|
|
37
|
+
const SERIALIZE_PRETTY_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_PRETTY_EMPTY, node);
|
|
38
|
+
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node);
|
|
39
|
+
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node);
|
|
40
|
+
if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
|
|
41
|
+
node.members.push(SERIALIZE_RAW_METHOD_EMPTY);
|
|
42
|
+
if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY"))
|
|
43
|
+
node.members.push(SERIALIZE_PRETTY_METHOD_EMPTY);
|
|
44
|
+
if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
|
|
45
|
+
node.members.push(INITIALIZE_METHOD_EMPTY);
|
|
46
|
+
if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
|
|
47
|
+
node.members.push(DESERIALIZE_METHOD_EMPTY);
|
|
48
|
+
}
|
|
49
|
+
filterMembers(members) {
|
|
50
|
+
return members.filter((v) => v instanceof FieldDeclaration && !v.decorators?.find((v) => v.name.text == "omit"));
|
|
10
51
|
}
|
|
11
|
-
visitMethodDeclaration() { }
|
|
12
52
|
visitClassDeclaration(node) {
|
|
13
53
|
if (!node.decorators?.length)
|
|
14
54
|
return;
|
|
15
|
-
|
|
16
|
-
for (const decorator of node.decorators) {
|
|
17
|
-
const name = decorator.name.text;
|
|
18
|
-
if (name === "json" || name === "serializable") {
|
|
19
|
-
found = true;
|
|
20
|
-
break;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
if (!found)
|
|
55
|
+
if (!node.decorators.find((v) => v.name.text == "json" || v.name.text == "serializable"))
|
|
24
56
|
return;
|
|
57
|
+
this.types = json_types;
|
|
25
58
|
const schema = new SchemaData();
|
|
26
59
|
schema.node = node;
|
|
27
60
|
schema.name = node.name.text;
|
|
28
|
-
const members = [
|
|
29
|
-
...node.members.filter((v) => v.kind === 54 /* NodeKind.FieldDeclaration */),
|
|
30
|
-
];
|
|
31
61
|
if (node.extendsType) {
|
|
32
62
|
schema.parent = this.schemasList.find((v) => v.name == node.extendsType?.name.identifier.text);
|
|
33
|
-
if (schema.parent?.members) {
|
|
34
|
-
for (let i = schema.parent.members.length - 1; i >= 0; i--) {
|
|
35
|
-
const replace = schema.members.find((v) => v.name == schema.parent?.members[i]?.name);
|
|
36
|
-
if (!replace) {
|
|
37
|
-
members.unshift(schema.parent?.members[i].node);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
63
|
}
|
|
64
|
+
const _members = [...node.members];
|
|
65
|
+
this.appendParentFields(node, schema, _members);
|
|
66
|
+
const members = this.filterMembers(_members);
|
|
42
67
|
if (!members.length) {
|
|
43
|
-
|
|
44
|
-
//let SERIALIZE_PRETTY_EMPTY = "__SERIALIZE_PRETTY(): string {\n return \"{}\";\n}";
|
|
45
|
-
let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}";
|
|
46
|
-
let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}";
|
|
47
|
-
if (process.env["JSON_DEBUG"]) {
|
|
48
|
-
console.log(SERIALIZE_RAW_EMPTY);
|
|
49
|
-
//console.log(SERIALIZE_PRETTY_EMPTY);
|
|
50
|
-
console.log(INITIALIZE_EMPTY);
|
|
51
|
-
console.log(DESERIALIZE_EMPTY);
|
|
52
|
-
}
|
|
53
|
-
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node);
|
|
54
|
-
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
|
|
55
|
-
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node);
|
|
56
|
-
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node);
|
|
57
|
-
if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
|
|
58
|
-
node.members.push(SERIALIZE_RAW_METHOD_EMPTY);
|
|
59
|
-
if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
|
|
60
|
-
node.members.push(INITIALIZE_METHOD_EMPTY);
|
|
61
|
-
if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
|
|
62
|
-
node.members.push(DESERIALIZE_METHOD_EMPTY);
|
|
63
|
-
this.schemasList.push(schema);
|
|
68
|
+
this.handleEmptyClass(node, schema, members);
|
|
64
69
|
}
|
|
65
70
|
for (const member of members) {
|
|
66
71
|
const name = member.name;
|
|
67
|
-
if (!(member instanceof FieldDeclaration))
|
|
68
|
-
continue;
|
|
69
72
|
if (!member.type) {
|
|
70
|
-
throw new Error("Fields must be strongly typed! Found " +
|
|
71
|
-
toString(member) +
|
|
72
|
-
" at " +
|
|
73
|
-
node.range.source.normalizedPath);
|
|
73
|
+
throw new Error("Fields must be strongly typed! Found " + toString(member) + " at " + node.range.source.normalizedPath);
|
|
74
74
|
}
|
|
75
75
|
const type = toString(member.type);
|
|
76
76
|
if (type.startsWith("(") && type.includes("=>"))
|
|
@@ -100,8 +100,7 @@ class JSONTransform extends BaseVisitor {
|
|
|
100
100
|
switch (decoratorName) {
|
|
101
101
|
case "alias": {
|
|
102
102
|
if (!args.length)
|
|
103
|
-
throw new Error("Expected 1 argument but got zero at @alias in " +
|
|
104
|
-
node.range.source.normalizedPath);
|
|
103
|
+
throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath);
|
|
105
104
|
mem.alias = args[0];
|
|
106
105
|
mem.flags.set(PropertyFlags.Alias, args);
|
|
107
106
|
break;
|
|
@@ -112,8 +111,7 @@ class JSONTransform extends BaseVisitor {
|
|
|
112
111
|
}
|
|
113
112
|
case "omitif": {
|
|
114
113
|
if (!decorator.args?.length)
|
|
115
|
-
throw new Error("Expected 1 argument but got zero at @omitif in " +
|
|
116
|
-
node.range.source.normalizedPath);
|
|
114
|
+
throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath);
|
|
117
115
|
mem.flags.set(PropertyFlags.OmitIf, args);
|
|
118
116
|
break;
|
|
119
117
|
}
|
|
@@ -124,22 +122,10 @@ class JSONTransform extends BaseVisitor {
|
|
|
124
122
|
}
|
|
125
123
|
}
|
|
126
124
|
}
|
|
127
|
-
mem.
|
|
125
|
+
if (!mem.flags.get(PropertyFlags.Omit))
|
|
126
|
+
mem.generate();
|
|
128
127
|
if (this.schemasList.find((v) => v.name == type)) {
|
|
129
|
-
mem.initialize =
|
|
130
|
-
"this." +
|
|
131
|
-
name.text +
|
|
132
|
-
" = changetype<nonnull<" +
|
|
133
|
-
mem.type +
|
|
134
|
-
">>(__new(offsetof<nonnull<" +
|
|
135
|
-
mem.type +
|
|
136
|
-
">>(), idof<nonnull<" +
|
|
137
|
-
mem.type +
|
|
138
|
-
">>()));\n changetype<nonnull<" +
|
|
139
|
-
mem.type +
|
|
140
|
-
">>(this." +
|
|
141
|
-
name.text +
|
|
142
|
-
").__INITIALIZE()";
|
|
128
|
+
mem.initialize = "this." + name.text + " = changetype<nonnull<" + mem.type + ">>(__new(offsetof<nonnull<" + mem.type + ">>(), idof<nonnull<" + mem.type + ">>()));\n changetype<nonnull<" + mem.type + ">>(this." + name.text + ").__INITIALIZE()";
|
|
143
129
|
}
|
|
144
130
|
else if (mem.value) {
|
|
145
131
|
mem.initialize = "this." + name.text + " = " + mem.value;
|
|
@@ -151,8 +137,7 @@ class JSONTransform extends BaseVisitor {
|
|
|
151
137
|
mem.initialize = "this." + name.text + ' = ""';
|
|
152
138
|
}
|
|
153
139
|
else if (type === "Array") {
|
|
154
|
-
mem.initialize =
|
|
155
|
-
"this." + name.text + " = instantiate<" + mem.type + ">()";
|
|
140
|
+
mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()";
|
|
156
141
|
}
|
|
157
142
|
else if (type === "bool" || type === "boolean") {
|
|
158
143
|
mem.initialize = "this." + name.text + " = false";
|
|
@@ -160,14 +145,7 @@ class JSONTransform extends BaseVisitor {
|
|
|
160
145
|
else if (type === "JSON.Raw") {
|
|
161
146
|
mem.initialize = "this." + name.text + ' = ""';
|
|
162
147
|
}
|
|
163
|
-
else if (type === "u8" ||
|
|
164
|
-
type === "u16" ||
|
|
165
|
-
type === "u32" ||
|
|
166
|
-
type === "u64" ||
|
|
167
|
-
type === "i8" ||
|
|
168
|
-
type === "i16" ||
|
|
169
|
-
type === "i32" ||
|
|
170
|
-
type === "i64") {
|
|
148
|
+
else if (type === "u8" || type === "u16" || type === "u32" || type === "u64" || type === "i8" || type === "i16" || type === "i32" || type === "i64") {
|
|
171
149
|
mem.initialize = "this." + name.text + " = 0";
|
|
172
150
|
}
|
|
173
151
|
else if (type === "f32" || type === "f64") {
|
|
@@ -182,15 +160,14 @@ class JSONTransform extends BaseVisitor {
|
|
|
182
160
|
let indent = " ";
|
|
183
161
|
if (!schema.members.length)
|
|
184
162
|
return;
|
|
185
|
-
found = false;
|
|
186
|
-
if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) ||
|
|
187
|
-
schema.members[0]?.flags.has(PropertyFlags.OmitIf)) {
|
|
163
|
+
let found = false;
|
|
164
|
+
if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) || schema.members[0]?.flags.has(PropertyFlags.OmitIf)) {
|
|
188
165
|
SERIALIZE_RAW += schema.members[0]?.serialize;
|
|
189
|
-
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.
|
|
166
|
+
SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty;
|
|
190
167
|
}
|
|
191
168
|
else {
|
|
192
169
|
SERIALIZE_RAW += schema.members[0]?.serialize + ",";
|
|
193
|
-
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.
|
|
170
|
+
SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty + ",\\n";
|
|
194
171
|
found = true;
|
|
195
172
|
}
|
|
196
173
|
if (schema.members[0]?.initialize)
|
|
@@ -199,22 +176,21 @@ class JSONTransform extends BaseVisitor {
|
|
|
199
176
|
const member = schema.members[i];
|
|
200
177
|
if (member.initialize)
|
|
201
178
|
INITIALIZE += " " + member.initialize + ";\n";
|
|
202
|
-
if (member.flags.has(PropertyFlags.
|
|
203
|
-
|
|
179
|
+
if (member.flags.has(PropertyFlags.Omit))
|
|
180
|
+
continue;
|
|
181
|
+
if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) {
|
|
204
182
|
SERIALIZE_RAW += member.serialize;
|
|
205
|
-
SERIALIZE_PRETTY += member.
|
|
183
|
+
SERIALIZE_PRETTY += member.serialize_pretty;
|
|
206
184
|
}
|
|
207
185
|
else {
|
|
208
186
|
SERIALIZE_RAW += member.serialize + ",";
|
|
209
|
-
SERIALIZE_PRETTY += indent + member.
|
|
187
|
+
SERIALIZE_PRETTY += indent + member.serialize_pretty + ",\\n";
|
|
210
188
|
found = true;
|
|
211
189
|
}
|
|
212
190
|
}
|
|
213
191
|
if (found) {
|
|
214
|
-
SERIALIZE_RAW +=
|
|
215
|
-
|
|
216
|
-
SERIALIZE_PRETTY +=
|
|
217
|
-
"`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}";
|
|
192
|
+
SERIALIZE_RAW += "`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}";
|
|
193
|
+
SERIALIZE_PRETTY += "`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}";
|
|
218
194
|
}
|
|
219
195
|
else {
|
|
220
196
|
SERIALIZE_RAW += "}`;\n return out;\n}";
|
|
@@ -243,35 +219,29 @@ class JSONTransform extends BaseVisitor {
|
|
|
243
219
|
const _name = encodeKey(firstMember.alias || firstMember.name);
|
|
244
220
|
if (_name.length === 1) {
|
|
245
221
|
if (first) {
|
|
246
|
-
DESERIALIZE +=
|
|
247
|
-
" if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
222
|
+
DESERIALIZE += " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
248
223
|
first = false;
|
|
249
224
|
}
|
|
250
225
|
else {
|
|
251
|
-
DESERIALIZE +=
|
|
252
|
-
"else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
226
|
+
DESERIALIZE += "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
253
227
|
}
|
|
254
228
|
}
|
|
255
229
|
else if (_name.length === 2) {
|
|
256
230
|
if (first) {
|
|
257
|
-
DESERIALIZE +=
|
|
258
|
-
" if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
231
|
+
DESERIALIZE += " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
259
232
|
first = false;
|
|
260
233
|
}
|
|
261
234
|
else {
|
|
262
|
-
DESERIALIZE +=
|
|
263
|
-
"else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
235
|
+
DESERIALIZE += "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
264
236
|
}
|
|
265
237
|
}
|
|
266
238
|
else if (_name.length === 4) {
|
|
267
239
|
if (first) {
|
|
268
|
-
DESERIALIZE +=
|
|
269
|
-
" if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
|
|
240
|
+
DESERIALIZE += " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
|
|
270
241
|
first = false;
|
|
271
242
|
}
|
|
272
243
|
else {
|
|
273
|
-
DESERIALIZE +=
|
|
274
|
-
"else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
|
|
244
|
+
DESERIALIZE += "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
|
|
275
245
|
}
|
|
276
246
|
}
|
|
277
247
|
else {
|
|
@@ -301,9 +271,7 @@ class JSONTransform extends BaseVisitor {
|
|
|
301
271
|
DESERIALIZE += ` if (${charCodeAt64(_name, 0)} === code) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
|
|
302
272
|
}
|
|
303
273
|
else {
|
|
304
|
-
DESERIALIZE =
|
|
305
|
-
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
306
|
-
`else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
|
|
274
|
+
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + `else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
|
|
307
275
|
}
|
|
308
276
|
}
|
|
309
277
|
else {
|
|
@@ -312,9 +280,7 @@ class JSONTransform extends BaseVisitor {
|
|
|
312
280
|
DESERIALIZE += ` if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
|
|
313
281
|
}
|
|
314
282
|
else {
|
|
315
|
-
DESERIALIZE =
|
|
316
|
-
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
317
|
-
` else if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
|
|
283
|
+
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
|
|
318
284
|
}
|
|
319
285
|
}
|
|
320
286
|
}
|
|
@@ -322,14 +288,10 @@ class JSONTransform extends BaseVisitor {
|
|
|
322
288
|
DESERIALIZE += ` default: {\n return false;\n }\n }\n`;
|
|
323
289
|
}
|
|
324
290
|
else if (_name.length == 4) {
|
|
325
|
-
DESERIALIZE =
|
|
326
|
-
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
327
|
-
` else {\n return false;\n }\n`;
|
|
291
|
+
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
|
|
328
292
|
}
|
|
329
293
|
else {
|
|
330
|
-
DESERIALIZE =
|
|
331
|
-
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
332
|
-
` else {\n return false;\n }\n`;
|
|
294
|
+
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
|
|
333
295
|
}
|
|
334
296
|
DESERIALIZE += " } ";
|
|
335
297
|
}
|
|
@@ -337,16 +299,18 @@ class JSONTransform extends BaseVisitor {
|
|
|
337
299
|
//console.log(sortedMembers);
|
|
338
300
|
if (process.env["JSON_DEBUG"]) {
|
|
339
301
|
console.log(SERIALIZE_RAW);
|
|
340
|
-
|
|
302
|
+
console.log(SERIALIZE_PRETTY);
|
|
341
303
|
console.log(INITIALIZE);
|
|
342
304
|
console.log(DESERIALIZE);
|
|
343
305
|
}
|
|
344
306
|
const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(SERIALIZE_RAW, node);
|
|
345
|
-
|
|
307
|
+
const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
|
|
346
308
|
const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
|
|
347
309
|
const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
|
|
348
310
|
if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
|
|
349
311
|
node.members.push(SERIALIZE_RAW_METHOD);
|
|
312
|
+
if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY"))
|
|
313
|
+
node.members.push(SERIALIZE_PRETTY_METHOD);
|
|
350
314
|
if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
|
|
351
315
|
node.members.push(INITIALIZE_METHOD);
|
|
352
316
|
if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
|
|
@@ -372,15 +336,13 @@ export default class Transformer extends Transform {
|
|
|
372
336
|
.sort((_a, _b) => {
|
|
373
337
|
const a = _a.internalPath;
|
|
374
338
|
const b = _b.internalPath;
|
|
375
|
-
if (a[0]
|
|
376
|
-
return -1;
|
|
377
|
-
}
|
|
378
|
-
else if (a[0] !== "~" && b[0] === "~") {
|
|
339
|
+
if (a[0] !== "~" && b[0] === "~") {
|
|
379
340
|
return 1;
|
|
380
341
|
}
|
|
381
|
-
|
|
382
|
-
return
|
|
342
|
+
if (a[0] === "~" && b[0] !== "~") {
|
|
343
|
+
return -1;
|
|
383
344
|
}
|
|
345
|
+
return 0;
|
|
384
346
|
});
|
|
385
347
|
// Loop over every source
|
|
386
348
|
for (const source of sources) {
|
|
@@ -392,14 +354,70 @@ export default class Transformer extends Transform {
|
|
|
392
354
|
// Check that every parent and child class is hooked up correctly
|
|
393
355
|
const schemas = transformer.schemasList;
|
|
394
356
|
for (const schema of schemas) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
357
|
+
checkInheritance(schema, schemas);
|
|
358
|
+
const invalidType = checkTypeCorrectness(schema, schemas);
|
|
359
|
+
if (invalidType) {
|
|
360
|
+
logError(`Type ${invalidType.type} implemented in property ${invalidType.path} is not a JSON-compatible type!\nEither decorate it with @omit or fix it!`);
|
|
399
361
|
}
|
|
400
362
|
}
|
|
401
363
|
}
|
|
402
364
|
}
|
|
365
|
+
function checkInheritance(schema, schemas) {
|
|
366
|
+
if (!schema.parent && schema.node.extendsType) {
|
|
367
|
+
if (schemas.find(v => v.node.name.text === schema.node.extendsType?.name.identifier.text))
|
|
368
|
+
return;
|
|
369
|
+
const extending = toString(schema.node.extendsType);
|
|
370
|
+
logError(`Schema ${schema.name} extends ${extending}, but ${extending} does not include the @json decorator!`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function checkTypeCorrectness(schema, schemas) {
|
|
374
|
+
const parent = schemas.find((v) => v.name === schema.parent?.name);
|
|
375
|
+
const generic_types = [...(schema?.node.typeParameters?.map((v) => v.name.text) || []), ...(parent?.node.typeParameters?.map((v) => v.name.text) || [])];
|
|
376
|
+
const member_types = [...(schema.members.map((v) => v.node.type.name.identifier.text) || [])];
|
|
377
|
+
const scopeTypes = new Set([...json_types, ...generic_types, ...member_types]);
|
|
378
|
+
for (const typ of member_types) {
|
|
379
|
+
if (typ === "JSON")
|
|
380
|
+
continue; // JSON.Raw, JSON.Box, JSON.Any, ect...
|
|
381
|
+
if (json_types.includes(typ))
|
|
382
|
+
continue;
|
|
383
|
+
if (generic_types.includes(typ))
|
|
384
|
+
continue;
|
|
385
|
+
const check = schemas.find((v) => v.name == typ);
|
|
386
|
+
if (!check)
|
|
387
|
+
logError(`Type ${typ} is not a JSON compatible type or does not include the @json flag!`);
|
|
388
|
+
}
|
|
389
|
+
for (const member of schema.members) {
|
|
390
|
+
const invalidType = checkType(schema, schemas, member.node.type, member, scopeTypes, schema.name);
|
|
391
|
+
if (invalidType)
|
|
392
|
+
logError(`Type ${invalidType.type} in ${invalidType.path} does not implement a JSON compatible type!\n${chalk.dim(` at ${member.node.range.source.normalizedPath.replace("~lib/", "./node_modules/")}`)}`);
|
|
393
|
+
}
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
function checkType(schema, schemas, typ, member, scopeTypes, path) {
|
|
397
|
+
path += "." + member.name;
|
|
398
|
+
if (schemas.find(v => v.node.name.text === typ.name.identifier.text))
|
|
399
|
+
scopeTypes.add(typ.name.identifier.text);
|
|
400
|
+
if (!scopeTypes.has(typ.name.identifier.text))
|
|
401
|
+
return { type: toString(typ), path };
|
|
402
|
+
if (typ.isNullable && isPrimitive(typ))
|
|
403
|
+
return { type: toString(typ), path };
|
|
404
|
+
if (typ.typeArguments?.length && typ.typeArguments?.length > 0) {
|
|
405
|
+
for (const ty of typ.typeArguments.filter((v) => v instanceof NamedTypeNode)) {
|
|
406
|
+
const check = checkType(schema, schemas, ty, member, scopeTypes, path);
|
|
407
|
+
if (check)
|
|
408
|
+
return { type: toString(typ), path };
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
if (scopeTypes.has(typ.name.identifier.text))
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
function logError(message) {
|
|
418
|
+
console.log("\n" + chalk.bold.bgRed(" Error ") + chalk.dim(":") + " " + message + "\n");
|
|
419
|
+
process.exit(1);
|
|
420
|
+
}
|
|
403
421
|
var PropertyFlags;
|
|
404
422
|
(function (PropertyFlags) {
|
|
405
423
|
PropertyFlags[PropertyFlags["Null"] = 0] = "Null";
|
|
@@ -410,18 +428,18 @@ var PropertyFlags;
|
|
|
410
428
|
PropertyFlags[PropertyFlags["JSON_Raw"] = 5] = "JSON_Raw";
|
|
411
429
|
})(PropertyFlags || (PropertyFlags = {}));
|
|
412
430
|
class Property {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
431
|
+
name = "";
|
|
432
|
+
alias = null;
|
|
433
|
+
type = "";
|
|
434
|
+
value = null;
|
|
435
|
+
flags = new Map();
|
|
436
|
+
serialize = null;
|
|
437
|
+
serialize_pretty = null;
|
|
438
|
+
deserialize = null;
|
|
439
|
+
initialize = null;
|
|
440
|
+
node;
|
|
441
|
+
right_s = "";
|
|
442
|
+
right_d = "";
|
|
425
443
|
generate() {
|
|
426
444
|
const name = this.name;
|
|
427
445
|
const escapedName = escapeString(JSON.stringify(this.alias || this.name));
|
|
@@ -430,7 +448,7 @@ class Property {
|
|
|
430
448
|
return;
|
|
431
449
|
if (this.flags.has(PropertyFlags.JSON_Raw)) {
|
|
432
450
|
if (this.flags.has(PropertyFlags.Null)) {
|
|
433
|
-
this.right_s = "(this." + name +
|
|
451
|
+
this.right_s = "(this." + name + ' || "null")';
|
|
434
452
|
this.right_d = "value_start === value_end - 4 && 30399761348886638 === load<u64>(changetype<usize>(data) + (value_start << 1)) ? null : data.substring(value_start, value_end)";
|
|
435
453
|
}
|
|
436
454
|
else {
|
|
@@ -440,47 +458,33 @@ class Property {
|
|
|
440
458
|
}
|
|
441
459
|
else {
|
|
442
460
|
this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")";
|
|
443
|
-
this.right_d =
|
|
444
|
-
"__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
|
|
461
|
+
this.right_d = "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
|
|
445
462
|
}
|
|
446
463
|
if (this.flags.has(PropertyFlags.OmitIf)) {
|
|
447
464
|
const condition = this.flags.get(PropertyFlags.OmitIf)[0];
|
|
448
465
|
if (!condition)
|
|
449
466
|
throw new Error("Could not find condition when using decorator @omitif! Provide at least one condition");
|
|
450
|
-
this.serialize =
|
|
451
|
-
|
|
452
|
-
condition +
|
|
453
|
-
' ? "" : \'' +
|
|
454
|
-
escapedName +
|
|
455
|
-
":' + " +
|
|
456
|
-
this.right_s +
|
|
457
|
-
' + ","}';
|
|
467
|
+
this.serialize = "${" + condition + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}';
|
|
468
|
+
this.serialize_pretty = "${" + condition + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}';
|
|
458
469
|
this.deserialize = "this." + name + " = " + this.right_d + ";";
|
|
459
470
|
}
|
|
460
471
|
else if (this.flags.has(PropertyFlags.OmitNull)) {
|
|
461
|
-
this.serialize =
|
|
462
|
-
|
|
463
|
-
name +
|
|
464
|
-
") == <usize>0" +
|
|
465
|
-
' ? "" : \'' +
|
|
466
|
-
escapedName +
|
|
467
|
-
":' + " +
|
|
468
|
-
this.right_s +
|
|
469
|
-
' + ","}';
|
|
472
|
+
this.serialize = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}';
|
|
473
|
+
this.serialize_pretty = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}';
|
|
470
474
|
this.deserialize = "this." + name + " = " + this.right_d + ";";
|
|
471
475
|
}
|
|
472
476
|
else {
|
|
473
477
|
this.serialize = escapedName + ":${" + this.right_s + "}";
|
|
478
|
+
this.serialize_pretty = escapedName + ": ${" + this.right_s + "}";
|
|
474
479
|
this.deserialize = "this." + name + " = " + this.right_d + ";";
|
|
475
480
|
}
|
|
476
481
|
}
|
|
477
482
|
}
|
|
478
483
|
class SchemaData {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
}
|
|
484
|
+
name = "";
|
|
485
|
+
members = [];
|
|
486
|
+
parent = null;
|
|
487
|
+
node;
|
|
484
488
|
}
|
|
485
489
|
function charCodeAt32(data, offset) {
|
|
486
490
|
return (data.charCodeAt(offset + 1) << 16) | data.charCodeAt(offset);
|
|
@@ -493,10 +497,7 @@ function charCodeAt64(data, offset) {
|
|
|
493
497
|
const secondCharCode = BigInt(data.charCodeAt(offset + 1));
|
|
494
498
|
const thirdCharCode = BigInt(data.charCodeAt(offset + 2));
|
|
495
499
|
const fourthCharCode = BigInt(data.charCodeAt(offset + 3));
|
|
496
|
-
const u64Value = (fourthCharCode << 48n) |
|
|
497
|
-
(thirdCharCode << 32n) |
|
|
498
|
-
(secondCharCode << 16n) |
|
|
499
|
-
firstCharCode;
|
|
500
|
+
const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode;
|
|
500
501
|
return u64Value;
|
|
501
502
|
}
|
|
502
503
|
function encodeKey(key) {
|
|
@@ -541,3 +542,7 @@ function getArgs(args) {
|
|
|
541
542
|
}
|
|
542
543
|
return out;
|
|
543
544
|
}
|
|
545
|
+
function isPrimitive(type) {
|
|
546
|
+
const primitives = new Set(["u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean"]);
|
|
547
|
+
return primitives.has(type.name.identifier.text);
|
|
548
|
+
}
|