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