json-as 0.7.0 → 0.7.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.
@@ -15,7 +15,6 @@ function canSer<T>(data: T, toBe: string): void {
15
15
  expect(serialized).toBe(toBe);
16
16
  }
17
17
 
18
- // @ts-ignore
19
18
  @json
20
19
  class Map4 {
21
20
  a: string;
@@ -24,7 +23,6 @@ class Map4 {
24
23
  d: string;
25
24
  }
26
25
 
27
- // @ts-ignore
28
26
  @json
29
27
  class Vec3 {
30
28
  x: f64;
@@ -32,7 +30,6 @@ class Vec3 {
32
30
  z: f64;
33
31
  }
34
32
 
35
- // @ts-ignore
36
33
  @json
37
34
  class Player {
38
35
  firstName: string;
@@ -179,7 +176,6 @@ describe("Ser externals", () => {
179
176
  })
180
177
  });
181
178
 
182
- // @ts-ignore
183
179
  @json
184
180
  class HttpResp {
185
181
  statusCode: number;
@@ -202,4 +198,148 @@ describe("Deser externals", () => {
202
198
  body: '{\n "args": {},\n "headers": {\n "content-length": "0",\n "accept": "*/*" \n}}'
203
199
  })
204
200
  })
205
- });
201
+ });
202
+
203
+ describe("Ser/de Maps", () => {
204
+ it("should serialize Map<string, string>", () => {
205
+ const m = new Map<string, string>();
206
+ m.set("a", "x");
207
+ m.set("b", "y");
208
+ m.set("c", "z");
209
+ canSer(m, '{"a":"x","b":"y","c":"z"}');
210
+ });
211
+ it("should serialize Map<string, string | null>", () => {
212
+ const m = new Map<string, string | null>();
213
+ m.set("a", "x");
214
+ m.set("b", "y");
215
+ m.set("c", null);
216
+ canSer(m, '{"a":"x","b":"y","c":null}');
217
+ });
218
+ it("should serialize Map<string, string[]]>", () => {
219
+ const m = new Map<string, string[]>();
220
+ m.set("a", ["a1", "a2", "a3"]);
221
+ m.set("b", ["b1", "b2", "b3"]);
222
+ m.set("c", ["c1", "c2", "c3"]);
223
+ canSer(m, '{"a":["a1","a2","a3"],"b":["b1","b2","b3"],"c":["c1","c2","c3"]}');
224
+ });
225
+ it("should serialize Map<string, u32>", () => {
226
+ const m = new Map<string, u32>();
227
+ m.set("a", 1);
228
+ m.set("b", 2);
229
+ m.set("c", 3);
230
+ canSer(m, '{"a":1,"b":2,"c":3}');
231
+ });
232
+ it("should serialize Map<string, bool>", () => {
233
+ const m = new Map<string, bool>();
234
+ m.set("a", true);
235
+ m.set("b", false);
236
+ m.set("c", true);
237
+ canSer(m, '{"a":true,"b":false,"c":true}');
238
+ });
239
+ it("should serialize Map<string, Vec3>", () => {
240
+ const m = new Map<string, Vec3>();
241
+ m.set("foo", { x: 1, y: 2, z: 3 });
242
+ m.set("bar", { x: 11.5, y: 12.5, z: 13.5 });
243
+ canSer(m, '{"foo":{"x":1.0,"y":2.0,"z":3.0},"bar":{"x":11.5,"y":12.5,"z":13.5}}');
244
+ });
245
+
246
+ it("should deserialize Map<string, string>", () => {
247
+ const m = new Map<string, string>();
248
+ m.set("a", "x");
249
+ m.set("b", "y");
250
+ m.set("c", "z");
251
+ canDeser('{"a":"x","b":"y","c":"z"}', m);
252
+ });
253
+ it("should deserialize Map<string, string | null>", () => {
254
+ const m = new Map<string, string | null>();
255
+ m.set("a", "x");
256
+ m.set("b", "y");
257
+ m.set("c", null);
258
+ canDeser('{"a":"x","b":"y","c":null}', m);
259
+ });
260
+ it("should deserialize Map<string, string[]>", () => {
261
+ const m = new Map<string, string[]>();
262
+ m.set("a", ["a1", "a2", "a3"]);
263
+ m.set("b", ["b1", "b2", "b3"]);
264
+ m.set("c", ["c1", "c2", "c3"]);
265
+ canDeser('{"a":["a1","a2","a3"],"b":["b1","b2","b3"],"c":["c1","c2","c3"]}', m);
266
+ });
267
+ it("should deserialize Map<string, u32>", () => {
268
+ const m = new Map<string, u32>();
269
+ m.set("a", 1);
270
+ m.set("b", 2);
271
+ m.set("c", 3);
272
+ canDeser('{"a":1,"b":2,"c":3}', m);
273
+ });
274
+ it("should deserialize Map<string, bool>", () => {
275
+ const m = new Map<string, bool>();
276
+ m.set("a", true);
277
+ m.set("b", false);
278
+ m.set("c", true);
279
+ canDeser('{"a":true,"b":false,"c":true}', m);
280
+ });
281
+ it("should deserialize Map<string, Vec3>", () => {
282
+ const m = new Map<string, Vec3>();
283
+ m.set("foo", { x: 1, y: 2, z: 3 });
284
+ m.set("bar", { x: 11.5, y: 12.5, z: 13.5 });
285
+ canDeser('{"foo":{"x":1.0,"y":2.0,"z":3.0},"bar":{"x":11.5,"y":12.5,"z":13.5}}', m);
286
+ });
287
+
288
+ it("should serialize Map<u32, bool>", () => {
289
+ const m = new Map<u32, bool>();
290
+ m.set(1, true);
291
+ m.set(2, false);
292
+ m.set(3, true);
293
+ canSer(m, '{"1":true,"2":false,"3":true}');
294
+ });
295
+ it("should deserialize Map<u32, bool>", () => {
296
+ const m = new Map<u32, bool>();
297
+ m.set(1, true);
298
+ m.set(2, false);
299
+ m.set(3, true);
300
+ canDeser('{"1":true,"2":false,"3":true}', m);
301
+ });
302
+
303
+ it("should serialize Map<bool, string>", () => {
304
+ const m = new Map<bool, string>();
305
+ m.set(true, "a");
306
+ m.set(false, "b");
307
+ canSer(m, '{"true":"a","false":"b"}');
308
+ });
309
+ it("should deserialize Map<bool, string>", () => {
310
+ const m = new Map<bool, string>();
311
+ m.set(true, "a");
312
+ m.set(false, "b");
313
+ canDeser('{"true":"a","false":"b"}', m);
314
+ });
315
+
316
+ it("should serialize Map<string, string>[]", () => {
317
+ const m1 = new Map<string, string>();
318
+ m1.set("a", "u");
319
+ m1.set("b", "v");
320
+ m1.set("c", "w");
321
+
322
+ const m2 = new Map<string, string>();
323
+ m2.set("d", "x");
324
+ m2.set("e", "y");
325
+ m2.set("f", "z");
326
+
327
+ const a = [m1, m2];
328
+ canSer(a, '[{"a":"u","b":"v","c":"w"},{"d":"x","e":"y","f":"z"}]');
329
+ });
330
+ it("should deserialize Map<string, string>[]", () => {
331
+ const m1 = new Map<string, string>();
332
+ m1.set("a", "u");
333
+ m1.set("b", "v");
334
+ m1.set("c", "w");
335
+
336
+ const m2 = new Map<string, string>();
337
+ m2.set("d", "x");
338
+ m2.set("e", "y");
339
+ m2.set("f", "z");
340
+
341
+ const a = [m1, m2];
342
+ canDeser('[{"a":"u","b":"v","c":"w"},{"d":"x","e":"y","f":"z"}]', a);
343
+ });
344
+
345
+ });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Class decorator that enables the class to be serializable as JSON.
3
+ */
4
+ declare function json(target: any): void;
5
+
6
+ /**
7
+ * Class decorator that enables the class to be serializable as JSON.
8
+ */
9
+ declare function serializable(target: any): void;
10
+
11
+ /**
12
+ * Property decorator that provides an alias name for JSON serialization.
13
+ */
14
+ declare function alias(name: string): Function;
package/assembly/index.ts CHANGED
@@ -1 +1,3 @@
1
+ /// <reference path="./index.d.ts" />
2
+
1
3
  export { JSON } from "./src/json";
