json-as 0.9.20 → 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 -0
- package/README.md +7 -16
- 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 +20 -0
- package/assembly/__tests__/float.spec.ts +52 -0
- package/assembly/__tests__/integer.spec.ts +28 -0
- package/assembly/__tests__/obj.spec.ts +4 -0
- package/assembly/__tests__/string.spec.ts +24 -0
- package/assembly/__tests__/test.spec.ts +28 -263
- 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 -5
- 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 +27 -22
- package/assembly/util/strings.ts +0 -0
- package/bench.js +1 -1
- package/package.json +8 -7
- package/transform/lib/index.js +222 -208
- package/transform/lib/visitor.js +448 -0
- package/transform/package.json +1 -1
- package/transform/src/index.ts +226 -258
- 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("=>"))
|
|
@@ -87,9 +87,12 @@ class JSONTransform extends BaseVisitor {
|
|
|
87
87
|
mem.type = type;
|
|
88
88
|
mem.value = value;
|
|
89
89
|
mem.node = member;
|
|
90
|
-
if (type
|
|
90
|
+
if (type.includes("JSON.Raw")) {
|
|
91
91
|
mem.flags.set(PropertyFlags.JSON_Raw, []);
|
|
92
92
|
}
|
|
93
|
+
if (member.type.isNullable) {
|
|
94
|
+
mem.flags.set(PropertyFlags.Null, []);
|
|
95
|
+
}
|
|
93
96
|
if (member.decorators) {
|
|
94
97
|
for (const decorator of member.decorators) {
|
|
95
98
|
const decoratorName = decorator.name.text;
|
|
@@ -97,8 +100,7 @@ class JSONTransform extends BaseVisitor {
|
|
|
97
100
|
switch (decoratorName) {
|
|
98
101
|
case "alias": {
|
|
99
102
|
if (!args.length)
|
|
100
|
-
throw new Error("Expected 1 argument but got zero at @alias in " +
|
|
101
|
-
node.range.source.normalizedPath);
|
|
103
|
+
throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath);
|
|
102
104
|
mem.alias = args[0];
|
|
103
105
|
mem.flags.set(PropertyFlags.Alias, args);
|
|
104
106
|
break;
|
|
@@ -109,8 +111,7 @@ class JSONTransform extends BaseVisitor {
|
|
|
109
111
|
}
|
|
110
112
|
case "omitif": {
|
|
111
113
|
if (!decorator.args?.length)
|
|
112
|
-
throw new Error("Expected 1 argument but got zero at @omitif in " +
|
|
113
|
-
node.range.source.normalizedPath);
|
|
114
|
+
throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath);
|
|
114
115
|
mem.flags.set(PropertyFlags.OmitIf, args);
|
|
115
116
|
break;
|
|
116
117
|
}
|
|
@@ -121,22 +122,10 @@ class JSONTransform extends BaseVisitor {
|
|
|
121
122
|
}
|
|
122
123
|
}
|
|
123
124
|
}
|
|
124
|
-
mem.
|
|
125
|
+
if (!mem.flags.get(PropertyFlags.Omit))
|
|
126
|
+
mem.generate();
|
|
125
127
|
if (this.schemasList.find((v) => v.name == type)) {
|
|
126
|
-
mem.initialize =
|
|
127
|
-
"this." +
|
|
128
|
-
name.text +
|
|
129
|
-
" = changetype<nonnull<" +
|
|
130
|
-
mem.type +
|
|
131
|
-
">>(__new(offsetof<nonnull<" +
|
|
132
|
-
mem.type +
|
|
133
|
-
">>(), idof<nonnull<" +
|
|
134
|
-
mem.type +
|
|
135
|
-
">>()));\n changetype<nonnull<" +
|
|
136
|
-
mem.type +
|
|
137
|
-
">>(this." +
|
|
138
|
-
name.text +
|
|
139
|
-
").__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()";
|
|
140
129
|
}
|
|
141
130
|
else if (mem.value) {
|
|
142
131
|
mem.initialize = "this." + name.text + " = " + mem.value;
|
|
@@ -148,8 +137,7 @@ class JSONTransform extends BaseVisitor {
|
|
|
148
137
|
mem.initialize = "this." + name.text + ' = ""';
|
|
149
138
|
}
|
|
150
139
|
else if (type === "Array") {
|
|
151
|
-
mem.initialize =
|
|
152
|
-
"this." + name.text + " = instantiate<" + mem.type + ">()";
|
|
140
|
+
mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()";
|
|
153
141
|
}
|
|
154
142
|
else if (type === "bool" || type === "boolean") {
|
|
155
143
|
mem.initialize = "this." + name.text + " = false";
|
|
@@ -157,14 +145,7 @@ class JSONTransform extends BaseVisitor {
|
|
|
157
145
|
else if (type === "JSON.Raw") {
|
|
158
146
|
mem.initialize = "this." + name.text + ' = ""';
|
|
159
147
|
}
|
|
160
|
-
else if (type === "u8" ||
|
|
161
|
-
type === "u16" ||
|
|
162
|
-
type === "u32" ||
|
|
163
|
-
type === "u64" ||
|
|
164
|
-
type === "i8" ||
|
|
165
|
-
type === "i16" ||
|
|
166
|
-
type === "i32" ||
|
|
167
|
-
type === "i64") {
|
|
148
|
+
else if (type === "u8" || type === "u16" || type === "u32" || type === "u64" || type === "i8" || type === "i16" || type === "i32" || type === "i64") {
|
|
168
149
|
mem.initialize = "this." + name.text + " = 0";
|
|
169
150
|
}
|
|
170
151
|
else if (type === "f32" || type === "f64") {
|
|
@@ -179,15 +160,14 @@ class JSONTransform extends BaseVisitor {
|
|
|
179
160
|
let indent = " ";
|
|
180
161
|
if (!schema.members.length)
|
|
181
162
|
return;
|
|
182
|
-
found = false;
|
|
183
|
-
if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) ||
|
|
184
|
-
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)) {
|
|
185
165
|
SERIALIZE_RAW += schema.members[0]?.serialize;
|
|
186
|
-
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.
|
|
166
|
+
SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty;
|
|
187
167
|
}
|
|
188
168
|
else {
|
|
189
169
|
SERIALIZE_RAW += schema.members[0]?.serialize + ",";
|
|
190
|
-
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.
|
|
170
|
+
SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty + ",\\n";
|
|
191
171
|
found = true;
|
|
192
172
|
}
|
|
193
173
|
if (schema.members[0]?.initialize)
|
|
@@ -196,89 +176,81 @@ class JSONTransform extends BaseVisitor {
|
|
|
196
176
|
const member = schema.members[i];
|
|
197
177
|
if (member.initialize)
|
|
198
178
|
INITIALIZE += " " + member.initialize + ";\n";
|
|
199
|
-
if (member.flags.has(PropertyFlags.
|
|
200
|
-
|
|
179
|
+
if (member.flags.has(PropertyFlags.Omit))
|
|
180
|
+
continue;
|
|
181
|
+
if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) {
|
|
201
182
|
SERIALIZE_RAW += member.serialize;
|
|
202
|
-
SERIALIZE_PRETTY += member.
|
|
183
|
+
SERIALIZE_PRETTY += member.serialize_pretty;
|
|
203
184
|
}
|
|
204
185
|
else {
|
|
205
186
|
SERIALIZE_RAW += member.serialize + ",";
|
|
206
|
-
SERIALIZE_PRETTY += indent + member.
|
|
187
|
+
SERIALIZE_PRETTY += indent + member.serialize_pretty + ",\\n";
|
|
207
188
|
found = true;
|
|
208
189
|
}
|
|
209
190
|
}
|
|
210
191
|
if (found) {
|
|
211
|
-
SERIALIZE_RAW +=
|
|
212
|
-
|
|
213
|
-
SERIALIZE_PRETTY +=
|
|
214
|
-
"`;\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}";
|
|
215
194
|
}
|
|
216
195
|
else {
|
|
217
|
-
SERIALIZE_RAW += "`;\n}
|
|
218
|
-
SERIALIZE_PRETTY += "`;\n}
|
|
196
|
+
SERIALIZE_RAW += "}`;\n return out;\n}";
|
|
197
|
+
SERIALIZE_PRETTY += "}`;\n return out;\n}";
|
|
219
198
|
}
|
|
220
199
|
INITIALIZE += " return this;\n}";
|
|
221
200
|
const sortedMembers = [];
|
|
222
|
-
const _sorted = schema.members.sort((a, b) => a.name.length - b.name.length);
|
|
223
|
-
let len =
|
|
224
|
-
let offset =
|
|
225
|
-
|
|
226
|
-
len = _sorted[0]?.name.length;
|
|
227
|
-
for (let i = 1; i < _sorted.length; i++) {
|
|
201
|
+
const _sorted = schema.members.sort((a, b) => (a.alias?.length || a.name.length) - (b.alias?.length || b.name.length));
|
|
202
|
+
let len = -1;
|
|
203
|
+
let offset = -1;
|
|
204
|
+
for (let i = 0; i < _sorted.length; i++) {
|
|
228
205
|
const member = _sorted[i];
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
offset++;
|
|
206
|
+
const _name = member.alias || member.name;
|
|
207
|
+
if (_name.length === len) {
|
|
208
|
+
sortedMembers[offset]?.push(member);
|
|
233
209
|
}
|
|
234
210
|
else {
|
|
235
|
-
sortedMembers
|
|
211
|
+
sortedMembers.push([member]);
|
|
212
|
+
len = _name.length;
|
|
213
|
+
offset++;
|
|
236
214
|
}
|
|
237
215
|
}
|
|
238
216
|
let first = true;
|
|
239
217
|
for (const memberSet of sortedMembers) {
|
|
240
218
|
const firstMember = memberSet[0];
|
|
241
|
-
const
|
|
242
|
-
if (
|
|
219
|
+
const _name = encodeKey(firstMember.alias || firstMember.name);
|
|
220
|
+
if (_name.length === 1) {
|
|
243
221
|
if (first) {
|
|
244
|
-
DESERIALIZE +=
|
|
245
|
-
" 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";
|
|
246
223
|
first = false;
|
|
247
224
|
}
|
|
248
225
|
else {
|
|
249
|
-
DESERIALIZE +=
|
|
250
|
-
"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";
|
|
251
227
|
}
|
|
252
228
|
}
|
|
253
|
-
else if (
|
|
229
|
+
else if (_name.length === 2) {
|
|
254
230
|
if (first) {
|
|
255
|
-
DESERIALIZE +=
|
|
256
|
-
" 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";
|
|
257
232
|
first = false;
|
|
258
233
|
}
|
|
259
234
|
else {
|
|
260
|
-
DESERIALIZE +=
|
|
261
|
-
"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";
|
|
262
236
|
}
|
|
263
237
|
}
|
|
264
|
-
else if (
|
|
238
|
+
else if (_name.length === 4) {
|
|
265
239
|
if (first) {
|
|
266
|
-
DESERIALIZE +=
|
|
267
|
-
" 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";
|
|
268
241
|
first = false;
|
|
269
242
|
}
|
|
270
243
|
else {
|
|
271
|
-
DESERIALIZE +=
|
|
272
|
-
"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";
|
|
273
245
|
}
|
|
274
246
|
}
|
|
275
247
|
else {
|
|
276
248
|
if (first) {
|
|
277
|
-
DESERIALIZE += " if (" +
|
|
249
|
+
DESERIALIZE += " if (" + _name.length + " === len) {\n";
|
|
278
250
|
first = false;
|
|
279
251
|
}
|
|
280
252
|
else {
|
|
281
|
-
DESERIALIZE += "else if (" +
|
|
253
|
+
DESERIALIZE += "else if (" + _name.length + " === len) {\n";
|
|
282
254
|
}
|
|
283
255
|
}
|
|
284
256
|
let f = true;
|
|
@@ -286,48 +258,40 @@ class JSONTransform extends BaseVisitor {
|
|
|
286
258
|
const member = memberSet[i];
|
|
287
259
|
if (!member.deserialize)
|
|
288
260
|
continue;
|
|
289
|
-
const
|
|
290
|
-
if (
|
|
291
|
-
DESERIALIZE += ` case ${
|
|
261
|
+
const _name = encodeKey(member.alias || member.name);
|
|
262
|
+
if (_name.length === 1) {
|
|
263
|
+
DESERIALIZE += ` case ${_name.charCodeAt(0)}: { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
|
|
292
264
|
}
|
|
293
|
-
else if (
|
|
294
|
-
DESERIALIZE += ` case ${charCodeAt32(
|
|
265
|
+
else if (_name.length === 2) {
|
|
266
|
+
DESERIALIZE += ` case ${charCodeAt32(_name, 0)}: { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
|
|
295
267
|
}
|
|
296
|
-
else if (
|
|
268
|
+
else if (_name.length === 4) {
|
|
297
269
|
if (f) {
|
|
298
270
|
f = false;
|
|
299
|
-
DESERIALIZE += ` if (${charCodeAt64(
|
|
271
|
+
DESERIALIZE += ` if (${charCodeAt64(_name, 0)} === code) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
|
|
300
272
|
}
|
|
301
273
|
else {
|
|
302
|
-
DESERIALIZE =
|
|
303
|
-
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
304
|
-
`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`;
|
|
305
275
|
}
|
|
306
276
|
}
|
|
307
277
|
else {
|
|
308
278
|
if (f) {
|
|
309
279
|
f = false;
|
|
310
|
-
DESERIALIZE += ` if (0
|
|
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`;
|
|
311
281
|
}
|
|
312
282
|
else {
|
|
313
|
-
DESERIALIZE =
|
|
314
|
-
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
315
|
-
` 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`;
|
|
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`;
|
|
316
284
|
}
|
|
317
285
|
}
|
|
318
286
|
}
|
|
319
|
-
if (
|
|
287
|
+
if (_name.length < 3) {
|
|
320
288
|
DESERIALIZE += ` default: {\n return false;\n }\n }\n`;
|
|
321
289
|
}
|
|
322
|
-
else if (
|
|
323
|
-
DESERIALIZE =
|
|
324
|
-
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
325
|
-
` else {\n return false;\n }\n`;
|
|
290
|
+
else if (_name.length == 4) {
|
|
291
|
+
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
|
|
326
292
|
}
|
|
327
293
|
else {
|
|
328
|
-
DESERIALIZE =
|
|
329
|
-
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
330
|
-
` else {\n return false;\n }\n`;
|
|
294
|
+
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
|
|
331
295
|
}
|
|
332
296
|
DESERIALIZE += " } ";
|
|
333
297
|
}
|
|
@@ -335,16 +299,18 @@ class JSONTransform extends BaseVisitor {
|
|
|
335
299
|
//console.log(sortedMembers);
|
|
336
300
|
if (process.env["JSON_DEBUG"]) {
|
|
337
301
|
console.log(SERIALIZE_RAW);
|
|
338
|
-
|
|
302
|
+
console.log(SERIALIZE_PRETTY);
|
|
339
303
|
console.log(INITIALIZE);
|
|
340
304
|
console.log(DESERIALIZE);
|
|
341
305
|
}
|
|
342
306
|
const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(SERIALIZE_RAW, node);
|
|
343
|
-
|
|
307
|
+
const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
|
|
344
308
|
const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
|
|
345
309
|
const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
|
|
346
310
|
if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
|
|
347
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);
|
|
348
314
|
if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
|
|
349
315
|
node.members.push(INITIALIZE_METHOD);
|
|
350
316
|
if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
|
|
@@ -370,15 +336,13 @@ export default class Transformer extends Transform {
|
|
|
370
336
|
.sort((_a, _b) => {
|
|
371
337
|
const a = _a.internalPath;
|
|
372
338
|
const b = _b.internalPath;
|
|
373
|
-
if (a[0]
|
|
374
|
-
return -1;
|
|
375
|
-
}
|
|
376
|
-
else if (a[0] !== "~" && b[0] === "~") {
|
|
339
|
+
if (a[0] !== "~" && b[0] === "~") {
|
|
377
340
|
return 1;
|
|
378
341
|
}
|
|
379
|
-
|
|
380
|
-
return
|
|
342
|
+
if (a[0] === "~" && b[0] !== "~") {
|
|
343
|
+
return -1;
|
|
381
344
|
}
|
|
345
|
+
return 0;
|
|
382
346
|
});
|
|
383
347
|
// Loop over every source
|
|
384
348
|
for (const source of sources) {
|
|
@@ -390,35 +354,92 @@ export default class Transformer extends Transform {
|
|
|
390
354
|
// Check that every parent and child class is hooked up correctly
|
|
391
355
|
const schemas = transformer.schemasList;
|
|
392
356
|
for (const schema of schemas) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
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!`);
|
|
397
361
|
}
|
|
398
362
|
}
|
|
399
363
|
}
|
|
400
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
|
+
}
|
|
401
421
|
var PropertyFlags;
|
|
402
422
|
(function (PropertyFlags) {
|
|
403
|
-
PropertyFlags[PropertyFlags["
|
|
404
|
-
PropertyFlags[PropertyFlags["
|
|
405
|
-
PropertyFlags[PropertyFlags["
|
|
406
|
-
PropertyFlags[PropertyFlags["
|
|
407
|
-
PropertyFlags[PropertyFlags["
|
|
423
|
+
PropertyFlags[PropertyFlags["Null"] = 0] = "Null";
|
|
424
|
+
PropertyFlags[PropertyFlags["Omit"] = 1] = "Omit";
|
|
425
|
+
PropertyFlags[PropertyFlags["OmitNull"] = 2] = "OmitNull";
|
|
426
|
+
PropertyFlags[PropertyFlags["OmitIf"] = 3] = "OmitIf";
|
|
427
|
+
PropertyFlags[PropertyFlags["Alias"] = 4] = "Alias";
|
|
428
|
+
PropertyFlags[PropertyFlags["JSON_Raw"] = 5] = "JSON_Raw";
|
|
408
429
|
})(PropertyFlags || (PropertyFlags = {}));
|
|
409
430
|
class Property {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
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 = "";
|
|
422
443
|
generate() {
|
|
423
444
|
const name = this.name;
|
|
424
445
|
const escapedName = escapeString(JSON.stringify(this.alias || this.name));
|
|
@@ -426,52 +447,44 @@ class Property {
|
|
|
426
447
|
if (this.flags.has(PropertyFlags.Omit))
|
|
427
448
|
return;
|
|
428
449
|
if (this.flags.has(PropertyFlags.JSON_Raw)) {
|
|
429
|
-
|
|
430
|
-
|
|
450
|
+
if (this.flags.has(PropertyFlags.Null)) {
|
|
451
|
+
this.right_s = "(this." + name + ' || "null")';
|
|
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)";
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
this.right_s = "this." + name;
|
|
456
|
+
this.right_d = "data.substring(value_start, value_end);";
|
|
457
|
+
}
|
|
431
458
|
}
|
|
432
459
|
else {
|
|
433
460
|
this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")";
|
|
434
|
-
this.right_d =
|
|
435
|
-
"__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
|
|
461
|
+
this.right_d = "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
|
|
436
462
|
}
|
|
437
463
|
if (this.flags.has(PropertyFlags.OmitIf)) {
|
|
438
464
|
const condition = this.flags.get(PropertyFlags.OmitIf)[0];
|
|
439
465
|
if (!condition)
|
|
440
466
|
throw new Error("Could not find condition when using decorator @omitif! Provide at least one condition");
|
|
441
|
-
this.serialize =
|
|
442
|
-
|
|
443
|
-
condition +
|
|
444
|
-
' ? "" : \'' +
|
|
445
|
-
escapedName +
|
|
446
|
-
":' + " +
|
|
447
|
-
this.right_s +
|
|
448
|
-
' + ","}';
|
|
467
|
+
this.serialize = "${" + condition + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}';
|
|
468
|
+
this.serialize_pretty = "${" + condition + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}';
|
|
449
469
|
this.deserialize = "this." + name + " = " + this.right_d + ";";
|
|
450
470
|
}
|
|
451
471
|
else if (this.flags.has(PropertyFlags.OmitNull)) {
|
|
452
|
-
this.serialize =
|
|
453
|
-
|
|
454
|
-
name +
|
|
455
|
-
") == <usize>0" +
|
|
456
|
-
' ? "" : \'' +
|
|
457
|
-
escapedName +
|
|
458
|
-
":' + " +
|
|
459
|
-
this.right_s +
|
|
460
|
-
' + ","}';
|
|
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 + ' + ","}';
|
|
461
474
|
this.deserialize = "this." + name + " = " + this.right_d + ";";
|
|
462
475
|
}
|
|
463
476
|
else {
|
|
464
477
|
this.serialize = escapedName + ":${" + this.right_s + "}";
|
|
478
|
+
this.serialize_pretty = escapedName + ": ${" + this.right_s + "}";
|
|
465
479
|
this.deserialize = "this." + name + " = " + this.right_d + ";";
|
|
466
480
|
}
|
|
467
481
|
}
|
|
468
482
|
}
|
|
469
483
|
class SchemaData {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
}
|
|
484
|
+
name = "";
|
|
485
|
+
members = [];
|
|
486
|
+
parent = null;
|
|
487
|
+
node;
|
|
475
488
|
}
|
|
476
489
|
function charCodeAt32(data, offset) {
|
|
477
490
|
return (data.charCodeAt(offset + 1) << 16) | data.charCodeAt(offset);
|
|
@@ -484,10 +497,7 @@ function charCodeAt64(data, offset) {
|
|
|
484
497
|
const secondCharCode = BigInt(data.charCodeAt(offset + 1));
|
|
485
498
|
const thirdCharCode = BigInt(data.charCodeAt(offset + 2));
|
|
486
499
|
const fourthCharCode = BigInt(data.charCodeAt(offset + 3));
|
|
487
|
-
const u64Value = (fourthCharCode << 48n) |
|
|
488
|
-
(thirdCharCode << 32n) |
|
|
489
|
-
(secondCharCode << 16n) |
|
|
490
|
-
firstCharCode;
|
|
500
|
+
const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode;
|
|
491
501
|
return u64Value;
|
|
492
502
|
}
|
|
493
503
|
function encodeKey(key) {
|
|
@@ -532,3 +542,7 @@ function getArgs(args) {
|
|
|
532
542
|
}
|
|
533
543
|
return out;
|
|
534
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
|
+
}
|