json-as 0.5.0 → 0.5.2

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.
@@ -0,0 +1,463 @@
1
+ import { StringSink } from "as-string-sink/assembly";
2
+ import { isSpace } from "util/string";
3
+ import { Type } from "./type";
4
+ import {
5
+ backSlashCode,
6
+ colonCode,
7
+ commaCode,
8
+ eCode,
9
+ fCode,
10
+ forwardSlashCode,
11
+ lCode,
12
+ leftBraceCode,
13
+ leftBracketCode,
14
+ nCode,
15
+ quoteCode,
16
+ rightBraceCode,
17
+ rightBracketCode,
18
+ tCode,
19
+ uCode,
20
+ } from "./chars";
21
+ import { unsafeCharCodeAt } from "./util";
22
+
23
+ /**
24
+ * JSON Encoder/Decoder for AssemblyScript
25
+ */
26
+ export class JSON {
27
+ /**
28
+ * Stringifies valid JSON data.
29
+ * ```js
30
+ * JSON.stringify<T>(data)
31
+ * ```
32
+ * @param data T
33
+ * @returns string
34
+ */
35
+ static stringify<T>(data: T): string {
36
+ // String
37
+ if (isString<T>()) {
38
+ return '"' + (<string>data).replaceAll('"', '\\"') + '"';
39
+ }
40
+ // Boolean
41
+ else if (isBoolean<T>()) {
42
+ return data ? "true" : "false";
43
+ }
44
+ // Nullable
45
+ else if (isNullable<T>() && data == null) {
46
+ return "null";
47
+ }
48
+ // Integers/Floats
49
+ // @ts-ignore
50
+ else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
51
+ // @ts-ignore
52
+ return data.toString();
53
+ }
54
+ // Class-Based serialization
55
+ // @ts-ignore
56
+ else if (isDefined(data.__JSON_Serialize)) {
57
+ // @ts-ignore
58
+ //if (isNullable<T>()) return "null";
59
+ // @ts-ignore
60
+ return data.__JSON_Serialize();
61
+ }
62
+ // ArrayLike
63
+ else if (isArrayLike<T>()) {
64
+ let result = new StringSink("[");
65
+ // @ts-ignore
66
+ if (data.length == 0) return "[]";
67
+ // @ts-ignore
68
+ for (let i = 0; i < data.length - 1; i++) {
69
+ // @ts-ignore
70
+ result.write(JSON.stringify(unchecked(data[i])) + ",");
71
+ }
72
+ // @ts-ignore
73
+ result.write(JSON.stringify(unchecked(data[data.length - 1])));
74
+ result.write("]");
75
+ return result.toString();
76
+ } else {
77
+ return "null";
78
+ }
79
+ }
80
+ /**
81
+ * Parses valid JSON strings into their original format.
82
+ * ```js
83
+ * JSON.parse<T>(data)
84
+ * ```
85
+ * @param data string
86
+ * @returns T
87
+ */
88
+ static parse<T>(data: string): T {
89
+ let type!: T;
90
+ if (isString<T>()) {
91
+ // @ts-ignore
92
+ return parseString(data);
93
+ } else if (isBoolean<T>()) {
94
+ // @ts-ignore
95
+ return parseBoolean<T>(data);
96
+ } else if (isFloat<T>() || isInteger<T>()) {
97
+ return parseNumber<T>(data);
98
+ } else if (isArrayLike<T>()) {
99
+ // @ts-ignore
100
+ return parseArray<T>(data.trimStart());
101
+ // @ts-ignore
102
+ } else if (isNullable<T>() && data == "null") {
103
+ // @ts-ignore
104
+ return null
105
+ // @ts-ignore
106
+ } else if (isDefined(type.__JSON_Deserialize)) {
107
+ return parseObject<T>(data.trimStart());
108
+ } else {
109
+ // @ts-ignore
110
+ return null;
111
+ }
112
+ }
113
+ private static parseObjectValue<T>(data: string): T {
114
+ let type!: T;
115
+ if (isString<T>()) {
116
+ // @ts-ignore
117
+ return data.replaceAll('\\"', '"');
118
+ } else if (isBoolean<T>()) {
119
+ // @ts-ignore
120
+ return parseBoolean<T>(data);
121
+ } else if (isFloat<T>() || isInteger<T>()) {
122
+ return parseNumber<T>(data);
123
+ } else if (isArrayLike<T>()) {
124
+ // @ts-ignore
125
+ return parseArray<T>(data);
126
+ // @ts-ignore
127
+ } else if (isNullable<T>() && data == "null") {
128
+ // @ts-ignore
129
+ return null
130
+ // @ts-ignore
131
+ } else if (isDefined(type.__JSON_Deserialize)) {
132
+ // @ts-ignore
133
+ //if (isNullable<T>()) return null;
134
+ return parseObject<T>(data);
135
+ } else {
136
+ // @ts-ignore
137
+ //return null;
138
+ throw new Error(`Could not parse value: ${data}`)
139
+ }
140
+ }
141
+ }
142
+
143
+ // @ts-ignore
144
+ @inline
145
+ function parseString(data: string): string {
146
+ return data.slice(1, data.length - 1).replaceAll('\\"', '"');
147
+ }
148
+
149
+ // @ts-ignore
150
+ @inline
151
+ function parseBoolean<T extends boolean>(data: string): T {
152
+ if (data.length > 3 && data.startsWith("true")) return <T>true;
153
+ else if (data.length > 4 && data.startsWith("false")) return <T>false;
154
+ else throw new Error(`JSON: Cannot parse "${data}" as boolean`);
155
+ }
156
+
157
+ // @ts-ignore
158
+ @inline
159
+ function parseNumber<T>(data: string): T {
160
+ let type: T;
161
+ // @ts-ignore
162
+ if (type instanceof f64) return F64.parseFloat(data);
163
+ // @ts-ignore
164
+ else if (type instanceof f32) return F32.parseFloat(data);
165
+ // @ts-ignore
166
+ else if (type instanceof u64) return U64.parseInt(data);
167
+ // @ts-ignore
168
+ else if (type instanceof u32) return U32.parseInt(data);
169
+ // @ts-ignore
170
+ else if (type instanceof u8) return U8.parseInt(data);
171
+ // @ts-ignore
172
+ else if (type instanceof u16) return U16.parseInt(data);
173
+ // @ts-ignore
174
+ else if (type instanceof i64) return I64.parseInt(data);
175
+ // @ts-ignore
176
+ else if (type instanceof i32) return I32.parseInt(data);
177
+ // @ts-ignore
178
+ else if (type instanceof i16) return I16.parseInt(data);
179
+ // @ts-ignore
180
+ else if (type instanceof i8) return I8.parseInt(data);
181
+ else
182
+ throw new Error(
183
+ `JSON: Cannot parse invalid data into a number. Either "${data}" is not a valid number, or <${nameof<T>()}> is an invald number type.`
184
+ );
185
+ }
186
+
187
+ // @ts-ignore
188
+ @inline
189
+ export function parseObject<T>(data: string): T {
190
+ let schema: T = changetype<T>(__new(offsetof<T>(), idof<T>()));
191
+ const result = new Map<string, string>();
192
+ let key = "";
193
+ let isKey = false;
194
+ let depth = 1;
195
+ let char = 0;
196
+ let outerLoopIndex = 1
197
+ for (; outerLoopIndex < data.length - 1; outerLoopIndex++) {
198
+ char = unsafeCharCodeAt(data, outerLoopIndex);
199
+ if (char === leftBracketCode) {
200
+ for (let arrayValueIndex = outerLoopIndex; arrayValueIndex < data.length - 1; arrayValueIndex++) {
201
+ char = unsafeCharCodeAt(data, arrayValueIndex);
202
+ if (char === leftBracketCode) {
203
+ depth = depth << 1;
204
+ } else if (char === rightBracketCode) {
205
+ depth = depth >> 1;
206
+ if (depth === 1) {
207
+ ++arrayValueIndex;
208
+ result.set(
209
+ key,
210
+ data.slice(outerLoopIndex, arrayValueIndex)
211
+ );
212
+ outerLoopIndex = arrayValueIndex;
213
+ isKey = false;
214
+ break;
215
+ }
216
+ }
217
+ }
218
+ } else if (char === leftBraceCode) {
219
+ for (let objectValueIndex = outerLoopIndex; objectValueIndex < data.length - 1; objectValueIndex++) {
220
+ char = unsafeCharCodeAt(data, objectValueIndex);
221
+ if (char === leftBraceCode) {
222
+ depth = depth << 1;
223
+ } else if (char === rightBraceCode) {
224
+ depth = depth >> 1;
225
+ if (depth === 1) {
226
+ ++objectValueIndex;
227
+ result.set(
228
+ key,
229
+ data.slice(outerLoopIndex, objectValueIndex)
230
+ );
231
+ outerLoopIndex = objectValueIndex;
232
+ isKey = false;
233
+ break;
234
+ }
235
+ }
236
+ }
237
+ } else if (char === quoteCode) {
238
+ for (let stringValueIndex = ++outerLoopIndex; stringValueIndex < data.length - 1; stringValueIndex++) {
239
+ char = unsafeCharCodeAt(data, stringValueIndex);
240
+ if (
241
+ char === quoteCode &&
242
+ unsafeCharCodeAt(data, stringValueIndex - 1) !== backSlashCode
243
+ ) {
244
+ if (isKey === false) {
245
+ key = data.slice(outerLoopIndex, stringValueIndex);
246
+ isKey = true;
247
+ } else {
248
+ result.set(
249
+ key,
250
+ data.slice(outerLoopIndex, stringValueIndex)
251
+ );
252
+ isKey = false;
253
+ }
254
+ outerLoopIndex = ++stringValueIndex;
255
+ break;
256
+ }
257
+ }
258
+ } else if (char == nCode) {
259
+ result.set(
260
+ key,
261
+ "null"
262
+ )
263
+ isKey = false;
264
+ } else if (
265
+ char === tCode &&
266
+ unsafeCharCodeAt(data, ++outerLoopIndex) === "r".charCodeAt(0) &&
267
+ unsafeCharCodeAt(data, ++outerLoopIndex) === "u".charCodeAt(0) &&
268
+ unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
269
+ ) {
270
+ result.set(key, "true");
271
+ isKey = false;
272
+ } else if (
273
+ char === fCode &&
274
+ unsafeCharCodeAt(data, ++outerLoopIndex) === "a".charCodeAt(0) &&
275
+ unsafeCharCodeAt(data, ++outerLoopIndex) === "l".charCodeAt(0) &&
276
+ unsafeCharCodeAt(data, ++outerLoopIndex) === "s".charCodeAt(0) &&
277
+ unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
278
+ ) {
279
+ result.set(key, "false");
280
+ isKey = false;
281
+ } else if ((char >= 48 && char <= 57) || char === 45) {
282
+ let numberValueIndex = ++outerLoopIndex;
283
+ for (; numberValueIndex < data.length; numberValueIndex++) {
284
+ char = unsafeCharCodeAt(data, numberValueIndex);
285
+ if (
286
+ char === commaCode ||
287
+ char === rightBraceCode ||
288
+ isSpace(char)
289
+ ) {
290
+ result.set(
291
+ key,
292
+ data.slice(outerLoopIndex - 1, numberValueIndex)
293
+ );
294
+ outerLoopIndex = numberValueIndex;
295
+ isKey = false;
296
+ break;
297
+ }
298
+ }
299
+ }
300
+ }
301
+ // @ts-ignore
302
+ const deserialized = changetype<nonnull<T>>(schema).__JSON_Deserialize<T>(result)
303
+ heap.free(changetype<usize>(schema));
304
+ return deserialized;
305
+ }
306
+
307
+ // @ts-ignore
308
+ @inline
309
+ // @ts-ignore
310
+ export function parseArray<T extends unknown[]>(data: string): T {
311
+ // TODO: Replace with opt
312
+ let type!: valueof<T>;
313
+ if (type instanceof String) {
314
+ return <T>parseStringArray(data);
315
+ } else if (isBoolean<valueof<T>>()) {
316
+ // @ts-ignore
317
+ return parseBooleanArray<T>(data);
318
+ } else if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
319
+ // @ts-ignore
320
+ return parseNumberArray<T>(data);
321
+ } else if (isArrayLike<valueof<T>>()) {
322
+ // @ts-ignore
323
+ return parseArrayArray<T>(data);
324
+ // @ts-ignore
325
+ } else if (isDefined(type.__JSON_Deserialize)) {
326
+ // @ts-ignore
327
+ return parseObjectArray<T>(data);
328
+ }
329
+ }
330
+
331
+ // @ts-ignore
332
+ @inline
333
+ export function parseStringArray(data: string): string[] {
334
+ const result: string[] = [];
335
+ let lastPos = 0;
336
+ let instr = false;
337
+ for (let i = 1; i < data.length - 1; i++) {
338
+ if (unsafeCharCodeAt(data, i) === quoteCode) {
339
+ if (instr === false) {
340
+ instr = true;
341
+ lastPos = i;
342
+ } else if (unsafeCharCodeAt(data, i - 1) !== backSlashCode) {
343
+ instr = false;
344
+ result.push(data.slice(lastPos + 1, i).replaceAll('\\"', '"'));
345
+ }
346
+ }
347
+ }
348
+ return result;
349
+ }
350
+
351
+ // @ts-ignore
352
+ @inline
353
+ export function parseBooleanArray<T extends boolean[]>(data: string): T {
354
+ const result = instantiate<T>();
355
+ let lastPos = 1;
356
+ let char = 0;
357
+ for (let i = 1; i < data.length - 1; i++) {
358
+ char = unsafeCharCodeAt(data, i);
359
+ /*// if char == "t" && i+3 == "e"
360
+ if (char === tCode && data.charCodeAt(i + 3) === eCode) {
361
+ //i += 3;
362
+ result.push(parseBoolean<valueof<T>>(data.slice(lastPos, i+2)));
363
+ //i++;
364
+ } else if (char === fCode && data.charCodeAt(i + 4) === eCode) {
365
+ //i += 4;
366
+ result.push(parseBoolean<valueof<T>>(data.slice(lastPos, i+3)));
367
+ //i++;
368
+ }*/
369
+ if (char === tCode || char === fCode) {
370
+ lastPos = i;
371
+ } else if (char === eCode) {
372
+ i++;
373
+ result.push(parseBoolean<valueof<T>>(data.slice(lastPos, i)));
374
+ }
375
+ }
376
+ return result;
377
+ }
378
+
379
+ // @ts-ignore
380
+ @inline
381
+ export function parseNumberArray<T extends number[]>(data: string): T {
382
+ const result = instantiate<T>();
383
+ let lastPos = 0;
384
+ let char = 0;
385
+ let i = 1;
386
+ for (; i < data.length - 1; i++) {
387
+ char = unsafeCharCodeAt(data, i);
388
+ if (lastPos === 0 && (char >= 48 && char <= 57) || char === 45) {
389
+ lastPos = i;
390
+ } else if ((isSpace(char) || char == commaCode) && lastPos > 0) {
391
+ result.push(parseNumber<valueof<T>>(data.slice(lastPos, i)));
392
+ lastPos = 0;
393
+ }
394
+ }
395
+ for (; i > lastPos - 1; i--) {
396
+ char = unsafeCharCodeAt(data, i);
397
+ if (char !== rightBracketCode) {
398
+ result.push(parseNumber<valueof<T>>(data.slice(lastPos, i + 1)));
399
+ break;
400
+ }
401
+ }
402
+ return result;
403
+ }
404
+
405
+ // @ts-ignore
406
+ @inline
407
+ export function parseArrayArray<T extends unknown[][]>(data: string): T {
408
+ const result = instantiate<T>();
409
+ let char = 0;
410
+ let lastPos = 0;
411
+ let depth = 1;
412
+ let i = 1;
413
+ // Find start of bracket
414
+ //for (; unsafeCharCodeAt(data, i) !== leftBracketCode; i++) {}
415
+ //i++;
416
+ for (; i < data.length - 1; i++) {
417
+ char = unsafeCharCodeAt(data, i);
418
+ if (char === leftBracketCode) {
419
+ if (depth === 1) {
420
+ lastPos = i;
421
+ }
422
+ // Shifting is 6% faster than incrementing
423
+ depth = depth << 1;
424
+ } else if (char === rightBracketCode) {
425
+ depth = depth >> 1;
426
+ if (depth === 1) {
427
+ i++;
428
+ result.push(JSON.parse<valueof<T>>(data.slice(lastPos, i)));
429
+ }
430
+ }
431
+ }
432
+ return result;
433
+ }
434
+
435
+ // @ts-ignore
436
+ @inline
437
+ export function parseObjectArray<T extends unknown[][]>(data: string): T {
438
+ const result = instantiate<T>();
439
+ let char = 0;
440
+ let lastPos = 1;
441
+ let depth = 1;
442
+ let i = 1;
443
+ // Find start of bracket
444
+ //for (; unsafeCharCodeAt(data, i) !== leftBracketCode; i++) { }
445
+ //i++;
446
+ for (; i < data.length - 1; i++) {
447
+ char = unsafeCharCodeAt(data, i);
448
+ if (char === leftBraceCode) {
449
+ if (depth === 1) {
450
+ lastPos = i;
451
+ }
452
+ // Shifting is 6% faster than incrementing
453
+ depth = depth << 1;
454
+ } else if (char === rightBraceCode) {
455
+ depth = depth >> 1;
456
+ if (depth === 1) {
457
+ i++;
458
+ result.push(JSON.parse<valueof<T>>(data.slice(lastPos, i)));
459
+ }
460
+ }
461
+ }
462
+ return result;
463
+ }
package/assembly/test.ts CHANGED
@@ -6,10 +6,7 @@ import {
6
6
  // @ts-ignore
7
7
  @json
8
8
  class Vec2 {
9
- /**
10
- * x > 4 && x < 100
11
- */
12
- private x: f32 = 0;
9
+ x: f32;
13
10
  y: f32;
14
11
  }
15
12
 
@@ -20,7 +17,7 @@ class Player {
20
17
  lastName: string;
21
18
  lastActive: i32[];
22
19
  age: i32;
23
- pos: Vec2;
20
+ pos: Vec2 | null;
24
21
  isVerified: boolean;
25
22
  }
26
23
 
@@ -30,21 +27,18 @@ const player: Player = {
30
27
  lastActive: [8, 27, 2022],
31
28
  age: 23,
32
29
  pos: {
30
+ x: 3.4,
33
31
  y: 1.2,
34
32
  },
35
33
  isVerified: true,
36
34
  };
37
35
 
38
36
  const vec: Vec2 = {
39
- y: 0.0
37
+ x: 3.4,
38
+ y: 1.2
40
39
  }
40
+
41
41
  const serializedPlayer = JSON.stringify<Player>(player);
42
42
  console.log("Serialized Player: " + serializedPlayer);
43
43
  const deserializedPlayer = JSON.parse<Player>(serializedPlayer);
44
- console.log("Deserialized Player: " + JSON.stringify(deserializedPlayer));
45
-
46
- const serializedVec2 = JSON.stringify<Vec2>(vec);
47
- console.log("Serialized Vec2: " + serializedVec2);
48
- const deserializedVec2 = JSON.parse<Vec2>(serializedVec2);
49
-
50
- console.log("Deserialized Vec2: " + JSON.stringify(deserializedVec2));
44
+ console.log("Deserialized Player: " + JSON.stringify(deserializedPlayer))
@@ -0,0 +1,13 @@
1
+ export class Type<T> {
2
+ // Edited by transform at compile-time
3
+ public value: any;
4
+ constructor(value: T) {
5
+ this.value = value;
6
+ }
7
+ set(data: any) {
8
+
9
+ }
10
+ static from<T>(value: T): Type<T> {
11
+ return new Type<T>(value);
12
+ }
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "JSON encoder/decoder for AssemblyScript",
5
5
  "types": "assembly/index.ts",
6
6
  "author": "Jairus Tanaka",
@@ -25,11 +25,11 @@
25
25
  "@serial-as/json": "^2.0.0",
26
26
  "assemblyscript": "^0.20.7",
27
27
  "assemblyscript-prettier": "^1.0.2",
28
+ "prettier": "^2.7.1",
28
29
  "typescript": "^4.7.2"
29
30
  },
30
31
  "dependencies": {
31
- "as-string-sink": "^0.5.0",
32
- "as-variant": "^0.4.0"
32
+ "as-string-sink": "^0.5.0"
33
33
  },
34
34
  "repository": {
35
35
  "type": "git",
@@ -7,6 +7,7 @@ class AsJSONTransform extends ClassDecorator {
7
7
  this.sources = [];
8
8
  this.encodeStmts = [];
9
9
  this.decodeStmts = [];
10
+ this.checkDecodeStmts = [];
10
11
  }
11
12
  visitMethodDeclaration() { }
12
13
  visitFieldDeclaration(node) {
@@ -17,21 +18,22 @@ class AsJSONTransform extends ClassDecorator {
17
18
  if (!node.type) {
18
19
  throw new Error(`Field ${name} is missing a type declaration`);
19
20
  }
20
- const type = getName(node.type);
21
+ let type = getName(node.type);
21
22
  // @ts-ignore
22
23
  this.encodeStmts.push(`"${name}":\${JSON.stringify<${type}>(this.${name})},`);
23
24
  // @ts-ignore
24
25
  this.decodeStmts.push(`${name}: JSON.parseObjectValue<${type}>(values.get("${name}")),\n`);
26
+ // @ts-ignore
27
+ this.checkDecodeStmts.push(' if (!values.has("${name}")) throw new Error("Key "${name}" was not found. Cannot instantiate object.");\n');
25
28
  }
26
29
  visitClassDeclaration(node) {
27
30
  if (!node.members) {
28
31
  return;
29
32
  }
30
33
  this.currentClass = node;
31
- const name = getName(node);
32
34
  this.visit(node.members);
33
- const serializedProp = `__JSON_Serialized: string = "";`;
34
- let serializeFunc = ``;
35
+ const serializedProp = '__JSON_Serialized: string = "";';
36
+ let serializeFunc = "";
35
37
  if (this.encodeStmts.length > 0) {
36
38
  const stmt = this.encodeStmts[this.encodeStmts.length - 1];
37
39
  this.encodeStmts[this.encodeStmts.length - 1] = stmt.slice(0, stmt.length - 1);
@@ -52,7 +54,8 @@ class AsJSONTransform extends ClassDecorator {
52
54
  }
53
55
  const deserializeFunc = `
54
56
  @inline
55
- __JSON_Deserialize(values: Map<string, string>): ${name} {
57
+ __JSON_Deserialize<T>(values: Map<string, string>): T {
58
+ ${process.argv.includes("--debugJSON") ? this.checkDecodeStmts.join("else") : ""}
56
59
  return {
57
60
  ${
58
61
  // @ts-ignore
@@ -62,7 +65,6 @@ class AsJSONTransform extends ClassDecorator {
62
65
  `;
63
66
  this.encodeStmts = [];
64
67
  this.decodeStmts = [];
65
- //console.log(serializeFunc, deserializeFunc)
66
68
  const serializedProperty = SimpleParser.parseClassMember(serializedProp, node);
67
69
  node.members.push(serializedProperty);
68
70
  const serializeMethod = SimpleParser.parseClassMember(serializeFunc, node);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@json-as/transform",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "JSON encoder/decoder for AssemblyScript",
5
5
  "main": "./lib/index.js",
6
6
  "author": "Jairus Tanaka",
@@ -15,6 +15,7 @@ class AsJSONTransform extends ClassDecorator {
15
15
  public sources: Source[] = [];
16
16
  public encodeStmts: string[] = [];
17
17
  public decodeStmts: string[] = [];
18
+ public checkDecodeStmts: string[] = [];
18
19
 
19
20
  visitMethodDeclaration(): void {}
20
21
  visitFieldDeclaration(node: FieldDeclaration): void {
@@ -25,8 +26,7 @@ class AsJSONTransform extends ClassDecorator {
25
26
  throw new Error(`Field ${name} is missing a type declaration`);
26
27
  }
27
28
 
28
- const type = getName(node.type);
29
-
29
+ let type = getName(node.type);
30
30
  // @ts-ignore
31
31
  this.encodeStmts.push(
32
32
  `"${name}":\${JSON.stringify<${type}>(this.${name})},`
@@ -36,6 +36,9 @@ class AsJSONTransform extends ClassDecorator {
36
36
  this.decodeStmts.push(
37
37
  `${name}: JSON.parseObjectValue<${type}>(values.get("${name}")),\n`
38
38
  );
39
+
40
+ // @ts-ignore
41
+ this.checkDecodeStmts.push(' if (!values.has("${name}")) throw new Error("Key "${name}" was not found. Cannot instantiate object.");\n')
39
42
  }
40
43
  visitClassDeclaration(node: ClassDeclaration): void {
41
44
  if (!node.members) {
@@ -44,13 +47,11 @@ class AsJSONTransform extends ClassDecorator {
44
47
 
45
48
  this.currentClass = node;
46
49
 
47
- const name = getName(node);
48
-
49
50
  this.visit(node.members);
50
51
 
51
- const serializedProp = `__JSON_Serialized: string = "";`;
52
+ const serializedProp = '__JSON_Serialized: string = "";';
52
53
 
53
- let serializeFunc = ``;
54
+ let serializeFunc = "";
54
55
 
55
56
  if (this.encodeStmts.length > 0) {
56
57
  const stmt = this.encodeStmts[this.encodeStmts.length - 1]!;
@@ -72,21 +73,20 @@ class AsJSONTransform extends ClassDecorator {
72
73
  }
73
74
  `;
74
75
  }
75
-
76
76
  const deserializeFunc = `
77
77
  @inline
78
- __JSON_Deserialize(values: Map<string, string>): ${name} {
78
+ __JSON_Deserialize<T>(values: Map<string, string>): T {
79
+ ${process.argv.includes("--debugJSON") ? this.checkDecodeStmts.join("else") : ""}
79
80
  return {
80
81
  ${
81
- // @ts-ignore
82
- this.decodeStmts.join("")
82
+ // @ts-ignore
83
+ this.decodeStmts.join("")
83
84
  }
84
85
  }
85
86
  }
86
87
  `;
87
88
  this.encodeStmts = [];
88
89
  this.decodeStmts = [];
89
- //console.log(serializeFunc, deserializeFunc)
90
90
  const serializedProperty = SimpleParser.parseClassMember(
91
91
  serializedProp,
92
92
  node