json-as 0.9.16 → 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 +2 -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 +22 -26
- 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 -420
- package/transform/package.json +1 -1
- package/transform/src/index.ts +244 -141
- 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,33 +38,34 @@ 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
|
-
for (let i =
|
|
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
|
-
|
|
55
|
+
members.unshift(schema.parent?.members[i]!.node);
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
if (!members.length) {
|
|
63
|
-
let SERIALIZE_RAW_EMPTY =
|
|
62
|
+
let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}';
|
|
64
63
|
//let SERIALIZE_PRETTY_EMPTY = "__SERIALIZE_PRETTY(): string {\n return \"{}\";\n}";
|
|
65
64
|
|
|
66
65
|
let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}";
|
|
67
66
|
|
|
68
|
-
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}";
|
|
69
69
|
|
|
70
70
|
if (process.env["JSON_DEBUG"]) {
|
|
71
71
|
console.log(SERIALIZE_RAW_EMPTY);
|
|
@@ -74,14 +74,26 @@ class JSONTransform extends BaseVisitor {
|
|
|
74
74
|
console.log(DESERIALIZE_EMPTY);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(
|
|
77
|
+
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(
|
|
78
|
+
SERIALIZE_RAW_EMPTY,
|
|
79
|
+
node,
|
|
80
|
+
);
|
|
78
81
|
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
|
|
79
|
-
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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);
|
|
85
97
|
|
|
86
98
|
this.schemasList.push(schema);
|
|
87
99
|
}
|
|
@@ -90,7 +102,12 @@ class JSONTransform extends BaseVisitor {
|
|
|
90
102
|
const name = member.name;
|
|
91
103
|
if (!(member instanceof FieldDeclaration)) continue;
|
|
92
104
|
if (!member.type) {
|
|
93
|
-
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
|
+
);
|
|
94
111
|
}
|
|
95
112
|
const type = toString(member.type!);
|
|
96
113
|
if (type.startsWith("(") && type.includes("=>")) continue;
|
|
@@ -99,7 +116,6 @@ class JSONTransform extends BaseVisitor {
|
|
|
99
116
|
if (member.flags == CommonFlags.Static) continue;
|
|
100
117
|
if (member.flags === CommonFlags.Private) continue;
|
|
101
118
|
if (member.flags === CommonFlags.Protected) continue;
|
|
102
|
-
if (member.decorators && member.decorators.find((v) => (<IdentifierExpression>v.name).text == "omit")) continue;
|
|
103
119
|
|
|
104
120
|
const mem = new Property();
|
|
105
121
|
mem.name = name.text;
|
|
@@ -107,95 +123,90 @@ class JSONTransform extends BaseVisitor {
|
|
|
107
123
|
mem.value = value;
|
|
108
124
|
mem.node = member;
|
|
109
125
|
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
if (decorator = member.decorators.find(v => (<IdentifierExpression>v.name).text == "alias") as DecoratorNode | null) {
|
|
113
|
-
if ((<IdentifierExpression>decorator.name).text == "alias") {
|
|
114
|
-
if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath);
|
|
115
|
-
mem.flags.push(PropertyFlags.Alias);
|
|
116
|
-
mem.alias = (decorator.args[0] as StringLiteralExpression).value;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
for (let i = 0; i < (member.decorators).length; i++) {
|
|
121
|
-
const decorator = member.decorators[i]!;
|
|
122
|
-
if ((<IdentifierExpression>decorator.name).text == "omitnull") {
|
|
123
|
-
mem.flags.push(PropertyFlags.OmitNull);
|
|
124
|
-
} else if ((<IdentifierExpression>decorator.name).text == "omitif") {
|
|
125
|
-
if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath);
|
|
126
|
-
mem.args?.push((decorator.args[0] as StringLiteralExpression).value);
|
|
127
|
-
mem.flags.push(PropertyFlags.OmitIf);
|
|
128
|
-
} else if ((<IdentifierExpression>decorator.name).text == "flatten") {
|
|
129
|
-
if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @flatten in " + node.range.source.normalizedPath);
|
|
130
|
-
mem.flags.push(PropertyFlags.Flatten);
|
|
131
|
-
mem.args = [(decorator.args[0] as StringLiteralExpression).value];
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (!mem.flags.length) {
|
|
137
|
-
mem.flags = [PropertyFlags.None];
|
|
138
|
-
if (type == "JSON.Raw") {
|
|
139
|
-
mem.serialize = escapeString(JSON.stringify(mem.alias || mem.name)) + ":${this." + name.text + "}";
|
|
140
|
-
mem.deserialize = "this." + name.text + " = " + "data.substring(value_start, value_end);"
|
|
141
|
-
} else {
|
|
142
|
-
mem.serialize = escapeString(JSON.stringify(mem.alias || mem.name)) + ":${__SERIALIZE<" + type + ">(this." + name.text + ")}";
|
|
143
|
-
mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));"
|
|
144
|
-
}
|
|
126
|
+
if (type == "JSON.Raw") {
|
|
127
|
+
mem.flags.set(PropertyFlags.JSON_Raw, []);
|
|
145
128
|
}
|
|
146
129
|
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
+
}
|
|
165
165
|
}
|
|
166
|
-
mem.name = name.text;
|
|
167
166
|
}
|
|
168
167
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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()";
|
|
172
185
|
} else if (mem.value) {
|
|
173
186
|
mem.initialize = "this." + name.text + " = " + mem.value;
|
|
174
|
-
} else if (
|
|
175
|
-
mem.initialize = "this." + name.text + " = new " + mem.type + "()"
|
|
176
|
-
} else if (
|
|
177
|
-
mem.initialize = "this." + name.text +
|
|
178
|
-
} else if (
|
|
179
|
-
mem.initialize =
|
|
180
|
-
|
|
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") {
|
|
181
195
|
mem.initialize = "this." + name.text + " = false";
|
|
182
|
-
} else if (
|
|
183
|
-
mem.initialize = "this." + name.text +
|
|
196
|
+
} else if (type === "JSON.Raw") {
|
|
197
|
+
mem.initialize = "this." + name.text + ' = ""';
|
|
184
198
|
} else if (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
199
|
+
type === "u8" ||
|
|
200
|
+
type === "u16" ||
|
|
201
|
+
type === "u32" ||
|
|
202
|
+
type === "u64" ||
|
|
203
|
+
type === "i8" ||
|
|
204
|
+
type === "i16" ||
|
|
205
|
+
type === "i32" ||
|
|
206
|
+
type === "i64"
|
|
193
207
|
) {
|
|
194
208
|
mem.initialize = "this." + name.text + " = 0";
|
|
195
|
-
} else if (
|
|
196
|
-
t === "f32" ||
|
|
197
|
-
t === "f64"
|
|
198
|
-
) {
|
|
209
|
+
} else if (type === "f32" || type === "f64") {
|
|
199
210
|
mem.initialize = "this." + name.text + " = 0.0";
|
|
200
211
|
}
|
|
201
212
|
|
|
@@ -207,7 +218,8 @@ class JSONTransform extends BaseVisitor {
|
|
|
207
218
|
|
|
208
219
|
let INITIALIZE = "__INITIALIZE(): this {\n";
|
|
209
220
|
|
|
210
|
-
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";
|
|
211
223
|
let indent = " ";
|
|
212
224
|
|
|
213
225
|
if (!schema.members.length) return;
|
|
@@ -215,8 +227,8 @@ class JSONTransform extends BaseVisitor {
|
|
|
215
227
|
found = false;
|
|
216
228
|
|
|
217
229
|
if (
|
|
218
|
-
schema.members[0]?.flags.
|
|
219
|
-
|
|
230
|
+
schema.members[0]?.flags.has(PropertyFlags.OmitNull) ||
|
|
231
|
+
schema.members[0]?.flags.has(PropertyFlags.OmitIf)
|
|
220
232
|
) {
|
|
221
233
|
SERIALIZE_RAW += schema.members[0]?.serialize;
|
|
222
234
|
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize;
|
|
@@ -226,14 +238,15 @@ class JSONTransform extends BaseVisitor {
|
|
|
226
238
|
found = true;
|
|
227
239
|
}
|
|
228
240
|
|
|
229
|
-
if (schema.members[0]?.initialize)
|
|
241
|
+
if (schema.members[0]?.initialize)
|
|
242
|
+
INITIALIZE += " " + schema.members[0]?.initialize + ";\n";
|
|
230
243
|
|
|
231
244
|
for (let i = 1; i < schema.members.length; i++) {
|
|
232
245
|
const member = schema.members[i]!;
|
|
233
246
|
if (member.initialize) INITIALIZE += " " + member.initialize + ";\n";
|
|
234
247
|
if (
|
|
235
|
-
member.flags.
|
|
236
|
-
|
|
248
|
+
member.flags.has(PropertyFlags.OmitNull) ||
|
|
249
|
+
member.flags.has(PropertyFlags.OmitIf)
|
|
237
250
|
) {
|
|
238
251
|
SERIALIZE_RAW += member.serialize;
|
|
239
252
|
SERIALIZE_PRETTY += member.serialize;
|
|
@@ -245,17 +258,21 @@ class JSONTransform extends BaseVisitor {
|
|
|
245
258
|
}
|
|
246
259
|
|
|
247
260
|
if (found) {
|
|
248
|
-
SERIALIZE_RAW +=
|
|
249
|
-
|
|
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}";
|
|
250
265
|
} else {
|
|
251
266
|
SERIALIZE_RAW += "`;\n};";
|
|
252
267
|
SERIALIZE_PRETTY += "`;\n};";
|
|
253
268
|
}
|
|
254
269
|
|
|
255
|
-
INITIALIZE += " return this;\n}"
|
|
270
|
+
INITIALIZE += " return this;\n}";
|
|
256
271
|
|
|
257
272
|
const sortedMembers: Property[][] = [];
|
|
258
|
-
const _sorted = schema.members.sort(
|
|
273
|
+
const _sorted = schema.members.sort(
|
|
274
|
+
(a, b) => a.name.length - b.name.length,
|
|
275
|
+
);
|
|
259
276
|
let len = 0;
|
|
260
277
|
let offset = 0;
|
|
261
278
|
sortedMembers.push([_sorted[0]!]);
|
|
@@ -264,7 +281,7 @@ class JSONTransform extends BaseVisitor {
|
|
|
264
281
|
const member = _sorted[i]!;
|
|
265
282
|
if (member.alias?.length || member.name.length > len) {
|
|
266
283
|
sortedMembers.push([member]);
|
|
267
|
-
len = member.alias?.length || member.name.length
|
|
284
|
+
len = member.alias?.length || member.name.length;
|
|
268
285
|
offset++;
|
|
269
286
|
} else {
|
|
270
287
|
sortedMembers[offset]!.push(member);
|
|
@@ -277,24 +294,30 @@ class JSONTransform extends BaseVisitor {
|
|
|
277
294
|
const name = encodeKey(firstMember.alias || firstMember.name);
|
|
278
295
|
if (name.length === 1) {
|
|
279
296
|
if (first) {
|
|
280
|
-
DESERIALIZE +=
|
|
297
|
+
DESERIALIZE +=
|
|
298
|
+
" if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
281
299
|
first = false;
|
|
282
300
|
} else {
|
|
283
|
-
DESERIALIZE +=
|
|
301
|
+
DESERIALIZE +=
|
|
302
|
+
"else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
284
303
|
}
|
|
285
304
|
} else if (name.length === 2) {
|
|
286
305
|
if (first) {
|
|
287
|
-
DESERIALIZE +=
|
|
306
|
+
DESERIALIZE +=
|
|
307
|
+
" if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
288
308
|
first = false;
|
|
289
309
|
} else {
|
|
290
|
-
DESERIALIZE +=
|
|
310
|
+
DESERIALIZE +=
|
|
311
|
+
"else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
291
312
|
}
|
|
292
313
|
} else if (name.length === 4) {
|
|
293
314
|
if (first) {
|
|
294
|
-
DESERIALIZE +=
|
|
315
|
+
DESERIALIZE +=
|
|
316
|
+
" if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
|
|
295
317
|
first = false;
|
|
296
318
|
} else {
|
|
297
|
-
DESERIALIZE +=
|
|
319
|
+
DESERIALIZE +=
|
|
320
|
+
"else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
|
|
298
321
|
}
|
|
299
322
|
} else {
|
|
300
323
|
if (first) {
|
|
@@ -318,28 +341,36 @@ class JSONTransform extends BaseVisitor {
|
|
|
318
341
|
f = false;
|
|
319
342
|
DESERIALIZE += ` if (${charCodeAt64(name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
|
|
320
343
|
} else {
|
|
321
|
-
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`;
|
|
322
347
|
}
|
|
323
348
|
} else {
|
|
324
349
|
if (f) {
|
|
325
350
|
f = false;
|
|
326
|
-
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`;
|
|
327
352
|
} else {
|
|
328
|
-
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`;
|
|
329
356
|
}
|
|
330
357
|
}
|
|
331
358
|
}
|
|
332
359
|
if (name.length < 3) {
|
|
333
|
-
DESERIALIZE += ` default: {\n return false;\n }\n }\n
|
|
360
|
+
DESERIALIZE += ` default: {\n return false;\n }\n }\n`;
|
|
334
361
|
} else if (name.length == 4) {
|
|
335
|
-
DESERIALIZE =
|
|
362
|
+
DESERIALIZE =
|
|
363
|
+
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
364
|
+
` else {\n return false;\n }\n`;
|
|
336
365
|
} else {
|
|
337
|
-
DESERIALIZE =
|
|
366
|
+
DESERIALIZE =
|
|
367
|
+
DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
|
|
368
|
+
` else {\n return false;\n }\n`;
|
|
338
369
|
}
|
|
339
370
|
DESERIALIZE += " } ";
|
|
340
371
|
}
|
|
341
372
|
|
|
342
|
-
DESERIALIZE += "\n return false;\n}"
|
|
373
|
+
DESERIALIZE += "\n return false;\n}";
|
|
343
374
|
|
|
344
375
|
//console.log(sortedMembers);
|
|
345
376
|
|
|
@@ -350,14 +381,20 @@ class JSONTransform extends BaseVisitor {
|
|
|
350
381
|
console.log(DESERIALIZE);
|
|
351
382
|
}
|
|
352
383
|
|
|
353
|
-
const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(
|
|
384
|
+
const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(
|
|
385
|
+
SERIALIZE_RAW,
|
|
386
|
+
node,
|
|
387
|
+
);
|
|
354
388
|
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
|
|
355
389
|
const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
|
|
356
390
|
const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
|
|
357
391
|
|
|
358
|
-
if (!node.members.find(v => v.name.text == "__SERIALIZE"))
|
|
359
|
-
|
|
360
|
-
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);
|
|
361
398
|
|
|
362
399
|
this.schemasList.push(schema);
|
|
363
400
|
}
|
|
@@ -404,27 +441,32 @@ export default class Transformer extends Transform {
|
|
|
404
441
|
for (const schema of schemas) {
|
|
405
442
|
if (schema.parent) {
|
|
406
443
|
const parent = schemas.find((v) => v.name === schema.parent?.name);
|
|
407
|
-
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
|
+
);
|
|
408
448
|
}
|
|
409
449
|
}
|
|
410
450
|
}
|
|
411
451
|
}
|
|
412
452
|
|
|
413
453
|
enum PropertyFlags {
|
|
414
|
-
None,
|
|
415
454
|
Omit,
|
|
416
455
|
OmitNull,
|
|
417
456
|
OmitIf,
|
|
418
457
|
Alias,
|
|
419
|
-
|
|
458
|
+
JSON_Raw,
|
|
420
459
|
}
|
|
421
460
|
|
|
422
461
|
class Property {
|
|
423
|
-
public name: string = ""
|
|
462
|
+
public name: string = "";
|
|
424
463
|
public alias: string | null = null;
|
|
425
464
|
public type: string = "";
|
|
426
465
|
public value: string | null = null;
|
|
427
|
-
public flags: PropertyFlags[] =
|
|
466
|
+
public flags: Map<PropertyFlags, string[]> = new Map<
|
|
467
|
+
PropertyFlags,
|
|
468
|
+
string[]
|
|
469
|
+
>();
|
|
428
470
|
public args: string[] | null = [];
|
|
429
471
|
|
|
430
472
|
public serialize: string | null = null;
|
|
@@ -432,11 +474,57 @@ class Property {
|
|
|
432
474
|
public initialize: string | null = null;
|
|
433
475
|
|
|
434
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
|
+
}
|
|
435
523
|
}
|
|
436
524
|
|
|
437
525
|
class SchemaData {
|
|
438
526
|
public name: string = "";
|
|
439
|
-
public members: Property[] = []
|
|
527
|
+
public members: Property[] = [];
|
|
440
528
|
public parent: SchemaData | null = null;
|
|
441
529
|
public node!: ClassDeclaration;
|
|
442
530
|
}
|
|
@@ -447,7 +535,9 @@ function charCodeAt32(data: string, offset: number): number {
|
|
|
447
535
|
|
|
448
536
|
function charCodeAt64(data: string, offset: number): bigint {
|
|
449
537
|
if (offset + 3 >= data.length) {
|
|
450
|
-
throw new Error(
|
|
538
|
+
throw new Error(
|
|
539
|
+
"The string must have at least 4 characters from the specified offset.",
|
|
540
|
+
);
|
|
451
541
|
}
|
|
452
542
|
|
|
453
543
|
const firstCharCode = BigInt(data.charCodeAt(offset));
|
|
@@ -455,7 +545,11 @@ function charCodeAt64(data: string, offset: number): bigint {
|
|
|
455
545
|
const thirdCharCode = BigInt(data.charCodeAt(offset + 2));
|
|
456
546
|
const fourthCharCode = BigInt(data.charCodeAt(offset + 3));
|
|
457
547
|
|
|
458
|
-
const u64Value =
|
|
548
|
+
const u64Value =
|
|
549
|
+
(fourthCharCode << 48n) |
|
|
550
|
+
(thirdCharCode << 32n) |
|
|
551
|
+
(secondCharCode << 16n) |
|
|
552
|
+
firstCharCode;
|
|
459
553
|
|
|
460
554
|
return u64Value;
|
|
461
555
|
}
|
|
@@ -466,15 +560,24 @@ function encodeKey(key: string): string {
|
|
|
466
560
|
}
|
|
467
561
|
|
|
468
562
|
function escapeString(data: string): string {
|
|
469
|
-
return data.replace(/\\/g, "\\\\")
|
|
470
|
-
.replace(/\`/g, '\\`');
|
|
563
|
+
return data.replace(/\\/g, "\\\\").replace(/\`/g, "\\`");
|
|
471
564
|
}
|
|
472
565
|
|
|
473
566
|
function escapeSlash(data: string): string {
|
|
474
|
-
return data.replace(/\\/g, "\\\\")
|
|
475
|
-
.replace(/\`/g, '\\`');
|
|
567
|
+
return data.replace(/\\/g, "\\\\").replace(/\`/g, "\\`");
|
|
476
568
|
}
|
|
477
569
|
|
|
478
570
|
function escapeQuote(data: string): string {
|
|
479
|
-
return data.replace(/\"/g, "
|
|
480
|
-
}
|
|
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,
|