@@ -43,13 +43,21 @@
43
43
  // @ts-ignore: Decorator is valid here
44
44
  @inline export const nullWord = "null";
45
45
  // @ts-ignore: Decorator is valid here
46
+ @inline export const leftBraceWord = "{";
47
+ // @ts-ignore: Decorator is valid here
46
48
  @inline export const leftBracketWord = "[";
47
49
  // @ts-ignore: Decorator is valid here
48
50
  @inline export const emptyArrayWord = "[]";
49
51
  // @ts-ignore: Decorator is valid here
52
+ @inline export const colonWord = ":";
53
+ // @ts-ignore: Decorator is valid here
50
54
  @inline export const commaWord = ",";
51
55
  // @ts-ignore: Decorator is valid here
56
+ @inline export const rightBraceWord = "}";
57
+ // @ts-ignore: Decorator is valid here
52
58
  @inline export const rightBracketWord = "]";
59
+ // @ts-ignore: Decorator is valid here
60
+ @inline export const quoteWord = "\"";
53
61
  // Escape Codes
54
62
  // @ts-ignore: Decorator is valid here
55
63
  @inline export const newLineCode = 10;
@@ -1,28 +1,39 @@
1
1
  import { StringSink } from "as-string-sink/assembly";
2
2
  import { isSpace } from "util/string";
