json-as 0.9.23 → 0.9.24

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/CHANGELOG CHANGED
@@ -30,6 +30,7 @@ v0.9.19 - Fix arguments in @omitif declarations not working properly
30
30
  v0.9.20 - Strings were being received with quotes attached via the toString functionality. Removed that.
31
31
  v0.9.22 - Fix #89 and #93. Several bug fixes some severe such as ",null" being prepended when using @omit. Properly warn when a schema has fields that are not compatible with json
32
32
  v0.9.23 - Comment out SIMD-related code for now
33
+ v9.9.24 - Remove transform changes from previous release
33
34
 
34
35
  [UNRELEASED] v1.0.0
35
36
  - Allow nullable primitives
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  __| || __|| || | | ___ | _ || __|
4
4
  | | ||__ || | || | | ||___|| ||__ |
5
5
  |_____||_____||_____||_|___| |__|__||_____|
6
- v0.9.23
6
+ v0.9.24
7
7
  </pre>
8
8
  </h5>
9
9
 
@@ -1,8 +1,3 @@
1
- import { bs } from "../custom/bs";
2
- import { serializeBool, serializeBool_BS } from "../serialize/bool";
3
- import { serialize_simd_v1, serializeString, serializeString_BS } from "../serialize/string";
4
-
5
- const out = memory.data(65536);
6
1
 
7
2
  bench("UTF-16 to UTF-8", () => {
8
3
  blackbox<ArrayBuffer>(String.UTF8.encode(blackbox<string>("hello world")));
@@ -1,4 +1,3 @@
1
- import { bs } from "../custom/bs";
2
1
  import {
3
2
  CHAR_B,
4
3
  BACK_SLASH,
@@ -4,19 +4,7 @@
4
4
  * @returns string
5
5
  */
6
6
 
7
- import { bs } from "../custom/bs";
8
-
9
7
  // @ts-ignore: Decorator valid here
10
8
  @inline export function serializeBool(data: bool): string {
11
9
  return data ? "true" : "false";
12
- }
13
-
14
- @inline export function serializeBool_BS(data: bool): void {
15
- if (data === true) {
16
- bs.write_64(28429475166421108); /* true */
17
- } else {
18
- //bs.write_128_n(i16x8(102, 97, 108, 115, 101, 0, 0, 0), 10);
19
- bs.write_64(32370086184550502); /* fals */
20
- bs.write_16(101); /* e */
21
- }
22
10
  }
@@ -1,14 +1,3 @@
1
- import {
2
- BACK_SLASH,
3
- BACKSPACE,
4
- CARRIAGE_RETURN,
5
- FORM_FEED,
6
- NEW_LINE,
7
- QUOTE,
8
- TAB
9
- } from "../custom/chars";
10
- import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
11
- import { bs } from "../custom/bs";
12
1
  import { _intTo16, intTo16, unsafeCharCodeAt } from "../custom/util";
13
2
  import { Sink } from "../custom/sink";
14
3
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "0.9.23",
3
+ "version": "0.9.24",
4
4
  "description": "The only JSON library you'll need for AssemblyScript. SIMD enabled",
5
5
  "types": "assembly/index.ts",
6
6
  "author": "Jairus Tanaka",
@@ -44,6 +44,7 @@
44
44
  "visitor-as": "^0.11.4"
45
45
  },
46
46
  "dependencies": {
47
+ "@hypermode/modus-sdk-as": "^0.13.0-prerelease-test-1",
47
48
  "as-virtual": "^0.2.0",
48
49
  "chalk": "^5.3.0"
49
50
  },
@@ -1,76 +1,74 @@
1
- import { FieldDeclaration, IdentifierExpression, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, NamedTypeNode } from "assemblyscript/dist/assemblyscript.js";
1
+ import { FieldDeclaration, IdentifierExpression, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, } 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"];
7
5
  class JSONTransform extends BaseVisitor {
8
- types = json_types;
9
6
  schemasList = [];
10
7
  currentClass;
11
8
  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"));
51
- }
9
+ visitMethodDeclaration() { }
52
10
  visitClassDeclaration(node) {
53
11
  if (!node.decorators?.length)
54
12
  return;
55
- if (!node.decorators.find((v) => v.name.text == "json" || v.name.text == "serializable"))
13
+ let found = false;
14
+ for (const decorator of node.decorators) {
15
+ const name = decorator.name.text;
16
+ if (name === "json" || name === "serializable") {
17
+ found = true;
18
+ break;
19
+ }
20
+ }
21
+ if (!found)
56
22
  return;
57
- this.types = json_types;
58
23
  const schema = new SchemaData();
59
24
  schema.node = node;
60
25
  schema.name = node.name.text;
26
+ const members = [
27
+ ...node.members.filter((v) => v.kind === 54 /* NodeKind.FieldDeclaration */),
28
+ ];
61
29
  if (node.extendsType) {
62
30
  schema.parent = this.schemasList.find((v) => v.name == node.extendsType?.name.identifier.text);
31
+ if (schema.parent?.members) {
32
+ for (let i = schema.parent.members.length - 1; i >= 0; i--) {
33
+ const replace = schema.members.find((v) => v.name == schema.parent?.members[i]?.name);
34
+ if (!replace) {
35
+ members.unshift(schema.parent?.members[i].node);
36
+ }
37
+ }
38
+ }
63
39
  }
64
- const _members = [...node.members];
65
- this.appendParentFields(node, schema, _members);
66
- const members = this.filterMembers(_members);
67
40
  if (!members.length) {
68
- this.handleEmptyClass(node, schema, members);
41
+ let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}';
42
+ //let SERIALIZE_PRETTY_EMPTY = "__SERIALIZE_PRETTY(): string {\n return \"{}\";\n}";
43
+ let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}";
44
+ let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}";
45
+ if (process.env["JSON_DEBUG"]) {
46
+ console.log(SERIALIZE_RAW_EMPTY);
47
+ //console.log(SERIALIZE_PRETTY_EMPTY);
48
+ console.log(INITIALIZE_EMPTY);
49
+ console.log(DESERIALIZE_EMPTY);
50
+ }
51
+ const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node);
52
+ //const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
53
+ const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node);
54
+ const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node);
55
+ if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
56
+ node.members.push(SERIALIZE_RAW_METHOD_EMPTY);
57
+ if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
58
+ node.members.push(INITIALIZE_METHOD_EMPTY);
59
+ if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
60
+ node.members.push(DESERIALIZE_METHOD_EMPTY);
61
+ this.schemasList.push(schema);
69
62
  }
