json-as 0.9.21 → 0.9.23

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.
@@ -1,119 +1,89 @@
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";
1
+ import { ClassDeclaration, FieldDeclaration, IdentifierExpression, Parser, Source, Expression, CommonFlags, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, DeclarationStatement, NamedTypeNode } from "assemblyscript/dist/assemblyscript.js";
17
2
 
18
3
  import { toString, isStdlib } from "visitor-as/dist/utils.js";
19
4
  import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
20
5
  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"];
21
9
 
22
10
  class JSONTransform extends BaseVisitor {
11
+ public types = json_types;
23
12
  public schemasList: SchemaData[] = [];
24
13
  public currentClass!: SchemaData;
25
14
  public sources = new Set<Source>();
26
15
 
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
-
16
+ appendParentFields(node: ClassDeclaration, schema: SchemaData, members: DeclarationStatement[]): void {
49
17
  if (node.extendsType) {
50
- schema.parent = this.schemasList.find(
51
- (v) => v.name == node.extendsType?.name.identifier.text,
52
- ) as SchemaData | null;
53
-
54
18
  if (schema.parent?.members) {
55
19
  for (let i = schema.parent.members.length - 1; i >= 0; i--) {
56
- const replace = schema.members.find(
57
- (v) => v.name == schema.parent?.members[i]?.name,
58
- );
20
+ const replace = schema.members.find((v) => v.name == schema.parent?.members[i]?.name);
59
21
  if (!replace) {
60
22
  members.unshift(schema.parent?.members[i]!.node);
61
23
  }
62
24
  }
25
+ this.appendParentFields(schema.parent.node, schema, members);
63
26
  }
64
27
  }
28
+ }
65
29
 
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}";
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}';
69
33
 
70
- let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}";
34
+ let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}";
71
35
 
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}";
36
+ let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}";
74
37
 
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
- }
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
+
67
+ if (node.extendsType) {
68
+ schema.parent = this.schemasList.find((v) => v.name == node.extendsType?.name.identifier.text) as SchemaData | null;
69
+ }
70
+
71
+ const _members = [...node.members];
72
+
73
+ this.appendParentFields(node, schema, _members);
81
74
 
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);
75
+ const members = this.filterMembers(_members);
76
+
77
+ if (!members.length) {
78
+ this.handleEmptyClass(node, schema, members);
104
79
  }
105
80
 
106
81
  for (const member of members) {
107
82
  const name = member.name;
108
- if (!(member instanceof FieldDeclaration)) continue;
109
83
  if (!member.type) {
110
- throw new Error(
111
- "Fields must be strongly typed! Found " +
112
- toString(member) +
113
- " at " +
114
- node.range.source.normalizedPath,
115
- );
84
+ throw new Error("Fields must be strongly typed! Found " + toString(member) + " at " + node.range.source.normalizedPath);
116
85
  }
86
+
117
87
  const type = toString(member.type!);
118
88
  if (type.startsWith("(") && type.includes("=>")) continue;
119
89
  const value = member.initializer ? toString(member.initializer!) : null;
@@ -144,11 +114,7 @@ class JSONTransform extends BaseVisitor {
144
114
 
145
115
  switch (decoratorName) {
146
116
  case "alias": {
147
- if (!args.length)
148
- throw new Error(
149
- "Expected 1 argument but got zero at @alias in " +
150
- node.range.source.normalizedPath,
151
- );
117
+ if (!args.length) throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath);
152
118
  mem.alias = args[0]!;
153
119
  mem.flags.set(PropertyFlags.Alias, args);
154
120
  break;
@@ -158,11 +124,7 @@ class JSONTransform extends BaseVisitor {
158
124
  break;
159
125
  }
160
126
  case "omitif": {
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
- );
127
+ if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath);
166
128
  mem.flags.set(PropertyFlags.OmitIf, args);
167
129
  break;
168
130
  }
@@ -174,23 +136,10 @@ class JSONTransform extends BaseVisitor {
174
136
  }
175
137
  }
176
138
 
177
- mem.generate();
139
+ if (!mem.flags.get(PropertyFlags.Omit)) mem.generate();
178
140
 
