json-as 0.8.7 → 0.8.8
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 +1 -7
- package/CHANGELOG +1 -3
- package/README.md +16 -26
- package/assembly/__benches__/as-json.ts +88 -0
- package/assembly/__benches__/as-tral.d.ts +1 -0
- package/assembly/__tests__/as-json.spec.ts +673 -0
- package/assembly/__tests__/as-pect.d.ts +1 -0
- package/assembly/deserialize/array/array.ts +1 -1
- package/assembly/deserialize/array/map.ts +1 -1
- package/assembly/deserialize/array/object.ts +1 -1
- package/assembly/deserialize/array.ts +1 -1
- package/assembly/deserialize/box.ts +1 -4
- package/assembly/deserialize/map.ts +1 -1
- package/assembly/deserialize/object.ts +125 -122
- package/assembly/index.d.ts +1 -7
- package/assembly/index.ts +1 -129
- package/assembly/serialize/array.ts +2 -3
- package/assembly/serialize/box.ts +1 -1
- package/assembly/serialize/map.ts +1 -1
- package/assembly/src/json.ts +124 -0
- package/assembly/test.ts +22 -33
- package/bench/benchmark.ts +3 -7
- package/bench.js +3 -14
- package/index.ts +1 -1
- package/package.json +8 -6
- package/transform/lib/index.js +183 -301
- package/transform/package.json +1 -1
- package/transform/src/index.ts +215 -301
- package/transform/tsconfig.json +2 -2
- package/tsconfig.json +102 -94
- package/assembly/__tests__/deserialize.spec.ts +0 -298
- package/assembly/__tests__/serialize.spec.ts +0 -375
- package/transform/lib/index.old.js +0 -257
- package/transform/lib/types.js +0 -17
- package/transform/src/index.old.ts +0 -312
package/transform/src/index.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ClassDeclaration,
|
|
3
3
|
FieldDeclaration,
|
|
4
|
-
IdentifierExpression,
|
|
5
|
-
NamedTypeNode,
|
|
6
|
-
StringLiteralExpression,
|
|
7
4
|
Parser,
|
|
8
5
|
Source,
|
|
9
6
|
SourceKind,
|
|
@@ -13,273 +10,237 @@ import {
|
|
|
13
10
|
import { toString, isStdlib } from "visitor-as/dist/utils.js";
|
|
14
11
|
import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
|
|
15
12
|
import { Transform } from "assemblyscript/dist/transform.js";
|
|
16
|
-
import { CommonFlags } from "types:assemblyscript/src/common";
|
|
17
13
|
|
|
18
|
-
class
|
|
14
|
+
class SchemaData {
|
|
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 {
|
|
19
27
|
public schemasList: SchemaData[] = [];
|
|
20
28
|
public currentClass!: SchemaData;
|
|
21
29
|
public sources = new Set<Source>();
|
|
22
30
|
|
|
23
31
|
visitMethodDeclaration(): void { }
|
|
24
32
|
visitClassDeclaration(node: ClassDeclaration): void {
|
|
33
|
+
const className = node.name.text;
|
|
25
34
|
if (!node.decorators?.length) return;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
let foundDecorator = false;
|
|
36
|
+
for (const decorator of node.decorators!) {
|
|
37
|
+
if (
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
decorator.name.text.toLowerCase() == "json" ||
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
decorator.name.text.toLowerCase() == "serializable"
|
|
42
|
+
)
|
|
43
|
+
foundDecorator = true;
|
|
35
44
|
}
|
|
36
|
-
if (!
|
|
37
|
-
|
|
38
|
-
const schema = new SchemaData();
|
|
39
|
-
schema.node = node;
|
|
40
|
-
schema.name = node.name.text;
|
|
41
|
-
|
|
42
|
-
const members = [
|
|
43
|
-
...node.members
|
|
44
|
-
];
|
|
45
|
+
if (!foundDecorator) return;
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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]!);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
47
|
+
// Prevent from being triggered twice.
|
|
48
|
+
for (const member of node.members) {
|
|
49
|
+
if (member.name.text == "__SERIALIZE") return;
|
|
59
50
|
}
|
|
60
51
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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;
|
|
52
|
+
this.currentClass = {
|
|
53
|
+
name: className,
|
|
54
|
+
keys: [],
|
|
55
|
+
values: [],
|
|
56
|
+
types: [],
|
|
57
|
+
parent: node.extendsType ? toString(node.extendsType) : "",
|
|
58
|
+
node: node,
|
|
59
|
+
encodeStmts: [],
|
|
60
|
+
setDataStmts: [],
|
|
61
|
+
initializeStmts: []
|
|
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]!);
|
|
93
73
|
}
|
|
94
74
|
}
|
|
75
|
+
}
|
|
95
76
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
}
|
|
77
|
+
const parentSchema = this.schemasList.find(
|
|
78
|
+
(v) => v.name == this.currentClass.parent
|
|
79
|
+
);
|
|
102
80
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
}
|
|
81
|
+
const members = [
|
|
82
|
+
...node.members
|
|
83
|
+
];
|
|
114
84
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
} else if (mem.value) {
|
|
119
|
-
mem.initialize = "this." + name.text + " = " + mem.value;
|
|
85
|
+
if (parentSchema) {
|
|
86
|
+
for (const mem of parentSchema.node.members) {
|
|
87
|
+
if (members.find(v => v.name === mem.name) == undefined) members.unshift(mem);
|
|
120
88
|
}
|
|
121
|
-
|
|
122
|
-
schema.members.push(mem);
|
|
123
89
|
}
|
|
124
90
|
|
|
125
|
-
|
|
126
|
-
|
|
91
|
+
for (const mem of members) {
|
|
92
|
+
// @ts-ignore
|
|
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)
|
|
127
97
|
|
|
128
|
-
|
|
98
|
+
if (!lineText.startsWith("private ") && !lineText.startsWith("static ")) {
|
|
129
99
|
|
|
130
|
-
|
|
131
|
-
|
|
100
|
+
// @ts-ignore
|
|
101
|
+
let type = toString(member.type);
|
|
132
102
|
|
|
133
|
-
|
|
103
|
+
const name = member.name.text;
|
|
104
|
+
let aliasName = name;
|
|
134
105
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
106
|
+
// @ts-ignore
|
|
107
|
+
if (member.decorators && member.decorators[0]?.name.text === "alias") {
|
|
108
|
+
if (member.decorators[0] && member.decorators[0].args![0]) {
|
|
109
|
+
// @ts-ignore
|
|
110
|
+
aliasName = member.decorators[0].args![0].value;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
this.currentClass.keys.push(name);
|
|
114
|
+
// @ts-ignore
|
|
115
|
+
this.currentClass.types.push(type);
|
|
116
|
+
// @ts-ignore
|
|
117
|
+
if (
|
|
118
|
+
[
|
|
119
|
+
"u8",
|
|
120
|
+
"i8",
|
|
121
|
+
"u16",
|
|
122
|
+
"i16",
|
|
123
|
+
"u32",
|
|
124
|
+
"i32",
|
|
125
|
+
"u64",
|
|
126
|
+
"i64",
|
|
127
|
+
].includes(type.toLowerCase())
|
|
128
|
+
) {
|
|
129
|
+
this.currentClass.encodeStmts.push(
|
|
130
|
+
`${encodeKey(aliasName)}:\${this.${name}},`
|
|
131
|
+
);
|
|
132
|
+
// @ts-ignore
|
|
133
|
+
this.currentClass.setDataStmts.push(
|
|
134
|
+
`if (key.equals(${JSON.stringify(aliasName)})) {
|
|
135
|
+
this.${name} = __atoi_fast<${type}>(data, val_start << 1, val_end << 1);
|
|
136
|
+
return;
|
|
137
|
+
}`
|
|
138
|
+
);
|
|
139
|
+
if (member.initializer) {
|
|
140
|
+
this.currentClass.initializeStmts.push(
|
|
141
|
+
`this.${name} = ${toString(member.initializer)}`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
} else // @ts-ignore
|
|
145
|
+
if (
|
|
146
|
+
[
|
|
147
|
+
"f32",
|
|
148
|
+
"f64",
|
|
149
|
+
].includes(type.toLowerCase())
|
|
150
|
+
) {
|
|
151
|
+
this.currentClass.encodeStmts.push(
|
|
152
|
+
`${encodeKey(aliasName)}:\${this.${name}},`
|
|
153
|
+
);
|
|
154
|
+
// @ts-ignore
|
|
155
|
+
this.currentClass.setDataStmts.push(
|
|
156
|
+
`if (key.equals(${JSON.stringify(aliasName)})) {
|
|
157
|
+
this.${name} = __parseObjectValue<${type}>(data.slice(val_start, val_end), initializeDefaultValues);
|
|
158
|
+
return;
|
|
159
|
+
}`
|
|
160
|
+
);
|
|
161
|
+
if (member.initializer) {
|
|
162
|
+
this.currentClass.initializeStmts.push(
|
|
163
|
+
`this.${name} = ${toString(member.initializer)}`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
this.currentClass.encodeStmts.push(
|
|
168
|
+
`${encodeKey(aliasName)}:\${__JSON_Stringify<${type}>(this.${name})},`
|
|
169
|
+
);
|
|
170
|
+
// @ts-ignore
|
|
171
|
+
this.currentClass.setDataStmts.push(
|
|
172
|
+
`if (key.equals(${JSON.stringify(aliasName)})) {
|
|
173
|
+
this.${name} = __parseObjectValue<${type}>(val_start ? data.slice(val_start, val_end) : data, initializeDefaultValues);
|
|
174
|
+
return;
|
|
175
|
+
}`
|
|
176
|
+
);
|
|
177
|
+
if (member.initializer) {
|
|
178
|
+
this.currentClass.initializeStmts.push(
|
|
179
|
+
`this.${name} = ${toString(member.initializer)}`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
164
184
|
}
|
|
165
185
|
}
|
|
166
186
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
187
|
+
let serializeFunc = "";
|
|
188
|
+
|
|
189
|
+
if (this.currentClass.encodeStmts.length > 0) {
|
|
190
|
+
const stmt =
|
|
191
|
+
this.currentClass.encodeStmts[
|
|
192
|
+
this.currentClass.encodeStmts.length - 1
|
|
193
|
+
]!;
|
|
194
|
+
this.currentClass.encodeStmts[this.currentClass.encodeStmts.length - 1] =
|
|
195
|
+
stmt!.slice(0, stmt.length - 1);
|
|
196
|
+
serializeFunc = `
|
|
197
|
+
__SERIALIZE(): string {
|
|
198
|
+
return \`{${this.currentClass.encodeStmts.join("")}}\`;
|
|
199
|
+
}`;
|
|
170
200
|
} else {
|
|
171
|
-
|
|
172
|
-
|
|
201
|
+
serializeFunc = `
|
|
202
|
+
__SERIALIZE(): string {
|
|
203
|
+
return "{}";
|
|
204
|
+
}`;
|
|
173
205
|
}
|
|
174
206
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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);
|
|
207
|
+
const setKeyFunc = `
|
|
208
|
+
__JSON_Set_Key(key: __Virtual<string>, data: string, val_start: i32, val_end: i32, initializeDefaultValues: boolean): void {
|
|
209
|
+
${this.currentClass.setDataStmts.join("\n ")}
|
|
191
210
|
}
|
|
192
|
-
|
|
211
|
+
`;
|
|
193
212
|
|
|
194
|
-
let
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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";
|
|
204
|
-
}
|
|
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`;
|
|
239
|
-
} else {
|
|
240
|
-
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + `else if (${charCodeAt64(name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
|
|
241
|
-
}
|
|
242
|
-
} else {
|
|
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`
|
|
246
|
-
} else {
|
|
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`
|
|
248
|
-
}
|
|
249
|
-
}
|
|
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`
|
|
213
|
+
let initializeFunc = "";
|
|
214
|
+
|
|
215
|
+
if (this.currentClass.initializeStmts.length > 0) {
|
|
216
|
+
initializeFunc = `
|
|
217
|
+
__JSON_Initialize(): void {
|
|
218
|
+
${this.currentClass.initializeStmts.join(";\n")};
|
|
257
219
|
}
|
|
258
|
-
|
|
220
|
+
`;
|
|
221
|
+
} else {
|
|
222
|
+
initializeFunc = `
|
|
223
|
+
__JSON_Initialize(): void {}
|
|
224
|
+
`;
|
|
259
225
|
}
|
|
226
|
+
const serializeMethod = SimpleParser.parseClassMember(serializeFunc, node);
|
|
227
|
+
node.members.push(serializeMethod);
|
|
260
228
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
//console.log(sortedMembers);
|
|
229
|
+
const setDataMethod = SimpleParser.parseClassMember(setKeyFunc, node);
|
|
230
|
+
node.members.push(setDataMethod);
|
|
264
231
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
//console.log(SERIALIZE_PRETTY);
|
|
268
|
-
console.log(INITIALIZE);
|
|
269
|
-
console.log(DESERIALIZE);
|
|
270
|
-
}
|
|
232
|
+
const initializeMethod = SimpleParser.parseClassMember(initializeFunc, node);
|
|
233
|
+
node.members.push(initializeMethod);
|
|
271
234
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
|
|
275
|
-
const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
|
|
235
|
+
this.schemasList.push(this.currentClass);
|
|
236
|
+
this.sources.add(node.name.range.source);
|
|
276
237
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
this.schemasList.push(schema);
|
|
238
|
+
// Uncomment to see the generated code for debugging.
|
|
239
|
+
//console.log(serializeFunc);
|
|
240
|
+
//console.log(setKeyFunc);
|
|
241
|
+
//console.log(initializeFunc);
|
|
282
242
|
}
|
|
243
|
+
|
|
283
244
|
visitSource(node: Source): void {
|
|
284
245
|
super.visitSource(node);
|
|
285
246
|
|
|
@@ -287,14 +248,35 @@ class JSONTransform extends BaseVisitor {
|
|
|
287
248
|
if (!this.sources.has(node)) {
|
|
288
249
|
return;
|
|
289
250
|
}
|
|
251
|
+
|
|
252
|
+
// Note, the following one liner would be easier, but it fails with an assertion error
|
|
253
|
+
// because as-virtual's SimpleParser doesn't set the parser.currentSource correctly.
|
|
254
|
+
//
|
|
255
|
+
// const stmt = SimpleParser.parseTopLevelStatement('import { Virtual as __Virtual } from "as-virtual/assembly";');
|
|
256
|
+
|
|
257
|
+
// ... So we have to do it the long way:
|
|
258
|
+
const txt = 'import { Virtual as __Virtual } from "as-virtual/assembly";'
|
|
259
|
+
const tokenizer = new Tokenizer(new Source(SourceKind.User, node.normalizedPath, txt));
|
|
260
|
+
const parser = new Parser();
|
|
261
|
+
parser.currentSource = tokenizer.source;
|
|
262
|
+
const stmt = parser.parseTopLevelStatement(tokenizer)!;
|
|
263
|
+
|
|
264
|
+
// Add the import statement to the top of the source.
|
|
265
|
+
node.statements.unshift(stmt);
|
|
290
266
|
}
|
|
291
267
|
}
|
|
292
268
|
|
|
269
|
+
function encodeKey(aliasName: string): string {
|
|
270
|
+
return JSON.stringify(aliasName)
|
|
271
|
+
.replace(/\\/g, "\\\\")
|
|
272
|
+
.replace(/\`/g, '\\`');
|
|
273
|
+
}
|
|
274
|
+
|
|
293
275
|
export default class Transformer extends Transform {
|
|
294
276
|
// Trigger the transform after parse.
|
|
295
277
|
afterParse(parser: Parser): void {
|
|
296
278
|
// Create new transform
|
|
297
|
-
const transformer = new
|
|
279
|
+
const transformer = new AsJSONTransform();
|
|
298
280
|
|
|
299
281
|
// Sort the sources so that user scripts are visited last
|
|
300
282
|
const sources = parser.sources
|
|
@@ -322,77 +304,9 @@ export default class Transformer extends Transform {
|
|
|
322
304
|
const schemas = transformer.schemasList;
|
|
323
305
|
for (const schema of schemas) {
|
|
324
306
|
if (schema.parent) {
|
|
325
|
-
const parent = schemas.find((v) => v.name === schema.parent
|
|
307
|
+
const parent = schemas.find((v) => v.name === schema.parent);
|
|
326
308
|
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.`);
|
|
327
309
|
}
|
|
328
310
|
}
|
|
329
311
|
}
|
|
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
312
|
}
|
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": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
|
|
8
|
+
"module": "es6" /* 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. */
|