70
63
  for (const member of members) {
71
64
  const name = member.name;
65
+ if (!(member instanceof FieldDeclaration))
66
+ continue;
72
67
  if (!member.type) {
73
- throw new Error("Fields must be strongly typed! Found " + toString(member) + " at " + node.range.source.normalizedPath);
68
+ throw new Error("Fields must be strongly typed! Found " +
69
+ toString(member) +
70
+ " at " +
71
+ node.range.source.normalizedPath);
74
72
  }
75
73
  const type = toString(member.type);
76
74
  if (type.startsWith("(") && type.includes("=>"))
@@ -100,7 +98,8 @@ class JSONTransform extends BaseVisitor {
100
98
  switch (decoratorName) {
101
99
  case "alias": {
102
100
  if (!args.length)
103
- throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath);
101
+ throw new Error("Expected 1 argument but got zero at @alias in " +
102
+ node.range.source.normalizedPath);
104
103
  mem.alias = args[0];
105
104
  mem.flags.set(PropertyFlags.Alias, args);
106
105
  break;
@@ -111,7 +110,8 @@ class JSONTransform extends BaseVisitor {
111
110
  }
112
111
  case "omitif": {
113
112
  if (!decorator.args?.length)
114
- throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath);
113
+ throw new Error("Expected 1 argument but got zero at @omitif in " +
114
+ node.range.source.normalizedPath);
115
115
  mem.flags.set(PropertyFlags.OmitIf, args);
116
116
  break;
117
117
  }
@@ -122,10 +122,22 @@ class JSONTransform extends BaseVisitor {
122
122
  }
123
123
  }
124
124
  }
125
- if (!mem.flags.get(PropertyFlags.Omit))
126
- mem.generate();
125
+ mem.generate();
127
126
  if (this.schemasList.find((v) => v.name == type)) {
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()";
127
+ mem.initialize =
128
+ "this." +
129
+ name.text +
130
+ " = changetype<nonnull<" +
131
+ mem.type +
132
+ ">>(__new(offsetof<nonnull<" +
133
+ mem.type +
134
+ ">>(), idof<nonnull<" +
135
+ mem.type +
136
+ ">>()));\n changetype<nonnull<" +
137
+ mem.type +
138
+ ">>(this." +
139
+ name.text +
140
+ ").__INITIALIZE()";
129
141
  }