179
141
  if (this.schemasList.find((v) => v.name == type)) {
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()";
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()";
194
143
  } else if (mem.value) {
195
144
  mem.initialize = "this." + name.text + " = " + mem.value;
196
145
  } else if (type === "Map") {
@@ -198,22 +147,12 @@ class JSONTransform extends BaseVisitor {
198
147
  } else if (type === "string") {
199
148
  mem.initialize = "this." + name.text + ' = ""';
200
149
  } else if (type === "Array") {
201
- mem.initialize =
202
- "this." + name.text + " = instantiate<" + mem.type + ">()";
150
+ mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()";
203
151
  } else if (type === "bool" || type === "boolean") {
204
152
  mem.initialize = "this." + name.text + " = false";
205
153
  } else if (type === "JSON.Raw") {
206
154
  mem.initialize = "this." + name.text + ' = ""';
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
- ) {
155
+ } else if (type === "u8" || type === "u16" || type === "u32" || type === "u64" || type === "i8" || type === "i16" || type === "i32" || type === "i64") {
217
156
  mem.initialize = "this." + name.text + " = 0";
218
157
  } else if (type === "f32" || type === "f64") {
219
158
  mem.initialize = "this." + name.text + " = 0.0";
@@ -227,50 +166,41 @@ class JSONTransform extends BaseVisitor {
227
166
 
228
167
  let INITIALIZE = "__INITIALIZE(): this {\n";
229
168
 
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";
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";
232
170
  let indent = " ";
233
171
 
234
172
  if (!schema.members.length) return;
235
173
 
236
- found = false;
174
+ let found = false;
237
175
 
238
- if (
239
- schema.members[0]?.flags.has(PropertyFlags.OmitNull) ||
240
- schema.members[0]?.flags.has(PropertyFlags.OmitIf)
241
- ) {
176
+ if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) || schema.members[0]?.flags.has(PropertyFlags.OmitIf)) {
242
177
  SERIALIZE_RAW += schema.members[0]?.serialize;
243
- SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize;
178
+ SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty;
244
179
  } else {
245
180
  SERIALIZE_RAW += schema.members[0]?.serialize + ",";
246
- SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize + ",\\n";
181
+ SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty + ",\\n";
247
182
  found = true;
248
183
  }
249
184
 
250
- if (schema.members[0]?.initialize)
251
- INITIALIZE += " " + schema.members[0]?.initialize + ";\n";
185
+ if (schema.members[0]?.initialize) INITIALIZE += " " + schema.members[0]?.initialize + ";\n";
252
186
 
253
187
  for (let i = 1; i < schema.members.length; i++) {
254
188
  const member = schema.members[i]!;
255
189
  if (member.initialize) INITIALIZE += " " + member.initialize + ";\n";
256
- if (
257
- member.flags.has(PropertyFlags.OmitNull) ||
258
- member.flags.has(PropertyFlags.OmitIf)
259
- ) {
190
+ if (member.flags.has(PropertyFlags.Omit)) continue;
191
+ if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) {
260
192
  SERIALIZE_RAW += member.serialize;
261
- SERIALIZE_PRETTY += member.serialize;
193
+ SERIALIZE_PRETTY += member.serialize_pretty;
262
194
  } else {
263
195
  SERIALIZE_RAW += member.serialize + ",";
264
- SERIALIZE_PRETTY += indent + member.serialize + ",\\n";
196
+ SERIALIZE_PRETTY += indent + member.serialize_pretty + ",\\n";
265
197
  found = true;
266
198
  }
267
199
  }
268
200
 
269
201
  if (found) {
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}";
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}";
274
204
  } else {
275
205
  SERIALIZE_RAW += "}`;\n return out;\n}";
276
206
  SERIALIZE_PRETTY += "}`;\n return out;\n}";
@@ -279,9 +209,7 @@ class JSONTransform extends BaseVisitor {
279
209
  INITIALIZE += " return this;\n}";
280
210
 
281
211
  const sortedMembers: Property[][] = [];
282
- const _sorted = schema.members.sort(
283
- (a, b) => (a.alias?.length! || a.name.length) - (b.alias?.length! || b.name.length),
284
- );
212
+ const _sorted = schema.members.sort((a, b) => (a.alias?.length! || a.name.length) - (b.alias?.length! || b.name.length));
285
213
  let len = -1;
286
214
  let offset = -1;
287
215
  for (let i = 0; i < _sorted.length; i++) {
@@ -302,30 +230,24 @@ class JSONTransform extends BaseVisitor {
302
230
  const _name = encodeKey(firstMember.alias || firstMember.name);
303
231
  if (_name.length === 1) {
304
232
  if (first) {
305
- DESERIALIZE +=
306
- " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
233
+ DESERIALIZE += " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
307
234
  first = false;
308
235
  } else {
309
- DESERIALIZE +=
310
- "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
236
+ DESERIALIZE += "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
311
237
  }
312
238
  } else if (_name.length === 2) {
313
239
  if (first) {
314
- DESERIALIZE +=
315
- " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
240
+ DESERIALIZE += " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
316
241
  first = false;
317
242
  } else {
318
- DESERIALIZE +=
319
- "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
243
+ DESERIALIZE += "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
320
244
  }
321
245
  } else if (_name.length === 4) {
322
246
  if (first) {
323
- DESERIALIZE +=
324
- " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
247
+ DESERIALIZE += " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
325
248
  first = false;
326
249
  } else {
327
- DESERIALIZE +=
328
- "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
250
+ DESERIALIZE += "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
329
251
  }
330
252
  } else {
331
253
  if (first) {
@@ -349,31 +271,23 @@ class JSONTransform extends BaseVisitor {
349
271
  f = false;
350
272
  DESERIALIZE += ` if (${charCodeAt64(_name, 0)} === code) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
351
273
  } else {
352
- DESERIALIZE =
353
- DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
354
- `else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
274
+ DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + `else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
355
275
  }
356
276
  } else {
357
277
  if (f) {
358
278
  f = false;
359
279
  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`;
360
280
  } else {
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`;
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`;
364
282
  }
365
283
  }
366
284
  }
367
285
  if (_name.length < 3) {
368
286
  DESERIALIZE += ` default: {\n return false;\n }\n }\n`;
369
287
  } else if (_name.length == 4) {
370
- DESERIALIZE =
371
- DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
372
- ` else {\n return false;\n }\n`;
288
+ DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
373
289
  } else {
374
- DESERIALIZE =
375
- DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
376
- ` else {\n return false;\n }\n`;
290
+ DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
377
291
  }
378
292
  DESERIALIZE += " } ";
379
293
  }
@@ -384,25 +298,20 @@ class JSONTransform extends BaseVisitor {
384
298
 
385
299
  if (process.env["JSON_DEBUG"]) {
386
300
  console.log(SERIALIZE_RAW);
387
- //console.log(SERIALIZE_PRETTY);
301
+ console.log(SERIALIZE_PRETTY);
388
302
  console.log(INITIALIZE);
389
303
  console.log(DESERIALIZE);
390
304
  }
391
305
 
392
- const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(
393
- SERIALIZE_RAW,
394
- node,
395
- );
396
- //const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
306
+ const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(SERIALIZE_RAW, node);
307
+ const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
397
308
  const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
398
309
  const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
399
310
 
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);
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);
406
315
 
407
316
  this.schemasList.push(schema);
408
317
  }
@@ -428,13 +337,13 @@ export default class Transformer extends Transform {
428
337
  .sort((_a, _b) => {
429
338
  const a = _a.internalPath;
430
339
  const b = _b.internalPath;
340
+ if (a[0] !== "~" && b[0] === "~") {
341
+ return 1;
342
+ }
431
343
  if (a[0] === "~" && b[0] !== "~") {
432
344
  return -1;
433
- } else if (a[0] !== "~" && b[0] === "~") {
434
- return 1;
435
- } else {
436
- return 0;
437
345
  }
346
+ return 0;
438
347
  });
439
348
 
440
349
  // Loop over every source
@@ -447,17 +356,85 @@ export default class Transformer extends Transform {
447
356
  // Check that every parent and child class is hooked up correctly
448
357
  const schemas = transformer.schemasList;
449
358
  for (const schema of schemas) {
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
- );
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!`);
456
363
  }
457
364
  }
458
365
  }
459
366
  }
460
367
 
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
+
461
438
  enum PropertyFlags {
462
439
  Null,
463
440
  Omit,
@@ -472,12 +449,10 @@ class Property {
472
449
  public alias: string | null = null;
473
450
  public type: string = "";
474
451
  public value: string | null = null;
475
- public flags: Map<PropertyFlags, string[]> = new Map<
476
- PropertyFlags,
477
- string[]
478
- >();
452
+ public flags: Map<PropertyFlags, string[]> = new Map<PropertyFlags, string[]>();
479
453
 
480
454
  public serialize: string | null = null;
455
+ public serialize_pretty: string | null = null;
481
456
  public deserialize: string | null = null;
482
457
  public initialize: string | null = null;
483
458
 
@@ -494,7 +469,7 @@ class Property {
494
469
 
495
470
  if (this.flags.has(PropertyFlags.JSON_Raw)) {
496
471
  if (this.flags.has(PropertyFlags.Null)) {
497
- this.right_s = "(this." + name + " || \"null\")";
472
+ this.right_s = "(this." + name + ' || "null")';
498
473
  this.right_d = "value_start === value_end - 4 && 30399761348886638 === load<u64>(changetype<usize>(data) + (value_start << 1)) ? null : data.substring(value_start, value_end)";
499
474
  } else {
500
475
  this.right_s = "this." + name;
@@ -502,38 +477,22 @@ class Property {
502
477
  }
503
478
  } else {
504
479
  this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")";
505
- this.right_d =
506
- "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
480
+ this.right_d = "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
507
481
  }
508
482
 
509
483
  if (this.flags.has(PropertyFlags.OmitIf)) {
510
484
  const condition = this.flags.get(PropertyFlags.OmitIf)![0];
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
- ' + ","}';
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 + ' + ","}';
523
488
  this.deserialize = "this." + name + " = " + this.right_d + ";";
524
489
  } else if (this.flags.has(PropertyFlags.OmitNull)) {
525
- this.serialize =
526
- "${changetype<usize>(this." +
527
- name +
528
- ") == <usize>0" +
529
- ' ? "" : \'' +
530
- escapedName +
531
- ":' + " +
532
- this.right_s +
533
- ' + ","}';
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 + ' + ","}';
534
492
  this.deserialize = "this." + name + " = " + this.right_d + ";";
535
493
  } else {
536
494
  this.serialize = escapedName + ":${" + this.right_s + "}";
495
+ this.serialize_pretty = escapedName + ": ${" + this.right_s + "}";
537
496
  this.deserialize = "this." + name + " = " + this.right_d + ";";
538
497
  }
539
498
  }
@@ -552,9 +511,7 @@ function charCodeAt32(data: string, offset: number): number {
552
511
 
553
512
  function charCodeAt64(data: string, offset: number): bigint {
554
513
  if (offset + 3 >= data.length) {
555
- throw new Error(
556
- "The string must have at least 4 characters from the specified offset.",
557
- );
514
+ throw new Error("The string must have at least 4 characters from the specified offset.");
558
515
  }
559
516
 
560
517
  const firstCharCode = BigInt(data.charCodeAt(offset));
@@ -562,11 +519,7 @@ function charCodeAt64(data: string, offset: number): bigint {
562
519
  const thirdCharCode = BigInt(data.charCodeAt(offset + 2));
563
520
  const fourthCharCode = BigInt(data.charCodeAt(offset + 3));
564
521
 
565
- const u64Value =
566
- (fourthCharCode << 48n) |
567
- (thirdCharCode << 32n) |
568
- (secondCharCode << 16n) |
569
- firstCharCode;
522
+ const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode;
570
523
 
571
524
  return u64Value;
572
525
  }
@@ -610,3 +563,9 @@ function getArgs(args: Expression[] | null): string[] {
610
563
  }
611
564
  return out;
612
565
  }
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
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ES2015",
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
5
  "downlevelIteration": true,
6
6
  "outDir": "./lib/",
7
7
 
@@ -1,17 +0,0 @@
1
- import { readFileSync } from "fs";
2
- import { WASI } from "wasi";
3
- import { argv, env } from "node:process";
4
-
5
- const wasm = readFileSync("./benchmark.wasm");
6
-
7
- const wasi = new WASI({
8
- version: "preview1",
9
- args: argv,
10
- env,
11
- preopens: {},
12
- });
13
-
14
- const mod = new WebAssembly.Module(wasm);
15
- const instance = new WebAssembly.Instance(mod, wasi.getImportObject());
16
-
17
- wasi.start(instance);