json-as 0.8.6 → 0.8.8

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.
Files changed (35) hide show
  1. package/CHANGELOG +2 -1
  2. package/assembly/__benches__/as-json.ts +1 -1
  3. package/assembly/deserialize/array/array.ts +31 -0
  4. package/assembly/deserialize/array/bool.ts +19 -0
  5. package/assembly/deserialize/array/float.ts +24 -0
  6. package/assembly/deserialize/array/integer.ts +24 -0
  7. package/assembly/deserialize/array/map.ts +27 -0
  8. package/assembly/deserialize/array/object.ts +27 -0
  9. package/assembly/deserialize/array/string.ts +29 -0
  10. package/assembly/deserialize/array.ts +37 -0
  11. package/assembly/deserialize/bool.ts +18 -0
  12. package/assembly/deserialize/box.ts +14 -0
  13. package/assembly/deserialize/date.ts +11 -0
  14. package/assembly/deserialize/float.ts +9 -0
  15. package/assembly/deserialize/integer.ts +7 -0
  16. package/assembly/deserialize/map.ts +182 -0
  17. package/assembly/deserialize/object.ts +139 -0
  18. package/assembly/deserialize/string.ts +88 -0
  19. package/assembly/serialize/array.ts +51 -0
  20. package/assembly/serialize/bool.ts +4 -0
  21. package/assembly/serialize/box.ts +10 -0
  22. package/assembly/serialize/date.ts +4 -0
  23. package/assembly/serialize/float.ts +4 -0
  24. package/assembly/serialize/integer.ts +5 -0
  25. package/assembly/serialize/map.ts +24 -0
  26. package/assembly/serialize/object.ts +7 -0
  27. package/assembly/serialize/string.ts +64 -0
  28. package/assembly/src/json.ts +55 -872
  29. package/assembly/src/sink.ts +286 -0
  30. package/assembly/src/util.ts +6 -0
  31. package/assembly/test.ts +8 -1
  32. package/package.json +1 -1
  33. package/transform/lib/index.js +3 -3
  34. package/transform/package.json +1 -1
  35. package/transform/src/index.ts +3 -3
@@ -1,48 +1,23 @@
1
- import { StringSink } from "as-string-sink/assembly";
2
- import { isSpace } from "util/string";
3
- import {
4
- aCode,
5
- bCode,
6
- eCode,
7
- fCode,
8
- lCode,
9
- nCode,
10
- rCode,
11
- sCode,
12
- tCode,
13
- uCode,
14
-
15
- backSlashCode,
16
- colonCode,
17
- commaCode,
18
- forwardSlashCode,
19
- leftBraceCode,
20
- leftBracketCode,
21
- quoteCode,
22
- rightBraceCode,
23
- rightBracketCode,
24
-
25
- backspaceCode,
26
- carriageReturnCode,
27
- tabCode,
28
- formFeedCode,
29
- newLineCode,
30
-
31
- commaWord,
32
- quoteWord,
33
-
34
- leftBraceWord,
35
- leftBracketWord,
36
- rightBracketWord,
37
- emptyArrayWord,
38
-
39
- trueWord,
40
- falseWord,
41
- nullWord,
42
- } from "./chars";
43
- import { snip_fast, unsafeCharCodeAt, containsCodePoint } from "./util";
44
- import { Virtual } from "as-virtual/assembly";
45
1
  import { Box } from "as-container/assembly";
2
+ import { serializeString } from "../serialize/string";
3
+ import { serializeBool } from "../serialize/bool";
4
+ import { serializeBox } from "../serialize/box";
5
+ import { serializeInteger } from "../serialize/integer";
6
+ import { serializeFloat } from "../serialize/float";
7
+ import { serializeObject } from "../serialize/object";
8
+ import { serializeDate } from "../serialize/date";
9
+ import { serializeArray } from "../serialize/array";
10
+ import { serializeMap } from "../serialize/map";
11
+ import { deserializeBoolean } from "../deserialize/bool";
12
+ import { deserializeArray } from "../deserialize/array";
13
+ import { deserializeFloat } from "../deserialize/float";
14
+ import { deserializeBox } from "../deserialize/box";
15
+ import { deserializeObject } from "../deserialize/object";
16
+ import { deserializeMap } from "../deserialize/map";
17
+ import { deserializeDate } from "../deserialize/date";
18
+ import { nullWord } from "./chars";
19
+ import { deserializeInteger } from "../deserialize/integer";
20
+ import { deserializeString } from "../deserialize/string";
46
21
 
47
22
  /**
48
23
  * JSON Encoder/Decoder for AssemblyScript
@@ -51,101 +26,44 @@ export namespace JSON {
51
26
  /**
52
27
  * Stringifies valid JSON data.
53
28
  * ```js
54
- * __JSON_Stringify<T>(data)
29
+ * JSON.stringify<T>(data)
55
30
  * ```
56
31
  * @param data T
57
32
  * @returns string
58
33
  */
59
34
  // @ts-ignore: Decorator
