json-as 0.8.3 → 0.8.5
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 +38 -1
- package/assembly/__tests__/as-json.spec.ts +25 -0
- package/assembly/index.d.ts +10 -0
- package/assembly/src/json.ts +54 -87
- package/assembly/test.ts +21 -5
- package/package.json +3 -2
- package/transform/lib/index.js +85 -56
- package/transform/package.json +3 -1
- package/transform/src/index.ts +110 -79
package/CHANGELOG
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
v0.8.2 - Properties starting with `static` or `private` would be ignored
|
|
2
|
-
v0.8.3 - Dirty fix to issue #68. Add __JSON_Stringify callable to global scope.
|
|
2
|
+
v0.8.3 - Dirty fix to issue #68. Add __JSON_Stringify callable to global scope.
|
|
3
|
+
v0.8.4 - Fix #71. Classes with the extending class overriding a property cause the property to be serialized twice.
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
██║ ██║███████║ ╚█████╔╝███████║╚██████╔╝██║ ╚████║
|
|
8
8
|
╚═╝ ╚═╝╚══════╝ ╚════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═══╝
|
|
9
9
|
|
|
10
|
-
v0.8.
|
|
10
|
+
v0.8.5
|
|
11
11
|
</pre>
|
|
12
12
|
</h3>
|
|
13
13
|
|
|
@@ -80,6 +80,43 @@ const parsed = JSON.parse<Player>(stringified);
|
|
|
80
80
|
|
|
81
81
|
If you use this project in your codebase, consider dropping a [star](https://github.com/JairusSW/as-json). I would really appreciate it!
|
|
82
82
|
|
|
83
|
+
## Performance
|
|
84
|
+
|
|
85
|
+
Run or view the benchmarks [here](https://github.com/JairusSW/as-json/tree/master/bench)
|
|
86
|
+
|
|
87
|
+
Below are benchmark results comparing JavaScript's built-in JSON implementation and `JSON-AS`
|
|
88
|
+
|
|
89
|
+
My library beats JSON (written in C++) on all counts *and*, I see many places where I can pull at least a 60% uplift in performance if I implement it.
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
Serialization Benchmarks:
|
|
93
|
+
|
|
94
|
+
| Value | JavaScript (ops/s) | JSON-as (ops/s) | JSON-AS with Pages |
|
|
95
|
+
|----------------------------|--------------------|-----------------|--------------------|
|
|
96
|
+
| "hello world" | 28,629,598 | 64,210,666 | + 124% |
|
|
97
|
+
| 12345 | 31,562,431 | 56,329,066 | 321,783,941 ops/s |
|
|
98
|
+
| 1.2345 | 15,977,278 | 20,322,939 | 30,307,616 ops/s |
|
|
99
|
+
| [[],[[]],[[],[[]]]] | 8,998,624 | 34,453,102 | + 283% |
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
Deserialization Benchmarks: (WIP)
|
|
104
|
+
|
|
105
|
+
| Value | JavaScript (ops/s) | JSON-AS (ops/s) | % Diff |
|
|
106
|
+
|----------------------------|--------------------|-----------------|--------|
|
|
107
|
+
| "12345" | 34,647,886 | 254,640,930 | + 635% |
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
And my PC specs:
|
|
111
|
+
|
|
112
|
+
| Component | Specification |
|
|
113
|
+
|-----------------|--------------------------------------|
|
|
114
|
+
| Wasmer Version | v4.3.0 |
|
|
115
|
+
| CPU | AMD Ryzen 7 7800x3D @ 6.00 GHz |
|
|
116
|
+
| Memory | T-Force DDR5 6000 MHz |
|
|
117
|
+
| OS | Ubuntu WSL2 |
|
|
118
|
+
| Graphics | AMD Radeon RX 6750XT |
|
|
119
|
+
|
|
83
120
|
## Issues
|
|
84
121
|
|
|
85
122
|
Please submit an issue to https://github.com/JairusSW/as-json/issues if you find anything wrong with this library
|
|
@@ -14,7 +14,32 @@ function canSer<T>(data: T, toBe: string): void {
|
|
|
14
14
|
const serialized = JSON.stringify<T>(data);
|
|
15
15
|
expect(serialized).toBe(toBe);
|
|
16
16
|
}
|
|
17
|
+
@json
|
|
18
|
+
class BaseObject {
|
|
19
|
+
a: string;
|
|
20
|
+
|
|
21
|
+
constructor(a: string) {
|
|
22
|
+
this.a = a;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@json
|
|
27
|
+
class DerivedObject extends BaseObject {
|
|
28
|
+
b: string;
|
|
29
|
+
|
|
30
|
+
constructor(a: string, b: string) {
|
|
31
|
+
super(a);
|
|
32
|
+
this.b = b;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
17
35
|
|
|
36
|
+
describe("Ser/de object hierarchies", () => {
|
|
37
|
+
it("should ser/de objects derived from base objects", () => {
|
|
38
|
+
const o = new DerivedObject("1", "2");
|
|
39
|
+
const s = '{"a":"1","b":"2"}';
|
|
40
|
+
canSerde(o, s);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
18
43
|
@json
|
|
19
44
|
class Map4 {
|
|
20
45
|
a: string;
|
package/assembly/index.d.ts
CHANGED
|
@@ -12,3 +12,13 @@ declare function serializable(target: any): void;
|
|
|
12
12
|
* Property decorator that provides an alias name for JSON serialization.
|
|
13
13
|
*/
|
|
14
14
|
declare function alias(name: string): Function;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Property decorator that allows a field to be omitted when equal to an Expression.
|
|
18
|
+
*/
|
|
19
|
+
declare function omitwhen(condition: string): Function;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Property decorator that allows a field to be omitted when a property is null.
|
|
23
|
+
*/
|
|
24
|
+
declare function omitnull(): Function;
|
package/assembly/src/json.ts
CHANGED
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
} from "./chars";
|
|
43
43
|
import { snip_fast, unsafeCharCodeAt, containsCodePoint } from "./util";
|
|
44
44
|
import { Virtual } from "as-virtual/assembly";
|
|
45
|
+
import { Box } from "as-container/assembly";
|
|
45
46
|
|
|
46
47
|
/**
|
|
47
48
|
* JSON Encoder/Decoder for AssemblyScript
|
|
@@ -62,7 +63,12 @@ export namespace JSON {
|
|
|
62
63
|
return serializeString(data as string);
|
|
63
64
|
} else if (isBoolean<T>()) {
|
|
64
65
|
return data ? "true" : "false";
|
|
65
|
-
} else if (
|
|
66
|
+
} 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) {
|
|
66
72
|
return nullWord;
|
|
67
73
|
// @ts-ignore
|
|
68
74
|
} else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
|
|
@@ -126,7 +132,7 @@ export namespace JSON {
|
|
|
126
132
|
result.write(serializeString(unchecked(keys[end]).toString()));
|
|
127
133
|
result.writeCodePoint(colonCode);
|
|
128
134
|
result.write(__JSON_Stringify(unchecked(values[end])));
|
|
129
|
-
|
|
135
|
+
|
|
130
136
|
result.writeCodePoint(rightBraceCode);
|
|
131
137
|
return result.toString();
|
|
132
138
|
} else {
|
|
@@ -135,86 +141,10 @@ export namespace JSON {
|
|
|
135
141
|
);
|
|
136
142
|
}
|
|
137
143
|
}
|
|
138
|
-
/**
|
|
139
|
-
* Stringifies valid JSON data.
|
|
140
|
-
* ```js
|
|
141
|
-
* __JSON_Stringify<T>(data)
|
|
142
|
-
* ```
|
|
143
|
-
* @param data T
|
|
144
|
-
* @returns string
|
|
145
|
-
*/
|
|
146
144
|
// @ts-ignore: Decorator
|
|
145
|
+
@unsafe
|
|
147
146
|
@inline export function stringifyTo<T>(data: T, out: string): void {
|
|
148
|
-
|
|
149
|
-
if (isString<T>() && data != null) {
|
|
150
|
-
out = serializeString(data as string);
|
|
151
|
-
return;
|
|
152
|
-
} else if (isBoolean<T>()) {
|
|
153
|
-
out = data ? trueWord : falseWord;
|
|
154
|
-
return;
|
|
155
|
-
} else if (isNullable<T>() && data == null) {
|
|
156
|
-
out = nullWord;
|
|
157
|
-
return;
|
|
158
|
-
// @ts-ignore
|
|
159
|
-
} else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
|
|
160
|
-
// @ts-ignore
|
|
161
|
-
out = data.toString();
|
|
162
|
-
return;
|
|
163
|
-
// @ts-ignore: Hidden function
|
|
164
|
-
} else if (isDefined(data.__JSON_Serialize)) {
|
|
165
|
-
// @ts-ignore: Hidden function
|
|
166
|
-
out = data.__JSON_Serialize();
|
|
167
|
-
return;
|
|
168
|
-
} else if (data instanceof Date) {
|
|
169
|
-
out = quoteWord + data.toISOString() + quoteWord;
|
|
170
|
-
return;
|
|
171
|
-
} else if (isArrayLike<T>()) {
|
|
172
|
-
// @ts-ignore
|
|
173
|
-
if (data.length == 0) {
|
|
174
|
-
out = emptyArrayWord;
|
|
175
|
-
return;
|
|
176
|
-
// @ts-ignore
|
|
177
|
-
} else if (isString<valueof<T>>()) {
|
|
178
|
-
out = leftBracketWord;
|
|
179
|
-
// @ts-ignore
|
|
180
|
-
for (let i = 0; i < data.length - 1; i++) {
|
|
181
|
-
// @ts-ignore
|
|
182
|
-
out += serializeString(unchecked(data[i]));
|
|
183
|
-
out += commaWord;
|
|
184
|
-
}
|
|
185
|
-
// @ts-ignore
|
|
186
|
-
out += serializeString(unchecked(data[data.length - 1]));
|
|
187
|
-
out += rightBracketWord;
|
|
188
|
-
return;
|
|
189
|
-
// @ts-ignore
|
|
190
|
-
} else if (isBoolean<valueof<T>>()) {
|
|
191
|
-
// @ts-ignore
|
|
192
|
-
out = leftBracketWord + data.join(commaWord) + rightBracketWord;
|
|
193
|
-
return;
|
|
194
|
-
// @ts-ignore
|
|
195
|
-
} else if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
|
|
196
|
-
// @ts-ignore
|
|
197
|
-
out = leftBracketWord + data.join(commaWord) + rightBracketWord;
|
|
198
|
-
return;
|
|
199
|
-
} else {
|
|
200
|
-
let result = new StringSink(leftBracketWord);
|
|
201
|
-
// @ts-ignore
|
|
202
|
-
for (let i = 0; i < data.length - 1; i++) {
|
|
203
|
-
// @ts-ignore
|
|
204
|
-
result.write(__JSON_Stringify(unchecked(data[i])));
|
|
205
|
-
result.writeCodePoint(commaCode);
|
|
206
|
-
}
|
|
207
|
-
// @ts-ignore
|
|
208
|
-
result.write(__JSON_Stringify(unchecked(data[data.length - 1])));
|
|
209
|
-
result.writeCodePoint(rightBracketCode);
|
|
210
|
-
out = result.toString();
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
} else {
|
|
214
|
-
throw new Error(
|
|
215
|
-
`Could not serialize data of type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
|
|
216
|
-
);
|
|
217
|
-
}
|
|
147
|
+
throw new Error("Method is deprecated");
|
|
218
148
|
}
|
|
219
149
|
/**
|
|
220
150
|
* Parses valid JSON strings into their original format.
|
|
@@ -227,7 +157,6 @@ export namespace JSON {
|
|
|
227
157
|
|
|
228
158
|
// @ts-ignore: Decorator
|
|
229
159
|
@inline export function parse<T>(data: string, initializeDefaultValues: boolean = false): T {
|
|
230
|
-
let type: T;
|
|
231
160
|
if (isString<T>()) {
|
|
232
161
|
// @ts-ignore
|
|
233
162
|
return parseString(data);
|
|
@@ -239,6 +168,15 @@ export namespace JSON {
|
|
|
239
168
|
} else if (isArrayLike<T>()) {
|
|
240
169
|
// @ts-ignore
|
|
241
170
|
return parseArray<T>(data.trimStart());
|
|
171
|
+
// @ts-ignore
|
|
172
|
+
}
|
|
173
|
+
let type: nonnull<T> = changetype<nonnull<T>>(0);
|
|
174
|
+
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);
|
|
242
180
|
} else if (isNullable<T>() && data == nullWord) {
|
|
243
181
|
// @ts-ignore
|
|
244
182
|
return null;
|
|
@@ -260,7 +198,6 @@ export namespace JSON {
|
|
|
260
198
|
|
|
261
199
|
// @ts-ignore: Decorator
|
|
262
200
|
@global @inline function __parseObjectValue<T>(data: string, initializeDefaultValues: boolean): T {
|
|
263
|
-
let type: T;
|
|
264
201
|
if (isString<T>()) {
|
|
265
202
|
// @ts-ignore
|
|
266
203
|
return data;
|
|
@@ -272,6 +209,15 @@ export namespace JSON {
|
|
|
272
209
|
} else if (isArrayLike<T>()) {
|
|
273
210
|
// @ts-ignore
|
|
274
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);
|
|
275
221
|
} else if (isNullable<T>() && data == nullWord) {
|
|
276
222
|
// @ts-ignore
|
|
277
223
|
return null;
|
|
@@ -442,6 +388,18 @@ export namespace JSON {
|
|
|
442
388
|
else if (type instanceof f32) return f32.parse(data);
|
|
443
389
|
}
|
|
444
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
|
+
|
|
445
403
|
// @ts-ignore: Decorator
|
|
446
404
|
@inline function parseObject<T>(data: string, initializeDefaultValues: boolean): T {
|
|
447
405
|
const schema: nonnull<T> = changetype<nonnull<T>>(
|
|
@@ -584,7 +542,7 @@ export namespace JSON {
|
|
|
584
542
|
);
|
|
585
543
|
|
|
586
544
|
if (!isDefined(map.set)) {
|
|
587
|
-
|
|
545
|
+
throw new Error("Tried to parse a map, but the types did not match!")
|
|
588
546
|
}
|
|
589
547
|
|
|
590
548
|
const key = Virtual.createEmpty<string>();
|
|
@@ -758,7 +716,7 @@ export namespace JSON {
|
|
|
758
716
|
}
|
|
759
717
|
}
|
|
760
718
|
|
|
761
|
-
|
|
719
|
+
throw new Error("Tried to parse array, but failed!")
|
|
762
720
|
}
|
|
763
721
|
|
|
764
722
|
// @ts-ignore: Decorator
|
|
@@ -892,14 +850,14 @@ function parseDate(dateTimeString: string): Date {
|
|
|
892
850
|
}
|
|
893
851
|
|
|
894
852
|
// Dirty fix
|
|
895
|
-
|
|
853
|
+
// @ts-ignore: Decorator
|
|
896
854
|
@global @inline function __JSON_Stringify<T>(data: T): string {
|
|
897
855
|
// String
|
|
898
856
|
if (isString<T>() && data != null) {
|
|
899
857
|
return serializeString(data as string);
|
|
900
858
|
} else if (isBoolean<T>()) {
|
|
901
859
|
return data ? "true" : "false";
|
|
902
|
-
} else if (isNullable<T>() && data ==
|
|
860
|
+
} else if (isNullable<T>() && changetype<usize>(data) == <usize>0) {
|
|
903
861
|
return nullWord;
|
|
904
862
|
// @ts-ignore
|
|
905
863
|
} else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
|
|
@@ -911,6 +869,11 @@ function parseDate(dateTimeString: string): Date {
|
|
|
911
869
|
return data.__JSON_Serialize();
|
|
912
870
|
} else if (data instanceof Date) {
|
|
913
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());
|
|
914
877
|
} else if (isArrayLike<T>()) {
|
|
915
878
|
// @ts-ignore
|
|
916
879
|
if (data.length == 0) {
|
|
@@ -963,7 +926,7 @@ function parseDate(dateTimeString: string): Date {
|
|
|
963
926
|
result.write(serializeString(unchecked(keys[end]).toString()));
|
|
964
927
|
result.writeCodePoint(colonCode);
|
|
965
928
|
result.write(__JSON_Stringify(unchecked(values[end])));
|
|
966
|
-
|
|
929
|
+
|
|
967
930
|
result.writeCodePoint(rightBraceCode);
|
|
968
931
|
return result.toString();
|
|
969
932
|
} else {
|
|
@@ -971,4 +934,8 @@ function parseDate(dateTimeString: string): Date {
|
|
|
971
934
|
`Could not serialize data of type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
|
|
972
935
|
);
|
|
973
936
|
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
@inline function parseDirectInference<T>(type: T, data: string, initializeDefaultValues: boolean = false): T {
|
|
940
|
+
return JSON.parse<T>(data, initializeDefaultValues)
|
|
974
941
|
}
|
package/assembly/test.ts
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
|
+
import { Box } from "as-container";
|
|
1
2
|
import { JSON } from "./src/json";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
@json
|
|
5
|
+
class Foo {
|
|
6
|
+
@omitnull
|
|
7
|
+
optionalNumber: Box<i32> | null = null;
|
|
8
|
+
@omitif("this.tristateValue!.unwrap() == false")
|
|
9
|
+
tristateValue: Box<bool> | null = null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const foo: Foo = {
|
|
13
|
+
optionalNumber: null,
|
|
14
|
+
tristateValue: Box.from(true)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
console.log(JSON.stringify(foo));
|
|
18
|
+
|
|
19
|
+
const p1 = JSON.parse<Box<i32> | null>("null");
|
|
20
|
+
console.log(JSON.stringify<Box<i32> | null>(p1));
|
|
21
|
+
console.log(changetype<usize>(p1).toString())
|
|
22
|
+
const p2 = JSON.parse<Foo>("{\"optionalNumber\":null,\"tristateValue\":false}");
|
|
23
|
+
console.log(JSON.stringify(p2));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-as",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.5",
|
|
4
4
|
"description": "JSON encoder/decoder for AssemblyScript",
|
|
5
5
|
"types": "assembly/index.ts",
|
|
6
6
|
"author": "Jairus Tanaka",
|
|
@@ -44,9 +44,10 @@
|
|
|
44
44
|
"visitor-as": "^0.11.4"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
+
"as-container": "^0.8.0",
|
|
47
48
|
"as-string-sink": "^0.5.3",
|
|
48
49
|
"as-variant": "^0.4.1",
|
|
49
|
-
"as-virtual": "^0.
|
|
50
|
+
"as-virtual": "^0.2.0"
|
|
50
51
|
},
|
|
51
52
|
"overrides": {
|
|
52
53
|
"assemblyscript": "$assemblyscript"
|
package/transform/lib/index.js
CHANGED
|
@@ -22,7 +22,7 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
22
22
|
}
|
|
23
23
|
visitMethodDeclaration() { }
|
|
24
24
|
visitClassDeclaration(node) {
|
|
25
|
-
var _c, _d;
|
|
25
|
+
var _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
26
26
|
const className = node.name.text;
|
|
27
27
|
if (!((_c = node.decorators) === null || _c === void 0 ? void 0 : _c.length))
|
|
28
28
|
return;
|
|
@@ -53,94 +53,123 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
53
53
|
setDataStmts: [],
|
|
54
54
|
initializeStmts: []
|
|
55
55
|
};
|
|
56
|
-
if (this.currentClass.parent.length
|
|
56
|
+
if (this.currentClass.parent.length) {
|
|
57
57
|
const parentSchema = this.schemasList.find((v) => v.name == this.currentClass.parent);
|
|
58
58
|
if (parentSchema === null || parentSchema === void 0 ? void 0 : parentSchema.encodeStmts) {
|
|
59
59
|
parentSchema === null || parentSchema === void 0 ? void 0 : parentSchema.encodeStmts.push((parentSchema === null || parentSchema === void 0 ? void 0 : parentSchema.encodeStmts.pop()) + ",");
|
|
60
|
-
|
|
60
|
+
for (let i = 0; i < parentSchema.keys.length; i++) {
|
|
61
|
+
const key = parentSchema.keys[i];
|
|
62
|
+
if (node.members.filter(v => v.name.text == key) == undefined)
|
|
63
|
+
this.currentClass.encodeStmts.unshift(parentSchema.encodeStmts[i]);
|
|
64
|
+
}
|
|
61
65
|
}
|
|
62
66
|
}
|
|
63
67
|
const parentSchema = this.schemasList.find((v) => v.name == this.currentClass.parent);
|
|
64
68
|
const members = [
|
|
65
|
-
...node.members
|
|
66
|
-
...(parentSchema ? parentSchema.node.members : []),
|
|
69
|
+
...node.members
|
|
67
70
|
];
|
|
71
|
+
if (parentSchema) {
|
|
72
|
+
for (const mem of parentSchema.node.members) {
|
|
73
|
+
if (members.find(v => v.name === mem.name) == undefined)
|
|
74
|
+
members.unshift(mem);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
68
77
|
for (const mem of members) {
|
|
69
78
|
// @ts-ignore
|
|
70
79
|
if (mem.type && mem.type.name && mem.type.name.identifier.text) {
|
|
71
80
|
const member = mem;
|
|
72
81
|
const lineText = toString(member);
|
|
73
82
|
//console.log("Member: " + lineText)
|
|
74
|
-
if (
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
if (lineText.startsWith("private ") && lineText.startsWith("static "))
|
|
84
|
+
continue;
|
|
85
|
+
const omitnull = (_d = member.decorators) === null || _d === void 0 ? void 0 : _d.find(v => v.name.text == "omitnull");
|
|
86
|
+
console.log((_e = member.decorators) === null || _e === void 0 ? void 0 : _e.find(v => v.name.text === "omitif"));
|
|
87
|
+
const omitif = (_k = (_j = (_h = (_g = (_f = member.decorators) === null || _f === void 0 ? void 0 : _f.find(v => v.name.text === "omitif")) === null || _g === void 0 ? void 0 : _g.args) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.value) !== null && _k !== void 0 ? _k : null;
|
|
88
|
+
// @ts-ignore
|
|
89
|
+
let type = toString(member.type);
|
|
90
|
+
const name = member.name.text;
|
|
91
|
+
let aliasName = name;
|
|
92
|
+
// @ts-ignore
|
|
93
|
+
if (member.decorators && ((_l = member.decorators[0]) === null || _l === void 0 ? void 0 : _l.name.text) === "alias") {
|
|
94
|
+
if (member.decorators[0] && member.decorators[0].args[0]) {
|
|
95
|
+
// @ts-ignore
|
|
96
|
+
aliasName = member.decorators[0].args[0].value;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
this.currentClass.keys.push(name);
|
|
100
|
+
// @ts-ignore
|
|
101
|
+
this.currentClass.types.push(type);
|
|
102
|
+
// @ts-ignore
|
|
103
|
+
if ([
|
|
104
|
+
"u8",
|
|
105
|
+
"i8",
|
|
106
|
+
"u16",
|
|
107
|
+
"i16",
|
|
108
|
+
"u32",
|
|
109
|
+
"i32",
|
|
110
|
+
"u64",
|
|
111
|
+
"i64",
|
|
112
|
+
].includes(type.toLowerCase())) {
|
|
113
|
+
if (omitif) {
|
|
114
|
+
this.currentClass.encodeStmts.push(`\${${omitif} ? "" : \`,${encodeKey(aliasName)}:\${this.${name}}\`}`);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
this.currentClass.encodeStmts.push(`,${encodeKey(aliasName)}:\${this.${name}}`);
|
|
85
118
|
}
|
|
86
|
-
this.currentClass.keys.push(name);
|
|
87
|
-
// @ts-ignore
|
|
88
|
-
this.currentClass.types.push(type);
|
|
89
119
|
// @ts-ignore
|
|
90
|
-
if (
|
|
91
|
-
"u8",
|
|
92
|
-
"i8",
|
|
93
|
-
"u16",
|
|
94
|
-
"i16",
|
|
95
|
-
"u32",
|
|
96
|
-
"i32",
|
|
97
|
-
"u64",
|
|
98
|
-
"i64",
|
|
99
|
-
].includes(type.toLowerCase())) {
|
|
100
|
-
this.currentClass.encodeStmts.push(`${encodeKey(aliasName)}:\${this.${name}},`);
|
|
101
|
-
// @ts-ignore
|
|
102
|
-
this.currentClass.setDataStmts.push(`if (key.equals(${JSON.stringify(aliasName)})) {
|
|
120
|
+
this.currentClass.setDataStmts.push(`if (key.equals(${JSON.stringify(aliasName)})) {
|
|
103
121
|
this.${name} = __atoi_fast<${type}>(data, val_start << 1, val_end << 1);
|
|
104
122
|
return;
|
|
105
123
|
}`);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
124
|
+
if (member.initializer) {
|
|
125
|
+
this.currentClass.initializeStmts.push(`this.${name} = ${toString(member.initializer)}`);
|
|
109
126
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
127
|
+
}
|
|
128
|
+
else if ([
|
|
129
|
+
"f32",
|
|
130
|
+
"f64",
|
|
131
|
+
].includes(type.toLowerCase())) {
|
|
132
|
+
if (omitif) {
|
|
133
|
+
this.currentClass.encodeStmts.push(`\${${omitif} ? "" : \`,${encodeKey(aliasName)}:\${this.${name}}\`}`);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
this.currentClass.encodeStmts.push(`,${encodeKey(aliasName)}:\${this.${name}}`);
|
|
137
|
+
}
|
|
138
|
+
// @ts-ignore
|
|
139
|
+
this.currentClass.setDataStmts.push(`if (key.equals(${JSON.stringify(aliasName)})) {
|
|
118
140
|
this.${name} = __parseObjectValue<${type}>(data.slice(val_start, val_end), initializeDefaultValues);
|
|
119
141
|
return;
|
|
120
142
|
}`);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
143
|
+
if (member.initializer) {
|
|
144
|
+
this.currentClass.initializeStmts.push(`this.${name} = ${toString(member.initializer)}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
if (omitnull) {
|
|
149
|
+
this.currentClass.encodeStmts.push(`c\${changetype<usize>(this.${name}) !== <usize>0 ? "" : \`${encodeKey(aliasName)}:\${__JSON_Stringify<${type}>(this.${name})}\`}`);
|
|
150
|
+
console.log(`\${changetype<usize>(this.${name}) != <usize>0 ? \`${encodeKey(aliasName)}:,\${__JSON_Stringify<${type}>(this.${name})}\` : ""}`);
|
|
151
|
+
}
|
|
152
|
+
else if (omitif) {
|
|
153
|
+
this.currentClass.encodeStmts.push(`\${${omitif} ? "" : \`${encodeKey(aliasName)}:,\${__JSON_Stringify<${type}>(this.${name})}\`}`);
|
|
124
154
|
}
|
|
125
155
|
else {
|
|
126
|
-
this.currentClass.encodeStmts.push(
|
|
127
|
-
|
|
128
|
-
|
|
156
|
+
this.currentClass.encodeStmts.push(`,${encodeKey(aliasName)}:\${__JSON_Stringify<${type}>(this.${name})}`);
|
|
157
|
+
}
|
|
158
|
+
// @ts-ignore
|
|
159
|
+
this.currentClass.setDataStmts.push(`if (key.equals(${JSON.stringify(aliasName)})) {
|
|
129
160
|
this.${name} = __parseObjectValue<${type}>(val_start ? data.slice(val_start, val_end) : data, initializeDefaultValues);
|
|
130
161
|
return;
|
|
131
162
|
}`);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
163
|
+
if (member.initializer) {
|
|
164
|
+
this.currentClass.initializeStmts.push(`this.${name} = ${toString(member.initializer)}`);
|
|
135
165
|
}
|
|
136
166
|
}
|
|
137
167
|
}
|
|
138
168
|
}
|
|
139
169
|
let serializeFunc = "";
|
|
140
170
|
if (this.currentClass.encodeStmts.length > 0) {
|
|
141
|
-
const stmt = this.currentClass.encodeStmts[
|
|
142
|
-
this.currentClass.encodeStmts[
|
|
143
|
-
stmt.slice(0, stmt.length - 1);
|
|
171
|
+
const stmt = this.currentClass.encodeStmts[0];
|
|
172
|
+
this.currentClass.encodeStmts[0] = stmt.slice(1);
|
|
144
173
|
serializeFunc = `
|
|
145
174
|
__JSON_Serialize(): string {
|
|
146
175
|
return \`{${this.currentClass.encodeStmts.join("")}}\`;
|
|
@@ -179,7 +208,7 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
179
208
|
this.schemasList.push(this.currentClass);
|
|
180
209
|
this.sources.add(node.name.range.source);
|
|
181
210
|
// Uncomment to see the generated code for debugging.
|
|
182
|
-
|
|
211
|
+
console.log(serializeFunc);
|
|
183
212
|
//console.log(setKeyFunc);
|
|
184
213
|
//console.log(initializeFunc);
|
|
185
214
|
}
|
package/transform/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@json-as/transform",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.5",
|
|
4
4
|
"description": "JSON encoder/decoder for AssemblyScript",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"author": "Jairus Tanaka",
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
"json",
|
|
26
26
|
"serialize",
|
|
27
27
|
"deserialize",
|
|
28
|
+
"stringify",
|
|
29
|
+
"data",
|
|
28
30
|
"serde"
|
|
29
31
|
],
|
|
30
32
|
"bugs": {
|
package/transform/src/index.ts
CHANGED
|
@@ -61,24 +61,33 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
61
61
|
initializeStmts: []
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
-
if (this.currentClass.parent.length
|
|
64
|
+
if (this.currentClass.parent.length) {
|
|
65
65
|
const parentSchema = this.schemasList.find(
|
|
66
66
|
(v) => v.name == this.currentClass.parent
|
|
67
67
|
);
|
|
68
68
|
if (parentSchema?.encodeStmts) {
|
|
69
69
|
parentSchema?.encodeStmts.push(parentSchema?.encodeStmts.pop() + ",");
|
|
70
|
-
|
|
70
|
+
for (let i = 0; i < parentSchema.keys.length; i++) {
|
|
71
|
+
const key = parentSchema.keys[i];
|
|
72
|
+
if (node.members.filter(v => v.name.text == key) == undefined) this.currentClass.encodeStmts.unshift(parentSchema.encodeStmts[i]!);
|
|
73
|
+
}
|
|
71
74
|
}
|
|
72
75
|
}
|
|
73
76
|
|
|
74
77
|
const parentSchema = this.schemasList.find(
|
|
75
78
|
(v) => v.name == this.currentClass.parent
|
|
76
79
|
);
|
|
80
|
+
|
|
77
81
|
const members = [
|
|
78
|
-
...node.members
|
|
79
|
-
...(parentSchema ? parentSchema.node.members : []),
|
|
82
|
+
...node.members
|
|
80
83
|
];
|
|
81
84
|
|
|
85
|
+
if (parentSchema) {
|
|
86
|
+
for (const mem of parentSchema.node.members) {
|
|
87
|
+
if (members.find(v => v.name === mem.name) == undefined) members.unshift(mem);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
82
91
|
for (const mem of members) {
|
|
83
92
|
// @ts-ignore
|
|
84
93
|
if (mem.type && mem.type.name && mem.type.name.identifier.text) {
|
|
@@ -86,91 +95,116 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
86
95
|
const lineText = toString(member);
|
|
87
96
|
//console.log("Member: " + lineText)
|
|
88
97
|
|
|
89
|
-
if (
|
|
98
|
+
if (lineText.startsWith("private ") && lineText.startsWith("static ")) continue;
|
|
90
99
|
|
|
91
|
-
|
|
92
|
-
|
|
100
|
+
const omitnull = member.decorators?.find(v => v.name.text == "omitnull");
|
|
101
|
+
console.log(member.decorators?.find(v => v.name.text === "omitif"))
|
|
102
|
+
const omitif = member.decorators?.find(v => v.name.text === "omitif")?.args?.[0]?.value ?? null;
|
|
93
103
|
|
|
94
|
-
|
|
95
|
-
|
|
104
|
+
// @ts-ignore
|
|
105
|
+
let type = toString(member.type);
|
|
96
106
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
107
|
+
const name = member.name.text;
|
|
108
|
+
let aliasName = name;
|
|
109
|
+
|
|
110
|
+
// @ts-ignore
|
|
111
|
+
if (member.decorators && member.decorators[0]?.name.text === "alias") {
|
|
112
|
+
if (member.decorators[0] && member.decorators[0].args![0]) {
|
|
113
|
+
// @ts-ignore
|
|
114
|
+
aliasName = member.decorators[0].args![0].value;
|
|
103
115
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
)
|
|
116
|
+
}
|
|
117
|
+
this.currentClass.keys.push(name);
|
|
118
|
+
// @ts-ignore
|
|
119
|
+
this.currentClass.types.push(type);
|
|
120
|
+
// @ts-ignore
|
|
121
|
+
if (
|
|
122
|
+
[
|
|
123
|
+
"u8",
|
|
124
|
+
"i8",
|
|
125
|
+
"u16",
|
|
126
|
+
"i16",
|
|
127
|
+
"u32",
|
|
128
|
+
"i32",
|
|
129
|
+
"u64",
|
|
130
|
+
"i64",
|
|
131
|
+
].includes(type.toLowerCase())
|
|
132
|
+
) {
|
|
133
|
+
if (omitif) {
|
|
120
134
|
this.currentClass.encodeStmts.push(
|
|
121
|
-
|
|
135
|
+
`\${${omitif} ? "" : \`,${encodeKey(aliasName)}:\${this.${name}}\`}`
|
|
122
136
|
);
|
|
123
|
-
|
|
124
|
-
this.currentClass.
|
|
125
|
-
|
|
137
|
+
} else {
|
|
138
|
+
this.currentClass.encodeStmts.push(
|
|
139
|
+
`,${encodeKey(aliasName)}:\${this.${name}}`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
// @ts-ignore
|
|
143
|
+
this.currentClass.setDataStmts.push(
|
|
144
|
+
`if (key.equals(${JSON.stringify(aliasName)})) {
|
|
126
145
|
this.${name} = __atoi_fast<${type}>(data, val_start << 1, val_end << 1);
|
|
127
146
|
return;
|
|
128
147
|
}`
|
|
148
|
+
);
|
|
149
|
+
if (member.initializer) {
|
|
150
|
+
this.currentClass.initializeStmts.push(
|
|
151
|
+
`this.${name} = ${toString(member.initializer)}`
|
|
129
152
|
);
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
153
|
+
}
|
|
154
|
+
} else if (
|
|
155
|
+
[
|
|
156
|
+
"f32",
|
|
157
|
+
"f64",
|
|
158
|
+
].includes(type.toLowerCase())
|
|
159
|
+
) {
|
|
160
|
+
if (omitif) {
|
|
161
|
+
this.currentClass.encodeStmts.push(
|
|
162
|
+
`\${${omitif} ? "" : \`,${encodeKey(aliasName)}:\${this.${name}}\`}`
|
|
163
|
+
);
|
|
164
|
+
} else {
|
|
165
|
+
this.currentClass.encodeStmts.push(
|
|
166
|
+
`,${encodeKey(aliasName)}:\${this.${name}}`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
// @ts-ignore
|
|
170
|
+
this.currentClass.setDataStmts.push(
|
|
171
|
+
`if (key.equals(${JSON.stringify(aliasName)})) {
|
|
148
172
|
this.${name} = __parseObjectValue<${type}>(data.slice(val_start, val_end), initializeDefaultValues);
|
|
149
173
|
return;
|
|
150
174
|
}`
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
175
|
+
);
|
|
176
|
+
if (member.initializer) {
|
|
177
|
+
this.currentClass.initializeStmts.push(
|
|
178
|
+
`this.${name} = ${toString(member.initializer)}`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
} else {
|
|
182
|
+
if (omitnull) {
|
|
183
|
+
this.currentClass.encodeStmts.push(
|
|
184
|
+
`${comma}\${changetype<usize>(this.${name}) !== <usize>0 ? "" : \`${encodeKey(aliasName)}:\${__JSON_Stringify<${type}>(this.${name})}\`}`
|
|
185
|
+
);
|
|
186
|
+
console.log(`\${changetype<usize>(this.${name}) != <usize>0 ? \`${encodeKey(aliasName)}:,\${__JSON_Stringify<${type}>(this.${name})}\` : ""}`)
|
|
187
|
+
} else if (omitif) {
|
|
188
|
+
this.currentClass.encodeStmts.push(
|
|
189
|
+
`\${${omitif} ? "" : \`${encodeKey(aliasName)}:,\${__JSON_Stringify<${type}>(this.${name})}\`}`
|
|
190
|
+
);
|
|
191
|
+
} else {
|
|
192
|
+
this.currentClass.encodeStmts.push(
|
|
193
|
+
`,${encodeKey(aliasName)}:\${__JSON_Stringify<${type}>(this.${name})}`
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
// @ts-ignore
|
|
197
|
+
this.currentClass.setDataStmts.push(
|
|
198
|
+
`if (key.equals(${JSON.stringify(aliasName)})) {
|
|
164
199
|
this.${name} = __parseObjectValue<${type}>(val_start ? data.slice(val_start, val_end) : data, initializeDefaultValues);
|
|
165
200
|
return;
|
|
166
201
|
}`
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
202
|
+
);
|
|
203
|
+
if (member.initializer) {
|
|
204
|
+
this.currentClass.initializeStmts.push(
|
|
205
|
+
`this.${name} = ${toString(member.initializer)}`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
174
208
|
}
|
|
175
209
|
}
|
|
176
210
|
}
|
|
@@ -179,11 +213,8 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
179
213
|
|
|
180
214
|
if (this.currentClass.encodeStmts.length > 0) {
|
|
181
215
|
const stmt =
|
|
182
|
-
this.currentClass.encodeStmts[
|
|
183
|
-
|
|
184
|
-
]!;
|
|
185
|
-
this.currentClass.encodeStmts[this.currentClass.encodeStmts.length - 1] =
|
|
186
|
-
stmt!.slice(0, stmt.length - 1);
|
|
216
|
+
this.currentClass.encodeStmts[0]!;
|
|
217
|
+
this.currentClass.encodeStmts[0] = stmt!.slice(1);
|
|
187
218
|
serializeFunc = `
|
|
188
219
|
__JSON_Serialize(): string {
|
|
189
220
|
return \`{${this.currentClass.encodeStmts.join("")}}\`;
|
|
@@ -227,7 +258,7 @@ class AsJSONTransform extends BaseVisitor {
|
|
|
227
258
|
this.sources.add(node.name.range.source);
|
|
228
259
|
|
|
229
260
|
// Uncomment to see the generated code for debugging.
|
|
230
|
-
|
|
261
|
+
console.log(serializeFunc);
|
|
231
262
|
//console.log(setKeyFunc);
|
|
232
263
|
//console.log(initializeFunc);
|
|
233
264
|
}
|