json-as 0.5.31 → 0.5.33
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/README.md +17 -13
- package/asconfig.json +2 -1
- package/assembly/__benches__/as-json.ts +73 -29
- package/assembly/src/json.ts +61 -50
- package/assembly/src/util.ts +22 -1
- package/assembly/test.ts +16 -27
- package/package.json +4 -4
- package/transform/lib/index.js +31 -38
- package/transform/lib/types.js +15 -0
- package/transform/package.json +4 -2
- package/transform/src/index.ts +38 -48
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|

|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
JSON for AssemblyScript focused on performance, low-overhead, and ease-of-use.
|
|
6
6
|
## Installation
|
|
7
7
|
|
|
8
8
|
```bash
|
|
@@ -18,13 +18,13 @@ For arbitrary-length numbers, use
|
|
|
18
18
|
npm install as-bignum
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
Add the transform to your `asc` command
|
|
21
|
+
Add the transform to your `asc` command (e.g. in package.json)
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
--transform json-as/transform
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
Alternatively, add it to your `asconfig.json`
|
|
28
28
|
|
|
29
29
|
```
|
|
30
30
|
{
|
|
@@ -75,10 +75,6 @@ const stringified = JSON.stringify<Player>(player);
|
|
|
75
75
|
const parsed = JSON.parse<Player>(stringified);
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
## Notes
|
|
79
|
-
|
|
80
|
-
Performance exceeds JavaScript JSON implementation by an average of 230% but this decreases with larger data packets.
|
|
81
|
-
|
|
82
78
|
## Planned Features
|
|
83
79
|
|
|
84
80
|
- [x] Serialize
|
|
@@ -101,17 +97,25 @@ Performance exceeds JavaScript JSON implementation by an average of 230% but thi
|
|
|
101
97
|
- [ ] Arrays
|
|
102
98
|
## Performance
|
|
103
99
|
|
|
104
|
-
|
|
100
|
+
Number parsing speed has doubled over the last 5 versions due to the use of a `atoi_fast` function found in `assembly/util.ts`. This can be further optimized with SIMD.
|
|
101
|
+
|
|
102
|
+
String serialization has more than tripled in performance (+360%). The algorithm was rewritten for less if statements and more traps.
|
|
103
|
+
|
|
104
|
+
String deserialization was quadrupled from 3.4m ops to 14.8 ops (435%). It went from using `.replaceAll` to a specialized algorithm.
|
|
105
|
+
|
|
106
|
+
Schema (object) parsing is being optimized on GitHub and should be at least doubled if not tripled. (Current speed of barely-optimized version is 6.9m ops) This is due to taking advantage of the types with a type map and eliminating extra checking.
|
|
107
|
+
|
|
108
|
+
**Serialize Object (Vec3):** 6.7m ops/5s
|
|
105
109
|
|
|
106
|
-
**Deserialize Object (Vec3):**
|
|
110
|
+
**Deserialize Object (Vec3):** 3.8m ops/5s
|
|
107
111
|
|
|
108
|
-
**Serialize Array (int[]):**
|
|
112
|
+
**Serialize Array (int[]):** 6.6m ops/5s
|
|
109
113
|
|
|
110
|
-
**Deserialize Array (int[]):**
|
|
114
|
+
**Deserialize Array (int[]):** 8.6m ops/5s
|
|
111
115
|
|
|
112
|
-
**Serialize String (5):**
|
|
116
|
+
**Serialize String (5):** 5.9m ops/5s
|
|
113
117
|
|
|
114
|
-
**Deserialize String (5):**
|
|
118
|
+
**Deserialize String (5):** 16.3m ops/5s
|
|
115
119
|
|
|
116
120
|
## Issues
|
|
117
121
|
|
package/asconfig.json
CHANGED
|
@@ -1,51 +1,95 @@
|
|
|
1
1
|
import { JSON } from "..";
|
|
2
|
+
import { backSlashCode, quoteCode } from "../src/chars";
|
|
3
|
+
import { atoi_fast, unsafeCharCodeAt } from "../src/util";
|
|
4
|
+
import { HASH } from "util/hash";
|
|
2
5
|
|
|
3
6
|
@json
|
|
4
7
|
class Vec3 {
|
|
5
8
|
x: i32;
|
|
6
9
|
y: i32;
|
|
7
10
|
z: i32;
|
|
11
|
+
|
|
12
|
+
/*@inline __JSON_Serialize(data: Vec3): string {
|
|
13
|
+
return `{"x":${data.x.toString()},"y":${data.y.toString()},"z":${data.z.toString()}}`;
|
|
14
|
+
}*/
|
|
15
|
+
|
|
16
|
+
@inline __JSON_Deserialize(data: string, to: Vec3): Vec3 {
|
|
17
|
+
let last = 1;
|
|
18
|
+
let char = 0;
|
|
19
|
+
let inStr = false;
|
|
20
|
+
let key: string | null = null;
|
|
21
|
+
let pos = 0;
|
|
22
|
+
for (; pos < data.length - 1; pos++) {
|
|
23
|
+
char = unsafeCharCodeAt(data, pos);
|
|
24
|
+
if (inStr === false && char === quoteCode) {
|
|
25
|
+
if (key != null) {
|
|
26
|
+
if (unsafeCharCodeAt(key, 0) == 120) {
|
|
27
|
+
to.x = atoi_fast<i32>(data.substring(last, pos - 1))
|
|
28
|
+
} else if (unsafeCharCodeAt(key, 0) == 121) {
|
|
29
|
+
to.y = atoi_fast<i32>(data.substring(last, pos - 1))
|
|
30
|
+
} else if (unsafeCharCodeAt(key, 0) == 122) {
|
|
31
|
+
to.z = atoi_fast<i32>(data.substring(last, pos - 1))
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
last = ++pos;
|
|
35
|
+
inStr = true;
|
|
36
|
+
} else if (char === quoteCode && unsafeCharCodeAt(data, pos - 1) != backSlashCode) {
|
|
37
|
+
inStr = false;
|
|
38
|
+
key = data.substring(last, pos);
|
|
39
|
+
last = pos += 2;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (key != null) {
|
|
43
|
+
if (unsafeCharCodeAt(key, 0) == 120) {
|
|
44
|
+
to.x = atoi_fast<i32>(data.substring(last, pos - 1))
|
|
45
|
+
} else if (unsafeCharCodeAt(key, 0) == 121) {
|
|
46
|
+
to.y = atoi_fast<i32>(data.substring(last, pos - 1))
|
|
47
|
+
} else if (unsafeCharCodeAt(key, 0) == 122) {
|
|
48
|
+
to.z = atoi_fast<i32>(data.substring(last, pos - 1))
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return to;
|
|
52
|
+
}
|
|
8
53
|
}
|
|
9
54
|
|
|
10
|
-
const vec: Vec3 =
|
|
11
|
-
x:
|
|
12
|
-
y:
|
|
13
|
-
z:
|
|
14
|
-
}
|
|
55
|
+
const vec: Vec3 = {
|
|
56
|
+
x: 3,
|
|
57
|
+
y: 1,
|
|
58
|
+
z: 8
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const vecOut = new Vec3();
|
|
15
62
|
|
|
63
|
+
const i32Max = blackbox("429496729");
|
|
64
|
+
/*
|
|
16
65
|
bench("Stringify Object (Vec3)", () => {
|
|
17
|
-
blackbox(
|
|
18
|
-
})
|
|
66
|
+
blackbox<string>(vec.__JSON_Serialize(vec));
|
|
67
|
+
});*/
|
|
19
68
|
|
|
69
|
+
bench("HASH String", () => {
|
|
70
|
+
blackbox<number>(HASH("Hello"));
|
|
71
|
+
})
|
|
72
|
+
// TODO: Make this allocate without crashing
|
|
20
73
|
bench("Parse Object (Vec3)", () => {
|
|
21
|
-
blackbox
|
|
22
|
-
});/*
|
|
23
|
-
|
|
24
|
-
bench("Stringify Array", () => {
|
|
25
|
-
blackbox(JSON.stringify(blackbox([1, 2, 3, 4, 5])));
|
|
74
|
+
blackbox<Vec3>(vec.__JSON_Deserialize('{"x":0,"y":0,"z":0}', vec));
|
|
26
75
|
});
|
|
27
|
-
|
|
28
|
-
|
|
76
|
+
|
|
77
|
+
bench("Stringify Number Array", () => {
|
|
78
|
+
blackbox(JSON.stringify<i32[]>([1, 2, 3]));
|
|
29
79
|
});
|
|
30
|
-
|
|
80
|
+
|
|
31
81
|
bench("Parse Array", () => {
|
|
32
|
-
blackbox(JSON.parse<i32[]>(blackbox("[1,2,3
|
|
82
|
+
blackbox(JSON.parse<i32[]>(blackbox("[1,2,3]")));
|
|
33
83
|
});
|
|
34
84
|
|
|
35
|
-
bench("Stringify
|
|
36
|
-
blackbox(
|
|
37
|
-
JSON.stringify<string[][]>(
|
|
38
|
-
blackbox([
|
|
39
|
-
["a", "b", "c"]
|
|
40
|
-
])
|
|
41
|
-
)
|
|
42
|
-
);
|
|
85
|
+
bench("Stringify Boolean Array", () => {
|
|
86
|
+
blackbox(JSON.stringify<boolean[]>([true, false, true]));
|
|
43
87
|
});
|
|
44
88
|
|
|
45
|
-
bench("
|
|
46
|
-
blackbox(JSON.
|
|
89
|
+
bench("Stringify String Array", () => {
|
|
90
|
+
blackbox(JSON.stringify<string[]>(["a", "b", "c"]));
|
|
47
91
|
});
|
|
48
|
-
|
|
92
|
+
|
|
49
93
|
bench("Stringify String", () => {
|
|
50
94
|
blackbox(JSON.stringify(blackbox("Hello \"World!")));
|
|
51
95
|
});
|
|
@@ -53,7 +97,7 @@ bench("Stringify String", () => {
|
|
|
53
97
|
bench("Parse String", () => {
|
|
54
98
|
blackbox(JSON.parse<string>(blackbox('"Hello \"World!"')));
|
|
55
99
|
});
|
|
56
|
-
|
|
100
|
+
|
|
57
101
|
bench("Stringify Boolean", () => {
|
|
58
102
|
blackbox(JSON.stringify(blackbox(true)));
|
|
59
103
|
});
|
|
@@ -76,4 +120,4 @@ bench("Stringify Float", () => {
|
|
|
76
120
|
|
|
77
121
|
bench("Parse Float", () => {
|
|
78
122
|
blackbox(JSON.parse<f32>(blackbox("3.14")));
|
|
79
|
-
})
|
|
123
|
+
});
|
package/assembly/src/json.ts
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
uCode,
|
|
24
24
|
emptyArrayWord
|
|
25
25
|
} from "./chars";
|
|
26
|
-
import { escapeChar, isBigNum, unsafeCharCodeAt } from "./util";
|
|
26
|
+
import { atoi_fast, escapeChar, isBigNum, unsafeCharCodeAt } from "./util";
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* JSON Encoder/Decoder for AssemblyScript
|
|
@@ -42,34 +42,21 @@ export namespace JSON {
|
|
|
42
42
|
if (isString<T>() && data != null) {
|
|
43
43
|
// @ts-ignore
|
|
44
44
|
return serializeString(data);
|
|
45
|
-
}
|
|
46
|
-
// Boolean
|
|
47
|
-
else if (isBoolean<T>()) {
|
|
45
|
+
} else if (isBoolean<T>()) {
|
|
48
46
|
return data ? "true" : "false";
|
|
49
|
-
}
|
|
50
|
-
// Nullable
|
|
51
|
-
else if (isNullable<T>() && data == null) {
|
|
47
|
+
} else if (isNullable<T>() && data == null) {
|
|
52
48
|
return "null";
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
// @ts-ignore
|
|
56
|
-
else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
} else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
|
|
57
51
|
// @ts-ignore
|
|
58
52
|
return data.toString();
|
|
59
|
-
}
|
|
60
|
-
// Class-Based serialization
|
|
61
|
-
// @ts-ignore
|
|
62
|
-
else if (isDefined(data.__JSON_Serialize)) {
|
|
63
53
|
// @ts-ignore
|
|
64
|
-
|
|
54
|
+
} else if (isDefined(data.__JSON_Serialize)) {
|
|
65
55
|
// @ts-ignore
|
|
66
56
|
return data.__JSON_Serialize();
|
|
67
|
-
}
|
|
68
|
-
else if (data instanceof Date) {
|
|
57
|
+
} else if (data instanceof Date) {
|
|
69
58
|
return data.toISOString();
|
|
70
|
-
}
|
|
71
|
-
// ArrayLike
|
|
72
|
-
else if (isArrayLike<T>()) {
|
|
59
|
+
} else if (isArrayLike<T>()) {
|
|
73
60
|
// @ts-ignore
|
|
74
61
|
if (data.length == 0) {
|
|
75
62
|
return emptyArrayWord;
|
|
@@ -87,18 +74,13 @@ export namespace JSON {
|
|
|
87
74
|
result += rightBracketWord;
|
|
88
75
|
return result;
|
|
89
76
|
// @ts-ignore
|
|
90
|
-
} else if (
|
|
91
|
-
let result = new StringSink(leftBracketWord);
|
|
77
|
+
} else if (isBoolean<valueof<T>>()) {
|
|
92
78
|
// @ts-ignore
|
|
93
|
-
|
|
94
|
-
// @ts-ignore
|
|
95
|
-
result.write(JSON.stringify(unchecked(data[i])));
|
|
96
|
-
result.write(commaWord);
|
|
97
|
-
}
|
|
79
|
+
return leftBracketWord + data.join(commaWord) + rightBracketWord;
|
|
98
80
|
// @ts-ignore
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return
|
|
81
|
+
} else if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
|
|
82
|
+
// @ts-ignore
|
|
83
|
+
return leftBracketWord + data.join(commaWord) + rightBracketWord;
|
|
102
84
|
} else {
|
|
103
85
|
let result = new StringSink(leftBracketWord);
|
|
104
86
|
// @ts-ignore
|
|
@@ -164,7 +146,48 @@ export namespace JSON {
|
|
|
164
146
|
let type: T;
|
|
165
147
|
if (isString<T>()) {
|
|
166
148
|
// @ts-ignore
|
|
167
|
-
|
|
149
|
+
let result = "";
|
|
150
|
+
let last = 0;
|
|
151
|
+
let char = 0;
|
|
152
|
+
for (let i = 0; i < data.length; i++) {
|
|
153
|
+
// \\"
|
|
154
|
+
if (unsafeCharCodeAt(data, i) === backSlashCode) {
|
|
155
|
+
char = unsafeCharCodeAt(data, ++i);
|
|
156
|
+
result += data.slice(last, i - 1)
|
|
157
|
+
if (char === 34) {
|
|
158
|
+
result += "\"";
|
|
159
|
+
last = ++i;
|
|
160
|
+
} else if (char === 110) {
|
|
161
|
+
result += "\n";
|
|
162
|
+
last = ++i;
|
|
163
|
+
// 92 98 114 116 102 117
|
|
164
|
+
} else if (char >= 92 && char <= 117) {
|
|
165
|
+
if (char === 92) {
|
|
166
|
+
result += "\\";
|
|
167
|
+
last = ++i;
|
|
168
|
+
} else if (char === 98) {
|
|
169
|
+
result += "\b";
|
|
170
|
+
last = ++i;
|
|
171
|
+
} else if (char === 102) {
|
|
172
|
+
result += "\f";
|
|
173
|
+
last = ++i;
|
|
174
|
+
} else if (char === 114) {
|
|
175
|
+
result += "\r";
|
|
176
|
+
last = ++i;
|
|
177
|
+
} else if (char === 116) {
|
|
178
|
+
result += "\t";
|
|
179
|
+
last = ++i;
|
|
180
|
+
} else if (char === 117 && load<u64>(changetype<usize>(data) + <usize>((i + 1) << 1)) === 27584753879220272) {
|
|
181
|
+
result += "\u000b";
|
|
182
|
+
i += 4;
|
|
183
|
+
last = ++i;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
result += data.slice(last);
|
|
189
|
+
// @ts-ignore
|
|
190
|
+
return result;
|
|
168
191
|
} else if (isBoolean<T>()) {
|
|
169
192
|
// @ts-ignore
|
|
170
193
|
return parseBoolean<T>(data);
|
|
@@ -193,16 +216,16 @@ export namespace JSON {
|
|
|
193
216
|
}
|
|
194
217
|
}
|
|
195
218
|
|
|
219
|
+
|
|
196
220
|
// @ts-ignore
|
|
197
221
|
@inline
|
|
198
|
-
// @ts-ignore
|
|
199
222
|
function serializeString(data: string): string {
|
|
200
223
|
// @ts-ignore
|
|
201
224
|
if (data.length === 0) return "\"\"";
|
|
202
225
|
// Fast path for Vectors (3)
|
|
203
226
|
let char: i32 = 0;
|
|
204
227
|
if (data.length === 1) {
|
|
205
|
-
char
|
|
228
|
+
char = unsafeCharCodeAt(data, 0);
|
|
206
229
|
if (char === 34) {
|
|
207
230
|
return "\\\"";
|
|
208
231
|
} else if (char === 92) {
|
|
@@ -359,28 +382,16 @@ function parseBoolean<T extends boolean>(data: string): T {
|
|
|
359
382
|
@inline
|
|
360
383
|
// @ts-ignore
|
|
361
384
|
export function parseNumber<T>(data: string): T {
|
|
385
|
+
if (isInteger<T>()) {
|
|
386
|
+
// @ts-ignore
|
|
387
|
+
return atoi_fast<T>(data);
|
|
388
|
+
}
|
|
362
389
|
// @ts-ignore
|
|
363
390
|
const type: T = 0;
|
|
364
391
|
// @ts-ignore
|
|
365
392
|
if (type instanceof f64) return f64.parse(data);
|
|
366
393
|
// @ts-ignore
|
|
367
394
|
else if (type instanceof f32) return f32.parse(data);
|
|
368
|
-
// @ts-ignore
|
|
369
|
-
else if (type instanceof u64) return u64.parse(data);
|
|
370
|
-
// @ts-ignore
|
|
371
|
-
else if (type instanceof u32) return u32.parse(data);
|
|
372
|
-
// @ts-ignore
|
|
373
|
-
else if (type instanceof u8) return u8.parse(data);
|
|
374
|
-
// @ts-ignore
|
|
375
|
-
else if (type instanceof u16) return u16.parse(data);
|
|
376
|
-
// @ts-ignore
|
|
377
|
-
else if (type instanceof i64) return i64.parse(data);
|
|
378
|
-
// @ts-ignore
|
|
379
|
-
else if (type instanceof i32) return i32.parse(data);
|
|
380
|
-
// @ts-ignore
|
|
381
|
-
else if (type instanceof i16) return i16.parse(data);
|
|
382
|
-
// @ts-ignore
|
|
383
|
-
else if (type instanceof i8) return i8.parse(data);
|
|
384
395
|
}
|
|
385
396
|
|
|
386
397
|
// @ts-ignore
|
package/assembly/src/util.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StringSink } from "as-string-sink/assembly";
|
|
2
|
-
import { isSpace } from "util/string";
|
|
2
|
+
import { CharCode, isSpace } from "util/string";
|
|
3
3
|
import { backSlashCode, quoteCode } from "./chars";
|
|
4
4
|
import { u128, u128Safe, u256, u256Safe, i128, i128Safe, i256Safe } from "as-bignum/assembly";
|
|
5
5
|
|
|
@@ -78,3 +78,24 @@ export function getArrayDepth<T>(depth: i32 = 1): i32 {
|
|
|
78
78
|
return depth;
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Implementation of ATOI. Can be much much faster with SIMD.
|
|
84
|
+
* Its pretty fast. (173m ops (atoi_fast) vs 89 ops (parseInt))
|
|
85
|
+
*/
|
|
86
|
+
@unsafe
|
|
87
|
+
@inline
|
|
88
|
+
export function atoi_fast<T extends number>(str: string): T {
|
|
89
|
+
// @ts-ignore
|
|
90
|
+
let val: T = 0;
|
|
91
|
+
for (let pos = 0; pos < str.length; pos += 2) {
|
|
92
|
+
// @ts-ignore
|
|
93
|
+
val = (val << 1) + (val << 3) + (load<u16>(changetype<usize>(str) + <usize>pos) - 48);
|
|
94
|
+
// We use load because in this case, there is no need to have bounds-checking
|
|
95
|
+
}
|
|
96
|
+
return val;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
*
|
|
101
|
+
*/
|
package/assembly/test.ts
CHANGED
|
@@ -1,38 +1,27 @@
|
|
|
1
|
+
import { backSlashCode, quoteCode } from "./src/chars";
|
|
1
2
|
import { JSON } from "./src/json";
|
|
3
|
+
import { atoi_fast, unsafeCharCodeAt } from "./src/util";
|
|
2
4
|
|
|
3
5
|
// @json or @serializable work here
|
|
4
6
|
@json
|
|
5
7
|
class Vec3 {
|
|
6
|
-
x
|
|
7
|
-
y
|
|
8
|
-
z
|
|
8
|
+
x: i32;
|
|
9
|
+
y: i32;
|
|
10
|
+
z: i32;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
lastActive!: i32[];
|
|
16
|
-
age!: i32;
|
|
17
|
-
pos!: Vec3 | null;
|
|
18
|
-
isVerified!: boolean;
|
|
13
|
+
const vec: Vec3 = {
|
|
14
|
+
x: 3,
|
|
15
|
+
y: 1,
|
|
16
|
+
z: 8
|
|
19
17
|
}
|
|
20
18
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
pos: {
|
|
27
|
-
x: 3.4,
|
|
28
|
-
y: 1.2,
|
|
29
|
-
z: 8.3
|
|
30
|
-
},
|
|
31
|
-
isVerified: true
|
|
32
|
-
};
|
|
19
|
+
const serializedVec3 = JSON.stringify(vec);
|
|
20
|
+
console.log(serializedVec3);
|
|
21
|
+
|
|
22
|
+
const parsedVec3 = JSON.parse<Vec3>(serializedVec3);
|
|
23
|
+
console.log(JSON.stringify(parsedVec3));
|
|
33
24
|
|
|
34
|
-
|
|
35
|
-
console.log(stringified);
|
|
25
|
+
console.log(`atoi_fast("429496729"): ${atoi_fast<i32>("429496729")}`);
|
|
36
26
|
|
|
37
|
-
|
|
38
|
-
console.log(JSON.stringify(parsed));
|
|
27
|
+
console.log(`strtol("429496729"): ${i32.parse("429496729")}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-as",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.33",
|
|
4
4
|
"description": "JSON encoder/decoder for AssemblyScript",
|
|
5
5
|
"types": "assembly/index.ts",
|
|
6
6
|
"author": "Jairus Tanaka",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"scripts": {
|
|
14
14
|
"aspect": "asp",
|
|
15
|
-
"bench:astral": "astral",
|
|
15
|
+
"bench:astral": "astral -Ospeed --noAssert --uncheckedBehavior always",
|
|
16
16
|
"build:test": "asc assembly/test.ts --target test --runtime stub",
|
|
17
17
|
"build:transform": "tsc -p ./transform",
|
|
18
18
|
"test:wasmtime": "wasmtime ./build/test.wasm",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@as-pect/cli": "^8.0.1",
|
|
25
25
|
"@as-tral/cli": "^2.0.0",
|
|
26
|
-
"@assemblyscript/loader": "^0.27.
|
|
26
|
+
"@assemblyscript/loader": "^0.27.1",
|
|
27
27
|
"@assemblyscript/wasi-shim": "^0.1.0",
|
|
28
|
-
"assemblyscript": "^0.27.
|
|
28
|
+
"assemblyscript": "^0.27.1",
|
|
29
29
|
"assemblyscript-prettier": "^1.0.7",
|
|
30
30
|
"prettier": "^2.8.4",
|
|
31
31
|
"typescript": "^4.9.5",
|
package/transform/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { toString, isStdlib } from "visitor-as/dist/utils.js";
|
|
2
2
|
import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
|
|
3
3
|
import { Transform } from "assemblyscript/dist/transform.js";
|
|
4
4
|
class SchemaData {
|
|
@@ -19,39 +19,6 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
19
19
|
this.sources = [];
|
|
20
20
|
}
|
|
21
21
|
visitMethodDeclaration() { }
|
|
22
|
-
visitFieldDeclaration(node) {
|
|
23
|
-
if (toString(node).startsWith("static"))
|
|
24
|
-
return;
|
|
25
|
-
const lineText = toString(node);
|
|
26
|
-
if (lineText.startsWith("private"))
|
|
27
|
-
return;
|
|
28
|
-
const name = getName(node);
|
|
29
|
-
if (!node.type) {
|
|
30
|
-
throw new Error(`Field ${name} is missing a type declaration`);
|
|
31
|
-
}
|
|
32
|
-
let type = getName(node.type);
|
|
33
|
-
// @ts-ignore
|
|
34
|
-
if (["u8", "i8", "u16", "i16", "u32", "i32", "f32", "u64", "i64", "f64"].includes(type.toLowerCase())) {
|
|
35
|
-
this.currentClass.encodeStmts.push(`"${name}":\${this.${name}.toString()},`);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
this.currentClass.encodeStmts.push(`"${name}":\${JSON.stringify<${type}>(this.${name})},`);
|
|
39
|
-
}
|
|
40
|
-
// @ts-ignore
|
|
41
|
-
//this.decodeStmts.push(
|
|
42
|
-
// `${name}: JSON.parseObjectValue<${type}>(values.get("${name}")),\n`
|
|
43
|
-
//);
|
|
44
|
-
// @ts-ignore
|
|
45
|
-
this.currentClass.setDataStmts.push(`if (key == "${name}") {
|
|
46
|
-
this.${name} = JSON.parseObjectValue<${type}>(value);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
`);
|
|
50
|
-
// @ts-ignore
|
|
51
|
-
//this.checkDecodeStmts.push(
|
|
52
|
-
// ' if (!values.has("${name}")) throw new Error("Key "${name}" was not found. Cannot instantiate object.");\n'
|
|
53
|
-
//);
|
|
54
|
-
}
|
|
55
22
|
visitClassDeclaration(node) {
|
|
56
23
|
var _c;
|
|
57
24
|
const className = node.name.text;
|
|
@@ -65,7 +32,7 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
65
32
|
}
|
|
66
33
|
if (!foundDecorator)
|
|
67
34
|
return;
|
|
68
|
-
// Prevent from being triggered twice
|
|
35
|
+
// Prevent from being triggered twice.
|
|
69
36
|
for (const member of node.members) {
|
|
70
37
|
if (member.name.text == "__JSON_Serialize")
|
|
71
38
|
return;
|
|
@@ -92,7 +59,35 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
92
59
|
}
|
|
93
60
|
const parentSchema = this.schemasList.find((v) => v.name == this.currentClass.parent);
|
|
94
61
|
const members = [...node.members, ...(parentSchema ? parentSchema.node.members : [])];
|
|
95
|
-
|
|
62
|
+
for (const mem of members) {
|
|
63
|
+
if (mem.type && mem.type.name && mem.type.name.identifier.text) {
|
|
64
|
+
const member = mem;
|
|
65
|
+
if (toString(member).startsWith("static"))
|
|
66
|
+
return;
|
|
67
|
+
const lineText = toString(member);
|
|
68
|
+
if (lineText.startsWith("private"))
|
|
69
|
+
return;
|
|
70
|
+
// @ts-ignore
|
|
71
|
+
const type = member.type.name.identifier.text;
|
|
72
|
+
const name = member.name.text;
|
|
73
|
+
this.currentClass.keys.push(name);
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
this.currentClass.types.push(type);
|
|
76
|
+
// @ts-ignore
|
|
77
|
+
if (["u8", "i8", "u16", "i16", "u32", "i32", "f32", "u64", "i64", "f64"].includes(type.toLowerCase())) {
|
|
78
|
+
this.currentClass.encodeStmts.push(`"${name}":\${this.${name}.toString()},`);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
this.currentClass.encodeStmts.push(`"${name}":\${JSON.stringify<${type}>(this.${name})},`);
|
|
82
|
+
}
|
|
83
|
+
// @ts-ignore
|
|
84
|
+
this.currentClass.setDataStmts.push(`if (key == "${name}") {
|
|
85
|
+
this.${name} = JSON.parseObjectValue<${type}>(value);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
96
91
|
let serializeFunc = "";
|
|
97
92
|
if (this.currentClass.encodeStmts.length > 0) {
|
|
98
93
|
const stmt = this.currentClass.encodeStmts[this.currentClass.encodeStmts.length - 1];
|
|
@@ -125,8 +120,6 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
125
120
|
const setDataMethod = SimpleParser.parseClassMember(setKeyFunc, node);
|
|
126
121
|
node.members.push(setDataMethod);
|
|
127
122
|
this.schemasList.push(this.currentClass);
|
|
128
|
-
//console.log(serializeFunc);
|
|
129
|
-
//console.log(setKeyFunc);
|
|
130
123
|
}
|
|
131
124
|
visitSource(node) {
|
|
132
125
|
super.visitSource(node);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export var Types;
|
|
2
|
+
(function (Types) {
|
|
3
|
+
Types[Types["String"] = 0] = "String";
|
|
4
|
+
Types[Types["u8"] = 1] = "u8";
|
|
5
|
+
Types[Types["i8"] = 2] = "i8";
|
|
6
|
+
Types[Types["u16"] = 3] = "u16";
|
|
7
|
+
Types[Types["i16"] = 4] = "i16";
|
|
8
|
+
Types[Types["u32"] = 5] = "u32";
|
|
9
|
+
Types[Types["i32"] = 6] = "i32";
|
|
10
|
+
Types[Types["u64"] = 7] = "u64";
|
|
11
|
+
Types[Types["i64"] = 8] = "i64";
|
|
12
|
+
Types[Types["f32"] = 9] = "f32";
|
|
13
|
+
Types[Types["f64"] = 10] = "f64";
|
|
14
|
+
Types[Types["boolean"] = 11] = "boolean";
|
|
15
|
+
})(Types || (Types = {}));
|
package/transform/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@json-as/transform",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.33",
|
|
4
4
|
"description": "JSON encoder/decoder for AssemblyScript",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"author": "Jairus Tanaka",
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
"Rom"
|
|
11
11
|
],
|
|
12
12
|
"license": "MIT",
|
|
13
|
-
"devDependencies": {
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"assemblyscript": "^0.27.1"
|
|
15
|
+
},
|
|
14
16
|
"dependencies": {},
|
|
15
17
|
"repository": {
|
|
16
18
|
"type": "git",
|
package/transform/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
Source,
|
|
5
5
|
Parser
|
|
6
6
|
} from "assemblyscript/dist/assemblyscript";
|
|
7
|
-
import {
|
|
7
|
+
import { toString, isStdlib } from "visitor-as/dist/utils.js";
|
|
8
8
|
import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
|
|
9
9
|
import { Transform } from "assemblyscript/dist/transform.js";
|
|
10
10
|
|
|
@@ -24,46 +24,6 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
24
24
|
public sources: Source[] = [];
|
|
25
25
|
|
|
26
26
|
visitMethodDeclaration(): void { }
|
|
27
|
-
visitFieldDeclaration(node: FieldDeclaration): void {
|
|
28
|
-
if (toString(node).startsWith("static")) return;
|
|
29
|
-
const lineText = toString(node);
|
|
30
|
-
if (lineText.startsWith("private")) return;
|
|
31
|
-
const name = getName(node);
|
|
32
|
-
if (!node.type) {
|
|
33
|
-
throw new Error(`Field ${name} is missing a type declaration`);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
let type = getName(node.type);
|
|
37
|
-
// @ts-ignore
|
|
38
|
-
if (["u8", "i8", "u16", "i16", "u32", "i32", "f32", "u64", "i64", "f64"].includes(type.toLowerCase())) {
|
|
39
|
-
this.currentClass.encodeStmts.push(
|
|
40
|
-
`"${name}":\${this.${name}.toString()},`
|
|
41
|
-
);
|
|
42
|
-
} else {
|
|
43
|
-
this.currentClass.encodeStmts.push(
|
|
44
|
-
`"${name}":\${JSON.stringify<${type}>(this.${name})},`
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// @ts-ignore
|
|
49
|
-
//this.decodeStmts.push(
|
|
50
|
-
// `${name}: JSON.parseObjectValue<${type}>(values.get("${name}")),\n`
|
|
51
|
-
//);
|
|
52
|
-
|
|
53
|
-
// @ts-ignore
|
|
54
|
-
this.currentClass.setDataStmts.push(
|
|
55
|
-
`if (key == "${name}") {
|
|
56
|
-
this.${name} = JSON.parseObjectValue<${type}>(value);
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
`
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
// @ts-ignore
|
|
63
|
-
//this.checkDecodeStmts.push(
|
|
64
|
-
// ' if (!values.has("${name}")) throw new Error("Key "${name}" was not found. Cannot instantiate object.");\n'
|
|
65
|
-
//);
|
|
66
|
-
}
|
|
67
27
|
visitClassDeclaration(node: ClassDeclaration): void {
|
|
68
28
|
const className = node.name.text;
|
|
69
29
|
if (!node.decorators?.length) return;
|
|
@@ -74,7 +34,7 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
74
34
|
}
|
|
75
35
|
if (!foundDecorator) return;
|
|
76
36
|
|
|
77
|
-
// Prevent from being triggered twice
|
|
37
|
+
// Prevent from being triggered twice.
|
|
78
38
|
for (const member of node.members) {
|
|
79
39
|
if (member.name.text == "__JSON_Serialize") return;
|
|
80
40
|
}
|
|
@@ -102,7 +62,40 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
102
62
|
|
|
103
63
|
const parentSchema = this.schemasList.find((v) => v.name == this.currentClass.parent);
|
|
104
64
|
const members = [...node.members, ...(parentSchema ? parentSchema.node.members : [])]
|
|
105
|
-
|
|
65
|
+
|
|
66
|
+
for (const mem of members) {
|
|
67
|
+
if (mem.type && mem.type.name && mem.type.name.identifier.text) {
|
|
68
|
+
const member: FieldDeclaration = mem;
|
|
69
|
+
if (toString(member).startsWith("static")) return;
|
|
70
|
+
const lineText = toString(member);
|
|
71
|
+
if (lineText.startsWith("private")) return;
|
|
72
|
+
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
const type = member.type.name.identifier.text;
|
|
75
|
+
const name = member.name.text;
|
|
76
|
+
this.currentClass.keys.push(name);
|
|
77
|
+
// @ts-ignore
|
|
78
|
+
this.currentClass.types.push(type);
|
|
79
|
+
// @ts-ignore
|
|
80
|
+
if (["u8", "i8", "u16", "i16", "u32", "i32", "f32", "u64", "i64", "f64"].includes(type.toLowerCase())) {
|
|
81
|
+
this.currentClass.encodeStmts.push(
|
|
82
|
+
`"${name}":\${this.${name}.toString()},`
|
|
83
|
+
);
|
|
84
|
+
} else {
|
|
85
|
+
this.currentClass.encodeStmts.push(
|
|
86
|
+
`"${name}":\${JSON.stringify<${type}>(this.${name})},`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
// @ts-ignore
|
|
90
|
+
this.currentClass.setDataStmts.push(
|
|
91
|
+
`if (key == "${name}") {
|
|
92
|
+
this.${name} = JSON.parseObjectValue<${type}>(value);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
106
99
|
|
|
107
100
|
let serializeFunc = "";
|
|
108
101
|
|
|
@@ -147,9 +140,6 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
147
140
|
node.members.push(setDataMethod);
|
|
148
141
|
|
|
149
142
|
this.schemasList.push(this.currentClass);
|
|
150
|
-
|
|
151
|
-
//console.log(serializeFunc);
|
|
152
|
-
//console.log(setKeyFunc);
|
|
153
143
|
}
|
|
154
144
|
visitSource(node: Source): void {
|
|
155
145
|
super.visitSource(node);
|
|
@@ -161,7 +151,7 @@ export default class Transformer extends Transform {
|
|
|
161
151
|
afterParse(parser: Parser): void {
|
|
162
152
|
// Create new transform
|
|
163
153
|
const transformer = new AsJSONTransform();
|
|
164
|
-
|
|
154
|
+
|
|
165
155
|
// Sort the sources so that user scripts are visited last
|
|
166
156
|
const sources = parser.sources.filter(source => !isStdlib(source)).sort((_a, _b) => {
|
|
167
157
|
const a = _a.internalPath
|
|
@@ -174,7 +164,7 @@ export default class Transformer extends Transform {
|
|
|
174
164
|
return 0;
|
|
175
165
|
}
|
|
176
166
|
})
|
|
177
|
-
|
|
167
|
+
|
|
178
168
|
// Loop over every source
|
|
179
169
|
for (const source of sources) {
|
|
180
170
|
// Ignore all lib and std. Visit everything else.
|