3
- import { E_INVALIDDATE } from "util/error";
4
3
  import {
5
- backSlashCode,
6
- commaCode,
7
- commaWord,
4
+ aCode,
8
5
  eCode,
9
6
  fCode,
7
+ lCode,
8
+ nCode,
9
+ rCode,
10
+ sCode,
11
+ tCode,
12
+ uCode,
13
+
14
+ backSlashCode,
15
+ colonCode,
16
+ commaCode,
10
17
  leftBraceCode,
11
18
  leftBracketCode,
12
- leftBracketWord,
13
- nCode,
14
- nullWord,
19
+ newLineCode,
15
20
  quoteCode,
16
- rCode,
17
21
  rightBraceCode,
18
22
  rightBracketCode,
23
+
24
+ colonWord,
25
+ commaWord,
26
+ quoteWord,
27
+
28
+ leftBraceWord,
29
+ leftBracketWord,
30
+ rightBraceWord,
19
31
  rightBracketWord,
20
- tCode,
21
- trueWord,
22
- uCode,
23
32
  emptyArrayWord,
33
+
34
+ trueWord,
24
35
  falseWord,
25
- newLineCode,
36
+ nullWord,
26
37
  } from "./chars";
27
38
  import { snip_fast, unsafeCharCodeAt } from "./util";
28
39
  import { Virtual } from "as-virtual/assembly";
@@ -47,7 +58,7 @@ export namespace JSON {
47
58
  } else if (isBoolean<T>()) {
48
59
  return data ? "true" : "false";
49
60
  } else if (isNullable<T>() && data == null) {
50
- return "null";
61
+ return nullWord;
51
62
  // @ts-ignore
52
63
  } else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
53
64
  // @ts-ignore
