json-as 0.9.20 → 0.9.22

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];
81
72
 
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);
73
+ this.appendParentFields(node, schema, _members);
74
+
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;
@@ -128,10 +98,14 @@ class JSONTransform extends BaseVisitor {
128
98
  mem.value = value;
129
99
  mem.node = member;
130
100
 
131
- if (type == "JSON.Raw") {
101
+ if (type.includes("JSON.Raw")) {
132
102
  mem.flags.set(PropertyFlags.JSON_Raw, []);
133
103
  }
134
104
 
105
+ if (member.type.isNullable) {
106
+ mem.flags.set(PropertyFlags.Null, []);
107
+ }
108
+
135
109
  if (member.decorators) {
136
110
  for (const decorator of member.decorators) {
137
111
  const decoratorName = (decorator.name as IdentifierExpression).text;
@@ -140,11 +114,7 @@ class JSONTransform extends BaseVisitor {
140
114
 
141
115
  switch (decoratorName) {
142
116
  case "alias": {
143
- if (!args.length)
144
- throw new Error(
145
- "Expected 1 argument but got zero at @alias in " +
146
- node.range.source.normalizedPath,
147
- );
117
+ if (!args.length) throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath);
148
118
  mem.alias = args[0]!;
149
119
  mem.flags.set(PropertyFlags.Alias, args);
150
120
  break;
@@ -154,11 +124,7 @@ class JSONTransform extends BaseVisitor {
154
124
  break;
155
125
  }
156
126
  case "omitif": {
157
- if (!decorator.args?.length)
158
- throw new Error(
159
- "Expected 1 argument but got zero at @omitif in " +
160
- node.range.source.normalizedPath,
161
- );
127
+ if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath);
162
128
  mem.flags.set(PropertyFlags.OmitIf, args);
163
129
  break;
164
130
  }
@@ -170,23 +136,10 @@ class JSONTransform extends BaseVisitor {
170
136
  }
171
137
  }
172
138
 
173
- mem.generate();
139
+ if (!mem.flags.get(PropertyFlags.Omit)) mem.generate();
174
140
 
175
141
  if (this.schemasList.find((v) => v.name == type)) {
176
- mem.initialize =
177
- "this." +
178
- name.text +
179
- " = changetype<nonnull<" +
180
- mem.type +
181
- ">>(__new(offsetof<nonnull<" +
182
- mem.type +
183
- ">>(), idof<nonnull<" +
184
- mem.type +
185
- ">>()));\n changetype<nonnull<" +
186
- mem.type +
187
- ">>(this." +
188
- name.text +
189
- ").__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()";
190
143
  } else if (mem.value) {
191
144
  mem.initialize = "this." + name.text + " = " + mem.value;
192
145
  } else if (type === "Map") {
@@ -194,22 +147,12 @@ class JSONTransform extends BaseVisitor {
194
147
  } else if (type === "string") {
195
148
  mem.initialize = "this." + name.text + ' = ""';
196
149
  } else if (type === "Array") {
197
- mem.initialize =
198
- "this." + name.text + " = instantiate<" + mem.type + ">()";
150
+ mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()";
199
151
  } else if (type === "bool" || type === "boolean") {
200
152
  mem.initialize = "this." + name.text + " = false";
201
153
  } else if (type === "JSON.Raw") {
202
154
  mem.initialize = "this." + name.text + ' = ""';
203
- } else if (
204
- type === "u8" ||
205
- type === "u16" ||
206
- type === "u32" ||
207
- type === "u64" ||
208
- type === "i8" ||
209
- type === "i16" ||
210
- type === "i32" ||
211
- type === "i64"
212
- ) {
155
+ } else if (type === "u8" || type === "u16" || type === "u32" || type === "u64" || type === "i8" || type === "i16" || type === "i32" || type === "i64") {
213
156
  mem.initialize = "this." + name.text + " = 0";
214
157
  } else if (type === "f32" || type === "f64") {
215
158
  mem.initialize = "this." + name.text + " = 0.0";
@@ -223,154 +166,128 @@ class JSONTransform extends BaseVisitor {
223
166
 
224
167
  let INITIALIZE = "__INITIALIZE(): this {\n";
225
168
 
226
- let DESERIALIZE =
227
- "__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";
228
170
  let indent = " ";
229
171
 
230
172
  if (!schema.members.length) return;
231
173
 
232
- found = false;
174
+ let found = false;
233
175
 
234
- if (
235
- schema.members[0]?.flags.has(PropertyFlags.OmitNull) ||
236
- schema.members[0]?.flags.has(PropertyFlags.OmitIf)
237
- ) {
176
+ if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) || schema.members[0]?.flags.has(PropertyFlags.OmitIf)) {
238
177
  SERIALIZE_RAW += schema.members[0]?.serialize;
239
- SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize;
178
+ SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty;
240
179
  } else {
241
180
  SERIALIZE_RAW += schema.members[0]?.serialize + ",";
242
- SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize + ",\\n";
181
+ SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty + ",\\n";
243
182
  found = true;
244
183
  }
245
184
 
246
- if (schema.members[0]?.initialize)
247
- INITIALIZE += " " + schema.members[0]?.initialize + ";\n";
185
+ if (schema.members[0]?.initialize) INITIALIZE += " " + schema.members[0]?.initialize + ";\n";
248
186
 
249
187
  for (let i = 1; i < schema.members.length; i++) {
250
188
  const member = schema.members[i]!;
251
189
  if (member.initialize) INITIALIZE += " " + member.initialize + ";\n";
252
- if (
253
- member.flags.has(PropertyFlags.OmitNull) ||
254
- member.flags.has(PropertyFlags.OmitIf)
255
- ) {
190
+ if (member.flags.has(PropertyFlags.Omit)) continue;
191
+ if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) {
256
192
  SERIALIZE_RAW += member.serialize;
257
- SERIALIZE_PRETTY += member.serialize;
193
+ SERIALIZE_PRETTY += member.serialize_pretty;
258
194
  } else {
259
195
  SERIALIZE_RAW += member.serialize + ",";
260
- SERIALIZE_PRETTY += indent + member.serialize + ",\\n";
196
+ SERIALIZE_PRETTY += indent + member.serialize_pretty + ",\\n";
261
197
  found = true;
262
198
  }
263
199
  }
264
200
 
265
201
  if (found) {
266
- SERIALIZE_RAW +=
267
- "`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}";
268
- SERIALIZE_PRETTY +=
269
- "`;\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}";
270
204
  } else {
271
- SERIALIZE_RAW += "`;\n};";
272
- SERIALIZE_PRETTY += "`;\n};";
205
+ SERIALIZE_RAW += "}`;\n return out;\n}";
206
+ SERIALIZE_PRETTY += "}`;\n return out;\n}";
273
207
  }
274
208
 
275
209
  INITIALIZE += " return this;\n}";
276
210
 
277
211
  const sortedMembers: Property[][] = [];
278
- const _sorted = schema.members.sort(
279
- (a, b) => a.name.length - b.name.length,
280
- );
281
- let len = 0;
282
- let offset = 0;
283
- sortedMembers.push([_sorted[0]!]);
284
- len = _sorted[0]?.name.length!;
285
- for (let i = 1; i < _sorted.length; i++) {
212
+ const _sorted = schema.members.sort((a, b) => (a.alias?.length! || a.name.length) - (b.alias?.length! || b.name.length));
213
+ let len = -1;
214
+ let offset = -1;
215
+ for (let i = 0; i < _sorted.length; i++) {
286
216
  const member = _sorted[i]!;
287
- if (member.alias?.length || member.name.length > len) {
217
+ const _name = member.alias || member.name;
218
+ if (_name.length === len) {
219
+ sortedMembers[offset]?.push(member);
220
+ } else {
288
221
  sortedMembers.push([member]);
289
- len = member.alias?.length || member.name.length;
222
+ len = _name.length;
290
223
  offset++;
291
- } else {
292
- sortedMembers[offset]!.push(member);
293
224
  }
294
225
  }
295
226
 
296
227
  let first = true;
297
228
  for (const memberSet of sortedMembers) {
298
229
  const firstMember = memberSet[0]!;
299
- const name = encodeKey(firstMember.alias || firstMember.name);
300
- if (name.length === 1) {
230
+ const _name = encodeKey(firstMember.alias || firstMember.name);
231
+ if (_name.length === 1) {
301
232
  if (first) {
302
- DESERIALIZE +=
303
- " 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";
304
234
  first = false;
305
235
  } else {
306
- DESERIALIZE +=
307
- "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";
308
237
  }
309
- } else if (name.length === 2) {
238
+ } else if (_name.length === 2) {
310
239
  if (first) {
311
- DESERIALIZE +=
312
- " 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";
313
241
  first = false;
314
242
  } else {
315
- DESERIALIZE +=
316
- "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";
317
244
  }
318
- } else if (name.length === 4) {
245
+ } else if (_name.length === 4) {
319
246
  if (first) {
320
- DESERIALIZE +=
321
- " 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";
322
248
  first = false;
323
249
  } else {
324
- DESERIALIZE +=
325
- "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";
326
251
  }
327
252
  } else {
328
253
  if (first) {
329
- DESERIALIZE += " if (" + name.length + " === len) {\n";
254
+ DESERIALIZE += " if (" + _name.length + " === len) {\n";
330
255
  first = false;
331
256
  } else {
332
- DESERIALIZE += "else if (" + name.length + " === len) {\n";
257
+ DESERIALIZE += "else if (" + _name.length + " === len) {\n";
333
258
  }
334
259
  }
335
260
  let f = true;
336
261
  for (let i = 0; i < memberSet.length; i++) {
337
262
  const member = memberSet[i]!;
338
263
  if (!member.deserialize) continue;
339
- const name = encodeKey(member.alias || member.name);
340
- if (name.length === 1) {
341
- DESERIALIZE += ` case ${name.charCodeAt(0)}: {\n ${member.deserialize}\n return true;\n }\n`;
342
- } else if (name.length === 2) {
343
- DESERIALIZE += ` case ${charCodeAt32(name, 0)}: {\n ${member.deserialize}\n return true;\n }\n`;
344
- } else if (name.length === 4) {
264
+ const _name = encodeKey(member.alias || member.name);
265
+ if (_name.length === 1) {
266
+ DESERIALIZE += ` case ${_name.charCodeAt(0)}: { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
267
+ } else if (_name.length === 2) {
268
+ DESERIALIZE += ` case ${charCodeAt32(_name, 0)}: { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
269
+ } else if (_name.length === 4) {
345
270
  if (f) {
346
271
  f = false;
347
- DESERIALIZE += ` if (${charCodeAt64(name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
272
+ DESERIALIZE += ` if (${charCodeAt64(_name, 0)} === code) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
348
273
  } else {
349
- DESERIALIZE =
350
- DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
351
- `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`;
352
275
  }
353
276
  } else {
354
277
  if (f) {
355
278
  f = false;
356
- DESERIALIZE += ` if (0 == memory.compare(changetype<usize>("${escapeQuote(escapeSlash(name))}"), changetype<usize>(data) + (key_start << 1), ${name.length << 1})) {\n ${member.deserialize}\n return true;\n }\n`;
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`;
357
280
  } else {
358
- DESERIALIZE =
359
- DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
360
- ` else if (0 == memory.compare(changetype<usize>("${escapeQuote(escapeSlash(name))}"), changetype<usize>(data) + (key_start << 1), ${name.length << 1})) {\n ${member.deserialize}\n return true;\n }\n`;
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
282
  }
362
283
  }
363
284
  }
364
- if (name.length < 3) {
285
+ if (_name.length < 3) {
365
286
  DESERIALIZE += ` default: {\n return false;\n }\n }\n`;
366
- } else if (name.length == 4) {
367
- DESERIALIZE =
368
- DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
369
- ` else {\n return false;\n }\n`;
287
+ } else if (_name.length == 4) {
288
+ DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
370
289
  } else {
371
- DESERIALIZE =
372
- DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
373
- ` else {\n return false;\n }\n`;
290
+ DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
374
291
  }
375
292
  DESERIALIZE += " } ";
376
293
  }
@@ -381,25 +298,20 @@ class JSONTransform extends BaseVisitor {
381
298
 
382
299
  if (process.env["JSON_DEBUG"]) {
383
300
  console.log(SERIALIZE_RAW);
384
- //console.log(SERIALIZE_PRETTY);
301
+ console.log(SERIALIZE_PRETTY);
385
302
  console.log(INITIALIZE);
386
303
  console.log(DESERIALIZE);
387
304
  }
388
305
 
389
- const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(
390
- SERIALIZE_RAW,
391
- node,
392
- );
393
- //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);
394
308
  const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
395
309
  const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
396
310
 
397
- if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
398
- node.members.push(SERIALIZE_RAW_METHOD);
399
- if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
400
- node.members.push(INITIALIZE_METHOD);
401
- if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
402
- 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);
403
315
 
404
316
  this.schemasList.push(schema);
405
317
  }
@@ -425,13 +337,13 @@ export default class Transformer extends Transform {
425
337
  .sort((_a, _b) => {
426
338
  const a = _a.internalPath;
427
339
  const b = _b.internalPath;
340
+ if (a[0] !== "~" && b[0] === "~") {
341
+ return 1;
342
+ }
428
343
  if (a[0] === "~" && b[0] !== "~") {
429
344
  return -1;
430
- } else if (a[0] !== "~" && b[0] === "~") {
431
- return 1;
432
- } else {
433
- return 0;
434
345
  }
346
+ return 0;
435
347
  });
436
348
 
437
349
  // Loop over every source
@@ -444,18 +356,87 @@ export default class Transformer extends Transform {
444
356
  // Check that every parent and child class is hooked up correctly
445
357
  const schemas = transformer.schemasList;
446
358
  for (const schema of schemas) {
447
- if (schema.parent) {
448
- const parent = schemas.find((v) => v.name === schema.parent?.name);
449
- if (!parent)
450
- throw new Error(
451
- `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.`,
452
- );
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!`);
453
363
  }
454
364
  }
455
365
  }
456
366
  }
457
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
+
458
438
  enum PropertyFlags {
439
+ Null,
459
440
  Omit,
460
441
  OmitNull,
461
442
  OmitIf,
@@ -468,12 +449,10 @@ class Property {
468
449
  public alias: string | null = null;
469
450
  public type: string = "";
470
451
  public value: string | null = null;
471
- public flags: Map<PropertyFlags, string[]> = new Map<
472
- PropertyFlags,
473
- string[]
474
- >();
452
+ public flags: Map<PropertyFlags, string[]> = new Map<PropertyFlags, string[]>();
475
453
 
476
454
  public serialize: string | null = null;
455
+ public serialize_pretty: string | null = null;
477
456
  public deserialize: string | null = null;
478
457
  public initialize: string | null = null;
479
458
 
@@ -489,42 +468,31 @@ class Property {
489
468
  if (this.flags.has(PropertyFlags.Omit)) return;
490
469
 
491
470
  if (this.flags.has(PropertyFlags.JSON_Raw)) {
492
- this.right_s = "this." + name;
493
- this.right_d = "data.substring(value_start, value_end);";
471
+ if (this.flags.has(PropertyFlags.Null)) {
472
+ this.right_s = "(this." + name + ' || "null")';
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)";
474
+ } else {
475
+ this.right_s = "this." + name;
476
+ this.right_d = "data.substring(value_start, value_end);";
477
+ }
494
478
  } else {
495
479
  this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")";
496
- this.right_d =
497
- "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
480
+ this.right_d = "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
498
481
  }
499
482
 
500
483
  if (this.flags.has(PropertyFlags.OmitIf)) {
501
484
  const condition = this.flags.get(PropertyFlags.OmitIf)![0];
502
- if (!condition)
503
- throw new Error(
504
- "Could not find condition when using decorator @omitif! Provide at least one condition",
505
- );
506
- this.serialize =
507
- "${" +
508
- condition +
509
- ' ? "" : \'' +
510
- escapedName +
511
- ":' + " +
512
- this.right_s +
513
- ' + ","}';
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 + ' + ","}';
514
488
  this.deserialize = "this." + name + " = " + this.right_d + ";";
515
489
  } else if (this.flags.has(PropertyFlags.OmitNull)) {
516
- this.serialize =
517
- "${changetype<usize>(this." +
518
- name +
519
- ") == <usize>0" +
520
- ' ? "" : \'' +
521
- escapedName +
522
- ":' + " +
523
- this.right_s +
524
- ' + ","}';
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
492
  this.deserialize = "this." + name + " = " + this.right_d + ";";
526
493
  } else {
527
494
  this.serialize = escapedName + ":${" + this.right_s + "}";
495
+ this.serialize_pretty = escapedName + ": ${" + this.right_s + "}";
528
496
  this.deserialize = "this." + name + " = " + this.right_d + ";";
529
497
  }
530
498
  }
@@ -543,9 +511,7 @@ function charCodeAt32(data: string, offset: number): number {
543
511
 
544
512
  function charCodeAt64(data: string, offset: number): bigint {
545
513
  if (offset + 3 >= data.length) {
546
- throw new Error(
547
- "The string must have at least 4 characters from the specified offset.",
548
- );
514
+ throw new Error("The string must have at least 4 characters from the specified offset.");
549
515
  }
550
516
 
551
517
  const firstCharCode = BigInt(data.charCodeAt(offset));
@@ -553,11 +519,7 @@ function charCodeAt64(data: string, offset: number): bigint {
553
519
  const thirdCharCode = BigInt(data.charCodeAt(offset + 2));
554
520
  const fourthCharCode = BigInt(data.charCodeAt(offset + 3));
555
521
 
556
- const u64Value =
557
- (fourthCharCode << 48n) |
558
- (thirdCharCode << 32n) |
559
- (secondCharCode << 16n) |
560
- firstCharCode;
522
+ const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode;
561
523
 
562
524
  return u64Value;
563
525
  }
@@ -601,3 +563,9 @@ function getArgs(args: Expression[] | null): string[] {
601
563
  }
602
564
  return out;
603
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
+ }