json-as 0.9.23 → 0.9.25

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,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(false);
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,30 @@ 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
+
397
+ const DESERIALIZE_SAFE = DESERIALIZE.replaceAll("__DESERIALIZE", "__DESERIALIZE_SAFE")
398
+ //const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
308
399
  const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
309
400
  const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
401
+ const DESERIALIZE_SAFE_METHOD = SimpleParser.parseClassMember(DESERIALIZE_SAFE, node);
310
402
 
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);
403
+ if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
404
+ node.members.push(SERIALIZE_RAW_METHOD);
405
+ if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
406
+ node.members.push(INITIALIZE_METHOD);
407
+ if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
408
+ node.members.push(DESERIALIZE_METHOD);
409
+ if (!node.members.find((v) => v.name.text == "__DESERIALIZE_SAFE"))
410
+ node.members.push(DESERIALIZE_SAFE_METHOD);
315
411
 
316
412
  this.schemasList.push(schema);
317
413
  }
@@ -337,13 +433,13 @@ export default class Transformer extends Transform {
337
433
  .sort((_a, _b) => {
338
434
  const a = _a.internalPath;
339
435
  const b = _b.internalPath;
340
- if (a[0] !== "~" && b[0] === "~") {
341
- return 1;
342
- }
343
436
  if (a[0] === "~" && b[0] !== "~") {
344
437
  return -1;
438
+ } else if (a[0] !== "~" && b[0] === "~") {
439
+ return 1;
440
+ } else {
441
+ return 0;
345
442
  }
346
- return 0;
347
443
  });
348
444
 
349
445
  // Loop over every source
@@ -356,85 +452,17 @@ export default class Transformer extends Transform {
356
452
  // Check that every parent and child class is hooked up correctly
357
453
  const schemas = transformer.schemasList;
358
454
  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!`);
455
+ if (schema.parent) {
456
+ const parent = schemas.find((v) => v.name === schema.parent?.name);
457
+ if (!parent)
458
+ throw new Error(
459
+ `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.`,
460
+ );
363
461
  }
364
462
  }
365
463
  }
366
464
  }
367
465
 
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
466
  enum PropertyFlags {
439
467
  Null,
440
468
  Omit,
@@ -449,10 +477,12 @@ class Property {
449
477
  public alias: string | null = null;
450
478
  public type: string = "";
451
479
  public value: string | null = null;
452
- public flags: Map<PropertyFlags, string[]> = new Map<PropertyFlags, string[]>();
480
+ public flags: Map<PropertyFlags, string[]> = new Map<
481
+ PropertyFlags,
482
+ string[]
483
+ >();
453
484
 
454
485
  public serialize: string | null = null;
455
- public serialize_pretty: string | null = null;
456
486
  public deserialize: string | null = null;
457
487
  public initialize: string | null = null;
458
488
 
@@ -461,7 +491,7 @@ class Property {
461
491
  private right_s: string = "";
462
492
  private right_d: string = "";
463
493
 
464
- public generate(): void {
494
+ public generate(safe: boolean): void {
465
495
  const name = this.name;
466
496
  const escapedName = escapeString(JSON.stringify(this.alias || this.name));
467
497
  const type = this.type;
@@ -469,7 +499,7 @@ class Property {
469
499
 
470
500
  if (this.flags.has(PropertyFlags.JSON_Raw)) {
471
501
  if (this.flags.has(PropertyFlags.Null)) {
472
- this.right_s = "(this." + name + ' || "null")';
502
+ this.right_s = "(this." + name + " || \"null\")";
473
503
  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
504
  } else {
475
505
  this.right_s = "this." + name;
@@ -477,22 +507,38 @@ class Property {
477
507
  }
478
508
  } else {
479
509
  this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")";
480
- this.right_d = "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
510
+ this.right_d =
511
+ (safe ? "__DESERIALIZE_SAFE" : "__DESERIALIZE") + "<" + type + ">(data.substring(value_start, value_end))";
481
512
  }
482
513
 
483
514
  if (this.flags.has(PropertyFlags.OmitIf)) {
484
515
  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 + ' + ","}';
516
+ if (!condition)
517
+ throw new Error(
518
+ "Could not find condition when using decorator @omitif! Provide at least one condition",
519
+ );
520
+ this.serialize =
521
+ "${" +
522
+ condition +
523
+ ' ? "" : \'' +
524
+ escapedName +
525
+ ":' + " +
526
+ this.right_s +
527
+ ' + ","}';
488
528
  this.deserialize = "this." + name + " = " + this.right_d + ";";
489
529
  } 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 + ' + ","}';
530
+ this.serialize =
531
+ "${changetype<usize>(this." +
532
+ name +
533
+ ") == <usize>0" +
534
+ ' ? "" : \'' +
535
+ escapedName +
536
+ ":' + " +
537
+ this.right_s +
538
+ ' + ","}';
492
539
  this.deserialize = "this." + name + " = " + this.right_d + ";";
493
540
  } else {
494
541
  this.serialize = escapedName + ":${" + this.right_s + "}";
495
- this.serialize_pretty = escapedName + ": ${" + this.right_s + "}";
496
542
  this.deserialize = "this." + name + " = " + this.right_d + ";";
497
543
  }
498
544
  }
@@ -511,7 +557,9 @@ function charCodeAt32(data: string, offset: number): number {
511
557
 
512
558
  function charCodeAt64(data: string, offset: number): bigint {
513
559
  if (offset + 3 >= data.length) {
514
- throw new Error("The string must have at least 4 characters from the specified offset.");
560
+ throw new Error(
561
+ "The string must have at least 4 characters from the specified offset.",
562
+ );
515
563
  }
516
564
 
517
565
  const firstCharCode = BigInt(data.charCodeAt(offset));
@@ -519,7 +567,11 @@ function charCodeAt64(data: string, offset: number): bigint {
519
567
  const thirdCharCode = BigInt(data.charCodeAt(offset + 2));
520
568
  const fourthCharCode = BigInt(data.charCodeAt(offset + 3));
521
569
 
522
- const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode;
570
+ const u64Value =
571
+ (fourthCharCode << 48n) |
572
+ (thirdCharCode << 32n) |
573
+ (secondCharCode << 16n) |
574
+ firstCharCode;
523
575
 
524
576
  return u64Value;
525
577
  }
@@ -563,9 +615,3 @@ function getArgs(args: Expression[] | null): string[] {
563
615
  }
564
616
  return out;
565
617
  }
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
- }