@@ -64,7 +75,7 @@ export namespace JSON {
64
75
  return emptyArrayWord;
65
76
  // @ts-ignore
66
77
  } else if (isString<valueof<T>>()) {
67
- let result = "[";
78
+ let result = leftBracketWord;
68
79
  // @ts-ignore
69
80
  for (let i = 0; i < data.length - 1; i++) {
70
81
  // @ts-ignore
@@ -96,6 +107,20 @@ export namespace JSON {
96
107
  result.write(rightBracketWord);
97
108
  return result.toString();
98
109
  }
110
+ } else if (data instanceof Map) {
111
+ let result = new StringSink(leftBraceWord);
112
+ let keys = data.keys();
113
+ let values = data.values();
114
+ for (let i = 0; i < data.size; i++) {
115
+ result.write(serializeString(keys[i].toString()));
116
+ result.write(colonWord);
117
+ result.write(JSON.stringify(values[i]));
118
+ if (i < data.size - 1) {
119
+ result.write(commaWord);
120
+ }
121
+ }
122
+ result.write(rightBraceWord);
123
+ return result.toString();
99
124
  } else {
100
125
  throw new Error(
101
126
  `Could not serialize data of type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
@@ -117,10 +142,10 @@ export namespace JSON {
117
142
  out = serializeString(data as string);
118
143
  return;
119
144
  } else if (isBoolean<T>()) {
120
- out = data ? "true" : "false";
145
+ out = data ? trueWord : falseWord;
121
146
  return;
122
147
  } else if (isNullable<T>() && data == null) {
123
- out = "null";
148
+ out = nullWord;
124
149
  return;
125
150
  // @ts-ignore
126
151
  } else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
@@ -133,7 +158,7 @@ export namespace JSON {
133
158
  out = data.__JSON_Serialize();
134
159
  return;
135
160
  } else if (data instanceof Date) {
136
- out = "\"" + data.toISOString() + "\"";
161
+ out = quoteWord + data.toISOString() + quoteWord;
137
162
  return;
138
163
  } else if (isArrayLike<T>()) {
139
164
  // @ts-ignore
@@ -142,7 +167,7 @@ export namespace JSON {
142
167
  return;
143
168
  // @ts-ignore
144
169
  } else if (isString<valueof<T>>()) {
145
- out = "[";
170
+ out = leftBracketWord;
146
171
  // @ts-ignore
147
172
  for (let i = 0; i < data.length - 1; i++) {
148
173
  // @ts-ignore
@@ -206,18 +231,18 @@ export namespace JSON {
206
231
  } else if (isArrayLike<T>()) {
207
232
  // @ts-ignore
208
233
  return parseArray<T>(data.trimStart());
209
- // @ts-ignore
210
- } else if (isNullable<T>() && data == "null") {
234
+ } else if (isNullable<T>() && data == nullWord) {
211
235
  // @ts-ignore
212
236
  return null;
213
237
  // @ts-ignore
214
238
  } else if (isDefined(type.__JSON_Set_Key)) {
215
239
  return parseObject<T>(data.trimStart(), initializeDefaultValues);
240
+ } else if (isMap<T>()) {
241
+ return parseMap<T>(data.trimStart(), initializeDefaultValues);
216
242
  } else if (idof<nonnull<T>>() == idof<Date>()) {
217
243
  // @ts-ignore
218
244
  return parseDate(data);
219
245
  } else {
220
- // @ts-ignore
221
246
  throw new Error(
222
247
  `Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
223
248
  );
@@ -229,7 +254,6 @@ export namespace JSON {
229
254
  @global @inline function __parseObjectValue<T>(data: string, initializeDefaultValues: boolean): T {
230
255
  let type: T;
231
256
  if (isString<T>()) {
232
- // @ts-ignore
233
257
  let result = "";
234
258
  let last = 0;
235
259
  for (let i = 0; i < data.length; i++) {
@@ -283,18 +307,18 @@ export namespace JSON {
283
307
  } else if (isArrayLike<T>()) {
284
308
  // @ts-ignore
285
309
  return parseArray<T>(data);
286
- // @ts-ignore
287
- } else if (isNullable<T>() && data == "null") {
310
+ } else if (isNullable<T>() && data == nullWord) {
288
311
  // @ts-ignore
289
312
  return null;
290
313
  // @ts-ignore
291
314
  } else if (isDefined(type.__JSON_Set_Key)) {
292
315
  return parseObject<T>(data.trimStart(), initializeDefaultValues);
316
+ } else if (isMap<T>()) {
317
+ return parseMap<T>(data.trimStart(), initializeDefaultValues);
293
318
  } else if (idof<nonnull<T>>() == idof<Date>()) {
294
319
  // @ts-ignore
295
320
  return parseDate(data);
296
321
  } else {
297
- // @ts-ignore
298
322
  throw new Error(
299
323
  `Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
300
324
  );
@@ -306,7 +330,6 @@ export namespace JSON {
306
330
  let result = new StringSink('"');
307
331
 
308
332
  let last: i32 = 0;
309
- // @ts-ignore
310
333
  for (let i = 0; i < data.length; i++) {
311
334
  const char = unsafeCharCodeAt(<string>data, i);
312
335
  if (char === 34 || char === 92) {
@@ -344,9 +367,11 @@ export namespace JSON {
344
367
  }
345
368
  }
346
369
  }
347
- if (result.length === 1) return '"' + data + '"';
348
- else result.write(<string>data, last);
349
- result.write("\"");
370
+ if (result.length === 1) {
371
+ return quoteWord + data + quoteWord;
372
+ }
373
+ result.write(<string>data, last);
374
+ result.write(quoteWord);
350
375
  return result.toString();
351
376
  }
352
377
 
@@ -410,14 +435,16 @@ export namespace JSON {
410
435
  }
411
436
  }
412
437
  }
413
- if ((data.length - 1) > last) result.write(data, last, data.length - 1);
438
+ if ((data.length - 1) > last) {
439
+ result.write(data, last, data.length - 1);
440
+ }
414
441
  return result.toString();
415
442
  }
416
443
 
417
444
  // @ts-ignore: Decorator
418
445
  @inline function parseBoolean<T extends boolean>(data: string): T {
419
- if (data.length > 3 && data.startsWith("true")) return <T>true;
420
- else if (data.length > 4 && data.startsWith("false")) return <T>false;
446
+ if (data.length > 3 && data.startsWith(trueWord)) return <T>true;
447
+ else if (data.length > 4 && data.startsWith(falseWord)) return <T>false;
421
448
  else throw new Error(`JSON: Cannot parse "${data}" as boolean`);
422
449
  }
423
450
 
@@ -437,13 +464,14 @@ export namespace JSON {
437
464
 
438
465
  // @ts-ignore: Decorator
439
466
  @inline function parseObject<T>(data: string, initializeDefaultValues: boolean): T {
440
- let schema: nonnull<T> = changetype<nonnull<T>>(
467
+ const schema: nonnull<T> = changetype<nonnull<T>>(
441
468
  __new(offsetof<nonnull<T>>(), idof<nonnull<T>>())
442
469
  );
470
+
443
471
  // @ts-ignore
444
472
  if (initializeDefaultValues) schema.__JSON_Initialize();
445
473
 
446
- let key = Virtual.createEmpty<string>();
474
+ const key = Virtual.createEmpty<string>();
447
475
  let isKey = false;
448
476
  let depth = 0;
449
477
  let outerLoopIndex = 1;
@@ -519,7 +547,12 @@ export namespace JSON {
519
547
  escaping = false;
520
548
  }
521
549
  }
522
- } else if (char == nCode) {
550
+ } else if (
551
+ char == nCode &&
552
+ unsafeCharCodeAt(data, ++outerLoopIndex) === uCode &&
553
+ unsafeCharCodeAt(data, ++outerLoopIndex) === lCode &&
554
+ unsafeCharCodeAt(data, ++outerLoopIndex) === lCode
555
+ ) {
523
556
  // @ts-ignore
524
557
  schema.__JSON_Set_Key<Virtual<string>>(key, nullWord, 0, 4, initializeDefaultValues);
525
558
  isKey = false;
@@ -534,9 +567,9 @@ export namespace JSON {
534
567
  isKey = false;
535
568
  } else if (
536
569
  char === fCode &&
537
- unsafeCharCodeAt(data, ++outerLoopIndex) === "a".charCodeAt(0) &&
538
- unsafeCharCodeAt(data, ++outerLoopIndex) === "l".charCodeAt(0) &&
539
- unsafeCharCodeAt(data, ++outerLoopIndex) === "s".charCodeAt(0) &&
570
+ unsafeCharCodeAt(data, ++outerLoopIndex) === aCode &&
571
+ unsafeCharCodeAt(data, ++outerLoopIndex) === lCode &&
572
+ unsafeCharCodeAt(data, ++outerLoopIndex) === sCode &&
540
573
  unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
541
574
  ) {
542
575
  // @ts-ignore
@@ -559,6 +592,156 @@ export namespace JSON {
559
592
  return schema;
560
593
  }
561
594
 
595
+ // @ts-ignore: Decorator
596
+ @inline function parseMap<T extends Map>(data: string, initializeDefaultValues: boolean): T {
597
+
598
+ const map: nonnull<T> = changetype<nonnull<T>>(
599
+ __new(offsetof<nonnull<T>>(), idof<nonnull<T>>())
600
+ );
601
+
602
+ if (!isDefined(map.set)) {
603
+ return unreachable();
604
+ }
605
+
606
+ const key = Virtual.createEmpty<string>();
607
+ let isKey = false;
608
+ let depth = 0;
609
+ let outerLoopIndex = 1;
610
+ for (; outerLoopIndex < data.length - 1; outerLoopIndex++) {
611
+ const char = unsafeCharCodeAt(data, outerLoopIndex);
612
+ if (char === leftBracketCode) {
613
+ for (
614
+ let arrayValueIndex = outerLoopIndex;
615
+ arrayValueIndex < data.length - 1;
616
+ arrayValueIndex++
617
+ ) {
618
+ const char = unsafeCharCodeAt(data, arrayValueIndex);
619
+ if (char === leftBracketCode) {
620
+ depth++;
621
+ } else if (char === rightBracketCode) {
622
+ depth--;
623
+ if (depth === 0) {
624
+ ++arrayValueIndex;
625
+ map.set(parseMapKey<indexof<T>>(key), JSON.parse<valueof<T>>(data.slice(outerLoopIndex, arrayValueIndex), initializeDefaultValues));
626
+ outerLoopIndex = arrayValueIndex;
627
+ isKey = false;
628
+ break;
629
+ }
630
+ }
631
+ }
632
+ } else if (char === leftBraceCode) {
633
+ for (
634
+ let objectValueIndex = outerLoopIndex;
635
+ objectValueIndex < data.length - 1;
636
+ objectValueIndex++
637
+ ) {
638
+ const char = unsafeCharCodeAt(data, objectValueIndex);
639
+ if (char === leftBraceCode) {
640
+ depth++;
641
+ } else if (char === rightBraceCode) {
642
+ depth--;
643
+ if (depth === 0) {
644
+ ++objectValueIndex;
645
+ map.set(parseMapKey<indexof<T>>(key), JSON.parse<valueof<T>>(data.slice(outerLoopIndex, objectValueIndex), initializeDefaultValues));
646
+ outerLoopIndex = objectValueIndex;
647
+ isKey = false;
648
+ break;
649
+ }
650
+ }
651
+ }
652
+ } else if (char === quoteCode) {
653
+ let escaping = false;
654
+ for (
655
+ let stringValueIndex = ++outerLoopIndex;
656
+ stringValueIndex < data.length - 1;
657
+ stringValueIndex++
658
+ ) {
659
+ const char = unsafeCharCodeAt(data, stringValueIndex);
660
+ if (char === backSlashCode && !escaping) {
661
+ escaping = true;
662
+ } else {
663
+ if (
664
+ char === quoteCode && !escaping
665
+ ) {
666
+ if (isKey === false) {
667
+ key.reinst(data, outerLoopIndex, stringValueIndex);
668
+ isKey = true;
669
+ } else {
670
+ if (isString<valueof<T>>()) {
671
+ map.set(parseMapKey<indexof<T>>(key), data.slice(outerLoopIndex, stringValueIndex));
672
+ }
673
+ isKey = false;
674
+ }
675
+ outerLoopIndex = ++stringValueIndex;
676
+ break;
677
+ }
678
+ escaping = false;
679
+ }
680
+ }
681
+ } else if (
682
+ char == nCode &&
683
+ unsafeCharCodeAt(data, ++outerLoopIndex) === uCode &&
684
+ unsafeCharCodeAt(data, ++outerLoopIndex) === lCode &&
685
+ unsafeCharCodeAt(data, ++outerLoopIndex) === lCode) {
686
+ if (isNullable<valueof<T>>()) {
687
+ map.set(parseMapKey<indexof<T>>(key), null);
688
+ }
689
+ isKey = false;
690
+ } else if (
691
+ char === tCode &&
692
+ unsafeCharCodeAt(data, ++outerLoopIndex) === rCode &&
693
+ unsafeCharCodeAt(data, ++outerLoopIndex) === uCode &&
694
+ unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
695
+ ) {
696
+ if (isBoolean<valueof<T>>()) {
697
+ map.set(parseMapKey<indexof<T>>(key), true);
698
+ }
699
+ isKey = false;
700
+ } else if (
701
+ char === fCode &&
702
+ unsafeCharCodeAt(data, ++outerLoopIndex) === aCode &&
703
+ unsafeCharCodeAt(data, ++outerLoopIndex) === lCode &&
704
+ unsafeCharCodeAt(data, ++outerLoopIndex) === sCode &&
705
+ unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
706
+ ) {
707
+ if (isBoolean<valueof<T>>()) {
708
+ map.set(parseMapKey<indexof<T>>(key), false);
709
+ }
710
+ isKey = false;
711
+ } else if ((char >= 48 && char <= 57) || char === 45) {
712
+ let numberValueIndex = ++outerLoopIndex;
713
+ for (; numberValueIndex < data.length; numberValueIndex++) {
714
+ const char = unsafeCharCodeAt(data, numberValueIndex);
715
+ if (char === colonCode || char === commaCode || char === rightBraceCode || isSpace(char)) {
716
+ if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
717
+ map.set(parseMapKey<indexof<T>>(key), parseNumber<valueof<T>>(data.slice(outerLoopIndex - 1, numberValueIndex)));
718
+ }
719
+ outerLoopIndex = numberValueIndex;
720
+ isKey = false;
721
+ break;
722
+ }
723
+ }
724
+ }
725
+ }
726
+
727
+ return map;
728
+ }
729
+
730
+ //@ts-ignore: Decorator
731
+ @inline function parseMapKey<T>(key: Virtual<string>): T {
732
+ const k = key.copyOut();
733
+ if (isString<T>()) {
734
+ return k as T;
735
+ } else if (isBoolean<T>()) {
736
+ // @ts-ignore
737
+ return parseBoolean<T>(k) as T;
738
+ } else if (isInteger<T>() || isFloat<T>()) {
739
+ return parseNumber<T>(k);
740
+ }
741
+
742
+ throw new Error(`JSON: Cannot parse JSON object to a Map with a key of type ${nameof<T>()}`);
743
+ }
744
+
562
745
  // @ts-ignore: Decorator
563
746
  @inline function parseArray<T extends unknown[]>(data: string): T {
564
747
  if (isString<valueof<T>>()) {
@@ -572,7 +755,8 @@ export namespace JSON {
572
755
  } else if (isArrayLike<valueof<T>>()) {
573
756
  // @ts-ignore
574
757
  return parseArrayArray<T>(data);
575
- // @ts-ignore
758
+ } else if (isMap<valueof<T>>()) {
759
+ return parseObjectArray<T>(data);
576
760
  } else if (isManaged<valueof<T>>() || isReference<valueof<T>>()) {
577
761
  // We instantiate the required memory for the class and fill it. This is extremely unsafe and uses "a bit of magic".
578
762
  const type = changetype<nonnull<valueof<T>>>(
@@ -580,11 +764,10 @@ export namespace JSON {
580
764
  );
581
765
  // @ts-ignore
582
766
  if (isDefined(type.__JSON_Set_Key)) {
583
- // @ts-ignore
584
767
  return parseObjectArray<T>(data);
585
768
  }
586
- return unreachable();
587
769
  }
770
+
588
771
  return unreachable();
589
772
  }
590
773
 
@@ -725,3 +908,9 @@ function parseDate(dateTimeString: string): Date {
725
908
  // is globally aliased to wasi_Date (or some other superclass).
726
909
  return new Date(d.getTime());
727
910
  }
911
+
912
+ // @ts-ignore: Decorator
913
+ @inline function isMap<T>(): bool {
914
+ let type = changetype<T>(0);
915
+ return type instanceof Map;
916
+ }
package/assembly/test.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { JSON } from "./src/json";
2
2
 
3
- // @ts-ignore
4
3
  @serializable
5
4
  class Vec3 {
6
5
  x: f64 = 3.4;
@@ -8,7 +7,6 @@ class Vec3 {
8
7
  z: f64 = 8.3;
9
8
  }
10
9
 
11
- // @ts-ignore
12
10
  @serializable
13
11
  class Player extends Vec3 {
14
12
  @alias("first name")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "JSON encoder/decoder for AssemblyScript",
5
5
  "types": "assembly/index.ts",
6
6
  "author": "Jairus Tanaka",
@@ -10,7 +10,8 @@
10
10
  "Derek Barrera",
11
11
  "Frankk Taylor",
12
12
  "lekiano",
13
- "Florian Guitton"
13
+ "Florian Guitton",
14
+ "Matt Johnson-Pint"
14
15
  ],
15
16
  "license": "MIT",
16
17
  "scripts": {
@@ -28,18 +29,18 @@
28
29
  "prettier": "as-prettier -w ."
29
30
  },
30
31
  "devDependencies": {
31
- "@as-pect/cli": "^8.0.1",
32
- "@as-tral/cli": "^2.0.1",
32
+ "@as-pect/cli": "^8.1.0",
33
+ "@as-tral/cli": "^3.0.2",
33
34
  "@assemblyscript/wasi-shim": "^0.1.0",
34
35
  "as-bench": "^0.0.0-alpha",
35
- "assemblyscript": "^0.27.18",
36
+ "assemblyscript": "^0.27.22",
36
37
  "assemblyscript-prettier": "^3.0.1",
37
38
  "benchmark": "^2.1.4",
38
39
  "kati": "^0.6.2",
39
40
  "microtime": "^3.1.1",
40
- "prettier": "^3.1.0",
41
+ "prettier": "^3.1.1",
41
42
  "tinybench": "^2.5.1",
42
- "typescript": "^5.2.2",
43
+ "typescript": "^5.3.3",
43
44
  "visitor-as": "^0.11.4"
44
45
  },
45
46
  "dependencies": {
@@ -47,6 +48,9 @@
47
48
  "as-variant": "^0.4.1",
48
49
  "as-virtual": "^0.1.9"
49
50
  },
51
+ "overrides": {
52
+ "assemblyscript": "$assemblyscript"
53
+ },
50
54
  "repository": {
51
55
  "type": "git",
52
56
  "url": "git+https://github.com/JairusSW/as-json.git"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@json-as/transform",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "JSON encoder/decoder for AssemblyScript",
5
5
  "main": "./lib/index.js",
6
6
  "author": "Jairus Tanaka",