60
35
  @inline export function stringify<T>(data: T): string {
61
- // String
62
- if (isString<T>() && data != null) {
36
+ if (isNullable<T>() && changetype<usize>(data) == <usize>0) {
37
+ return nullWord;
38
+ // @ts-ignore
39
+ } else if (isString<T>()) {
63
40
  return serializeString(data as string);
64
41
  } else if (isBoolean<T>()) {
65
- return data ? "true" : "false";
42
+ return serializeBool(data as bool);
66
43
  } else if (data instanceof Box) {
67
- if (isNullable<T>() && (changetype<usize>(data._val) == <usize>0 || changetype<usize>(data) == <usize>0)) {
68
- return nullWord;
69
- }
70
- return JSON.stringify(data.unwrap());
71
- } else if (isNullable<T>() && changetype<usize>(data) == <usize>0) {
72
- return nullWord;
44
+ return serializeBox(data);
45
+ } else if (isInteger<T>()) {
73
46
  // @ts-ignore
74
- } else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
47
+ return serializeInteger<T>(data);
48
+ } else if (isFloat<T>(data)) {
75
49
  // @ts-ignore
76
- return data.toString();
77
- // @ts-ignore: Hidden function
78
- } else if (isDefined(data.__JSON_Serialize)) {
79
- // @ts-ignore: Hidden function
80
- return data.__JSON_Serialize();
81
- } else if (data instanceof Date) {
82
- return `"${data.toISOString()}"`;
83
- } else if (isArrayLike<T>()) {
50
+ return serializeFloat<T>(data);
51
+ // @ts-ignore: Function is generated by transform
52
+ } else if (isDefined(data.__SERIALIZE())) {
84
53
  // @ts-ignore
85
- if (data.length == 0) {
86
- return emptyArrayWord;
87
- // @ts-ignore
88
- } else if (isString<valueof<T>>()) {
89
- let result = leftBracketWord;
90
- // @ts-ignore
91
- for (let i = 0; i < data.length - 1; i++) {
92
- // @ts-ignore
93
- result += serializeString(unchecked(data[i]));
94
- result += commaWord;
95
- }
96
- // @ts-ignore
97
- result += serializeString(unchecked(data[data.length - 1]));
98
- result += rightBracketWord;
99
- return result;
100
- // @ts-ignore
101
- } else if (isBoolean<valueof<T>>()) {
102
- // @ts-ignore
103
- return leftBracketWord + data.join(commaWord) + rightBracketWord;
104
- // @ts-ignore
105
- } else if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
106
- // @ts-ignore
107
- return leftBracketWord + data.join(commaWord) + rightBracketWord;
108
- } else {
109
- let result = new StringSink(leftBracketWord);
110
- // @ts-ignore
111
- for (let i = 0; i < data.length - 1; i++) {
112
- // @ts-ignore
113
- result.write(__JSON_Stringify(unchecked(data[i])));
114
- result.writeCodePoint(commaCode);
115
- }
116
- // @ts-ignore
117
- result.write(__JSON_Stringify(unchecked(data[data.length - 1])));
118
- result.writeCodePoint(rightBracketCode);
119
- return result.toString();
120
- }
54
+ return serializeObject(data);
55
+ } else if (data instanceof Date) {
56
+ return serializeDate(data);
57
+ } else if (data instanceof Array) {
58
+ return serializeArray(data);
121
59
  } else if (data instanceof Map) {
122
- let result = new StringSink(leftBraceWord);
123
- let keys = data.keys();
124
- let values = data.values();
125
- const end = data.size - 1;
126
- for (let i = 0; i < end; i++) {
127
- result.write(serializeString(unchecked(keys[i]).toString()));
128
- result.writeCodePoint(colonCode);
129
- result.write(__JSON_Stringify(unchecked(values[i])));
130
- result.writeCodePoint(commaCode);
131
- }
132
- result.write(serializeString(unchecked(keys[end]).toString()));
133
- result.writeCodePoint(colonCode);
134
- result.write(__JSON_Stringify(unchecked(values[end])));
135
-
136
- result.writeCodePoint(rightBraceCode);
137
- return result.toString();
60
+ return serializeMap(data);
138
61
  } else {
139
62
  throw new Error(
140
63
  `Could not serialize data of type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
141
64
  );
142
65
  }
143
66
  }
144
- // @ts-ignore: Decorator
145
- @unsafe
146
- @inline export function stringifyTo<T>(data: T, out: string): void {
147
- throw new Error("Method is deprecated");
148
- }
149
67
  /**
150
68
  * Parses valid JSON strings into their original format.
151
69
  * ```js
@@ -159,35 +77,31 @@ export namespace JSON {
159
77
  @inline export function parse<T>(data: string, initializeDefaultValues: boolean = false): T {
160
78
  if (isString<T>()) {
161
79
  // @ts-ignore
162
- return parseString(data);
80
+ return deserializeString(data);
163
81
  } else if (isBoolean<T>()) {
82
+ return deserializeBoolean(data) as T;
83
+ } else if (isInteger<T>()) {
84
+ return deserializeInteger<T>(data);
85
+ } else if (isFloat<T>()) {
86
+ return deserializeFloat<T>(data);
87
+ } else if (isArray<T>()) {
164
88
  // @ts-ignore
165
- return parseBoolean<T>(data);
166
- } else if (isFloat<T>() || isInteger<T>()) {
167
- return parseNumber<T>(data);
168
- } else if (isArrayLike<T>()) {
169
- // @ts-ignore
170
- return parseArray<T>(data.trimStart());
171
- // @ts-ignore
89
+ return deserializeArray<T>(data);
172
90
  }
173
91
  let type: nonnull<T> = changetype<nonnull<T>>(0);
174
92
  if (type instanceof Box) {
175
- const instance = changetype<nonnull<T>>(__new(offsetof<nonnull<T>>(), idof<nonnull<T>>()))// as Box<usize>;
176
- const val = instance._val;
177
- instance._val = parseDirectInference(val, data);
178
- // @ts-ignore
179
- return changetype<T>(instance);
93
+ return deserializeBox<T>(data);
180
94
  } else if (isNullable<T>() && data == nullWord) {
181
95
  // @ts-ignore
182
96
  return null;
183
97
  // @ts-ignore
184
98
  } else if (isDefined(type.__JSON_Set_Key)) {
185
- return parseObject<T>(data.trimStart(), initializeDefaultValues);
186
- } else if (isMap<T>()) {
187
- return parseMap<T>(data.trimStart(), initializeDefaultValues);
188
- } else if (idof<nonnull<T>>() == idof<Date>()) {
99
+ return deserializeObject<T>(data.trimStart(), initializeDefaultValues);
100
+ } else if (type instanceof Map) {
101
+ return deserializeMap<T>(data.trimStart());
102
+ } else if (type instanceof Date) {
189
103
  // @ts-ignore
190
- return parseDate(data);
104
+ return deserializeDate(data);
191
105
  } else {
192
106
  throw new Error(
193
107
  `Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
@@ -198,744 +112,13 @@ export namespace JSON {
198
112
 
199
113
  // @ts-ignore: Decorator
200
114
  @global @inline function __parseObjectValue<T>(data: string, initializeDefaultValues: boolean): T {
201
- if (isString<T>()) {
202
- // @ts-ignore
203
- return data;
204
- } else if (isBoolean<T>()) {
205
- // @ts-ignore
206
- return parseBoolean<T>(data);
207
- } else if (isFloat<T>() || isInteger<T>()) {
208
- return parseNumber<T>(data);
209
- } else if (isArrayLike<T>()) {
210
- // @ts-ignore
211
- return parseArray<T>(data);
212
- // @ts-ignore
213
- }
214
- let type: nonnull<T> = changetype<nonnull<T>>(0);
215
- if (type instanceof Box) {
216
- const instance = changetype<nonnull<T>>(__new(offsetof<nonnull<T>>(), idof<nonnull<T>>()))// as Box<usize>;
217
- const val = instance._val;
218
- instance._val = parseDirectInference(val, data);
219
- // @ts-ignore
220
- return changetype<T>(instance);
221
- } else if (isNullable<T>() && data == nullWord) {
222
- // @ts-ignore
223
- return null;
224
- // @ts-ignore
225
- } else if (isDefined(type.__JSON_Set_Key)) {
226
- return parseObject<T>(data.trimStart(), initializeDefaultValues);
227
- } else if (isMap<T>()) {
228
- return parseMap<T>(data.trimStart(), initializeDefaultValues);
229
- } else if (idof<nonnull<T>>() == idof<Date>()) {
230
- // @ts-ignore
231
- return parseDate(data);
232
- } else {
233
- throw new Error(
234
- `Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
235
- );
236
- }
237
- }
238
-
239
- // @ts-ignore: Decorator
240
- @inline function serializeString(data: string): string {
241
- if (data.length === 0) {
242
- return quoteWord + quoteWord;
243
- }
244
-
245
- let result = new StringSink(quoteWord);
246
-
247
- let last: i32 = 0;
248
- for (let i = 0; i < data.length; i++) {
249
- const char = unsafeCharCodeAt(<string>data, i);
250
- if (char === quoteCode || char === backSlashCode) {
251
- result.write(<string>data, last, i);
252
- result.writeCodePoint(backSlashCode);
253
- last = i;
254
- } else if (char < 16) {
255
- result.write(<string>data, last, i);
256
- last = i + 1;
257
- switch (char) {
258
- case backspaceCode: {
259
- result.write("\\b");
260
- break;
261
- }
262
- case tabCode: {
263
- result.write("\\t");
264
- break;
265
- }
266
- case newLineCode: {
267
- result.write("\\n");
268
- break;
269
- }
270
- case formFeedCode: {
271
- result.write("\\f");
272
- break;
273
- }
274
- case carriageReturnCode: {
275
- result.write("\\r");
276
- break;
277
- }
278
- default: {
279
- // all chars 0-31 must be encoded as a four digit unicode escape sequence
280
- // \u0000 to \u000f handled here
281
- result.write("\\u000");
282
- result.write(char.toString(16));
283
- break;
284
- }
285
- }
286
- } else if (char < 32) {
287
- result.write(<string>data, last, i);
288
- last = i + 1;
289
- // all chars 0-31 must be encoded as a four digit unicode escape sequence
290
- // \u0010 to \u001f handled here
291
- result.write("\\u00");
292
- result.write(char.toString(16));
293
- }
294
- }
295
- result.write(<string>data, last);
296
- result.writeCodePoint(quoteCode);
297
- return result.toString();
298
- }
299
-
300
- // @ts-ignore: Decorator
301
- @inline function parseString(data: string, start: i32 = 0, end: i32 = 0): string {
302
- end = end || data.length - 1;
303
- let result = StringSink.withCapacity(end - start - 1);
304
- let last = start + 1;
305
- for (let i = last; i < end; i++) {
306
- if (unsafeCharCodeAt(data, i) !== backSlashCode) {
307
- continue;
308
- }
309
- const char = unsafeCharCodeAt(data, ++i);
310
- result.write(data, last, i - 1);
311
- switch (char) {
312
- case quoteCode: {
313
- result.writeCodePoint(quoteCode);
314
- last = i + 1;
315
- break;
316
- }
317
- case backSlashCode: {
318
- result.writeCodePoint(backSlashCode);
319
- last = i + 1;
320
- break;
321
- }
322
- case forwardSlashCode: {
323
- result.writeCodePoint(forwardSlashCode);
324
- last = i + 1;
325
- break;
326
- }
327
- case bCode: {
328
- result.writeCodePoint(backspaceCode);
329
- last = i + 1;
330
- break;
331
- }
332
- case fCode: {
333
- result.writeCodePoint(formFeedCode);
334
- last = i + 1;
335
- break;
336
- }
337
- case nCode: {
338
- result.writeCodePoint(newLineCode);
339
- last = i + 1;
340
- break;
341
- }
342
- case rCode: {
343
- result.writeCodePoint(carriageReturnCode);
344
- last = i + 1;
345
- break;
346
- }
347
- case tCode: {
348
- result.writeCodePoint(tabCode);
349
- last = i + 1;
350
- break;
351
- }
352
- case uCode: {
353
- const code = u16.parse(data.slice(i + 1, i + 5), 16);
354
- result.writeCodePoint(code);
355
- i += 4;
356
- last = i + 1;
357
- break;
358
- }
359
- default: {
360
- throw new Error(`JSON: Cannot parse "${data}" as string. Invalid escape sequence: \\${data.charAt(i)}`);
361
- }
362
- }
363
- }
364
- if (end > last) {
365
- result.write(data, last, end);
366
- }
367
- return result.toString()
368
- }
369
-
370
- // @ts-ignore: Decorator
371
- @inline function parseBoolean<T extends boolean>(data: string): T {
372
- if (data.length > 3 && data.startsWith(trueWord)) return <T>true;
373
- else if (data.length > 4 && data.startsWith(falseWord)) return <T>false;
374
- else throw new Error(`JSON: Cannot parse "${data}" as boolean`);
375
- }
376
-
377
- // @ts-ignore: Decorator
378
- @inline function parseNumber<T>(data: string): T {
379
- if (isInteger<T>()) {
380
- // @ts-ignore
381
- return snip_fast<T>(data);
382
- }
383
- // @ts-ignore
384
- const type: T = 0;
385
115
  // @ts-ignore
386
- if (type instanceof f64) return f64.parse(data);
387
- // @ts-ignore
388
- else if (type instanceof f32) return f32.parse(data);
389
- }
390
-
391
- // @ts-ignore: Decorator
392
- @inline function parseNumberDirectInference<T>(type: T, data: string): T {
393
- if (isInteger(type)) {
394
- // @ts-ignore
395
- return snip_fast<T>(data);
396
- }
397
- // @ts-ignore
398
- if (type instanceof f64) return f64.parse(data);
399
- // @ts-ignore
400
- else if (type instanceof f32) return f32.parse(data);
401
- }
402
-
403
- // @ts-ignore: Decorator
404
- @inline function parseObject<T>(data: string, initializeDefaultValues: boolean): T {
405
- const schema: nonnull<T> = changetype<nonnull<T>>(
406
- __new(offsetof<nonnull<T>>(), idof<nonnull<T>>())
407
- );
408
-
409
- // @ts-ignore
410
- if (initializeDefaultValues) schema.__JSON_Initialize();
411
-
412
- const key = Virtual.createEmpty<string>();
413
- let isKey = false;
414
- let depth = 0;
415
- let outerLoopIndex = 1;
416
- for (; outerLoopIndex < data.length - 1; outerLoopIndex++) {
417
- const char = unsafeCharCodeAt(data, outerLoopIndex);
418
- if (char === leftBracketCode) {
419
- for (
420
- let arrayValueIndex = outerLoopIndex;
421
- arrayValueIndex < data.length - 1;
422
- arrayValueIndex++
423
- ) {
424
- const char = unsafeCharCodeAt(data, arrayValueIndex);
425
- if (char === leftBracketCode) {
426
- depth++;
427
- } else if (char === rightBracketCode) {
428
- depth--;
429
- if (depth === 0) {
430
- ++arrayValueIndex;
431
- // @ts-ignore
432
- schema.__JSON_Set_Key(key, data, outerLoopIndex, arrayValueIndex, initializeDefaultValues);
433
- outerLoopIndex = arrayValueIndex;
434
- isKey = false;
435
- break;
436
- }
437
- }
438
- }
439
- } else if (char === leftBraceCode) {
440
- for (
441
- let objectValueIndex = outerLoopIndex;
442
- objectValueIndex < data.length - 1;
443
- objectValueIndex++
444
- ) {
445
- const char = unsafeCharCodeAt(data, objectValueIndex);
446
- if (char === leftBraceCode) {
447
- depth++;
448
- } else if (char === rightBraceCode) {
449
- depth--;
450
- if (depth === 0) {
451
- ++objectValueIndex;
452
- // @ts-ignore
453
- schema.__JSON_Set_Key(key, data, outerLoopIndex, objectValueIndex, initializeDefaultValues);
454
- outerLoopIndex = objectValueIndex;
455
- isKey = false;
456
- break;
457
- }
458
- }
459
- }
460
- } else if (char === quoteCode) {
461
- let escaping = false;
462
- for (
463
- let stringValueIndex = ++outerLoopIndex;
464
- stringValueIndex < data.length - 1;
465
- stringValueIndex++
466
- ) {
467
- const char = unsafeCharCodeAt(data, stringValueIndex);
468
- if (char === backSlashCode && !escaping) {
469
- escaping = true;
470
- } else {
471
- if (char === quoteCode && !escaping) {
472
- if (isKey === false) {
473
- // perf: we can avoid creating a new string here if the key doesn't contain any escape sequences
474
- if (containsCodePoint(data, backSlashCode, outerLoopIndex, stringValueIndex)) {
475
- key.reinst(parseString(data, outerLoopIndex - 1, stringValueIndex));
476
- } else {
477
- key.reinst(data, outerLoopIndex, stringValueIndex);
478
- }
479
- isKey = true;
480
- } else {
481
- const value = parseString(data, outerLoopIndex - 1, stringValueIndex);
482
- // @ts-ignore
483
- schema.__JSON_Set_Key(key, value, 0, value.length, initializeDefaultValues);
484
- isKey = false;
485
- }
486
- outerLoopIndex = ++stringValueIndex;
487
- break;
488
- }
489
- escaping = false;
490
- }
491
- }
492
- } else if (
493
- char == nCode &&
494
- unsafeCharCodeAt(data, ++outerLoopIndex) === uCode &&
495
- unsafeCharCodeAt(data, ++outerLoopIndex) === lCode &&
496
- unsafeCharCodeAt(data, ++outerLoopIndex) === lCode
497
- ) {
498
- // @ts-ignore
499
- schema.__JSON_Set_Key(key, nullWord, 0, 4, initializeDefaultValues);
500
- isKey = false;
501
- } else if (
502
- char === tCode &&
503
- unsafeCharCodeAt(data, ++outerLoopIndex) === rCode &&
504
- unsafeCharCodeAt(data, ++outerLoopIndex) === uCode &&
505
- unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
506
- ) {
507
- // @ts-ignore
508
- schema.__JSON_Set_Key(key, trueWord, 0, 4, initializeDefaultValues);
509
- isKey = false;
510
- } else if (
511
- char === fCode &&
512
- unsafeCharCodeAt(data, ++outerLoopIndex) === aCode &&
513
- unsafeCharCodeAt(data, ++outerLoopIndex) === lCode &&
514
- unsafeCharCodeAt(data, ++outerLoopIndex) === sCode &&
515
- unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
516
- ) {
517
- // @ts-ignore
518
- schema.__JSON_Set_Key(key, falseWord, 0, 5, initializeDefaultValues);
519
- isKey = false;
520
- } else if ((char >= 48 && char <= 57) || char === 45) {
521
- let numberValueIndex = ++outerLoopIndex;
522
- for (; numberValueIndex < data.length; numberValueIndex++) {
523
- const char = unsafeCharCodeAt(data, numberValueIndex);
524
- if (char === commaCode || char === rightBraceCode || isSpace(char)) {
525
- // @ts-ignore
526
- schema.__JSON_Set_Key(key, data, outerLoopIndex - 1, numberValueIndex, initializeDefaultValues);
527
- outerLoopIndex = numberValueIndex;
528
- isKey = false;
529
- break;
530
- }
531
- }
532
- }
533
- }
534
- return schema;
535
- }
536
-
537
- // @ts-ignore: Decorator
538
- @inline function parseMap<T extends Map>(data: string, initializeDefaultValues: boolean): T {
539
-
540
- const map: nonnull<T> = changetype<nonnull<T>>(
541
- __new(offsetof<nonnull<T>>(), idof<nonnull<T>>())
542
- );
543
-
544
- if (!isDefined(map.set)) {
545
- throw new Error("Tried to parse a map, but the types did not match!")
546
- }
547
-
548
- const key = Virtual.createEmpty<string>();
549
- let isKey = false;
550
- let depth = 0;
551
- let outerLoopIndex = 1;
552
- for (; outerLoopIndex < data.length - 1; outerLoopIndex++) {
553
- const char = unsafeCharCodeAt(data, outerLoopIndex);
554
- if (char === leftBracketCode) {
555
- for (
556
- let arrayValueIndex = outerLoopIndex;
557
- arrayValueIndex < data.length - 1;
558
- arrayValueIndex++
559
- ) {
560
- const char = unsafeCharCodeAt(data, arrayValueIndex);
561
- if (char === leftBracketCode) {
562
- depth++;
563
- } else if (char === rightBracketCode) {
564
- depth--;
565
- if (depth === 0) {
566
- ++arrayValueIndex;
567
- map.set(parseMapKey<indexof<T>>(key), JSON.parse<valueof<T>>(data.slice(outerLoopIndex, arrayValueIndex), initializeDefaultValues));
568
- outerLoopIndex = arrayValueIndex;
569
- isKey = false;
570
- break;
571
- }
572
- }
573
- }
574
- } else if (char === leftBraceCode) {
575
- for (
576
- let objectValueIndex = outerLoopIndex;
577
- objectValueIndex < data.length - 1;
578
- objectValueIndex++
579
- ) {
580
- const char = unsafeCharCodeAt(data, objectValueIndex);
581
- if (char === leftBraceCode) {
582
- depth++;
583
- } else if (char === rightBraceCode) {
584
- depth--;
585
- if (depth === 0) {
586
- ++objectValueIndex;
587
- map.set(parseMapKey<indexof<T>>(key), JSON.parse<valueof<T>>(data.slice(outerLoopIndex, objectValueIndex), initializeDefaultValues));
588
- outerLoopIndex = objectValueIndex;
589
- isKey = false;
590
- break;
591
- }
592
- }
593
- }
594
- } else if (char === quoteCode) {
595
- let escaping = false;
596
- for (
597
- let stringValueIndex = ++outerLoopIndex;
598
- stringValueIndex < data.length - 1;
599
- stringValueIndex++
600
- ) {
601
- const char = unsafeCharCodeAt(data, stringValueIndex);
602
- if (char === backSlashCode && !escaping) {
603
- escaping = true;
604
- } else {
605
- if (
606
- char === quoteCode && !escaping
607
- ) {
608
- if (isKey === false) {
609
- // perf: we can avoid creating a new string here if the key doesn't contain any escape sequences
610
- if (containsCodePoint(data, backSlashCode, outerLoopIndex, stringValueIndex)) {
611
- key.reinst(parseString(data, outerLoopIndex - 1, stringValueIndex));
612
- } else {
613
- key.reinst(data, outerLoopIndex, stringValueIndex);
614
- }
615
- isKey = true;
616
- } else {
617
- if (isString<valueof<T>>()) {
618
- const value = parseString(data, outerLoopIndex - 1, stringValueIndex);
619
- map.set(parseMapKey<indexof<T>>(key), value);
620
- }
621
- isKey = false;
622
- }
623
- outerLoopIndex = ++stringValueIndex;
624
- break;
625
- }
626
- escaping = false;
627
- }
628
- }
629
- } else if (
630
- char == nCode &&
631
- unsafeCharCodeAt(data, ++outerLoopIndex) === uCode &&
632
- unsafeCharCodeAt(data, ++outerLoopIndex) === lCode &&
633
- unsafeCharCodeAt(data, ++outerLoopIndex) === lCode) {
634
- if (isNullable<valueof<T>>()) {
635
- map.set(parseMapKey<indexof<T>>(key), null);
636
- }
637
- isKey = false;
638
- } else if (
639
- char === tCode &&
640
- unsafeCharCodeAt(data, ++outerLoopIndex) === rCode &&
641
- unsafeCharCodeAt(data, ++outerLoopIndex) === uCode &&
642
- unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
643
- ) {
644
- if (isBoolean<valueof<T>>()) {
645
- map.set(parseMapKey<indexof<T>>(key), true);
646
- }
647
- isKey = false;
648
- } else if (
649
- char === fCode &&
650
- unsafeCharCodeAt(data, ++outerLoopIndex) === aCode &&
651
- unsafeCharCodeAt(data, ++outerLoopIndex) === lCode &&
652
- unsafeCharCodeAt(data, ++outerLoopIndex) === sCode &&
653
- unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
654
- ) {
655
- if (isBoolean<valueof<T>>()) {
656
- map.set(parseMapKey<indexof<T>>(key), false);
657
- }
658
- isKey = false;
659
- } else if ((char >= 48 && char <= 57) || char === 45) {
660
- let numberValueIndex = ++outerLoopIndex;
661
- for (; numberValueIndex < data.length; numberValueIndex++) {
662
- const char = unsafeCharCodeAt(data, numberValueIndex);
663
- if (char === colonCode || char === commaCode || char === rightBraceCode || isSpace(char)) {
664
- if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
665
- map.set(parseMapKey<indexof<T>>(key), parseNumber<valueof<T>>(data.slice(outerLoopIndex - 1, numberValueIndex)));
666
- }
667
- outerLoopIndex = numberValueIndex;
668
- isKey = false;
669
- break;
670
- }
671
- }
672
- }
673
- }
674
-
675
- return map;
676
- }
677
-
678
- //@ts-ignore: Decorator
679
- @inline function parseMapKey<T>(key: Virtual<string>): T {
680
- const k = key.copyOut();
681
- if (isString<T>()) {
682
- return k as T;
683
- } else if (isBoolean<T>()) {
684
- // @ts-ignore
685
- return parseBoolean<T>(k) as T;
686
- } else if (isInteger<T>() || isFloat<T>()) {
687
- return parseNumber<T>(k);
688
- }
689
-
690
- throw new Error(`JSON: Cannot parse JSON object to a Map with a key of type ${nameof<T>()}`);
691
- }
692
-
693
- // @ts-ignore: Decorator
694
- @inline function parseArray<T extends unknown[]>(data: string): T {
695
- if (isString<valueof<T>>()) {
696
- return <T>parseStringArray(data);
697
- } else if (isBoolean<valueof<T>>()) {
698
- // @ts-ignore
699
- return parseBooleanArray<T>(data);
700
- } else if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
701
- // @ts-ignore
702
- return parseNumberArray<T>(data);
703
- } else if (isArrayLike<valueof<T>>()) {
704
- // @ts-ignore
705
- return parseArrayArray<T>(data);
706
- } else if (isMap<valueof<T>>()) {
707
- return parseObjectArray<T>(data);
708
- } else if (isManaged<valueof<T>>() || isReference<valueof<T>>()) {
709
- // We instantiate the required memory for the class and fill it. This is extremely unsafe and uses "a bit of magic".
710
- const type = changetype<nonnull<valueof<T>>>(
711
- __new(offsetof<nonnull<valueof<T>>>(), idof<nonnull<valueof<T>>>())
712
- );
713
- // @ts-ignore
714
- if (isDefined(type.__JSON_Set_Key)) {
715
- return parseObjectArray<T>(data);
716
- }
717
- }
718
-
719
- throw new Error("Tried to parse array, but failed!")
720
- }
721
-
722
- // @ts-ignore: Decorator
723
- @inline function parseStringArray(data: string): string[] {
724
- const result: string[] = [];
725
- let lastPos = 0;
726
- let instr = false;
727
- let escaping = false;
728
- for (let i = 1; i < data.length - 1; i++) {
729
- const char = unsafeCharCodeAt(data, i);
730
- if (char === backSlashCode && !escaping) {
731
- escaping = true;
732
- } else {
733
- if (char === quoteCode && !escaping) {
734
- if (instr === false) {
735
- instr = true;
736
- lastPos = i;
737
- } else {
738
- instr = false;
739
- result.push(parseString(data, lastPos, i));
740
- }
741
- }
742
- escaping = false;
743
- }
744
- }
745
- return result;
746
- }
747
-
748
- // @ts-ignore: Decorator
749
- @inline function parseBooleanArray<T extends boolean[]>(data: string): T {
750
- const result = instantiate<T>();
751
- let lastPos = 1;
752
- for (let i = 1; i < data.length - 1; i++) {
753
- const char = unsafeCharCodeAt(data, i);
754
- if (char === tCode || char === fCode) {
755
- lastPos = i;
756
- } else if (char === eCode) {
757
- i++;
758
- result.push(parseBoolean<valueof<T>>(data.slice(lastPos, i)));
759
- }
760
- }
761
- return result;
762
- }
763
-
764
- // @ts-ignore: Decorator
765
- @inline function parseNumberArray<T extends number[]>(data: string): T {
766
- const result = instantiate<T>();
767
- let lastPos = 0;
768
- let i = 1;
769
- let awaitingParse = false;
770
- for (; i < data.length; i++) {
771
- const char = unsafeCharCodeAt(data, i);
772
- if (lastPos === 0 && ((char >= 48 && char <= 57) || char === 45)) {
773
- awaitingParse = true;
774
- lastPos = i;
775
- } else if (awaitingParse && (isSpace(char) || char == commaCode || char == rightBracketCode) && lastPos > 0) {
776
- awaitingParse = false;
777
- result.push(parseNumber<valueof<T>>(data.slice(lastPos, i)));
778
- lastPos = 0;
779
- }
780
- }
781
- return result;
782
- }
783
-
784
- // @ts-ignore: Decorator
785
- @inline function parseArrayArray<T extends unknown[][]>(data: string): T {
786
- const result = instantiate<T>();
787
- let lastPos = 0;
788
- let depth = 0;
789
- let i = 1;
790
- // Find start of bracket
791
- //for (; unsafeCharCodeAt(data, i) !== leftBracketCode; i++) {}
792
- //i++;
793
- for (; i < data.length - 1; i++) {
794
- const char = unsafeCharCodeAt(data, i);
795
- if (char === leftBracketCode) {
796
- if (depth === 0) {
797
- lastPos = i;
798
- }
799
- // Shifting is 6% faster than incrementing
800
- depth++;
801
- } else if (char === rightBracketCode) {
802
- depth--;
803
- if (depth === 0) {
804
- i++;
805
- result.push(JSON.parse<valueof<T>>(data.slice(lastPos, i)));
806
- }
807
- }
808
- }
809
- return result;
810
- }
811
-
812
- // @ts-ignore: Decorator
813
- @inline function parseObjectArray<T extends unknown[]>(data: string): T {
814
- const result = instantiate<T>();
815
- let lastPos: u32 = 1;
816
- let depth: u32 = 0;
817
- for (let pos: u32 = 0; pos < <u32>data.length; pos++) {
818
- const char = unsafeCharCodeAt(data, pos);
819
- if (char === leftBraceCode) {
820
- if (depth === 0) {
821
- lastPos = pos;
822
- }
823
- depth++;
824
- } else if (char === rightBraceCode) {
825
- depth--;
826
- if (depth === 0) {
827
- pos++;
828
- result.push(JSON.parse<valueof<T>>(data.slice(lastPos, pos)));
829
- //lastPos = pos + 2;
830
- }
831
- }
832
- }
833
- return result;
834
- }
835
-
836
- function parseDate(dateTimeString: string): Date {
837
- // Use AssemblyScript's date parser
838
- const d = Date.fromString(dateTimeString);
839
-
840
- // Return a new object instead of the one that the parser returned.
841
- // This may seem redundant, but addreses the issue when Date
842
- // is globally aliased to wasi_Date (or some other superclass).
843
- return new Date(d.getTime());
844
- }
845
-
846
- // @ts-ignore: Decorator
847
- @inline function isMap<T>(): bool {
848
- let type = changetype<T>(0);
849
- return type instanceof Map;
116
+ if (isString<T>()) return data;
117
+ return JSON.parse<T>(data, initializeDefaultValues);
850
118
  }
851
119
 
852
120
  // Dirty fix
853
121
  // @ts-ignore: Decorator
854
122
  @global @inline function __JSON_Stringify<T>(data: T): string {
855
- // String
856
- if (isString<T>() && data != null) {
857
- return serializeString(data as string);
858
- } else if (isBoolean<T>()) {
859
- return data ? "true" : "false";
860
- } else if (isNullable<T>() && changetype<usize>(data) == <usize>0) {
861
- return nullWord;
862
- // @ts-ignore
863
- } else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
864
- // @ts-ignore
865
- return data.toString();
866
- // @ts-ignore: Hidden function
867
- } else if (isDefined(data.__JSON_Serialize)) {
868
- // @ts-ignore: Hidden function
869
- return data.__JSON_Serialize();
870
- } else if (data instanceof Date) {
871
- return `"${data.toISOString()}"`;
872
- } else if (data instanceof Box) {
873
- if (isNullable<T>() && changetype<usize>(data) == <usize>0) {
874
- return nullWord;
875
- }
876
- return JSON.stringify(data.unwrap());
877
- } else if (isArrayLike<T>()) {
878
- // @ts-ignore
879
- if (data.length == 0) {
880
- return emptyArrayWord;
881
- // @ts-ignore
882
- } else if (isString<valueof<T>>()) {
883
- let result = leftBracketWord;
884
- // @ts-ignore
885
- for (let i = 0; i < data.length - 1; i++) {
886
- // @ts-ignore
887
- result += serializeString(unchecked(data[i]));
888
- result += commaWord;
889
- }
890
- // @ts-ignore
891
- result += serializeString(unchecked(data[data.length - 1]));
892
- result += rightBracketWord;
893
- return result;
894
- // @ts-ignore
895
- } else if (isBoolean<valueof<T>>()) {
896
- // @ts-ignore
897
- return leftBracketWord + data.join(commaWord) + rightBracketWord;
898
- // @ts-ignore
899
- } else if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
900
- // @ts-ignore
901
- return leftBracketWord + data.join(commaWord) + rightBracketWord;
902
- } else {
903
- let result = new StringSink(leftBracketWord);
904
- // @ts-ignore
905
- for (let i = 0; i < data.length - 1; i++) {
906
- // @ts-ignore
907
- result.write(__JSON_Stringify(unchecked(data[i])));
908
- result.writeCodePoint(commaCode);
909
- }
910
- // @ts-ignore
911
- result.write(__JSON_Stringify(unchecked(data[data.length - 1])));
912
- result.writeCodePoint(rightBracketCode);
913
- return result.toString();
914
- }
915
- } else if (data instanceof Map) {
916
- let result = new StringSink(leftBraceWord);
917
- let keys = data.keys();
918
- let values = data.values();
919
- const end = data.size - 1;
920
- for (let i = 0; i < end; i++) {
921
- result.write(serializeString(unchecked(keys[i]).toString()));
922
- result.writeCodePoint(colonCode);
923
- result.write(__JSON_Stringify(unchecked(values[i])));
924
- result.writeCodePoint(commaCode);
925
- }
926
- result.write(serializeString(unchecked(keys[end]).toString()));
927
- result.writeCodePoint(colonCode);
928
- result.write(__JSON_Stringify(unchecked(values[end])));
929
-
930
- result.writeCodePoint(rightBraceCode);
931
- return result.toString();
932
- } else {
933
- throw new Error(
934
- `Could not serialize data of type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
935
- );
936
- }
937
- }
938
-
939
- @inline function parseDirectInference<T>(type: T, data: string, initializeDefaultValues: boolean = false): T {
940
- return JSON.parse<T>(data, initializeDefaultValues)
123
+ return JSON.stringify(data);
941
124
  }