json-as 0.8.5 → 0.8.7
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/workflows/nodejs.yml +7 -1
- package/CHANGELOG +6 -1
- package/README.md +26 -16
- package/assembly/__tests__/deserialize.spec.ts +298 -0
- package/assembly/__tests__/serialize.spec.ts +375 -0
- package/assembly/deserialize/array/array.ts +31 -0
- package/assembly/deserialize/array/bool.ts +19 -0
- package/assembly/deserialize/array/float.ts +24 -0
- package/assembly/deserialize/array/integer.ts +24 -0
- package/assembly/deserialize/array/map.ts +27 -0
- package/assembly/deserialize/array/object.ts +27 -0
- package/assembly/deserialize/array/string.ts +29 -0
- package/assembly/deserialize/array.ts +37 -0
- package/assembly/deserialize/bool.ts +18 -0
- package/assembly/deserialize/box.ts +17 -0
- package/assembly/deserialize/date.ts +11 -0
- package/assembly/deserialize/float.ts +9 -0
- package/assembly/deserialize/integer.ts +7 -0
- package/assembly/deserialize/map.ts +182 -0
- package/assembly/deserialize/object.ts +136 -0
- package/assembly/deserialize/string.ts +88 -0
- package/assembly/index.d.ts +7 -1
- package/assembly/index.ts +129 -1
- package/assembly/serialize/array.ts +52 -0
- package/assembly/serialize/bool.ts +4 -0
- package/assembly/serialize/box.ts +10 -0
- package/assembly/serialize/date.ts +4 -0
- package/assembly/serialize/float.ts +4 -0
- package/assembly/serialize/integer.ts +5 -0
- package/assembly/serialize/map.ts +24 -0
- package/assembly/serialize/object.ts +7 -0
- package/assembly/serialize/string.ts +64 -0
- package/assembly/src/sink.ts +286 -0
- package/assembly/src/util.ts +6 -0
- package/assembly/test.ts +34 -16
- package/bench/benchmark.ts +7 -3
- package/bench.js +14 -3
- package/index.ts +1 -1
- package/package.json +6 -8
- package/transform/lib/index.js +296 -198
- package/transform/lib/index.old.js +257 -0
- package/transform/lib/types.js +17 -0
- package/transform/package.json +1 -1
- package/transform/src/index.old.ts +312 -0
- package/transform/src/index.ts +298 -234
- package/transform/tsconfig.json +2 -2
- package/tsconfig.json +94 -102
- package/assembly/__benches__/as-json.ts +0 -88
- package/assembly/__benches__/as-tral.d.ts +0 -1
- package/assembly/__tests__/as-json.spec.ts +0 -671
- package/assembly/__tests__/as-pect.d.ts +0 -1
- package/assembly/src/json.ts +0 -941
package/transform/src/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ClassDeclaration,
|
|
3
3
|
FieldDeclaration,
|
|
4
|
+
IdentifierExpression,
|
|
5
|
+
NamedTypeNode,
|
|
6
|
+
StringLiteralExpression,
|
|
4
7
|
Parser,
|
|
5
8
|
Source,
|
|
6
9
|
SourceKind,
|
|
@@ -10,259 +13,273 @@ import {
|
|
|
10
13
|
import { toString, isStdlib } from "visitor-as/dist/utils.js";
|
|
11
14
|
import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
|
|
12
15
|
import { Transform } from "assemblyscript/dist/transform.js";
|
|
16
|
+
import { CommonFlags } from "types:assemblyscript/src/common";
|
|
13
17
|
|
|
14
|
-
class
|
|
15
|
-
public keys: string[] = [];
|
|
16
|
-
public values: string[] = [];
|
|
17
|
-
public types: string[] = [];
|
|
18
|
-
public name: string = "";
|
|
19
|
-
public parent: string = "";
|
|
20
|
-
public node!: ClassDeclaration;
|
|
21
|
-
public encodeStmts: string[] = [];
|
|
22
|
-
public setDataStmts: string[] = [];
|
|
23
|
-
public initializeStmts: string[] = [];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
class AsJSONTransform extends BaseVisitor {
|
|
18
|
+
class JSONTransform extends BaseVisitor {
|
|
27
19
|
public schemasList: SchemaData[] = [];
|
|
28
20
|
public currentClass!: SchemaData;
|
|
29
21
|
public sources = new Set<Source>();
|
|
30
22
|
|
|
31
23
|
visitMethodDeclaration(): void { }
|
|
32
24
|
visitClassDeclaration(node: ClassDeclaration): void {
|
|
33
|
-
const className = node.name.text;
|
|
34
25
|
if (!node.decorators?.length) return;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
26
|
+
if (!node.members?.length) return;
|
|
27
|
+
|
|
28
|
+
let found = false;
|
|
29
|
+
for (const decorator of node.decorators) {
|
|
30
|
+
const name = (<IdentifierExpression>decorator.name).text;
|
|
31
|
+
if (name === "json" || name === "serializable") {
|
|
32
|
+
found = true;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
44
35
|
}
|
|
45
|
-
if (!
|
|
36
|
+
if (!found) return;
|
|
46
37
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
const schema = new SchemaData();
|
|
39
|
+
schema.node = node;
|
|
40
|
+
schema.name = node.name.text;
|
|
41
|
+
|
|
42
|
+
const members = [
|
|
43
|
+
...node.members
|
|
44
|
+
];
|
|
51
45
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (this.currentClass.parent.length) {
|
|
65
|
-
const parentSchema = this.schemasList.find(
|
|
66
|
-
(v) => v.name == this.currentClass.parent
|
|
67
|
-
);
|
|
68
|
-
if (parentSchema?.encodeStmts) {
|
|
69
|
-
parentSchema?.encodeStmts.push(parentSchema?.encodeStmts.pop() + ",");
|
|
70
|
-
for (let i = 0; i < parentSchema.keys.length; i++) {
|
|
71
|
-
const key = parentSchema.keys[i];
|
|
72
|
-
if (node.members.filter(v => v.name.text == key) == undefined) this.currentClass.encodeStmts.unshift(parentSchema.encodeStmts[i]!);
|
|
46
|
+
if (node.extendsType) {
|
|
47
|
+
schema.parent = this.schemasList.find(
|
|
48
|
+
(v) => v.name == node.extendsType?.name.identifier.text
|
|
49
|
+
) as SchemaData | null;
|
|
50
|
+
|
|
51
|
+
if (schema.parent?.members) {
|
|
52
|
+
for (let i = 0; i < schema.parent.members.length; i++) {
|
|
53
|
+
const replace = schema.members.find(
|
|
54
|
+
(v) => v.name == schema.parent?.members[i]?.name
|
|
55
|
+
)
|
|
56
|
+
if (!replace) schema.members.unshift(schema.parent.members[i]!);
|
|
73
57
|
}
|
|
74
58
|
}
|
|
75
59
|
}
|
|
76
60
|
|
|
77
|
-
const
|
|
78
|
-
(
|
|
79
|
-
|
|
61
|
+
for (const member of members) {
|
|
62
|
+
if (!(member instanceof FieldDeclaration)) continue;
|
|
63
|
+
const name = member.name;
|
|
64
|
+
if (!member.type) {
|
|
65
|
+
throw new Error("Fields must be strongly typed! Found " + toString(member) + " at " + node.range.source.normalizedPath);
|
|
66
|
+
}
|
|
67
|
+
const type = toString(member.type!);
|
|
68
|
+
const value = member.initializer ? toString(member.initializer!) : null;
|
|
69
|
+
|
|
70
|
+
if (member.flags == CommonFlags.Static) continue;
|
|
71
|
+
if (member.flags === CommonFlags.Private) continue;
|
|
72
|
+
if (member.flags === CommonFlags.Protected) continue;
|
|
73
|
+
|
|
74
|
+
const mem = new Property();
|
|
75
|
+
mem.name = name.text;
|
|
76
|
+
mem.type = type;
|
|
77
|
+
mem.value = value;
|
|
78
|
+
mem.node = member;
|
|
79
|
+
|
|
80
|
+
for (const decorator of member.decorators || []) {
|
|
81
|
+
if ((<IdentifierExpression>decorator.name).text == "alias") {
|
|
82
|
+
if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath);
|
|
83
|
+
mem.flag = PropertyFlags.Alias;
|
|
84
|
+
mem.alias = (decorator.args[0] as StringLiteralExpression).value;
|
|
85
|
+
} else if ((<IdentifierExpression>decorator.name).text == "omit") {
|
|
86
|
+
mem.flag = PropertyFlags.Omit;
|
|
87
|
+
} else if ((<IdentifierExpression>decorator.name).text == "omitnull") {
|
|
88
|
+
mem.flag = PropertyFlags.OmitNull;
|
|
89
|
+
} else if ((<IdentifierExpression>decorator.name).text == "omitif") {
|
|
90
|
+
if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath);
|
|
91
|
+
mem.args?.push((decorator.args[0] as StringLiteralExpression).value);
|
|
92
|
+
mem.flag = PropertyFlags.OmitIf;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
80
95
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
96
|
+
if (mem.flag === PropertyFlags.Alias) {
|
|
97
|
+
mem.name = mem.alias!;
|
|
98
|
+
} else if (mem.flag === PropertyFlags.None) {
|
|
99
|
+
mem.serialize = escapeString(JSON.stringify(mem.name)) + ":${__SERIALIZE<" + type + ">(this." + name.text + ")}";
|
|
100
|
+
mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (mem.flag == PropertyFlags.OmitNull) {
|
|
104
|
+
mem.serialize = "${changetype<usize>(this." + mem.name + ") == <usize>0" + " ? \"\" : '" + escapeString(JSON.stringify(mem.name)) + ":' + __SERIALIZE<" + type + ">(this." + name.text + ") + \",\"}";
|
|
105
|
+
mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));"
|
|
106
|
+
} else if (mem.flag == PropertyFlags.OmitIf) {
|
|
107
|
+
mem.serialize = "${" + mem.args![0]! + " ? \"\" : '" + escapeString(JSON.stringify(mem.name)) + ":' + __SERIALIZE<" + type + ">(this." + name.text + ")}";
|
|
108
|
+
mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));"
|
|
109
|
+
} else if (mem.flag == PropertyFlags.Alias) {
|
|
110
|
+
mem.serialize = escapeString(JSON.stringify(mem.name)) + ":${__SERIALIZE<" + type + ">(this." + name.text + ")}";
|
|
111
|
+
mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));"
|
|
112
|
+
mem.name = name.text;
|
|
113
|
+
}
|
|
84
114
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
115
|
+
const t = (mem.node.type as NamedTypeNode).name.identifier.text;
|
|
116
|
+
if (this.schemasList.find(v => v.name == t)) {
|
|
117
|
+
mem.initialize = "this." + name.text + " = changetype<nonnull<" + t + ">>(__new(offsetof<nonnull<" + t + ">>(), idof<nonnull<" + t + ">>()));\n changetype<nonnull<" + t + ">>(this." + name.text + ").__INITIALIZE()"
|
|
118
|
+
} else if (mem.value) {
|
|
119
|
+
mem.initialize = "this." + name.text + " = " + mem.value;
|
|
88
120
|
}
|
|
121
|
+
|
|
122
|
+
schema.members.push(mem);
|
|
89
123
|
}
|
|
90
124
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (mem.type && mem.type.name && mem.type.name.identifier.text) {
|
|
94
|
-
const member = mem as FieldDeclaration;
|
|
95
|
-
const lineText = toString(member);
|
|
96
|
-
//console.log("Member: " + lineText)
|
|
125
|
+
let SERIALIZE_RAW = "@inline __SERIALIZE(): string {\n let out = `{";
|
|
126
|
+
let SERIALIZE_PRETTY = "@inline __SERIALIZE_PRETTY(): string {\n let out = `{";
|
|
97
127
|
|
|
98
|
-
|
|
128
|
+
let INITIALIZE = "@inline __INITIALIZE(): this {\n";
|
|
99
129
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const omitif = member.decorators?.find(v => v.name.text === "omitif")?.args?.[0]?.value ?? null;
|
|
130
|
+
let DESERIALIZE = "@inline __DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n const len = key_end - key_start;\n"
|
|
131
|
+
let indent = " ";
|
|
103
132
|
|
|
104
|
-
|
|
105
|
-
let type = toString(member.type);
|
|
133
|
+
if (!schema.members.length) return;
|
|
106
134
|
|
|
107
|
-
|
|
108
|
-
let aliasName = name;
|
|
135
|
+
found = false;
|
|
109
136
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
137
|
+
if (
|
|
138
|
+
schema.members[0]?.flag === PropertyFlags.OmitNull
|
|
139
|
+
|| schema.members[0]?.flag === PropertyFlags.OmitIf
|
|
140
|
+
) {
|
|
141
|
+
SERIALIZE_RAW += schema.members[0]?.serialize;
|
|
142
|
+
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize;
|
|
143
|
+
} else {
|
|
144
|
+
SERIALIZE_RAW += schema.members[0]?.serialize + ",";
|
|
145
|
+
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize + ",\\n";
|
|
146
|
+
found = true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (schema.members[0]?.initialize) INITIALIZE += " " + schema.members[0]?.initialize + ";\n";
|
|
150
|
+
|
|
151
|
+
for (let i = 1; i < schema.members.length; i++) {
|
|
152
|
+
const member = schema.members[i]!;
|
|
153
|
+
if (member.initialize) INITIALIZE += " " + member.initialize + ";\n";
|
|
154
|
+
if (
|
|
155
|
+
member.flag === PropertyFlags.OmitNull
|
|
156
|
+
|| member.flag === PropertyFlags.OmitIf
|
|
157
|
+
) {
|
|
158
|
+
SERIALIZE_RAW += member.serialize;
|
|
159
|
+
SERIALIZE_PRETTY += member.serialize;
|
|
160
|
+
} else {
|
|
161
|
+
SERIALIZE_RAW += member.serialize + ",";
|
|
162
|
+
SERIALIZE_PRETTY += indent + member.serialize + ",\\n";
|
|
163
|
+
found = true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (found) {
|
|
168
|
+
SERIALIZE_RAW += "`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}";
|
|
169
|
+
SERIALIZE_PRETTY += "`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}";
|
|
170
|
+
} else {
|
|
171
|
+
SERIALIZE_RAW += "`;\n};";
|
|
172
|
+
SERIALIZE_PRETTY += "`;\n};";
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
INITIALIZE += " return this;\n}"
|
|
176
|
+
|
|
177
|
+
const sortedMembers: Property[][] = [];
|
|
178
|
+
const _sorted = schema.members.sort((a, b) => a.name.length - b.name.length);
|
|
179
|
+
let len = 0;
|
|
180
|
+
let offset = 0;
|
|
181
|
+
sortedMembers.push([_sorted[0]!]);
|
|
182
|
+
len = _sorted[0]?.name.length!;
|
|
183
|
+
for (let i = 1; i < _sorted.length; i++) {
|
|
184
|
+
const member = _sorted[i]!;
|
|
185
|
+
if (member.alias?.length || member.name.length > len) {
|
|
186
|
+
sortedMembers.push([member]);
|
|
187
|
+
len = member.alias?.length || member.name.length
|
|
188
|
+
offset++;
|
|
189
|
+
} else {
|
|
190
|
+
sortedMembers[offset]!.push(member);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
let first = true;
|
|
195
|
+
for (const memberSet of sortedMembers) {
|
|
196
|
+
const firstMember = memberSet[0]!;
|
|
197
|
+
const name = encodeKey(firstMember.alias || firstMember.name);
|
|
198
|
+
if (name.length === 1) {
|
|
199
|
+
if (first) {
|
|
200
|
+
DESERIALIZE += " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
201
|
+
first = false;
|
|
202
|
+
} else {
|
|
203
|
+
DESERIALIZE += "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
116
204
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
) {
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return
|
|
147
|
-
}
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
`this.${name} = ${toString(member.initializer)}`
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
} else if (
|
|
155
|
-
[
|
|
156
|
-
"f32",
|
|
157
|
-
"f64",
|
|
158
|
-
].includes(type.toLowerCase())
|
|
159
|
-
) {
|
|
160
|
-
if (omitif) {
|
|
161
|
-
this.currentClass.encodeStmts.push(
|
|
162
|
-
`\${${omitif} ? "" : \`,${encodeKey(aliasName)}:\${this.${name}}\`}`
|
|
163
|
-
);
|
|
205
|
+
} else if (name.length === 2) {
|
|
206
|
+
if (first) {
|
|
207
|
+
DESERIALIZE += " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
208
|
+
first = false;
|
|
209
|
+
} else {
|
|
210
|
+
DESERIALIZE += "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
211
|
+
}
|
|
212
|
+
} else if (name.length === 4) {
|
|
213
|
+
if (first) {
|
|
214
|
+
DESERIALIZE += " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
|
|
215
|
+
first = false;
|
|
216
|
+
} else {
|
|
217
|
+
DESERIALIZE += "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
if (first) {
|
|
221
|
+
DESERIALIZE += " if (" + name.length + " === len) {\n";
|
|
222
|
+
first = false;
|
|
223
|
+
} else {
|
|
224
|
+
DESERIALIZE += "else if (" + name.length + " === len) {\n";
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
let f = true;
|
|
228
|
+
for (let i = 0; i < memberSet.length; i++) {
|
|
229
|
+
const member = memberSet[i]!;
|
|
230
|
+
const name = encodeKey(member.alias || member.name);
|
|
231
|
+
if (name.length === 1) {
|
|
232
|
+
DESERIALIZE += ` case ${name.charCodeAt(0)}: {\n ${member.deserialize}\n return true;\n }\n`;
|
|
233
|
+
} else if (name.length === 2) {
|
|
234
|
+
DESERIALIZE += ` case ${charCodeAt32(name, 0)}: {\n ${member.deserialize}\n return true;\n }\n`;
|
|
235
|
+
} else if (name.length === 4) {
|
|
236
|
+
if (f) {
|
|
237
|
+
f = false;
|
|
238
|
+
DESERIALIZE += ` if (${charCodeAt64(name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
|
|
164
239
|
} else {
|
|
165
|
-
|
|
166
|
-
`,${encodeKey(aliasName)}:\${this.${name}}`
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
// @ts-ignore
|
|
170
|
-
this.currentClass.setDataStmts.push(
|
|
171
|
-
`if (key.equals(${JSON.stringify(aliasName)})) {
|
|
172
|
-
this.${name} = __parseObjectValue<${type}>(data.slice(val_start, val_end), initializeDefaultValues);
|
|
173
|
-
return;
|
|
174
|
-
}`
|
|
175
|
-
);
|
|
176
|
-
if (member.initializer) {
|
|
177
|
-
this.currentClass.initializeStmts.push(
|
|
178
|
-
`this.${name} = ${toString(member.initializer)}`
|
|
179
|
-
);
|
|
240
|
+
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + `else if (${charCodeAt64(name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
|
|
180
241
|
}
|
|
181
242
|
} else {
|
|
182
|
-
if (
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
);
|
|
186
|
-
console.log(`\${changetype<usize>(this.${name}) != <usize>0 ? \`${encodeKey(aliasName)}:,\${__JSON_Stringify<${type}>(this.${name})}\` : ""}`)
|
|
187
|
-
} else if (omitif) {
|
|
188
|
-
this.currentClass.encodeStmts.push(
|
|
189
|
-
`\${${omitif} ? "" : \`${encodeKey(aliasName)}:,\${__JSON_Stringify<${type}>(this.${name})}\`}`
|
|
190
|
-
);
|
|
243
|
+
if (f) {
|
|
244
|
+
f = false;
|
|
245
|
+
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`
|
|
191
246
|
} else {
|
|
192
|
-
|
|
193
|
-
`,${encodeKey(aliasName)}:\${__JSON_Stringify<${type}>(this.${name})}`
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
// @ts-ignore
|
|
197
|
-
this.currentClass.setDataStmts.push(
|
|
198
|
-
`if (key.equals(${JSON.stringify(aliasName)})) {
|
|
199
|
-
this.${name} = __parseObjectValue<${type}>(val_start ? data.slice(val_start, val_end) : data, initializeDefaultValues);
|
|
200
|
-
return;
|
|
201
|
-
}`
|
|
202
|
-
);
|
|
203
|
-
if (member.initializer) {
|
|
204
|
-
this.currentClass.initializeStmts.push(
|
|
205
|
-
`this.${name} = ${toString(member.initializer)}`
|
|
206
|
-
);
|
|
247
|
+
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})) {\n ${member.deserialize}\n return true;\n }\n`
|
|
207
248
|
}
|
|
208
249
|
}
|
|
209
250
|
}
|
|
251
|
+
if (name.length < 3) {
|
|
252
|
+
DESERIALIZE += ` default: {\n return false;\n }\n }\n`
|
|
253
|
+
} else if (name.length == 4) {
|
|
254
|
+
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`
|
|
255
|
+
} else {
|
|
256
|
+
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`
|
|
257
|
+
}
|
|
258
|
+
DESERIALIZE += " } ";
|
|
210
259
|
}
|
|
211
260
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (this.currentClass.encodeStmts.length > 0) {
|
|
215
|
-
const stmt =
|
|
216
|
-
this.currentClass.encodeStmts[0]!;
|
|
217
|
-
this.currentClass.encodeStmts[0] = stmt!.slice(1);
|
|
218
|
-
serializeFunc = `
|
|
219
|
-
__JSON_Serialize(): string {
|
|
220
|
-
return \`{${this.currentClass.encodeStmts.join("")}}\`;
|
|
221
|
-
}`;
|
|
222
|
-
} else {
|
|
223
|
-
serializeFunc = `
|
|
224
|
-
__JSON_Serialize(): string {
|
|
225
|
-
return "{}";
|
|
226
|
-
}`;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const setKeyFunc = `
|
|
230
|
-
__JSON_Set_Key(key: __Virtual<string>, data: string, val_start: i32, val_end: i32, initializeDefaultValues: boolean): void {
|
|
231
|
-
${this.currentClass.setDataStmts.join("\n ")}
|
|
232
|
-
}
|
|
233
|
-
`;
|
|
261
|
+
DESERIALIZE += "\n return false;\n}"
|
|
234
262
|
|
|
235
|
-
|
|
263
|
+
//console.log(sortedMembers);
|
|
236
264
|
|
|
237
|
-
if (
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
`;
|
|
243
|
-
} else {
|
|
244
|
-
initializeFunc = `
|
|
245
|
-
__JSON_Initialize(): void {}
|
|
246
|
-
`;
|
|
265
|
+
if (process.env["JSON_DEBUG"]) {
|
|
266
|
+
console.log(SERIALIZE_RAW);
|
|
267
|
+
//console.log(SERIALIZE_PRETTY);
|
|
268
|
+
console.log(INITIALIZE);
|
|
269
|
+
console.log(DESERIALIZE);
|
|
247
270
|
}
|
|
248
|
-
const serializeMethod = SimpleParser.parseClassMember(serializeFunc, node);
|
|
249
|
-
node.members.push(serializeMethod);
|
|
250
|
-
|
|
251
|
-
const setDataMethod = SimpleParser.parseClassMember(setKeyFunc, node);
|
|
252
|
-
node.members.push(setDataMethod);
|
|
253
271
|
|
|
254
|
-
const
|
|
255
|
-
|
|
272
|
+
const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(SERIALIZE_RAW, node);
|
|
273
|
+
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
|
|
274
|
+
const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
|
|
275
|
+
const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
|
|
256
276
|
|
|
257
|
-
|
|
258
|
-
|
|
277
|
+
if (!node.members.find(v => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_RAW_METHOD);
|
|
278
|
+
if (!node.members.find(v => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD);
|
|
279
|
+
if (!node.members.find(v => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD);
|
|
259
280
|
|
|
260
|
-
|
|
261
|
-
console.log(serializeFunc);
|
|
262
|
-
//console.log(setKeyFunc);
|
|
263
|
-
//console.log(initializeFunc);
|
|
281
|
+
this.schemasList.push(schema);
|
|
264
282
|
}
|
|
265
|
-
|
|
266
283
|
visitSource(node: Source): void {
|
|
267
284
|
super.visitSource(node);
|
|
268
285
|
|
|
@@ -270,35 +287,14 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
270
287
|
if (!this.sources.has(node)) {
|
|
271
288
|
return;
|
|
272
289
|
}
|
|
273
|
-
|
|
274
|
-
// Note, the following one liner would be easier, but it fails with an assertion error
|
|
275
|
-
// because as-virtual's SimpleParser doesn't set the parser.currentSource correctly.
|
|
276
|
-
//
|
|
277
|
-
// const stmt = SimpleParser.parseTopLevelStatement('import { Virtual as __Virtual } from "as-virtual/assembly";');
|
|
278
|
-
|
|
279
|
-
// ... So we have to do it the long way:
|
|
280
|
-
const txt = 'import { Virtual as __Virtual } from "as-virtual/assembly";'
|
|
281
|
-
const tokenizer = new Tokenizer(new Source(SourceKind.User, node.normalizedPath, txt));
|
|
282
|
-
const parser = new Parser();
|
|
283
|
-
parser.currentSource = tokenizer.source;
|
|
284
|
-
const stmt = parser.parseTopLevelStatement(tokenizer)!;
|
|
285
|
-
|
|
286
|
-
// Add the import statement to the top of the source.
|
|
287
|
-
node.statements.unshift(stmt);
|
|
288
290
|
}
|
|
289
291
|
}
|
|
290
292
|
|
|
291
|
-
function encodeKey(aliasName: string): string {
|
|
292
|
-
return JSON.stringify(aliasName)
|
|
293
|
-
.replace(/\\/g, "\\\\")
|
|
294
|
-
.replace(/\`/g, '\\`');
|
|
295
|
-
}
|
|
296
|
-
|
|
297
293
|
export default class Transformer extends Transform {
|
|
298
294
|
// Trigger the transform after parse.
|
|
299
295
|
afterParse(parser: Parser): void {
|
|
300
296
|
// Create new transform
|
|
301
|
-
const transformer = new
|
|
297
|
+
const transformer = new JSONTransform();
|
|
302
298
|
|
|
303
299
|
// Sort the sources so that user scripts are visited last
|
|
304
300
|
const sources = parser.sources
|
|
@@ -326,9 +322,77 @@ export default class Transformer extends Transform {
|
|
|
326
322
|
const schemas = transformer.schemasList;
|
|
327
323
|
for (const schema of schemas) {
|
|
328
324
|
if (schema.parent) {
|
|
329
|
-
const parent = schemas.find((v) => v.name === schema.parent);
|
|
325
|
+
const parent = schemas.find((v) => v.name === schema.parent?.name);
|
|
330
326
|
if (!parent) throw new Error(`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.`);
|
|
331
327
|
}
|
|
332
328
|
}
|
|
333
329
|
}
|
|
334
330
|
}
|
|
331
|
+
|
|
332
|
+
enum PropertyFlags {
|
|
333
|
+
None,
|
|
334
|
+
Omit,
|
|
335
|
+
OmitNull,
|
|
336
|
+
OmitIf,
|
|
337
|
+
Alias
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
class Property {
|
|
341
|
+
public name: string = ""
|
|
342
|
+
public alias: string | null = null;
|
|
343
|
+
public type: string = "";
|
|
344
|
+
public value: string | null = null;
|
|
345
|
+
public flag: PropertyFlags = PropertyFlags.None;
|
|
346
|
+
public args: string[] | null = [];
|
|
347
|
+
|
|
348
|
+
public serialize: string | null = null;
|
|
349
|
+
public deserialize: string | null = null;
|
|
350
|
+
public initialize: string | null = null;
|
|
351
|
+
|
|
352
|
+
public node!: FieldDeclaration;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
class SchemaData {
|
|
356
|
+
public name: string = "";
|
|
357
|
+
public members: Property[] = []
|
|
358
|
+
public parent: SchemaData | null = null;
|
|
359
|
+
public node!: ClassDeclaration;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function charCodeAt32(data: string, offset: number): number {
|
|
363
|
+
return (data.charCodeAt(offset + 1) << 16) | data.charCodeAt(offset);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function charCodeAt64(data: string, offset: number): bigint {
|
|
367
|
+
if (offset + 3 >= data.length) {
|
|
368
|
+
throw new Error("The string must have at least 4 characters from the specified offset.");
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const firstCharCode = BigInt(data.charCodeAt(offset));
|
|
372
|
+
const secondCharCode = BigInt(data.charCodeAt(offset + 1));
|
|
373
|
+
const thirdCharCode = BigInt(data.charCodeAt(offset + 2));
|
|
374
|
+
const fourthCharCode = BigInt(data.charCodeAt(offset + 3));
|
|
375
|
+
|
|
376
|
+
const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode;
|
|
377
|
+
|
|
378
|
+
return u64Value;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function encodeKey(key: string): string {
|
|
382
|
+
const data = JSON.stringify(key);
|
|
383
|
+
return data.slice(1, data.length - 1);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function escapeString(data: string): string {
|
|
387
|
+
return data.replace(/\\/g, "\\\\")
|
|
388
|
+
.replace(/\`/g, '\\`');
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function escapeSlash(data: string): string {
|
|
392
|
+
return data.replace(/\\/g, "\\\\")
|
|
393
|
+
.replace(/\`/g, '\\`');
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function escapeQuote(data: string): string {
|
|
397
|
+
return data.replace(/\"/g, "\\\"");
|
|
398
|
+
}
|
package/transform/tsconfig.json
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
/* Basic Options */
|
|
6
6
|
// "incremental": true, /* Enable incremental compilation */
|
|
7
|
-
"target": "
|
|
8
|
-
"module": "
|
|
7
|
+
"target": "es2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
|
|
8
|
+
"module": "es2020" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
|
|
9
9
|
// "lib": [], /* Specify library files to be included in the compilation. */
|
|
10
10
|
// "allowJs": true, /* Allow javascript files to be compiled. */
|
|
11
11
|
// "checkJs": true, /* Report errors in .js files. */
|