130
142
  else if (mem.value) {
131
143
  mem.initialize = "this." + name.text + " = " + mem.value;
@@ -137,7 +149,8 @@ class JSONTransform extends BaseVisitor {
137
149
  mem.initialize = "this." + name.text + ' = ""';
138
150
  }
139
151
  else if (type === "Array") {
140
- mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()";
152
+ mem.initialize =
153
+ "this." + name.text + " = instantiate<" + mem.type + ">()";
141
154
  }
142
155
  else if (type === "bool" || type === "boolean") {
143
156
  mem.initialize = "this." + name.text + " = false";
@@ -145,7 +158,14 @@ class JSONTransform extends BaseVisitor {
145
158
  else if (type === "JSON.Raw") {
146
159
  mem.initialize = "this." + name.text + ' = ""';
147
160
  }
148
- else if (type === "u8" || type === "u16" || type === "u32" || type === "u64" || type === "i8" || type === "i16" || type === "i32" || type === "i64") {
161
+ else if (type === "u8" ||
162
+ type === "u16" ||
163
+ type === "u32" ||
164
+ type === "u64" ||
165
+ type === "i8" ||
166
+ type === "i16" ||
167
+ type === "i32" ||
168
+ type === "i64") {
149
169
  mem.initialize = "this." + name.text + " = 0";
150
170
  }
151
171
  else if (type === "f32" || type === "f64") {
@@ -160,14 +180,15 @@ class JSONTransform extends BaseVisitor {
160
180
  let indent = " ";
161
181
  if (!schema.members.length)
162
182
  return;
163
- let found = false;
164
- if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) || schema.members[0]?.flags.has(PropertyFlags.OmitIf)) {
183
+ found = false;
184
+ if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) ||
185
+ schema.members[0]?.flags.has(PropertyFlags.OmitIf)) {
165
186
  SERIALIZE_RAW += schema.members[0]?.serialize;
166
- SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty;
187
+ SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize;
167
188
  }
168
189
  else {
169
190
  SERIALIZE_RAW += schema.members[0]?.serialize + ",";
170
- SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty + ",\\n";
191
+ SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize + ",\\n";
171
192
  found = true;
172
193
  }
173
194
  if (schema.members[0]?.initialize)
@@ -176,21 +197,22 @@ class JSONTransform extends BaseVisitor {
176
197
  const member = schema.members[i];
177
198
  if (member.initialize)
178
199
  INITIALIZE += " " + member.initialize + ";\n";
179
- if (member.flags.has(PropertyFlags.Omit))
180
- continue;
181
- if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) {
200
+ if (member.flags.has(PropertyFlags.OmitNull) ||
201
+ member.flags.has(PropertyFlags.OmitIf)) {
182
202
  SERIALIZE_RAW += member.serialize;
183
- SERIALIZE_PRETTY += member.serialize_pretty;
203
+ SERIALIZE_PRETTY += member.serialize;
184
204
  }
185
205
  else {
186
206
  SERIALIZE_RAW += member.serialize + ",";
187
- SERIALIZE_PRETTY += indent + member.serialize_pretty + ",\\n";
207
+ SERIALIZE_PRETTY += indent + member.serialize + ",\\n";
188
208
  found = true;
189
209
  }
190
210
  }
191
211
  if (found) {
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}";
212
+ SERIALIZE_RAW +=
213
+ "`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}";
214
+ SERIALIZE_PRETTY +=
215
+ "`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}";
194
216
  }
195
217
  else {
196
218
  SERIALIZE_RAW += "}`;\n return out;\n}";
@@ -219,29 +241,35 @@ class JSONTransform extends BaseVisitor {
219
241
  const _name = encodeKey(firstMember.alias || firstMember.name);
220
242
  if (_name.length === 1) {
221
243
  if (first) {
222
- DESERIALIZE += " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
244
+ DESERIALIZE +=
245
+ " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
223
246
  first = false;
224
247
  }
225
248
  else {
226
- DESERIALIZE += "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
249
+ DESERIALIZE +=
250
+ "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
227
251
  }
228
252
  }
229
253
  else if (_name.length === 2) {
230
254
  if (first) {
231
- DESERIALIZE += " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
255
+ DESERIALIZE +=
256
+ " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
232
257
  first = false;
233
258
  }
234
259
  else {
235
- DESERIALIZE += "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
260
+ DESERIALIZE +=
261
+ "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
236
262
  }
237
263
  }
238
264
  else if (_name.length === 4) {
239
265
  if (first) {
240
- DESERIALIZE += " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
266
+ DESERIALIZE +=
267
+ " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
241
268
  first = false;
242
269
  }
243
270
  else {
244
- DESERIALIZE += "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
271
+ DESERIALIZE +=
272
+ "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
245
273
  }
246
274
  }
247
275
  else {
@@ -271,7 +299,9 @@ class JSONTransform extends BaseVisitor {
271
299
  DESERIALIZE += ` if (${charCodeAt64(_name, 0)} === code) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
272
300
  }
273
301
  else {
274
- DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + `else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
302
+ DESERIALIZE =
303
+ DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
304
+ `else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
275
305
  }
276
306
  }
277
307
  else {
@@ -280,7 +310,9 @@ class JSONTransform extends BaseVisitor {
280
310
  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`;
281
311
  }
282
312
  else {
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`;
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})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
284
316
  }
285
317
  }
286
318
  }
@@ -288,10 +320,14 @@ class JSONTransform extends BaseVisitor {
288
320
  DESERIALIZE += ` default: {\n return false;\n }\n }\n`;
289
321
  }
290
322
  else if (_name.length == 4) {
291
- DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
323
+ DESERIALIZE =
324
+ DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
325
+ ` else {\n return false;\n }\n`;
292
326
  }
293
327
  else {
294
- DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
328
+ DESERIALIZE =
329
+ DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
330
+ ` else {\n return false;\n }\n`;
295
331
  }
296
332
  DESERIALIZE += " } ";
297
333
  }
@@ -299,18 +335,16 @@ class JSONTransform extends BaseVisitor {
299
335
  //console.log(sortedMembers);
300
336
  if (process.env["JSON_DEBUG"]) {
301
337
  console.log(SERIALIZE_RAW);
302
- console.log(SERIALIZE_PRETTY);
338
+ //console.log(SERIALIZE_PRETTY);
303
339
  console.log(INITIALIZE);
304
340
  console.log(DESERIALIZE);
305
341
  }
306
342
  const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(SERIALIZE_RAW, node);
307
- const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
343
+ //const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
308
344
  const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
309
345
  const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
310
346
  if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
311
347
  node.members.push(SERIALIZE_RAW_METHOD);
312
- if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY"))
313
- node.members.push(SERIALIZE_PRETTY_METHOD);
314
348
  if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
315
349
  node.members.push(INITIALIZE_METHOD);
316
350
  if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
@@ -336,13 +370,15 @@ export default class Transformer extends Transform {
336
370
  .sort((_a, _b) => {
337
371
  const a = _a.internalPath;
338
372
  const b = _b.internalPath;
339
- if (a[0] !== "~" && b[0] === "~") {
340
- return 1;
341
- }
342
373
  if (a[0] === "~" && b[0] !== "~") {
343
374
  return -1;
344
375
  }
345
- return 0;
376
+ else if (a[0] !== "~" && b[0] === "~") {
377
+ return 1;
378
+ }
379
+ else {
380
+ return 0;
381
+ }
346
382
  });
347
383
  // Loop over every source
348
384
  for (const source of sources) {
@@ -354,70 +390,14 @@ export default class Transformer extends Transform {
354
390
  // Check that every parent and child class is hooked up correctly
355
391
  const schemas = transformer.schemasList;
356
392
  for (const schema of schemas) {
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!`);
393
+ if (schema.parent) {
394
+ const parent = schemas.find((v) => v.name === schema.parent?.name);
395
+ if (!parent)
396
+ 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.`);
361
397
  }
362
398
  }
363
399
  }
364
400
  }
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
- }
421
401
  var PropertyFlags;
422
402
  (function (PropertyFlags) {
423
403
  PropertyFlags[PropertyFlags["Null"] = 0] = "Null";
@@ -434,7 +414,6 @@ class Property {
434
414
  value = null;
435
415
  flags = new Map();
436
416
  serialize = null;
437
- serialize_pretty = null;
438
417
  deserialize = null;
439
418
  initialize = null;
440
419
  node;
@@ -448,7 +427,7 @@ class Property {
448
427
  return;
449
428
  if (this.flags.has(PropertyFlags.JSON_Raw)) {
450
429
  if (this.flags.has(PropertyFlags.Null)) {
451
- this.right_s = "(this." + name + ' || "null")';
430
+ this.right_s = "(this." + name + " || \"null\")";
452
431
  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
432
  }
454
433
  else {
@@ -458,24 +437,37 @@ class Property {
458
437
  }
459
438
  else {
460
439
  this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")";
461
- this.right_d = "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
440
+ this.right_d =
441
+ "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
462
442
  }
463
443
  if (this.flags.has(PropertyFlags.OmitIf)) {
464
444
  const condition = this.flags.get(PropertyFlags.OmitIf)[0];
465
445
  if (!condition)
466
446
  throw new Error("Could not find condition when using decorator @omitif! Provide at least one condition");
467
- this.serialize = "${" + condition + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}';
468
- this.serialize_pretty = "${" + condition + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}';
447
+ this.serialize =
448
+ "${" +
449
+ condition +
450
+ ' ? "" : \'' +
451
+ escapedName +
452
+ ":' + " +
453
+ this.right_s +
454
+ ' + ","}';
469
455
  this.deserialize = "this." + name + " = " + this.right_d + ";";
470
456
  }
471
457
  else if (this.flags.has(PropertyFlags.OmitNull)) {
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 + ' + ","}';
458
+ this.serialize =
459
+ "${changetype<usize>(this." +
460
+ name +
461
+ ") == <usize>0" +
462
+ ' ? "" : \'' +
463
+ escapedName +
464
+ ":' + " +
465
+ this.right_s +
466
+ ' + ","}';
474
467
  this.deserialize = "this." + name + " = " + this.right_d + ";";
475
468
  }
476
469
  else {
477
470
  this.serialize = escapedName + ":${" + this.right_s + "}";
478
- this.serialize_pretty = escapedName + ": ${" + this.right_s + "}";
479
471
  this.deserialize = "this." + name + " = " + this.right_d + ";";
480
472
  }
481
473
  }
@@ -497,7 +489,10 @@ function charCodeAt64(data, offset) {
497
489
  const secondCharCode = BigInt(data.charCodeAt(offset + 1));
498
490
  const thirdCharCode = BigInt(data.charCodeAt(offset + 2));
499
491
  const fourthCharCode = BigInt(data.charCodeAt(offset + 3));
500
- const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode;
492
+ const u64Value = (fourthCharCode << 48n) |
493
+ (thirdCharCode << 32n) |
494
+ (secondCharCode << 16n) |
495
+ firstCharCode;
501
496
  return u64Value;
502
497
  }
503
498
  function encodeKey(key) {
@@ -542,7 +537,3 @@ function getArgs(args) {
542
537
  }
543
538
  return out;
544
539
  }
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
- }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@json-as/transform",
3
- "version": "0.9.23",
3
+ "version": "0.9.24",
4
4
  "description": "The only JSON library you'll need for AssemblyScript. SIMD enabled",
5
5
  "main": "./lib/index.js",
6
6
  "author": "Jairus Tanaka",
@@ -1,89 +1,119 @@
1
- import { ClassDeclaration, FieldDeclaration, IdentifierExpression, Parser, Source, Expression, CommonFlags, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, DeclarationStatement, NamedTypeNode } from "assemblyscript/dist/assemblyscript.js";
1
+ import {
2
+ ClassDeclaration,
3
+ FieldDeclaration,
4
+ IdentifierExpression,
5
+ Parser,
6
+ Source,
7
+ NodeKind,
8
+ Expression,
9
+ CommonFlags,
10
+ StringLiteralExpression,
11
+ IntegerLiteralExpression,
12
+ FloatLiteralExpression,
13
+ NullExpression,
14
+ TrueExpression,
15
+ FalseExpression,
16
+ } from "assemblyscript/dist/assemblyscript.js";
2
17
 
3
18
  import { toString, isStdlib } from "visitor-as/dist/utils.js";
4
19
  import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
5
20
  import { Transform } from "assemblyscript/dist/transform.js";
6
- import chalk from "chalk";
7
-
8
- const json_types = ["Array", "string", "String", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean", "Map", "Date"];
9
21
 
10
22
  class JSONTransform extends BaseVisitor {
11
- public types = json_types;
12
23
  public schemasList: SchemaData[] = [];
13
24
  public currentClass!: SchemaData;
14
25
  public sources = new Set<Source>();
15
26
 
16
- appendParentFields(node: ClassDeclaration, schema: SchemaData, members: DeclarationStatement[]): void {
27
+ visitMethodDeclaration(): void { }
28
+ visitClassDeclaration(node: ClassDeclaration): void {
29
+ if (!node.decorators?.length) return;
30
+
31
+ let found = false;
32
+ for (const decorator of node.decorators) {
33
+ const name = (<IdentifierExpression>decorator.name).text;
34
+ if (name === "json" || name === "serializable") {
35
+ found = true;
36
+ break;
37
+ }
38
+ }
39
+ if (!found) return;
40
+
41
+ const schema = new SchemaData();
42
+ schema.node = node;
43
+ schema.name = node.name.text;
44
+
45
+ const members = [
46
+ ...node.members.filter((v) => v.kind === NodeKind.FieldDeclaration),
47
+ ];
48
+
17
49
  if (node.extendsType) {
50
+ schema.parent = this.schemasList.find(
51
+ (v) => v.name == node.extendsType?.name.identifier.text,
52
+ ) as SchemaData | null;
53
+
18
54
  if (schema.parent?.members) {
19
55
  for (let i = schema.parent.members.length - 1; i >= 0; i--) {
20
- const replace = schema.members.find((v) => v.name == schema.parent?.members[i]?.name);
56
+ const replace = schema.members.find(
57
+ (v) => v.name == schema.parent?.members[i]?.name,
58
+ );
21
59
  if (!replace) {
22
60
  members.unshift(schema.parent?.members[i]!.node);
23
61
  }
24
62
  }
25
- this.appendParentFields(schema.parent.node, schema, members);
26
63
  }
27
64
  }
28
- }
29
-
30
- handleEmptyClass(node: ClassDeclaration, schema: SchemaData, members: DeclarationStatement[]): void {
31
- let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}';
32
- let SERIALIZE_PRETTY_EMPTY = '__SERIALIZE_PRETTY(): string {\n return "{}";\n}';
33
-
34
- let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}";
35
-
36
- let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}";
37
-
38
- if (process.env["JSON_DEBUG"]) {
39
- console.log(SERIALIZE_RAW_EMPTY);
40
- console.log(SERIALIZE_PRETTY_EMPTY);
41
- console.log(INITIALIZE_EMPTY);
42
- console.log(DESERIALIZE_EMPTY);
43
- }
44
-
45
- const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node);
46
- const SERIALIZE_PRETTY_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_PRETTY_EMPTY, node);
47
- const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node);
48
- const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node);
49
-
50
- if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_RAW_METHOD_EMPTY);
51
- if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY")) node.members.push(SERIALIZE_PRETTY_METHOD_EMPTY);
52
- if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD_EMPTY);
53
- if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD_EMPTY);
54
- }
55
- filterMembers(members: DeclarationStatement[]): FieldDeclaration[] {
56
- return members.filter((v) => v instanceof FieldDeclaration && !v.decorators?.find((v) => (<IdentifierExpression>v.name).text == "omit")) as FieldDeclaration[];
57
- }
58
- visitClassDeclaration(node: ClassDeclaration): void {
59
- if (!node.decorators?.length) return;
60
- if (!node.decorators.find((v) => (<IdentifierExpression>v.name).text == "json" || (<IdentifierExpression>v.name).text == "serializable")) return;
61
- this.types = json_types;
62
-
63
- const schema = new SchemaData();
64
- schema.node = node;
65
- schema.name = node.name.text;
66
65
 
67
- if (node.extendsType) {
68
- schema.parent = this.schemasList.find((v) => v.name == node.extendsType?.name.identifier.text) as SchemaData | null;
69
- }
66
+ if (!members.length) {
67
+ let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}';
68
+ //let SERIALIZE_PRETTY_EMPTY = "__SERIALIZE_PRETTY(): string {\n return \"{}\";\n}";
70
69
 
71
- const _members = [...node.members];
70
+ let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}";
72
71
 
73
- this.appendParentFields(node, schema, _members);
72
+ let DESERIALIZE_EMPTY =
73
+ "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}";
74
74
 
75
- const members = this.filterMembers(_members);
75
+ if (process.env["JSON_DEBUG"]) {
76
+ console.log(SERIALIZE_RAW_EMPTY);
77
+ //console.log(SERIALIZE_PRETTY_EMPTY);
78
+ console.log(INITIALIZE_EMPTY);
79
+ console.log(DESERIALIZE_EMPTY);
80
+ }
76
81
 
77
- if (!members.length) {
78
- this.handleEmptyClass(node, schema, members);
82
+ const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(
83
+ SERIALIZE_RAW_EMPTY,
84
+ node,
85
+ );
86
+ //const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
87
+ const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(
88
+ INITIALIZE_EMPTY,
89
+ node,
90
+ );
91
+ const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(
92
+ DESERIALIZE_EMPTY,
93
+ node,
94
+ );
95
+
96
+ if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
97
+ node.members.push(SERIALIZE_RAW_METHOD_EMPTY);
98
+ if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
99
+ node.members.push(INITIALIZE_METHOD_EMPTY);
100
+ if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
101
+ node.members.push(DESERIALIZE_METHOD_EMPTY);
102
+
103
+ this.schemasList.push(schema);
79
104
  }
80
105
 
81
106
  for (const member of members) {
82
107
  const name = member.name;
108
+ if (!(member instanceof FieldDeclaration)) continue;
83
109
  if (!member.type) {
84
- throw new Error("Fields must be strongly typed! Found " + toString(member) + " at " + node.range.source.normalizedPath);
110
+ throw new Error(
111
+ "Fields must be strongly typed! Found " +
112
+ toString(member) +
113
+ " at " +
114
+ node.range.source.normalizedPath,
115
+ );
85
116
  }
86
-
87
117
  const type = toString(member.type!);
88
118
  if (type.startsWith("(") && type.includes("=>")) continue;
89
119
  const value = member.initializer ? toString(member.initializer!) : null;
@@ -114,7 +144,11 @@ class JSONTransform extends BaseVisitor {
114
144
 
115
145
  switch (decoratorName) {
116
146
  case "alias": {
117
- if (!args.length) throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath);
147
+ if (!args.length)
148
+ throw new Error(
149
+ "Expected 1 argument but got zero at @alias in " +
150
+ node.range.source.normalizedPath,
151
+ );
118
152
  mem.alias = args[0]!;
119
153
  mem.flags.set(PropertyFlags.Alias, args);
120
154
  break;
@@ -124,7 +158,11 @@ class JSONTransform extends BaseVisitor {
124
158
  break;
125
159
  }
126
160
  case "omitif": {
127
- if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath);
161
+ if (!decorator.args?.length)
162
+ throw new Error(
163
+ "Expected 1 argument but got zero at @omitif in " +
164
+ node.range.source.normalizedPath,
165
+ );
128
166
  mem.flags.set(PropertyFlags.OmitIf, args);
129
167
  break;
130
168
  }
@@ -136,10 +174,23 @@ class JSONTransform extends BaseVisitor {
136
174
  }
137
175
  }
138
176
 
139
- if (!mem.flags.get(PropertyFlags.Omit)) mem.generate();
177
+ mem.generate();
140
178
 
141
179
  if (this.schemasList.find((v) => v.name == type)) {
142
- 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()";
180
+ mem.initialize =
181
+ "this." +
182
+ name.text +
183
+ " = changetype<nonnull<" +
184
+ mem.type +
185
+ ">>(__new(offsetof<nonnull<" +
186
+ mem.type +
187
+ ">>(), idof<nonnull<" +
188
+ mem.type +
189
+ ">>()));\n changetype<nonnull<" +
190
+ mem.type +
191
+ ">>(this." +
192
+ name.text +
193
+ ").__INITIALIZE()";
143
194
  } else if (mem.value) {
144
195
  mem.initialize = "this." + name.text + " = " + mem.value;
145
196
  } else if (type === "Map") {
@@ -147,12 +198,22 @@ class JSONTransform extends BaseVisitor {
147
198
  } else if (type === "string") {
148
199
  mem.initialize = "this." + name.text + ' = ""';
149
200
  } else if (type === "Array") {
150
- mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()";
201
+ mem.initialize =
202
+ "this." + name.text + " = instantiate<" + mem.type + ">()";
151
203
  } else if (type === "bool" || type === "boolean") {
152
204
  mem.initialize = "this." + name.text + " = false";
153
205
  } else if (type === "JSON.Raw") {
154
206
  mem.initialize = "this." + name.text + ' = ""';
155
- } else if (type === "u8" || type === "u16" || type === "u32" || type === "u64" || type === "i8" || type === "i16" || type === "i32" || type === "i64") {
207
+ } else if (
208
+ type === "u8" ||
209
+ type === "u16" ||
210
+ type === "u32" ||
211
+ type === "u64" ||
212
+ type === "i8" ||
213
+ type === "i16" ||
214
+ type === "i32" ||
215
+ type === "i64"
216
+ ) {
156
217
  mem.initialize = "this." + name.text + " = 0";
157
218
  } else if (type === "f32" || type === "f64") {
158
219
  mem.initialize = "this." + name.text + " = 0.0";
@@ -166,41 +227,50 @@ class JSONTransform extends BaseVisitor {
166
227
 
167
228
  let INITIALIZE = "__INITIALIZE(): this {\n";
168
229
 
169
- let DESERIALIZE = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n const len = key_end - key_start;\n";
230
+ let DESERIALIZE =
231
+ "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n const len = key_end - key_start;\n";
170
232
  let indent = " ";
171
233
 
172
234
  if (!schema.members.length) return;
173
235
 
174
- let found = false;
236
+ found = false;
175
237
 
176
- if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) || schema.members[0]?.flags.has(PropertyFlags.OmitIf)) {
238
+ if (
239
+ schema.members[0]?.flags.has(PropertyFlags.OmitNull) ||
240
+ schema.members[0]?.flags.has(PropertyFlags.OmitIf)
241
+ ) {
177
242
  SERIALIZE_RAW += schema.members[0]?.serialize;
178
- SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty;
243
+ SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize;
179
244
  } else {
180
245
  SERIALIZE_RAW += schema.members[0]?.serialize + ",";
181
- SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty + ",\\n";
246
+ SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize + ",\\n";
182
247
  found = true;
183
248
  }
184
249
 
185
- if (schema.members[0]?.initialize) INITIALIZE += " " + schema.members[0]?.initialize + ";\n";
250
+ if (schema.members[0]?.initialize)
251
+ INITIALIZE += " " + schema.members[0]?.initialize + ";\n";
186
252
 
187
253
  for (let i = 1; i < schema.members.length; i++) {
188
254
  const member = schema.members[i]!;
189
255
  if (member.initialize) INITIALIZE += " " + member.initialize + ";\n";
190
- if (member.flags.has(PropertyFlags.Omit)) continue;
191
- if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) {
256
+ if (
257
+ member.flags.has(PropertyFlags.OmitNull) ||
258
+ member.flags.has(PropertyFlags.OmitIf)
259
+ ) {
192
260
  SERIALIZE_RAW += member.serialize;
193
- SERIALIZE_PRETTY += member.serialize_pretty;
261
+ SERIALIZE_PRETTY += member.serialize;
194
262
  } else {
195
263
  SERIALIZE_RAW += member.serialize + ",";
196
- SERIALIZE_PRETTY += indent + member.serialize_pretty + ",\\n";
264
+ SERIALIZE_PRETTY += indent + member.serialize + ",\\n";
197
265
  found = true;
198
266
  }
199
267
  }
200
268
 
201
269
  if (found) {
202
- SERIALIZE_RAW += "`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}";
203
- SERIALIZE_PRETTY += "`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}";
270
+ SERIALIZE_RAW +=
271
+ "`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}";
272
+ SERIALIZE_PRETTY +=
273
+ "`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}";
204
274
  } else {
205
275
  SERIALIZE_RAW += "}`;\n return out;\n}";
206
276
  SERIALIZE_PRETTY += "}`;\n return out;\n}";
@@ -209,7 +279,9 @@ class JSONTransform extends BaseVisitor {
209
279
  INITIALIZE += " return this;\n}";
210
280
 
211
281
  const sortedMembers: Property[][] = [];
212
- const _sorted = schema.members.sort((a, b) => (a.alias?.length! || a.name.length) - (b.alias?.length! || b.name.length));
282
+ const _sorted = schema.members.sort(
283
+ (a, b) => (a.alias?.length! || a.name.length) - (b.alias?.length! || b.name.length),
284
+ );
213
285
  let len = -1;
214
286
  let offset = -1;
215
287
  for (let i = 0; i < _sorted.length; i++) {
@@ -230,24 +302,30 @@ class JSONTransform extends BaseVisitor {
230
302
  const _name = encodeKey(firstMember.alias || firstMember.name);
231
303
  if (_name.length === 1) {
232
304
  if (first) {
233
- DESERIALIZE += " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
305
+ DESERIALIZE +=
306
+ " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
234
307
  first = false;
235
308
  } else {
236
- DESERIALIZE += "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
309
+ DESERIALIZE +=
310
+ "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
237
311
  }
238
312
  } else if (_name.length === 2) {
239
313
  if (first) {
240
- DESERIALIZE += " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
314
+ DESERIALIZE +=
315
+ " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
241
316
  first = false;
242
317
  } else {
243
- DESERIALIZE += "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
318
+ DESERIALIZE +=
319
+ "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
244
320
  }
245
321
  } else if (_name.length === 4) {
246
322
  if (first) {
247
- DESERIALIZE += " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
323
+ DESERIALIZE +=
324
+ " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
248
325
  first = false;
249
326
  } else {
250
- DESERIALIZE += "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
327
+ DESERIALIZE +=
328
+ "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
251
329
  }
252
330
  } else {
253
331
  if (first) {
@@ -271,23 +349,31 @@ class JSONTransform extends BaseVisitor {
271
349
  f = false;
272
350
  DESERIALIZE += ` if (${charCodeAt64(_name, 0)} === code) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
273
351
  } else {
274
- DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + `else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
352
+ DESERIALIZE =
353
+ DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
354
+ `else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
275
355
  }
276
356
  } else {
277
357
  if (f) {
278
358
  f = false;
279
359
  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`;
280
360
  } else {
281
- 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`;
361
+ DESERIALIZE =
362
+ DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
363
+ ` 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`;
282
364
  }
283
365
  }
284
366
  }
285
367
  if (_name.length < 3) {
286
368
  DESERIALIZE += ` default: {\n return false;\n }\n }\n`;
287
369
  } else if (_name.length == 4) {
288
- DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
370
+ DESERIALIZE =
371
+ DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
372
+ ` else {\n return false;\n }\n`;
289
373
  } else {
290
- DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
374
+ DESERIALIZE =
375
+ DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
376
+ ` else {\n return false;\n }\n`;
291
377
  }
292
378
  DESERIALIZE += " } ";
293
379
  }
@@ -298,20 +384,25 @@ class JSONTransform extends BaseVisitor {
298
384
 
299
385
  if (process.env["JSON_DEBUG"]) {
300
386
  console.log(SERIALIZE_RAW);
301
- console.log(SERIALIZE_PRETTY);
387
+ //console.log(SERIALIZE_PRETTY);
302
388
  console.log(INITIALIZE);
303
389
  console.log(DESERIALIZE);
304
390
  }
305
391
 
306
- const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(SERIALIZE_RAW, node);
307
- const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
392
+ const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(
393
+ SERIALIZE_RAW,
394
+ node,
395
+ );
396
+ //const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
308
397
  const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
309
398
  const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
310
399
 
311
- if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_RAW_METHOD);
312
- if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY")) node.members.push(SERIALIZE_PRETTY_METHOD);
313
- if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD);
314
- if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD);
400
+ if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
401
+ node.members.push(SERIALIZE_RAW_METHOD);
402
+ if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
403
+ node.members.push(INITIALIZE_METHOD);
404
+ if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
405
+ node.members.push(DESERIALIZE_METHOD);
315
406
 
316
407
  this.schemasList.push(schema);
317
408
  }
@@ -337,13 +428,13 @@ export default class Transformer extends Transform {
337
428
  .sort((_a, _b) => {
338
429
  const a = _a.internalPath;
339
430
  const b = _b.internalPath;
340
- if (a[0] !== "~" && b[0] === "~") {
341
- return 1;
342
- }
343
431
  if (a[0] === "~" && b[0] !== "~") {
344
432
  return -1;
433
+ } else if (a[0] !== "~" && b[0] === "~") {
434
+ return 1;
435
+ } else {
436
+ return 0;
345
437
  }
346
- return 0;
347
438
  });
348
439
 
349
440
  // Loop over every source
@@ -356,85 +447,17 @@ export default class Transformer extends Transform {
356
447
  // Check that every parent and child class is hooked up correctly
357
448
  const schemas = transformer.schemasList;
358
449
  for (const schema of schemas) {
359
- checkInheritance(schema, schemas);
360
- const invalidType = checkTypeCorrectness(schema, schemas);
361
- if (invalidType) {
362
- logError(`Type ${invalidType.type} implemented in property ${invalidType.path} is not a JSON-compatible type!\nEither decorate it with @omit or fix it!`);
450
+ if (schema.parent) {
451
+ const parent = schemas.find((v) => v.name === schema.parent?.name);
452
+ if (!parent)
453
+ throw new Error(
454
+ `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.`,
455
+ );
363
456
  }
364
457
  }
365
458
  }
366
459
  }
367
460
 
368
- function checkInheritance(schema: SchemaData, schemas: SchemaData[]): void {
369
- if (!schema.parent && schema.node.extendsType) {
370
- if (schemas.find(v => v.node.name.text === schema.node.extendsType?.name.identifier.text!)) return;
371
- const extending = toString(schema.node.extendsType);
372
- logError(`Schema ${schema.name} extends ${extending}, but ${extending} does not include the @json decorator!`);
373
- }
374
- }
375
-
376
- function checkTypeCorrectness(
377
- schema: SchemaData,
378
- schemas: SchemaData[]
379
- ): {
380
- type: string;
381
- path: string;
382
- } | null {
383
- const parent = schemas.find((v) => v.name === schema.parent?.name);
384
- const generic_types = [...(schema?.node.typeParameters?.map<string>((v) => v.name.text) || []), ...(parent?.node.typeParameters?.map<string>((v) => v.name.text) || [])];
385
- const member_types = [...(schema.members.map((v) => (<NamedTypeNode>v.node.type).name.identifier.text) || [])];
386
- const scopeTypes = new Set<string>([...json_types, ...generic_types, ...member_types]);
387
-
388
- for (const typ of member_types) {
389
- if (typ === "JSON") continue; // JSON.Raw, JSON.Box, JSON.Any, ect...
390
- if (json_types.includes(typ)) continue;
391
- if (generic_types.includes(typ)) continue;
392
- const check = schemas.find((v) => v.name == typ);
393
- if (!check) logError(`Type ${typ} is not a JSON compatible type or does not include the @json flag!`);
394
- }
395
-
396
- for (const member of schema.members) {
397
- const invalidType = checkType(schema, schemas, member.node.type as NamedTypeNode, member, scopeTypes, schema.name);
398
- if (invalidType) 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/")}`)}`);
399
- }
400
-
401
- return null;
402
- }
403
-
404
- function checkType(
405
- schema: SchemaData,
406
- schemas: SchemaData[],
407
- typ: NamedTypeNode,
408
- member: Property,
409
- scopeTypes: Set<string>,
410
- path: string,
411
- ): {
412
- type: string;
413
- path: string;
414
- } | null {
415
- path += "." + member.name;
416
- if (schemas.find(v => v.node.name.text === typ.name.identifier.text)) scopeTypes.add(typ.name.identifier.text);
417
- if (!scopeTypes.has(typ.name.identifier.text)) return { type: toString(typ), path };
418
-
419
- if (typ.isNullable && isPrimitive(typ)) return { type: toString(typ), path };
420
-
421
- if (typ.typeArguments?.length && typ.typeArguments?.length > 0) {
422
- for (const ty of typ.typeArguments.filter((v) => v instanceof NamedTypeNode)) {
423
- const check = checkType(schema, schemas, ty, member, scopeTypes, path);
424
- if (check) return { type: toString(typ), path };
425
- }
426
- } else {
427
- if (scopeTypes.has(typ.name.identifier.text)) return null;
428
- }
429
-
430
- return null;
431
- }
432
-
433
- function logError(message: string): never {
434
- console.log("\n" + chalk.bold.bgRed(" Error ") + chalk.dim(":") + " " + message + "\n");
435
- process.exit(1);
436
- }
437
-
438
461
  enum PropertyFlags {
439
462
  Null,
440
463
  Omit,
@@ -449,10 +472,12 @@ class Property {
449
472
  public alias: string | null = null;
450
473
  public type: string = "";
451
474
  public value: string | null = null;
452
- public flags: Map<PropertyFlags, string[]> = new Map<PropertyFlags, string[]>();
475
+ public flags: Map<PropertyFlags, string[]> = new Map<
476
+ PropertyFlags,
477
+ string[]
478
+ >();
453
479
 
454
480
  public serialize: string | null = null;
455
- public serialize_pretty: string | null = null;
456
481
  public deserialize: string | null = null;
457
482
  public initialize: string | null = null;
458
483
 
@@ -469,7 +494,7 @@ class Property {
469
494
 
470
495
  if (this.flags.has(PropertyFlags.JSON_Raw)) {
471
496
  if (this.flags.has(PropertyFlags.Null)) {
472
- this.right_s = "(this." + name + ' || "null")';
497
+ this.right_s = "(this." + name + " || \"null\")";
473
498
  this.right_d = "value_start === value_end - 4 && 30399761348886638 === load<u64>(changetype<usize>(data) + (value_start << 1)) ? null : data.substring(value_start, value_end)";
474
499
  } else {
475
500
  this.right_s = "this." + name;
@@ -477,22 +502,38 @@ class Property {
477
502
  }
478
503
  } else {
479
504
  this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")";
480
- this.right_d = "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
505
+ this.right_d =
506
+ "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
481
507
  }
482
508
 
483
509
  if (this.flags.has(PropertyFlags.OmitIf)) {
484
510
  const condition = this.flags.get(PropertyFlags.OmitIf)![0];
485
- if (!condition) throw new Error("Could not find condition when using decorator @omitif! Provide at least one condition");
486
- this.serialize = "${" + condition + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}';
487
- this.serialize_pretty = "${" + condition + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}';
511
+ if (!condition)
512
+ throw new Error(
513
+ "Could not find condition when using decorator @omitif! Provide at least one condition",
514
+ );
515
+ this.serialize =
516
+ "${" +
517
+ condition +
518
+ ' ? "" : \'' +
519
+ escapedName +
520
+ ":' + " +
521
+ this.right_s +
522
+ ' + ","}';
488
523
  this.deserialize = "this." + name + " = " + this.right_d + ";";
489
524
  } else if (this.flags.has(PropertyFlags.OmitNull)) {
490
- this.serialize = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}';
491
- this.serialize_pretty = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}';
525
+ this.serialize =
526
+ "${changetype<usize>(this." +
527
+ name +
528
+ ") == <usize>0" +
529
+ ' ? "" : \'' +
530
+ escapedName +
531
+ ":' + " +
532
+ this.right_s +
533
+ ' + ","}';
492
534
  this.deserialize = "this." + name + " = " + this.right_d + ";";
493
535
  } else {
494
536
  this.serialize = escapedName + ":${" + this.right_s + "}";
495
- this.serialize_pretty = escapedName + ": ${" + this.right_s + "}";
496
537
  this.deserialize = "this." + name + " = " + this.right_d + ";";
497
538
  }
498
539
  }
@@ -511,7 +552,9 @@ function charCodeAt32(data: string, offset: number): number {
511
552
 
512
553
  function charCodeAt64(data: string, offset: number): bigint {
513
554
  if (offset + 3 >= data.length) {
514
- throw new Error("The string must have at least 4 characters from the specified offset.");
555
+ throw new Error(
556
+ "The string must have at least 4 characters from the specified offset.",
557
+ );
515
558
  }
516
559
 
517
560
  const firstCharCode = BigInt(data.charCodeAt(offset));
@@ -519,7 +562,11 @@ function charCodeAt64(data: string, offset: number): bigint {
519
562
  const thirdCharCode = BigInt(data.charCodeAt(offset + 2));
520
563
  const fourthCharCode = BigInt(data.charCodeAt(offset + 3));
521
564
 
522
- const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode;
565
+ const u64Value =
566
+ (fourthCharCode << 48n) |
567
+ (thirdCharCode << 32n) |
568
+ (secondCharCode << 16n) |
569
+ firstCharCode;
523
570
 
524
571
  return u64Value;
525
572
  }
@@ -563,9 +610,3 @@ function getArgs(args: Expression[] | null): string[] {
563
610
  }
564
611
  return out;
565
612
  }
566
-
567
- function isPrimitive(type: NamedTypeNode): boolean {
568
- const primitives = new Set(["u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean"]);
569
-
570
- return primitives.has(type.name.identifier.text);
571
- }