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,76 +1,76 @@
1
- import { FieldDeclaration, IdentifierExpression, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, } from "assemblyscript/dist/assemblyscript.js";
1
+ import { FieldDeclaration, IdentifierExpression, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, NamedTypeNode } from "assemblyscript/dist/assemblyscript.js";
2
2
  import { toString, isStdlib } from "visitor-as/dist/utils.js";
3
3
  import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
4
4
  import { Transform } from "assemblyscript/dist/transform.js";
5
+ import chalk from "chalk";
6
+ const json_types = ["Array", "string", "String", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean", "Map", "Date"];
5
7
  class JSONTransform extends BaseVisitor {
6
- constructor() {
7
- super(...arguments);
8
- this.schemasList = [];
9
- this.sources = new Set();
8
+ types = json_types;
9
+ schemasList = [];
10
+ currentClass;
11
+ sources = new Set();
12
+ appendParentFields(node, schema, members) {
13
+ if (node.extendsType) {
14
+ if (schema.parent?.members) {
15
+ for (let i = schema.parent.members.length - 1; i >= 0; i--) {
16
+ const replace = schema.members.find((v) => v.name == schema.parent?.members[i]?.name);
17
+ if (!replace) {
18
+ members.unshift(schema.parent?.members[i].node);
19
+ }
20
+ }
21
+ this.appendParentFields(schema.parent.node, schema, members);
22
+ }
23
+ }
24
+ }
25
+ handleEmptyClass(node, schema, members) {
26
+ let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}';
27
+ let SERIALIZE_PRETTY_EMPTY = '__SERIALIZE_PRETTY(): string {\n return "{}";\n}';
28
+ let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}";
29
+ let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}";
30
+ if (process.env["JSON_DEBUG"]) {
31
+ console.log(SERIALIZE_RAW_EMPTY);
32
+ console.log(SERIALIZE_PRETTY_EMPTY);
33
+ console.log(INITIALIZE_EMPTY);
34
+ console.log(DESERIALIZE_EMPTY);
35
+ }
36
+ const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node);
37
+ const SERIALIZE_PRETTY_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_PRETTY_EMPTY, node);
38
+ const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node);
39
+ const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node);
40
+ if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
41
+ node.members.push(SERIALIZE_RAW_METHOD_EMPTY);
42
+ if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY"))
43
+ node.members.push(SERIALIZE_PRETTY_METHOD_EMPTY);
44
+ if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
45
+ node.members.push(INITIALIZE_METHOD_EMPTY);
46
+ if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
47
+ node.members.push(DESERIALIZE_METHOD_EMPTY);
48
+ }
49
+ filterMembers(members) {
50
+ return members.filter((v) => v instanceof FieldDeclaration && !v.decorators?.find((v) => v.name.text == "omit"));
10
51
  }
11
- visitMethodDeclaration() { }
12
52
  visitClassDeclaration(node) {
13
53
  if (!node.decorators?.length)
14
54
  return;
15
- let found = false;
16
- for (const decorator of node.decorators) {
17
- const name = decorator.name.text;
18
- if (name === "json" || name === "serializable") {
19
- found = true;
20
- break;
21
- }
22
- }
23
- if (!found)
55
+ if (!node.decorators.find((v) => v.name.text == "json" || v.name.text == "serializable"))
24
56
  return;
57
+ this.types = json_types;
25
58
  const schema = new SchemaData();
26
59
  schema.node = node;
27
60
  schema.name = node.name.text;
28
- const members = [
29
- ...node.members.filter((v) => v.kind === 54 /* NodeKind.FieldDeclaration */),
30
- ];
31
61
  if (node.extendsType) {
32
62
  schema.parent = this.schemasList.find((v) => v.name == node.extendsType?.name.identifier.text);
33
- if (schema.parent?.members) {
34
- for (let i = schema.parent.members.length - 1; i >= 0; i--) {
35
- const replace = schema.members.find((v) => v.name == schema.parent?.members[i]?.name);
36
- if (!replace) {
37
- members.unshift(schema.parent?.members[i].node);
38
- }
39
- }
40
- }
41
63
  }
64
+ const _members = [...node.members];
65
+ this.appendParentFields(node, schema, _members);
66
+ const members = this.filterMembers(_members);
42
67
  if (!members.length) {
43
- let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}';
44
- //let SERIALIZE_PRETTY_EMPTY = "__SERIALIZE_PRETTY(): string {\n return \"{}\";\n}";
45
- let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}";
46
- let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}";
47
- if (process.env["JSON_DEBUG"]) {
48
- console.log(SERIALIZE_RAW_EMPTY);
49
- //console.log(SERIALIZE_PRETTY_EMPTY);
50
- console.log(INITIALIZE_EMPTY);
51
- console.log(DESERIALIZE_EMPTY);
52
- }
53
- const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node);
54
- //const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
55
- const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node);
56
- const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node);
57
- if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
58
- node.members.push(SERIALIZE_RAW_METHOD_EMPTY);
59
- if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
60
- node.members.push(INITIALIZE_METHOD_EMPTY);
61
- if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
62
- node.members.push(DESERIALIZE_METHOD_EMPTY);
63
- this.schemasList.push(schema);
68
+ this.handleEmptyClass(node, schema, members);
64
69
  }
