json-as 0.9.23 → 0.9.25
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.
- package/CHANGELOG +2 -1
- package/README.md +1 -1
- package/assembly/__benches__/misc.bench.ts +33 -0
- package/assembly/custom/util.ts +14 -11
- package/assembly/deserialize/array.ts +8 -0
- package/assembly/deserialize/bool.ts +16 -0
- package/assembly/deserialize/date.ts +17 -9
- package/assembly/deserialize/float.ts +12 -0
- package/assembly/deserialize/integer.ts +9 -0
- package/assembly/deserialize/map.ts +7 -0
- package/assembly/deserialize/object.ts +135 -0
- package/assembly/deserialize/string.ts +8 -2
- package/assembly/index.ts +59 -11
- package/assembly/serialize/bool.ts +0 -12
- package/assembly/serialize/string.ts +0 -11
- package/assembly/test.ts +23 -23
- package/package.json +3 -2
- package/transform/lib/index.js +155 -172
- package/transform/lib/index.js.map +1 -0
- package/transform/package.json +1 -1
- package/transform/src/index.ts +235 -189
- package/transform/tsconfig.json +6 -26
- package/assembly/__benches__/bool.bench.ts +0 -14
- package/assembly/__benches__/simd.bench.ts +0 -36
- package/assembly/__benches__/string.bench.ts +0 -21
- package/assembly/util/strings.ts +0 -0
package/CHANGELOG
CHANGED
|
@@ -30,7 +30,8 @@ v0.9.19 - Fix arguments in @omitif declarations not working properly
|
|
|
30
30
|
v0.9.20 - Strings were being received with quotes attached via the toString functionality. Removed that.
|
|
31
31
|
v0.9.22 - Fix #89 and #93. Several bug fixes some severe such as ",null" being prepended when using @omit. Properly warn when a schema has fields that are not compatible with json
|
|
32
32
|
v0.9.23 - Comment out SIMD-related code for now
|
|
33
|
-
|
|
33
|
+
v0.9.24 - Remove transform changes from previous release
|
|
34
|
+
v0.9.25 - Implement JSON.parseSafe
|
|
34
35
|
[UNRELEASED] v1.0.0
|
|
35
36
|
- Allow nullable primitives
|
|
36
37
|
- Port over JSON.Value
|
package/README.md
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { JSON } from "..";
|
|
2
|
+
import { BRACE_LEFT, BRACKET_LEFT, CHAR_F, CHAR_T, QUOTE } from "../custom/chars";
|
|
3
|
+
|
|
4
|
+
bench("Match Type (string)", () => {
|
|
5
|
+
blackbox<boolean>(matchType(blackbox<string>("\""), JSON.Types.String));
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
bench("Match Type (bool)", () => {
|
|
9
|
+
blackbox<boolean>(matchType(blackbox<string>("t"), JSON.Types.Bool));
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
bench("Match Type (array)", () => {
|
|
13
|
+
blackbox<boolean>(matchType(blackbox<string>("["), JSON.Types.Array));
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
bench("Match Type (struct)", () => {
|
|
17
|
+
blackbox<boolean>(matchType(blackbox<string>("{"), JSON.Types.Obj));
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
bench("Match Type (raw)", () => {
|
|
21
|
+
blackbox<boolean>(matchType(blackbox<string>("\""), JSON.Types.Raw));
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
@inline function matchType(data: string, type: JSON.Types): boolean {
|
|
25
|
+
const firstChar = load<u8>(changetype<usize>(data));
|
|
26
|
+
if (JSON.Types.String == type && firstChar == QUOTE) return true;
|
|
27
|
+
else if (JSON.Types.Bool == type && (firstChar == CHAR_T || firstChar == CHAR_F)) return true;
|
|
28
|
+
else if (JSON.Types.Array == type && firstChar == BRACKET_LEFT) return true;
|
|
29
|
+
else if (JSON.Types.Obj == type && firstChar == BRACE_LEFT) return true;
|
|
30
|
+
else if (type < 7 && type > 0 && (firstChar < 58 && firstChar > 46)) return true;
|
|
31
|
+
else if (JSON.Types.Raw == type) return true;
|
|
32
|
+
else return false;
|
|
33
|
+
}
|
package/assembly/custom/util.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isSpace } from "util/string";
|
|
2
|
-
import { BACK_SLASH, QUOTE } from "./chars";
|
|
2
|
+
import { BACK_SLASH, BRACE_LEFT, BRACKET_LEFT, CHAR_F, CHAR_T, QUOTE } from "./chars";
|
|
3
3
|
import { Sink } from "./sink";
|
|
4
|
+
import { JSON } from "..";
|
|
4
5
|
|
|
5
6
|
// @ts-ignore: Decorator
|
|
6
7
|
export function isMap<T>(): bool {
|
|
@@ -9,12 +10,12 @@ export function isMap<T>(): bool {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
// @ts-ignore: Decorator
|
|
12
|
-
export function unsafeCharCodeAt(data: string, pos: i32): i32 {
|
|
13
|
+
@inline export function unsafeCharCodeAt(data: string, pos: i32): i32 {
|
|
13
14
|
return load<u16>(changetype<usize>(data) + ((<usize>pos) << 1));
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
// @ts-ignore: Decorator
|
|
17
|
-
export function removeWhitespace(data: string): string {
|
|
18
|
+
@inline export function removeWhitespace(data: string): string {
|
|
18
19
|
const result = new Sink();
|
|
19
20
|
let instr = false;
|
|
20
21
|
for (let i = 0; i < data.length; i++) {
|
|
@@ -35,7 +36,7 @@ export function removeWhitespace(data: string): string {
|
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
// @ts-ignore: Decorator
|
|
38
|
-
export function escapeChar(char: string): string {
|
|
39
|
+
@inline export function escapeChar(char: string): string {
|
|
39
40
|
switch (unsafeCharCodeAt(char, 0)) {
|
|
40
41
|
case 0x22:
|
|
41
42
|
return '\\"';
|
|
@@ -93,7 +94,7 @@ export function getArrayDepth<T extends ArrayLike>(depth: i32 = 1): i32 {
|
|
|
93
94
|
* @param str - Any number. Can include scientific notation.
|
|
94
95
|
*/
|
|
95
96
|
// @ts-ignore: Decorator
|
|
96
|
-
export function snip_fast<T extends number>(str: string, len: u32 = 0, offset: u32 = 0): T {
|
|
97
|
+
@inline export function snip_fast<T extends number>(str: string, len: u32 = 0, offset: u32 = 0): T {
|
|
97
98
|
if (isSigned<T>()) {
|
|
98
99
|
const firstChar: u32 = load<u16>(changetype<usize>(str));
|
|
99
100
|
if (firstChar === 48) return 0 as T;
|
|
@@ -258,7 +259,7 @@ export function snip_fast<T extends number>(str: string, len: u32 = 0, offset: u
|
|
|
258
259
|
*/
|
|
259
260
|
|
|
260
261
|
// @ts-ignore
|
|
261
|
-
export function __atoi_fast<T extends number>(str: string, start: u32 = 0, end: u32 = 0): T {
|
|
262
|
+
@inline export function __atoi_fast<T extends number>(str: string, start: u32 = 0, end: u32 = 0): T {
|
|
262
263
|
// @ts-ignore
|
|
263
264
|
let val: T = 0;
|
|
264
265
|
if (!end) end = start + u32(str.length << 1);
|
|
@@ -293,7 +294,7 @@ export function __atoi_fast<T extends number>(str: string, start: u32 = 0, end:
|
|
|
293
294
|
*/
|
|
294
295
|
|
|
295
296
|
// @ts-ignore
|
|
296
|
-
export function parseSciInteger<T extends number>(str: string): T {
|
|
297
|
+
@inline export function parseSciInteger<T extends number>(str: string): T {
|
|
297
298
|
// @ts-ignore
|
|
298
299
|
let val: T = 0;
|
|
299
300
|
let offset = 0;
|
|
@@ -328,7 +329,7 @@ export function parseSciInteger<T extends number>(str: string): T {
|
|
|
328
329
|
}
|
|
329
330
|
|
|
330
331
|
// @ts-ignore
|
|
331
|
-
function sciNote<T extends number>(num: T): T {
|
|
332
|
+
@inline function sciNote<T extends number>(num: T): T {
|
|
332
333
|
let res = 1;
|
|
333
334
|
// @ts-ignore
|
|
334
335
|
if (num > 0) {
|
|
@@ -345,7 +346,7 @@ function sciNote<T extends number>(num: T): T {
|
|
|
345
346
|
}
|
|
346
347
|
|
|
347
348
|
// @ts-ignore
|
|
348
|
-
function equalsSlice(p1_data: string, p1_start: i32, p1_end: i32, p2_data: string, p2_start: i32, p2_end: i32): boolean {
|
|
349
|
+
@inline function equalsSlice(p1_data: string, p1_start: i32, p1_end: i32, p2_data: string, p2_start: i32, p2_end: i32): boolean {
|
|
349
350
|
const p1_len = p1_end - p1_start;
|
|
350
351
|
const p2_len = p2_end - p2_start;
|
|
351
352
|
if (p1_len != p2_len) return false;
|
|
@@ -356,14 +357,15 @@ function equalsSlice(p1_data: string, p1_start: i32, p1_end: i32, p2_data: strin
|
|
|
356
357
|
}
|
|
357
358
|
|
|
358
359
|
// @ts-ignore
|
|
359
|
-
export function containsCodePoint(str: string, code: u32, start: i32, end: i32): bool {
|
|
360
|
+
@inline export function containsCodePoint(str: string, code: u32, start: i32, end: i32): bool {
|
|
360
361
|
for (let i = start; i <= end; i++) {
|
|
361
362
|
if (unsafeCharCodeAt(str, i) == code) return true;
|
|
362
363
|
}
|
|
363
364
|
return false;
|
|
364
365
|
}
|
|
365
366
|
|
|
366
|
-
|
|
367
|
+
// @ts-ignore: Decorator
|
|
368
|
+
@inline export function _intTo16(int: i32): i32 {
|
|
367
369
|
if (int < 10) {
|
|
368
370
|
// 0-10
|
|
369
371
|
return 48 + int;
|
|
@@ -373,6 +375,7 @@ export function _intTo16(int: i32): i32 {
|
|
|
373
375
|
}
|
|
374
376
|
}
|
|
375
377
|
|
|
378
|
+
// @ts-ignore: Decorator
|
|
376
379
|
@inline export function intTo16(int: i32): i32 {
|
|
377
380
|
const high = int >> 4;
|
|
378
381
|
const low = int & 0x0F;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BRACKET_LEFT } from "../custom/chars";
|
|
1
2
|
import { isMap } from "../custom/util";
|
|
2
3
|
import { deserializeArrayArray } from "./array/array";
|
|
3
4
|
import { deserializeBooleanArray } from "./array/bool";
|
|
@@ -36,3 +37,10 @@ export function deserializeArray<T extends unknown[]>(data: string): T {
|
|
|
36
37
|
throw new Error("Could not parse array of type " + nameof<T>() + "!");
|
|
37
38
|
}
|
|
38
39
|
}
|
|
40
|
+
|
|
41
|
+
// @ts-ignore: Decorator valid here
|
|
42
|
+
export function deserializeArray_Safe<T extends unknown[]>(data: string): T {
|
|
43
|
+
const firstChar = load<u8>(changetype<usize>(data));
|
|
44
|
+
if (firstChar != BRACKET_LEFT) throw new Error("Mismatched Types! Expected " + nameof<T>() + " but got \"" + data.slice(0, 100) + "\" instead!");
|
|
45
|
+
return deserializeArray<T>(data);
|
|
46
|
+
}
|
|
@@ -15,4 +15,20 @@ import { unsafeCharCodeAt } from "../custom/util";
|
|
|
15
15
|
if (len === 4 && firstChar === CHAR_T && load<u64>(ptr) === 28429475166421108) return true;
|
|
16
16
|
else if (len === 5 && firstChar === CHAR_F && load<u64>(ptr, 2) === 28429466576093281) return false;
|
|
17
17
|
return false//ERROR(`Expected to find boolean, but found "${data.slice(0, 100)}" instead!`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Deserialize a string to type boolean (safely)
|
|
22
|
+
* @param data data to parse
|
|
23
|
+
* @returns boolean
|
|
24
|
+
*/
|
|
25
|
+
// @ts-ignore: Decorator valid here
|
|
26
|
+
@inline export function deserializeBoolean_Safe(data: string, start: i32 = 0, end: i32 = 0): boolean {
|
|
27
|
+
if (!end) end = data.length;
|
|
28
|
+
const len = end - start;
|
|
29
|
+
const ptr = changetype<usize>(data) + <usize>(start << 1);
|
|
30
|
+
const firstChar = unsafeCharCodeAt(data, start);
|
|
31
|
+
if (len === 4 && firstChar === CHAR_T && load<u64>(ptr) === 28429475166421108) return true;
|
|
32
|
+
else if (len === 5 && firstChar === CHAR_F && load<u64>(ptr, 2) === 28429466576093281) return false;
|
|
33
|
+
throw new Error("Mismatched Types! Expected boolean but got \"" + data.slice(0, 100) + "\" instead!");
|
|
18
34
|
}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
import { QUOTE } from "../custom/chars";
|
|
2
|
+
|
|
1
3
|
// @ts-ignore: Decorator valid here
|
|
2
4
|
@inline export function deserializeDate(dateTimeString: string): Date {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
// Use AssemblyScript's date parser
|
|
6
|
+
const d = Date.fromString(dateTimeString);
|
|
7
|
+
|
|
8
|
+
// Return a new object instead of the one that the parser returned.
|
|
9
|
+
// This may seem redundant, but addreses the issue when Date
|
|
10
|
+
// is globally aliased to wasi_Date (or some other superclass).
|
|
11
|
+
return new Date(d.getTime());
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// @ts-ignore: Decorator valid here
|
|
15
|
+
@inline export function deserializeDate_Safe(dateTimeString: string): Date {
|
|
16
|
+
const firstChar = load<u8>(changetype<usize>(dateTimeString));
|
|
17
|
+
if (firstChar != QUOTE) throw new Error("Mismatched Types! Expected Date but got \"" + dateTimeString.slice(0, 100) + "\" instead!");
|
|
18
|
+
return deserializeDate(dateTimeString);
|
|
19
|
+
}
|
|
@@ -6,4 +6,16 @@
|
|
|
6
6
|
if (type instanceof f64) return f64.parse(data);
|
|
7
7
|
// @ts-ignore
|
|
8
8
|
return f32.parse(data);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// @ts-ignore: Decorator valid here
|
|
12
|
+
@inline export function deserializeFloat_Safe<T>(data: string): T {
|
|
13
|
+
const firstChar = load<u8>(changetype<usize>(data));
|
|
14
|
+
if ((firstChar < 48 || firstChar > 57) && firstChar != 45) throw new Error("Mismatched Types! Expected float but got \""+data.slice(0, 100)+"\" instead!");
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
const type: T = 0;
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
if (type instanceof f64) return f64.parse(data);
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
return f32.parse(data);
|
|
9
21
|
}
|
|
@@ -4,4 +4,13 @@ import { snip_fast } from "../custom/util";
|
|
|
4
4
|
@inline export function deserializeInteger<T>(data: string): T {
|
|
5
5
|
// @ts-ignore
|
|
6
6
|
return snip_fast<T>(data);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// @ts-ignore: Decorator valid here
|
|
10
|
+
@inline export function deserializeInteger_Safe<T>(data: string): T {
|
|
11
|
+
const firstChar = load<u8>(changetype<usize>(data));
|
|
12
|
+
console.log(firstChar.toString())
|
|
13
|
+
if ((firstChar < 48 || firstChar > 57) && firstChar != 45) throw new Error("Mismatched Types! Expected " + nameof<T>() + " but got \""+data.slice(0, 100)+"\" instead!");
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
return snip_fast<T>(data);
|
|
7
16
|
}
|
|
@@ -180,3 +180,10 @@ function deserializeMapKey<T>(key: Virtual<string>): T {
|
|
|
180
180
|
|
|
181
181
|
throw new Error(`JSON: Cannot parse JSON object to a Map with a key of type ${nameof<T>()}`);
|
|
182
182
|
}
|
|
183
|
+
|
|
184
|
+
// @ts-ignore: Decorator valid here
|
|
185
|
+
@inline export function deserializeMap_Safe<T extends Map>(data: string): T {
|
|
186
|
+
const firstChar = load<u8>(changetype<usize>(data));
|
|
187
|
+
if (firstChar != BRACE_LEFT) throw new Error("Mismatched Types! Expected " + nameof<T>() + " but got \"" + data.slice(0, 100) + "\" instead!");
|
|
188
|
+
return deserializeMap<T>(data);
|
|
189
|
+
}
|
|
@@ -133,4 +133,139 @@ import { isSpace } from "util/string";
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
return schema;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// @ts-ignore: Decorator valid here
|
|
139
|
+
@inline export function deserializeObject_Safe<T>(data: string): T {
|
|
140
|
+
const firstChar = load<u8>(changetype<usize>(data));
|
|
141
|
+
if (firstChar != BRACE_LEFT) throw new Error("Mismatched Types! Expected " + nameof<T>() + " but got \"" + data.slice(0, 100) + "\" instead!");
|
|
142
|
+
const schema: nonnull<T> = changetype<nonnull<T>>(
|
|
143
|
+
__new(offsetof<nonnull<T>>(), idof<nonnull<T>>())
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
// @ts-ignore
|
|
147
|
+
schema.__INITIALIZE();
|
|
148
|
+
|
|
149
|
+
let key_start: i32 = 0;
|
|
150
|
+
let key_end: i32 = 0;
|
|
151
|
+
let isKey = false;
|
|
152
|
+
let depth = 0;
|
|
153
|
+
let outerLoopIndex = 1;
|
|
154
|
+
for (; outerLoopIndex < data.length - 1; outerLoopIndex++) {
|
|
155
|
+
const char = unsafeCharCodeAt(data, outerLoopIndex);
|
|
156
|
+
if (char === BRACKET_LEFT) {
|
|
157
|
+
for (
|
|
158
|
+
let arrayValueIndex = outerLoopIndex;
|
|
159
|
+
arrayValueIndex < data.length - 1;
|
|
160
|
+
arrayValueIndex++
|
|
161
|
+
) {
|
|
162
|
+
const char = unsafeCharCodeAt(data, arrayValueIndex);
|
|
163
|
+
if (char === BRACKET_LEFT) {
|
|
164
|
+
depth++;
|
|
165
|
+
} else if (char === BRACKET_RIGHT) {
|
|
166
|
+
depth--;
|
|
167
|
+
if (depth === 0) {
|
|
168
|
+
++arrayValueIndex;
|
|
169
|
+
// @ts-ignore
|
|
170
|
+
schema.__DESERIALIZE_SAFE(data, key_start, key_end, outerLoopIndex, arrayValueIndex);
|
|
171
|
+
outerLoopIndex = arrayValueIndex;
|
|
172
|
+
isKey = false;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} else if (char === BRACE_LEFT) {
|
|
178
|
+
for (
|
|
179
|
+
let objectValueIndex = outerLoopIndex;
|
|
180
|
+
objectValueIndex < data.length - 1;
|
|
181
|
+
objectValueIndex++
|
|
182
|
+
) {
|
|
183
|
+
const char = unsafeCharCodeAt(data, objectValueIndex);
|
|
184
|
+
if (char === BRACE_LEFT) {
|
|
185
|
+
depth++;
|
|
186
|
+
} else if (char === BRACE_RIGHT) {
|
|
187
|
+
depth--;
|
|
188
|
+
if (depth === 0) {
|
|
189
|
+
++objectValueIndex;
|
|
190
|
+
// @ts-ignore
|
|
191
|
+
schema.__DESERIALIZE_SAFE(data, key_start, key_end, outerLoopIndex, objectValueIndex);
|
|
192
|
+
outerLoopIndex = objectValueIndex;
|
|
193
|
+
isKey = false;
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
} else if (char === QUOTE) {
|
|
199
|
+
let escaping = false;
|
|
200
|
+
for (
|
|
201
|
+
let stringValueIndex = ++outerLoopIndex;
|
|
202
|
+
stringValueIndex < data.length - 1;
|
|
203
|
+
stringValueIndex++
|
|
204
|
+
) {
|
|
205
|
+
const char = unsafeCharCodeAt(data, stringValueIndex);
|
|
206
|
+
if (char === BACK_SLASH && !escaping) {
|
|
207
|
+
escaping = true;
|
|
208
|
+
} else {
|
|
209
|
+
if (char === QUOTE && !escaping) {
|
|
210
|
+
if (isKey === false) {
|
|
211
|
+
key_start = outerLoopIndex;
|
|
212
|
+
key_end = stringValueIndex;
|
|
213
|
+
isKey = true;
|
|
214
|
+
} else {
|
|
215
|
+
// @ts-ignore
|
|
216
|
+
schema.__DESERIALIZE_SAFE(data, key_start, key_end, outerLoopIndex - 1, stringValueIndex + 1);
|
|
217
|
+
isKey = false;
|
|
218
|
+
}
|
|
219
|
+
outerLoopIndex = ++stringValueIndex;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
escaping = false;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
} else if (
|
|
226
|
+
char == CHAR_N &&
|
|
227
|
+
unsafeCharCodeAt(data, outerLoopIndex + 1) === CHAR_U &&
|
|
228
|
+
unsafeCharCodeAt(data, outerLoopIndex + 2) === CHAR_L &&
|
|
229
|
+
unsafeCharCodeAt(data, outerLoopIndex + 3) === CHAR_L
|
|
230
|
+
) {
|
|
231
|
+
// @ts-ignore
|
|
232
|
+
schema.__DESERIALIZE_SAFE(data, key_start, key_end, outerLoopIndex, outerLoopIndex + 4);
|
|
233
|
+
outerLoopIndex += 3;
|
|
234
|
+
isKey = false;
|
|
235
|
+
} else if (
|
|
236
|
+
char === CHAR_T &&
|
|
237
|
+
unsafeCharCodeAt(data, outerLoopIndex + 1) === CHAR_R &&
|
|
238
|
+
unsafeCharCodeAt(data, outerLoopIndex + 2) === CHAR_U &&
|
|
239
|
+
unsafeCharCodeAt(data, outerLoopIndex + 3) === CHAR_E
|
|
240
|
+
) {
|
|
241
|
+
// @ts-ignore
|
|
242
|
+
schema.__DESERIALIZE_SAFE(data, key_start, key_end, outerLoopIndex, outerLoopIndex + 4);
|
|
243
|
+
outerLoopIndex += 3;
|
|
244
|
+
isKey = false;
|
|
245
|
+
} else if (
|
|
246
|
+
char === CHAR_F &&
|
|
247
|
+
unsafeCharCodeAt(data, outerLoopIndex + 1) === CHAR_A &&
|
|
248
|
+
unsafeCharCodeAt(data, outerLoopIndex + 2) === CHAR_L &&
|
|
249
|
+
unsafeCharCodeAt(data, outerLoopIndex + 3) === CHAR_S &&
|
|
250
|
+
unsafeCharCodeAt(data, outerLoopIndex + 4) === CHAR_E
|
|
251
|
+
) {
|
|
252
|
+
// @ts-ignore
|
|
253
|
+
schema.__DESERIALIZE_SAFE(data, key_start, key_end, outerLoopIndex, outerLoopIndex + 5);
|
|
254
|
+
outerLoopIndex += 4;
|
|
255
|
+
isKey = false;
|
|
256
|
+
} else if ((char >= 48 && char <= 57) || char === 45) {
|
|
257
|
+
let numberValueIndex = ++outerLoopIndex;
|
|
258
|
+
for (; numberValueIndex < data.length; numberValueIndex++) {
|
|
259
|
+
const char = unsafeCharCodeAt(data, numberValueIndex);
|
|
260
|
+
if (char === COMMA || char === BRACE_RIGHT || isSpace(char)) {
|
|
261
|
+
// @ts-ignore
|
|
262
|
+
schema.__DESERIALIZE_SAFE(data, key_start, key_end, outerLoopIndex - 1, numberValueIndex);
|
|
263
|
+
outerLoopIndex = numberValueIndex;
|
|
264
|
+
isKey = false;
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return schema;
|
|
136
271
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { bs } from "../custom/bs";
|
|
2
1
|
import {
|
|
3
2
|
CHAR_B,
|
|
4
3
|
BACK_SLASH,
|
|
@@ -155,4 +154,11 @@ import { unsafeCharCodeAt } from "../custom/util";
|
|
|
155
154
|
// if (end > last) {
|
|
156
155
|
// result.write(data, last, end);
|
|
157
156
|
// }
|
|
158
|
-
// }
|
|
157
|
+
// }
|
|
158
|
+
|
|
159
|
+
// @ts-ignore: Decorator valid here
|
|
160
|
+
@inline export function deserializeString_Safe(data: string, start: i32 = 0, end: i32 = 0): string {
|
|
161
|
+
const firstChar = load<u8>(changetype<usize>(data));
|
|
162
|
+
if (firstChar != QUOTE) throw new Error("Mismatched Types! Expected string but got \""+data.slice(0, 100)+"\" instead!");
|
|
163
|
+
return deserializeString(data, start, end);
|
|
164
|
+
}
|
package/assembly/index.ts
CHANGED
|
@@ -7,15 +7,15 @@ import { serializeObject, serializeObject_Pretty } from "./serialize/object";
|
|
|
7
7
|
import { serializeDate } from "./serialize/date";
|
|
8
8
|
import { serializeArray } from "./serialize/array";
|
|
9
9
|
import { serializeMap } from "./serialize/map";
|
|
10
|
-
import { deserializeBoolean } from "./deserialize/bool";
|
|
11
|
-
import { deserializeArray } from "./deserialize/array";
|
|
10
|
+
import { deserializeBoolean, deserializeBoolean_Safe } from "./deserialize/bool";
|
|
11
|
+
import { deserializeArray, deserializeArray_Safe } from "./deserialize/array";
|
|
12
12
|
import { deserializeFloat } from "./deserialize/float";
|
|
13
|
-
import { deserializeObject } from "./deserialize/object";
|
|
14
|
-
import { deserializeMap } from "./deserialize/map";
|
|
13
|
+
import { deserializeObject, deserializeObject_Safe } from "./deserialize/object";
|
|
14
|
+
import { deserializeMap, deserializeMap_Safe } from "./deserialize/map";
|
|
15
15
|
import { deserializeDate } from "./deserialize/date";
|
|
16
|
-
import { NULL_WORD } from "./custom/chars";
|
|
17
|
-
import { deserializeInteger } from "./deserialize/integer";
|
|
18
|
-
import { deserializeString } from "./deserialize/string";
|
|
16
|
+
import { BRACE_LEFT, BRACKET_LEFT, CHAR_F, CHAR_N, CHAR_T, NULL_WORD, QUOTE } from "./custom/chars";
|
|
17
|
+
import { deserializeInteger, deserializeInteger_Safe } from "./deserialize/integer";
|
|
18
|
+
import { deserializeString, deserializeString_Safe } from "./deserialize/string";
|
|
19
19
|
import { Sink } from "./custom/sink";
|
|
20
20
|
import { getArrayDepth } from "./custom/util";
|
|
21
21
|
|
|
@@ -174,7 +174,7 @@ export namespace JSON {
|
|
|
174
174
|
* @returns string
|
|
175
175
|
*/
|
|
176
176
|
// @ts-ignore: Decorator
|
|
177
|
-
export function stringify<T>(data: T/*, options: SerializeOptions = DEFAULT_SERIALIZE_OPTIONS*/): string {
|
|
177
|
+
@inline export function stringify<T>(data: T/*, options: SerializeOptions = DEFAULT_SERIALIZE_OPTIONS*/): string {
|
|
178
178
|
if (isBoolean<T>()) {
|
|
179
179
|
return serializeBool(data as bool);
|
|
180
180
|
} else if (isInteger<T>()) {
|
|
@@ -222,7 +222,7 @@ export namespace JSON {
|
|
|
222
222
|
*/
|
|
223
223
|
|
|
224
224
|
// @ts-ignore: Decorator
|
|
225
|
-
export function parse<T>(data: string): T {
|
|
225
|
+
@inline export function parse<T>(data: string): T {
|
|
226
226
|
if (isBoolean<T>()) {
|
|
227
227
|
return deserializeBoolean(data) as T;
|
|
228
228
|
} else if (isInteger<T>()) {
|
|
@@ -256,14 +256,62 @@ export namespace JSON {
|
|
|
256
256
|
);
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Parses valid JSON strings into their original format (safely).
|
|
261
|
+
* ```js
|
|
262
|
+
* JSON.parseSafe<T>(data)
|
|
263
|
+
* ```
|
|
264
|
+
* @param data string
|
|
265
|
+
* @returns T
|
|
266
|
+
*/
|
|
267
|
+
|
|
268
|
+
// @ts-ignore: Decorator
|
|
269
|
+
@inline export function parseSafe<T>(data: string): T {
|
|
270
|
+
if (isBoolean<T>()) {
|
|
271
|
+
return deserializeBoolean_Safe(data) as T;
|
|
272
|
+
} else if (isInteger<T>()) {
|
|
273
|
+
return deserializeInteger_Safe<T>(data);
|
|
274
|
+
} else if (isFloat<T>()) {
|
|
275
|
+
return deserializeFloat<T>(data);
|
|
276
|
+
} else if (isNullable<T>() && data.length === 4 && data == "null") {
|
|
277
|
+
// @ts-ignore
|
|
278
|
+
return null;
|
|
279
|
+
} else if (isString<T>()) {
|
|
280
|
+
// @ts-ignore
|
|
281
|
+
return deserializeString_Safe(data);
|
|
282
|
+
} else if (isArray<T>()) {
|
|
283
|
+
// @ts-ignore
|
|
284
|
+
return deserializeArray_Safe<nonnull<T>>(data);
|
|
285
|
+
}
|
|
286
|
+
let type: nonnull<T> = changetype<nonnull<T>>(0);
|
|
287
|
+
// @ts-ignore: Defined by transform
|
|
288
|
+
if (isDefined(type.__DESERIALIZE)) {
|
|
289
|
+
// @ts-ignore
|
|
290
|
+
return deserializeObject_Safe<nonnull<T>>(data.trimStart());
|
|
291
|
+
} else if (type instanceof Map) {
|
|
292
|
+
// @ts-ignore
|
|
293
|
+
return deserializeMap_Safe<nonnull<T>>(data.trimStart());
|
|
294
|
+
} else if (type instanceof Date) {
|
|
295
|
+
// @ts-ignore
|
|
296
|
+
return deserializeDate_Safe(data);
|
|
297
|
+
} else {
|
|
298
|
+
throw new Error(
|
|
299
|
+
`Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
259
303
|
}
|
|
260
304
|
|
|
261
305
|
// This allows JSON.stringify and JSON.parse to be available globally through an alias
|
|
262
306
|
// @ts-ignore: Decorator
|
|
263
|
-
@global function __SERIALIZE<T>(data: T): string {
|
|
307
|
+
@global @inline function __SERIALIZE<T>(data: T): string {
|
|
264
308
|
return JSON.stringify(data);
|
|
265
309
|
}
|
|
266
310
|
// @ts-ignore: Decorator
|
|
267
|
-
@global function __DESERIALIZE<T>(data: string): T {
|
|
311
|
+
@global @inline function __DESERIALIZE<T>(data: string): T {
|
|
268
312
|
return JSON.parse<T>(data);
|
|
313
|
+
}
|
|
314
|
+
// @ts-ignore: Decorator
|
|
315
|
+
@global @inline function __DESERIALIZE_SAFE<T>(data: string): T {
|
|
316
|
+
return JSON.parseSafe<T>(data);
|
|
269
317
|
}
|
|
@@ -4,19 +4,7 @@
|
|
|
4
4
|
* @returns string
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { bs } from "../custom/bs";
|
|
8
|
-
|
|
9
7
|
// @ts-ignore: Decorator valid here
|
|
10
8
|
@inline export function serializeBool(data: bool): string {
|
|
11
9
|
return data ? "true" : "false";
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
@inline export function serializeBool_BS(data: bool): void {
|
|
15
|
-
if (data === true) {
|
|
16
|
-
bs.write_64(28429475166421108); /* true */
|
|
17
|
-
} else {
|
|
18
|
-
//bs.write_128_n(i16x8(102, 97, 108, 115, 101, 0, 0, 0), 10);
|
|
19
|
-
bs.write_64(32370086184550502); /* fals */
|
|
20
|
-
bs.write_16(101); /* e */
|
|
21
|
-
}
|
|
22
10
|
}
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BACK_SLASH,
|
|
3
|
-
BACKSPACE,
|
|
4
|
-
CARRIAGE_RETURN,
|
|
5
|
-
FORM_FEED,
|
|
6
|
-
NEW_LINE,
|
|
7
|
-
QUOTE,
|
|
8
|
-
TAB
|
|
9
|
-
} from "../custom/chars";
|
|
10
|
-
import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
|
|
11
|
-
import { bs } from "../custom/bs";
|
|
12
1
|
import { _intTo16, intTo16, unsafeCharCodeAt } from "../custom/util";
|
|
13
2
|
import { Sink } from "../custom/sink";
|
|
14
3
|
|
package/assembly/test.ts
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
import { JSON } from "."
|
|
2
2
|
|
|
3
3
|
@json
|
|
4
|
-
class Vec3
|
|
4
|
+
class Vec3 {
|
|
5
5
|
public x: i32 = 0;
|
|
6
6
|
public y: i32 = 0;
|
|
7
|
-
public z:
|
|
7
|
+
public z: i32 = 0;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
@json
|
|
11
|
-
class Base {
|
|
12
|
-
|
|
13
|
-
}
|
|
10
|
+
// @json
|
|
11
|
+
// class Base {
|
|
12
|
+
// public bam: string = "harekogkeorgke"
|
|
13
|
+
// }
|
|
14
14
|
|
|
15
|
-
@json
|
|
16
|
-
class Foo extends Base {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
15
|
+
// @json
|
|
16
|
+
// class Foo extends Base {
|
|
17
|
+
// public bar: JSON.Raw = "\"this is ok\'"
|
|
18
|
+
// public baz: i32 = 0;
|
|
19
|
+
// public pos: Vec3<Vec3<i32>> = {
|
|
20
|
+
// x: 1,
|
|
21
|
+
// y: 2,
|
|
22
|
+
// z: {
|
|
23
|
+
// x: 1,
|
|
24
|
+
// y: 2,
|
|
25
|
+
// z: 3
|
|
26
|
+
// }
|
|
27
|
+
// }
|
|
28
|
+
// // ^ this is not okay
|
|
29
|
+
// }
|
|
30
30
|
|
|
31
|
-
const serialized = JSON.stringify(new
|
|
31
|
+
const serialized = JSON.stringify(new Vec3());
|
|
32
32
|
console.log("Serialized: " + serialized);
|
|
33
|
-
const deserialized = JSON.
|
|
33
|
+
const deserialized = JSON.parseSafe<Vec3>(`{"x":1,"y":true,"z":3}`);
|
|
34
34
|
console.log("Deserialized: " + JSON.stringify(deserialized));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-as",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.25",
|
|
4
4
|
"description": "The only JSON library you'll need for AssemblyScript. SIMD enabled",
|
|
5
5
|
"types": "assembly/index.ts",
|
|
6
6
|
"author": "Jairus Tanaka",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"test": "ast test && rm -rf ./build/",
|
|
20
20
|
"pretest": "rm -rf ./build/ && ast build",
|
|
21
21
|
"bench": "astral --enable simd --runtime stub",
|
|
22
|
-
"build:test": "rm -rf ./build/ && asc assembly/test.ts --transform ./transform -o ./build/test.wasm",
|
|
22
|
+
"build:test": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm",
|
|
23
23
|
"build:transform": "tsc -p ./transform",
|
|
24
24
|
"test:wasmtime": "wasmtime ./build/test.wasm",
|
|
25
25
|
"test:wavm": "wavm run ./build/test.wasm",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"visitor-as": "^0.11.4"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
+
"@hypermode/modus-sdk-as": "^0.13.0-prerelease-test-1",
|
|
47
48
|
"as-virtual": "^0.2.0",
|
|
48
49
|
"chalk": "^5.3.0"
|
|
49
50
|
},
|