65
70
  for (const member of members) {
66
71
  const name = member.name;
67
- if (!(member instanceof FieldDeclaration))
68
- continue;
69
72
  if (!member.type) {
70
- throw new Error("Fields must be strongly typed! Found " +
71
- toString(member) +
72
- " at " +
73
- node.range.source.normalizedPath);
73
+ throw new Error("Fields must be strongly typed! Found " + toString(member) + " at " + node.range.source.normalizedPath);
74
74
  }
75
75
  const type = toString(member.type);
76
76
  if (type.startsWith("(") && type.includes("=>"))
@@ -87,9 +87,12 @@ class JSONTransform extends BaseVisitor {
87
87
  mem.type = type;
88
88
  mem.value = value;
89
89
  mem.node = member;
90
- if (type == "JSON.Raw") {
90
+ if (type.includes("JSON.Raw")) {
91
91
  mem.flags.set(PropertyFlags.JSON_Raw, []);
92
92
  }
93
+ if (member.type.isNullable) {
94
+ mem.flags.set(PropertyFlags.Null, []);
95
+ }
93
96
  if (member.decorators) {
94
97
  for (const decorator of member.decorators) {
95
98
  const decoratorName = decorator.name.text;
@@ -97,8 +100,7 @@ class JSONTransform extends BaseVisitor {
97
100
  switch (decoratorName) {
98
101
  case "alias": {
99
102
  if (!args.length)
100
- throw new Error("Expected 1 argument but got zero at @alias in " +
101
- node.range.source.normalizedPath);
103
+ throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath);
102
104
  mem.alias = args[0];
103
105
  mem.flags.set(PropertyFlags.Alias, args);
104
106
  break;
@@ -109,8 +111,7 @@ class JSONTransform extends BaseVisitor {
109
111
  }
110
112
  case "omitif": {
111
113
  if (!decorator.args?.length)
112
- throw new Error("Expected 1 argument but got zero at @omitif in " +
113
- node.range.source.normalizedPath);
114
+ throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath);
114
115
  mem.flags.set(PropertyFlags.OmitIf, args);
115
116
  break;
116
117
  }
@@ -121,22 +122,10 @@ class JSONTransform extends BaseVisitor {
121
122
  }
122
123
  }
123
124
  }
124
- mem.generate();
125
+ if (!mem.flags.get(PropertyFlags.Omit))
126
+ mem.generate();
125
127
  if (this.schemasList.find((v) => v.name == type)) {
126
- mem.initialize =
127
- "this." +
128
- name.text +
129
- " = changetype<nonnull<" +
130
- mem.type +
131
- ">>(__new(offsetof<nonnull<" +
132
- mem.type +
133
- ">>(), idof<nonnull<" +
134
- mem.type +
135
- ">>()));\n changetype<nonnull<" +
136
- mem.type +
137
- ">>(this." +
138
- name.text +
139
- ").__INITIALIZE()";
128
+ mem.initialize = "this." + name.text + " = changetype<nonnull<" + mem.type + ">>(__new(offsetof<nonnull<" + mem.type + ">>(), idof<nonnull<" + mem.type + ">>()));\n changetype<nonnull<" + mem.type + ">>(this." + name.text + ").__INITIALIZE()";
140
129
  }
141
130
  else if (mem.value) {
142
131
  mem.initialize = "this." + name.text + " = " + mem.value;
@@ -148,8 +137,7 @@ class JSONTransform extends BaseVisitor {
148
137
  mem.initialize = "this." + name.text + ' = ""';
149
138
  }
150
139
  else if (type === "Array") {
151
- mem.initialize =
152
- "this." + name.text + " = instantiate<" + mem.type + ">()";
140
+ mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()";
153
141
  }
154
142
  else if (type === "bool" || type === "boolean") {
155
143
  mem.initialize = "this." + name.text + " = false";
@@ -157,14 +145,7 @@ class JSONTransform extends BaseVisitor {
157
145
  else if (type === "JSON.Raw") {
158
146
  mem.initialize = "this." + name.text + ' = ""';
159
147
  }
160
- else if (type === "u8" ||
161
- type === "u16" ||
162
- type === "u32" ||
163
- type === "u64" ||
164
- type === "i8" ||
165
- type === "i16" ||
166
- type === "i32" ||
167
- type === "i64") {
148
+ else if (type === "u8" || type === "u16" || type === "u32" || type === "u64" || type === "i8" || type === "i16" || type === "i32" || type === "i64") {
168
149
  mem.initialize = "this." + name.text + " = 0";
169
150
  }
170
151
  else if (type === "f32" || type === "f64") {
@@ -179,15 +160,14 @@ class JSONTransform extends BaseVisitor {
179
160
  let indent = " ";
180
161
  if (!schema.members.length)
181
162
  return;
182
- found = false;
183
- if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) ||
184
- schema.members[0]?.flags.has(PropertyFlags.OmitIf)) {
163
+ let found = false;
164
+ if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) || schema.members[0]?.flags.has(PropertyFlags.OmitIf)) {
185
165
  SERIALIZE_RAW += schema.members[0]?.serialize;
186
- SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize;
166
+ SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty;
187
167
  }
188
168
  else {
189
169
  SERIALIZE_RAW += schema.members[0]?.serialize + ",";
190
- SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize + ",\\n";
170
+ SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty + ",\\n";
191
171
  found = true;
192
172
  }
193
173
  if (schema.members[0]?.initialize)
@@ -196,89 +176,81 @@ class JSONTransform extends BaseVisitor {
196
176
  const member = schema.members[i];
197
177
  if (member.initialize)
198
178
  INITIALIZE += " " + member.initialize + ";\n";
199
- if (member.flags.has(PropertyFlags.OmitNull) ||
200
- member.flags.has(PropertyFlags.OmitIf)) {
179
+ if (member.flags.has(PropertyFlags.Omit))
180
+ continue;
181
+ if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) {
201
182
  SERIALIZE_RAW += member.serialize;
202
- SERIALIZE_PRETTY += member.serialize;
183
+ SERIALIZE_PRETTY += member.serialize_pretty;
203
184
  }
204
185
  else {
205
186
  SERIALIZE_RAW += member.serialize + ",";
206
- SERIALIZE_PRETTY += indent + member.serialize + ",\\n";
187
+ SERIALIZE_PRETTY += indent + member.serialize_pretty + ",\\n";
207
188
  found = true;
208
189
  }
209
190
  }
210
191
  if (found) {
211
- SERIALIZE_RAW +=
212
- "`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}";
213
- SERIALIZE_PRETTY +=
214
- "`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}";
192
+ SERIALIZE_RAW += "`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}";
193
+ SERIALIZE_PRETTY += "`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}";
215
194
  }
216
195
  else {
217
- SERIALIZE_RAW += "`;\n};";
218
- SERIALIZE_PRETTY += "`;\n};";
196
+ SERIALIZE_RAW += "}`;\n return out;\n}";
197
+ SERIALIZE_PRETTY += "}`;\n return out;\n}";
219
198
  }
220
199
  INITIALIZE += " return this;\n}";
221
200
  const sortedMembers = [];
222
- const _sorted = schema.members.sort((a, b) => a.name.length - b.name.length);
223
- let len = 0;
224
- let offset = 0;
225
- sortedMembers.push([_sorted[0]]);
226
- len = _sorted[0]?.name.length;
227
- for (let i = 1; i < _sorted.length; i++) {
201
+ const _sorted = schema.members.sort((a, b) => (a.alias?.length || a.name.length) - (b.alias?.length || b.name.length));
202
+ let len = -1;
203
+ let offset = -1;
204
+ for (let i = 0; i < _sorted.length; i++) {
228
205
  const member = _sorted[i];
229
- if (member.alias?.length || member.name.length > len) {
230
- sortedMembers.push([member]);
231
- len = member.alias?.length || member.name.length;
232
- offset++;
206
+ const _name = member.alias || member.name;
207
+ if (_name.length === len) {
208
+ sortedMembers[offset]?.push(member);
233
209
  }
234
210
  else {
235
- sortedMembers[offset].push(member);
211
+ sortedMembers.push([member]);
212
+ len = _name.length;
213
+ offset++;
236
214
  }
237
215
  }
238
216
  let first = true;
239
217
  for (const memberSet of sortedMembers) {
240
218
  const firstMember = memberSet[0];
241
- const name = encodeKey(firstMember.alias || firstMember.name);
242
- if (name.length === 1) {
219
+ const _name = encodeKey(firstMember.alias || firstMember.name);
220
+ if (_name.length === 1) {
243
221
  if (first) {
244
- DESERIALIZE +=
245
- " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
222
+ DESERIALIZE += " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
246
223
  first = false;
247
224
  }
248
225
  else {
249
- DESERIALIZE +=
250
- "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
226
+ DESERIALIZE += "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n";
251
227
  }
252
228
  }
253
- else if (name.length === 2) {
229
+ else if (_name.length === 2) {
254
230
  if (first) {
255
- DESERIALIZE +=
256
- " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
231
+ DESERIALIZE += " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
257
232
  first = false;
258
233
  }
259
234
  else {
260
- DESERIALIZE +=
261
- "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
235
+ DESERIALIZE += "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
262
236
  }
263
237
  }
264
- else if (name.length === 4) {
238
+ else if (_name.length === 4) {
265
239
  if (first) {
266
- DESERIALIZE +=
267
- " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
240
+ DESERIALIZE += " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
268
241
  first = false;
269
242
  }
270
243
  else {
271
- DESERIALIZE +=
272
- "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
244
+ DESERIALIZE += "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
273
245
  }
274
246
  }
275
247
  else {
276
248
  if (first) {
277
- DESERIALIZE += " if (" + name.length + " === len) {\n";
249
+ DESERIALIZE += " if (" + _name.length + " === len) {\n";
278
250
  first = false;
279
251
  }
280
252
  else {
281
- DESERIALIZE += "else if (" + name.length + " === len) {\n";
253
+ DESERIALIZE += "else if (" + _name.length + " === len) {\n";
282
254
  }
283
255
  }
284
256
  let f = true;
@@ -286,48 +258,40 @@ class JSONTransform extends BaseVisitor {
286
258
  const member = memberSet[i];
287
259
  if (!member.deserialize)
288
260
  continue;
289
- const name = encodeKey(member.alias || member.name);
290
- if (name.length === 1) {
291
- DESERIALIZE += ` case ${name.charCodeAt(0)}: {\n ${member.deserialize}\n return true;\n }\n`;
261
+ const _name = encodeKey(member.alias || member.name);
262
+ if (_name.length === 1) {
263
+ DESERIALIZE += ` case ${_name.charCodeAt(0)}: { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
292
264
  }
293
- else if (name.length === 2) {
294
- DESERIALIZE += ` case ${charCodeAt32(name, 0)}: {\n ${member.deserialize}\n return true;\n }\n`;
265
+ else if (_name.length === 2) {
266
+ DESERIALIZE += ` case ${charCodeAt32(_name, 0)}: { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
295
267
  }
296
- else if (name.length === 4) {
268
+ else if (_name.length === 4) {
297
269
  if (f) {
298
270
  f = false;
299
- DESERIALIZE += ` if (${charCodeAt64(name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
271
+ DESERIALIZE += ` if (${charCodeAt64(_name, 0)} === code) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
300
272
  }
301
273
  else {
302
- DESERIALIZE =
303
- DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
304
- `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`;
305
275
  }
306
276
  }
307
277
  else {
308
278
  if (f) {
309
279
  f = false;
310
- 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`;
280
+ 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`;
311
281
  }
312
282
  else {
313
- DESERIALIZE =
314
- DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
315
- ` else if (0 == memory.compare(changetype<usize>("${escapeQuote(escapeSlash(name))}"), changetype<usize>(data) + (key_start << 1), ${name.length << 1})) {\n ${member.deserialize}\n return true;\n }\n`;
283
+ DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
316
284
  }
317
285
  }
318
286
  }
319
- if (name.length < 3) {
287
+ if (_name.length < 3) {
320
288
  DESERIALIZE += ` default: {\n return false;\n }\n }\n`;
321
289
  }
322
- else if (name.length == 4) {
323
- DESERIALIZE =
324
- DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
325
- ` else {\n return false;\n }\n`;
290
+ else if (_name.length == 4) {
291
+ DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
326
292
  }
327
293
  else {
328
- DESERIALIZE =
329
- DESERIALIZE.slice(0, DESERIALIZE.length - 1) +
330
- ` else {\n return false;\n }\n`;
294
+ DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
331
295
  }
332
296
  DESERIALIZE += " } ";
333
297
  }
@@ -335,16 +299,18 @@ class JSONTransform extends BaseVisitor {
335
299
  //console.log(sortedMembers);
336
300
  if (process.env["JSON_DEBUG"]) {
337
301
  console.log(SERIALIZE_RAW);
338
- //console.log(SERIALIZE_PRETTY);
302
+ console.log(SERIALIZE_PRETTY);
339
303
  console.log(INITIALIZE);
340
304
  console.log(DESERIALIZE);
341
305
  }
342
306
  const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(SERIALIZE_RAW, node);
343
- //const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
307
+ const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
344
308
  const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
345
309
  const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
346
310
  if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
347
311
  node.members.push(SERIALIZE_RAW_METHOD);
312
+ if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY"))
313
+ node.members.push(SERIALIZE_PRETTY_METHOD);
348
314
  if (!node.members.find((v) => v.name.text == "__INITIALIZE"))
349
315
  node.members.push(INITIALIZE_METHOD);
350
316
  if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
@@ -370,15 +336,13 @@ export default class Transformer extends Transform {
370
336
  .sort((_a, _b) => {
371
337
  const a = _a.internalPath;
372
338
  const b = _b.internalPath;
373
- if (a[0] === "~" && b[0] !== "~") {
374
- return -1;
375
- }
376
- else if (a[0] !== "~" && b[0] === "~") {
339
+ if (a[0] !== "~" && b[0] === "~") {
377
340
  return 1;
378
341
  }
379
- else {
380
- return 0;
342
+ if (a[0] === "~" && b[0] !== "~") {
343
+ return -1;
381
344
  }
345
+ return 0;
382
346
  });
383
347
  // Loop over every source
384
348
  for (const source of sources) {
@@ -390,35 +354,92 @@ export default class Transformer extends Transform {
390
354
  // Check that every parent and child class is hooked up correctly
391
355
  const schemas = transformer.schemasList;
392
356
  for (const schema of schemas) {
393
- if (schema.parent) {
394
- const parent = schemas.find((v) => v.name === schema.parent?.name);
395
- if (!parent)
396
- throw new Error(`Class ${schema.name} extends its parent class ${schema.parent}, but ${schema.parent} does not include a @json or @serializable decorator! Add the decorator and rebuild.`);
357
+ checkInheritance(schema, schemas);
358
+ const invalidType = checkTypeCorrectness(schema, schemas);
359
+ if (invalidType) {
360
+ logError(`Type ${invalidType.type} implemented in property ${invalidType.path} is not a JSON-compatible type!\nEither decorate it with @omit or fix it!`);
397
361
  }
398
362
  }
399
363
  }
400
364
  }
365
+ function checkInheritance(schema, schemas) {
366
+ if (!schema.parent && schema.node.extendsType) {
367
+ if (schemas.find(v => v.node.name.text === schema.node.extendsType?.name.identifier.text))
368
+ return;
369
+ const extending = toString(schema.node.extendsType);
370
+ logError(`Schema ${schema.name} extends ${extending}, but ${extending} does not include the @json decorator!`);
371
+ }
372
+ }
373
+ function checkTypeCorrectness(schema, schemas) {
374
+ const parent = schemas.find((v) => v.name === schema.parent?.name);
375
+ const generic_types = [...(schema?.node.typeParameters?.map((v) => v.name.text) || []), ...(parent?.node.typeParameters?.map((v) => v.name.text) || [])];
376
+ const member_types = [...(schema.members.map((v) => v.node.type.name.identifier.text) || [])];
377
+ const scopeTypes = new Set([...json_types, ...generic_types, ...member_types]);
378
+ for (const typ of member_types) {
379
+ if (typ === "JSON")
380
+ continue; // JSON.Raw, JSON.Box, JSON.Any, ect...
381
+ if (json_types.includes(typ))
382
+ continue;
383
+ if (generic_types.includes(typ))
384
+ continue;
385
+ const check = schemas.find((v) => v.name == typ);
386
+ if (!check)
387
+ logError(`Type ${typ} is not a JSON compatible type or does not include the @json flag!`);
388
+ }
389
+ for (const member of schema.members) {
390
+ const invalidType = checkType(schema, schemas, member.node.type, member, scopeTypes, schema.name);
391
+ if (invalidType)
392
+ logError(`Type ${invalidType.type} in ${invalidType.path} does not implement a JSON compatible type!\n${chalk.dim(` at ${member.node.range.source.normalizedPath.replace("~lib/", "./node_modules/")}`)}`);
393
+ }
394
+ return null;
395
+ }
396
+ function checkType(schema, schemas, typ, member, scopeTypes, path) {
397
+ path += "." + member.name;
398
+ if (schemas.find(v => v.node.name.text === typ.name.identifier.text))
399
+ scopeTypes.add(typ.name.identifier.text);
400
+ if (!scopeTypes.has(typ.name.identifier.text))
401
+ return { type: toString(typ), path };
402
+ if (typ.isNullable && isPrimitive(typ))
403
+ return { type: toString(typ), path };
404
+ if (typ.typeArguments?.length && typ.typeArguments?.length > 0) {
405
+ for (const ty of typ.typeArguments.filter((v) => v instanceof NamedTypeNode)) {
406
+ const check = checkType(schema, schemas, ty, member, scopeTypes, path);
407
+ if (check)
408
+ return { type: toString(typ), path };
409
+ }
410
+ }
411
+ else {
412
+ if (scopeTypes.has(typ.name.identifier.text))
413
+ return null;
414
+ }
415
+ return null;
416
+ }
417
+ function logError(message) {
418
+ console.log("\n" + chalk.bold.bgRed(" Error ") + chalk.dim(":") + " " + message + "\n");
419
+ process.exit(1);
420
+ }
401
421
  var PropertyFlags;
402
422
  (function (PropertyFlags) {
403
- PropertyFlags[PropertyFlags["Omit"] = 0] = "Omit";
404
- PropertyFlags[PropertyFlags["OmitNull"] = 1] = "OmitNull";
405
- PropertyFlags[PropertyFlags["OmitIf"] = 2] = "OmitIf";
406
- PropertyFlags[PropertyFlags["Alias"] = 3] = "Alias";
407
- PropertyFlags[PropertyFlags["JSON_Raw"] = 4] = "JSON_Raw";
423
+ PropertyFlags[PropertyFlags["Null"] = 0] = "Null";
424
+ PropertyFlags[PropertyFlags["Omit"] = 1] = "Omit";
425
+ PropertyFlags[PropertyFlags["OmitNull"] = 2] = "OmitNull";
426
+ PropertyFlags[PropertyFlags["OmitIf"] = 3] = "OmitIf";
427
+ PropertyFlags[PropertyFlags["Alias"] = 4] = "Alias";
428
+ PropertyFlags[PropertyFlags["JSON_Raw"] = 5] = "JSON_Raw";
408
429
  })(PropertyFlags || (PropertyFlags = {}));
409
430
  class Property {
410
- constructor() {
411
- this.name = "";
412
- this.alias = null;
413
- this.type = "";
414
- this.value = null;
415
- this.flags = new Map();
416
- this.serialize = null;
417
- this.deserialize = null;
418
- this.initialize = null;
419
- this.right_s = "";
420
- this.right_d = "";
421
- }
431
+ name = "";
432
+ alias = null;
433
+ type = "";
434
+ value = null;
435
+ flags = new Map();
436
+ serialize = null;
437
+ serialize_pretty = null;
438
+ deserialize = null;
439
+ initialize = null;
440
+ node;
441
+ right_s = "";
442
+ right_d = "";
422
443
  generate() {
423
444
  const name = this.name;
424
445
  const escapedName = escapeString(JSON.stringify(this.alias || this.name));
@@ -426,52 +447,44 @@ class Property {
426
447
  if (this.flags.has(PropertyFlags.Omit))
427
448
  return;
428
449
  if (this.flags.has(PropertyFlags.JSON_Raw)) {
429
- this.right_s = "this." + name;
430
- this.right_d = "data.substring(value_start, value_end);";
450
+ if (this.flags.has(PropertyFlags.Null)) {
451
+ this.right_s = "(this." + name + ' || "null")';
452
+ this.right_d = "value_start === value_end - 4 && 30399761348886638 === load<u64>(changetype<usize>(data) + (value_start << 1)) ? null : data.substring(value_start, value_end)";
453
+ }
454
+ else {
455
+ this.right_s = "this." + name;
456
+ this.right_d = "data.substring(value_start, value_end);";
457
+ }
431
458
  }
432
459
  else {
433
460
  this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")";
434
- this.right_d =
435
- "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
461
+ this.right_d = "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))";
436
462
  }
437
463
  if (this.flags.has(PropertyFlags.OmitIf)) {
438
464
  const condition = this.flags.get(PropertyFlags.OmitIf)[0];
439
465
  if (!condition)
440
466
  throw new Error("Could not find condition when using decorator @omitif! Provide at least one condition");
441
- this.serialize =
442
- "${" +
443
- condition +
444
- ' ? "" : \'' +
445
- escapedName +
446
- ":' + " +
447
- this.right_s +
448
- ' + ","}';
467
+ this.serialize = "${" + condition + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}';
468
+ this.serialize_pretty = "${" + condition + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}';
449
469
  this.deserialize = "this." + name + " = " + this.right_d + ";";
450
470
  }
451
471
  else if (this.flags.has(PropertyFlags.OmitNull)) {
452
- this.serialize =
453
- "${changetype<usize>(this." +
454
- name +
455
- ") == <usize>0" +
456
- ' ? "" : \'' +
457
- escapedName +
458
- ":' + " +
459
- this.right_s +
460
- ' + ","}';
472
+ this.serialize = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}';
473
+ this.serialize_pretty = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}';
461
474
  this.deserialize = "this." + name + " = " + this.right_d + ";";
462
475
  }
463
476
  else {
464
477
  this.serialize = escapedName + ":${" + this.right_s + "}";
478
+ this.serialize_pretty = escapedName + ": ${" + this.right_s + "}";
465
479
  this.deserialize = "this." + name + " = " + this.right_d + ";";
466
480
  }
467
481
  }
468
482
  }
469
483
  class SchemaData {
470
- constructor() {
471
- this.name = "";
472
- this.members = [];
473
- this.parent = null;
474
- }
484
+ name = "";
485
+ members = [];
486
+ parent = null;
487
+ node;
475
488
  }
476
489
  function charCodeAt32(data, offset) {
477
490
  return (data.charCodeAt(offset + 1) << 16) | data.charCodeAt(offset);
@@ -484,10 +497,7 @@ function charCodeAt64(data, offset) {
484
497
  const secondCharCode = BigInt(data.charCodeAt(offset + 1));
485
498
  const thirdCharCode = BigInt(data.charCodeAt(offset + 2));
486
499
  const fourthCharCode = BigInt(data.charCodeAt(offset + 3));
487
- const u64Value = (fourthCharCode << 48n) |
488
- (thirdCharCode << 32n) |
489
- (secondCharCode << 16n) |
490
- firstCharCode;
500
+ const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode;
491
501
  return u64Value;
492
502
  }
493
503
  function encodeKey(key) {
@@ -532,3 +542,7 @@ function getArgs(args) {
532
542
  }
533
543
  return out;
534
544
  }
545
+ function isPrimitive(type) {
546
+ const primitives = new Set(["u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean"]);
547
+ return primitives.has(type.name.identifier.text);
548
+ }