json-as 1.0.4 → 1.0.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.md +10 -1
- package/README.md +26 -8
- package/SECURITY.md +2 -1
- package/assembly/__benches__/large.bench.ts +3 -0
- package/assembly/__benches__/vec3.bench.ts +3 -0
- package/assembly/__tests__/arbitrary.spec.ts +3 -3
- package/assembly/__tests__/array.spec.ts +5 -8
- package/assembly/__tests__/box.spec.ts +10 -20
- package/assembly/__tests__/custom.spec.ts +5 -6
- package/assembly/__tests__/date.spec.ts +4 -6
- package/assembly/__tests__/float.spec.ts +3 -3
- package/assembly/__tests__/map.spec.ts +1 -1
- package/assembly/__tests__/raw.spec.ts +3 -3
- package/assembly/__tests__/struct.spec.ts +24 -14
- package/assembly/deserialize/simd/string.ts +1 -2
- package/assembly/deserialize/simple/array/struct.ts +2 -3
- package/assembly/deserialize/simple/array.ts +1 -1
- package/assembly/deserialize/simple/bool.ts +1 -1
- package/assembly/deserialize/simple/map.ts +3 -4
- package/assembly/deserialize/simple/object.ts +2 -3
- package/assembly/deserialize/simple/raw.ts +1 -1
- package/assembly/deserialize/simple/struct.ts +2 -3
- package/assembly/index.ts +23 -7
- package/assembly/serialize/simd/string.ts +1 -0
- package/assembly/serialize/simple/integer.ts +1 -1
- package/assembly/serialize/simple/object.ts +7 -6
- package/assembly/test.ts +23 -24
- package/bench.js +2 -4
- package/index.ts +1 -1
- package/lib/as-bs.ts +4 -13
- package/package.json +5 -3
- package/run-tests.sh +1 -1
- package/transform/lib/index.js +58 -55
- package/transform/lib/index.js.map +1 -1
- package/transform/src/index.ts +72 -131
package/assembly/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { bs } from "../lib/as-bs";
|
|
|
4
4
|
import { serializeString } from "./serialize/simple/string";
|
|
5
5
|
import { serializeArray } from "./serialize/simple/array";
|
|
6
6
|
import { serializeMap } from "./serialize/simple/map";
|
|
7
|
+
import { serializeDate } from "./serialize/simple/date";
|
|
7
8
|
import { deserializeBoolean } from "./deserialize/simple/bool";
|
|
8
9
|
import { deserializeArray } from "./deserialize/simple/array";
|
|
9
10
|
import { deserializeFloat } from "./deserialize/simple/float";
|
|
@@ -28,6 +29,8 @@ import { serializeObject } from "./serialize/simple/object";
|
|
|
28
29
|
import { deserializeObject } from "./deserialize/simple/object";
|
|
29
30
|
import { serializeRaw } from "./serialize/simple/raw";
|
|
30
31
|
import { deserializeRaw } from "./deserialize/simple/raw";
|
|
32
|
+
import { isSpace } from "util/string";
|
|
33
|
+
import { deserializeString_SIMD } from "./deserialize/simd/string";
|
|
31
34
|
|
|
32
35
|
/**
|
|
33
36
|
* Offset of the 'storage' property in the JSON.Value class.
|
|
@@ -179,8 +182,14 @@ export namespace JSON {
|
|
|
179
182
|
// @ts-ignore
|
|
180
183
|
return null;
|
|
181
184
|
} else if (isString<T>()) {
|
|
185
|
+
if (dataSize < 4) throw new Error("Cannot parse data as string because it was formatted incorrectly!");
|
|
186
|
+
// if (ASC_FEATURE_SIMD) {
|
|
187
|
+
// // @ts-ignore
|
|
188
|
+
// return changetype<string>(deserializeString_SIMD(dataPtr, dataPtr + dataSize, __new(dataSize - 4, idof<string>())));
|
|
189
|
+
// } else {
|
|
182
190
|
// @ts-ignore
|
|
183
191
|
return deserializeString(dataPtr, dataPtr + dataSize, __new(dataSize - 4, idof<string>()));
|
|
192
|
+
// }
|
|
184
193
|
} else if (isArray<T>()) {
|
|
185
194
|
// @ts-ignore
|
|
186
195
|
return inline.always(deserializeArray<nonnull<T>>(dataPtr, dataPtr + dataSize, changetype<usize>(instantiate<T>())));
|
|
@@ -210,6 +219,7 @@ export namespace JSON {
|
|
|
210
219
|
// @ts-ignore: type
|
|
211
220
|
return deserializeRaw(dataPtr, dataPtr + dataSize);
|
|
212
221
|
} else if (type instanceof JSON.Value) {
|
|
222
|
+
// should cut out whitespace here
|
|
213
223
|
// @ts-ignore
|
|
214
224
|
return inline.always(deserializeArbitrary(dataPtr, dataPtr + dataSize, 0));
|
|
215
225
|
} else if (type instanceof JSON.Obj) {
|
|
@@ -478,7 +488,6 @@ export namespace JSON {
|
|
|
478
488
|
const out = changetype<JSON.Obj>(__new(offsetof<JSON.Obj>(), idof<JSON.Obj>()));
|
|
479
489
|
|
|
480
490
|
if (value instanceof Map) {
|
|
481
|
-
|
|
482
491
|
}
|
|
483
492
|
return out;
|
|
484
493
|
}
|
|
@@ -579,14 +588,15 @@ export namespace JSON {
|
|
|
579
588
|
} else if (isFloat<T>()) {
|
|
580
589
|
return deserializeFloat<T>(srcStart, srcEnd);
|
|
581
590
|
} else if (isString<T>()) {
|
|
591
|
+
if (srcEnd - srcStart < 4) throw new Error("Cannot parse data as string because it was formatted incorrectly!");
|
|
582
592
|
// @ts-ignore: type
|
|
583
593
|
return deserializeString(srcStart, srcEnd, dst);
|
|
584
|
-
} else if (isArray<T>()) {
|
|
585
|
-
// @ts-ignore: type
|
|
586
|
-
return inline.always(deserializeArray<T>(srcStart, srcEnd, dst));
|
|
587
594
|
} else if (isNullable<T>() && srcEnd - srcStart == 8 && load<u64>(srcStart) == 30399761348886638) {
|
|
588
595
|
// @ts-ignore
|
|
589
596
|
return null;
|
|
597
|
+
} else if (isArray<T>()) {
|
|
598
|
+
// @ts-ignore: type
|
|
599
|
+
return inline.always(deserializeArray<T>(srcStart, srcEnd, dst));
|
|
590
600
|
} else {
|
|
591
601
|
let type: nonnull<T> = changetype<nonnull<T>>(0);
|
|
592
602
|
// @ts-ignore: Defined by transform
|
|
@@ -630,9 +640,15 @@ export namespace JSON {
|
|
|
630
640
|
}
|
|
631
641
|
|
|
632
642
|
// @ts-ignore: inline
|
|
633
|
-
@inline export function toRaw(data: string): JSON.Raw {
|
|
643
|
+
@inline export function toRaw(data: string): JSON.Raw {
|
|
644
|
+
return new JSON.Raw(data);
|
|
645
|
+
}
|
|
634
646
|
// @ts-ignore: inline
|
|
635
|
-
@inline export function fromRaw(data: JSON.Raw): string {
|
|
647
|
+
@inline export function fromRaw(data: JSON.Raw): string {
|
|
648
|
+
return data.data;
|
|
649
|
+
}
|
|
636
650
|
|
|
637
651
|
// @ts-ignore: inline
|
|
638
|
-
@inline export function toBox<T>(data: T): JSON.Box<T> {
|
|
652
|
+
@inline export function toBox<T>(data: T): JSON.Box<T> {
|
|
653
|
+
return new JSON.Box<T>(data);
|
|
654
|
+
}
|
|
@@ -5,13 +5,14 @@ import { bytes } from "../../util";
|
|
|
5
5
|
|
|
6
6
|
export function serializeObject(data: JSON.Obj): void {
|
|
7
7
|
if (!data.size) {
|
|
8
|
-
|
|
8
|
+
bs.proposeSize(4);
|
|
9
|
+
store<u32>(bs.offset, 8192123);
|
|
9
10
|
bs.offset += 4;
|
|
10
11
|
return;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
bs.
|
|
14
|
+
|
|
15
|
+
bs.proposeSize(load<u32>(changetype<usize>(data), offsetof<JSON.Obj>("stackSize")) - 2);
|
|
15
16
|
const keys = data.keys();
|
|
16
17
|
const values = data.values();
|
|
17
18
|
|
|
@@ -25,7 +26,7 @@ export function serializeObject(data: JSON.Obj): void {
|
|
|
25
26
|
const keySize = bytes(firstKey);
|
|
26
27
|
store<u16>(bs.offset, QUOTE);
|
|
27
28
|
memory.copy(bs.offset + 2, changetype<usize>(firstKey), keySize);
|
|
28
|
-
store<u32>(bs.offset += keySize + 2, 3801122); // ":
|
|
29
|
+
store<u32>((bs.offset += keySize + 2), 3801122); // ":
|
|
29
30
|
bs.offset += 4;
|
|
30
31
|
JSON.__serialize(unchecked(values[0]));
|
|
31
32
|
|
|
@@ -34,11 +35,11 @@ export function serializeObject(data: JSON.Obj): void {
|
|
|
34
35
|
const keySize = bytes(key);
|
|
35
36
|
store<u32>(bs.offset, 2228268); // ,"
|
|
36
37
|
memory.copy(bs.offset + 4, changetype<usize>(key), keySize);
|
|
37
|
-
store<u32>(bs.offset += keySize + 4, 3801122); // ":
|
|
38
|
+
store<u32>((bs.offset += keySize + 4), 3801122); // ":
|
|
38
39
|
bs.offset += 4;
|
|
39
40
|
JSON.__serialize(unchecked(values[i]));
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
store<u16>(bs.offset, BRACE_RIGHT);
|
|
43
44
|
bs.offset += 2;
|
|
44
|
-
}
|
|
45
|
+
}
|
package/assembly/test.ts
CHANGED
|
@@ -5,9 +5,10 @@ import { bytes } from "./util";
|
|
|
5
5
|
class Obj {
|
|
6
6
|
public a: string = "hello";
|
|
7
7
|
public b: string = "world";
|
|
8
|
-
public c: string = "\
|
|
8
|
+
public c: string = '"\t\f\u0000\u0001';
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
@json
|
|
12
13
|
class Vec3 {
|
|
13
14
|
x: f32 = 0.0;
|
|
@@ -15,8 +16,10 @@ class Vec3 {
|
|
|
15
16
|
z: f32 = 0.0;
|
|
16
17
|
}
|
|
17
18
|
|
|
19
|
+
|
|
18
20
|
@json
|
|
19
21
|
class Player {
|
|
22
|
+
|
|
20
23
|
@alias("first name")
|
|
21
24
|
firstName!: string;
|
|
22
25
|
lastName!: string;
|
|
@@ -24,11 +27,13 @@ class Player {
|
|
|
24
27
|
// Drop in a code block, function, or expression that evaluates to a boolean
|
|
25
28
|
@omitif((self: Player) => self.age < 18)
|
|
26
29
|
age!: i32;
|
|
30
|
+
|
|
27
31
|
@omitnull()
|
|
28
32
|
pos!: Vec3 | null;
|
|
29
33
|
isVerified!: boolean;
|
|
30
34
|
}
|
|
31
35
|
|
|
36
|
+
|
|
32
37
|
@json
|
|
33
38
|
class Point {
|
|
34
39
|
x: f64 = 0.0;
|
|
@@ -37,10 +42,12 @@ class Point {
|
|
|
37
42
|
this.x = x;
|
|
38
43
|
this.y = y;
|
|
39
44
|
}
|
|
45
|
+
|
|
40
46
|
@serializer
|
|
41
47
|
serializer(self: Point): string {
|
|
42
48
|
return `(${self.x},${self.y})`;
|
|
43
49
|
}
|
|
50
|
+
|
|
44
51
|
@deserializer
|
|
45
52
|
deserializer(data: string): Point | null {
|
|
46
53
|
const dataSize = bytes(data);
|
|
@@ -50,18 +57,17 @@ class Point {
|
|
|
50
57
|
const x = data.slice(1, c);
|
|
51
58
|
const y = data.slice(c + 1, data.length - 1);
|
|
52
59
|
|
|
53
|
-
return new Point(
|
|
54
|
-
f64.parse(x),
|
|
55
|
-
f64.parse(y)
|
|
56
|
-
);
|
|
60
|
+
return new Point(f64.parse(x), f64.parse(y));
|
|
57
61
|
}
|
|
58
62
|
}
|
|
59
63
|
|
|
64
|
+
|
|
60
65
|
@json
|
|
61
66
|
class InnerObj<T> {
|
|
62
|
-
obj: T = instantiate<T>()
|
|
67
|
+
obj: T = instantiate<T>();
|
|
63
68
|
}
|
|
64
69
|
|
|
70
|
+
|
|
65
71
|
@json
|
|
66
72
|
class ObjWithBracketString {
|
|
67
73
|
data: string = "";
|
|
@@ -75,9 +81,9 @@ const player: Player = {
|
|
|
75
81
|
pos: {
|
|
76
82
|
x: 3.4,
|
|
77
83
|
y: 1.2,
|
|
78
|
-
z: 8.3
|
|
84
|
+
z: 8.3,
|
|
79
85
|
},
|
|
80
|
-
isVerified: true
|
|
86
|
+
isVerified: true,
|
|
81
87
|
};
|
|
82
88
|
|
|
83
89
|
const a1 = JSON.stringify("\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u000f\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f");
|
|
@@ -98,7 +104,7 @@ const a4 = new JSON.Obj();
|
|
|
98
104
|
a4.set("x", 1.5);
|
|
99
105
|
a4.set("y", 5.4);
|
|
100
106
|
a4.set("z", 9.8);
|
|
101
|
-
a4.set("obj", obj)
|
|
107
|
+
a4.set("obj", obj);
|
|
102
108
|
a4.set<boolean>("bool", false);
|
|
103
109
|
|
|
104
110
|
console.log("a4: " + JSON.stringify(a4));
|
|
@@ -115,37 +121,30 @@ const a7 = JSON.parse<JSON.Value[]>('["string",true,3.14,{"x":1.0,"y":2.0,"z":3.
|
|
|
115
121
|
|
|
116
122
|
console.log("a7: " + JSON.stringify(a7));
|
|
117
123
|
|
|
118
|
-
const a8 = JSON.stringify(["hello", JSON.stringify("world"),"working?"]);
|
|
124
|
+
const a8 = JSON.stringify(["hello", JSON.stringify("world"), "working?"]);
|
|
119
125
|
|
|
120
126
|
console.log("a8: " + a8);
|
|
121
127
|
|
|
122
|
-
const a9 = JSON.stringify<JSON.Raw>(JSON.Raw.from("
|
|
128
|
+
const a9 = JSON.stringify<JSON.Raw>(JSON.Raw.from('"hello world"'));
|
|
123
129
|
|
|
124
130
|
console.log("a9: " + a9);
|
|
125
131
|
|
|
126
132
|
const m10 = new Map<string, JSON.Raw>();
|
|
127
|
-
m10.set("hello", new JSON.Raw("
|
|
128
|
-
m10.set("pos", new JSON.Raw(
|
|
133
|
+
m10.set("hello", new JSON.Raw('"world"'));
|
|
134
|
+
m10.set("pos", new JSON.Raw('{"x":1.0,"y":2.0,"z":3.0}'));
|
|
129
135
|
|
|
130
136
|
const a10 = JSON.stringify(m10);
|
|
131
137
|
|
|
132
138
|
console.log("a10: " + a10);
|
|
133
139
|
|
|
134
|
-
const a11 = JSON.parse<
|
|
140
|
+
const a11 = JSON.parse<JSON.Obj>(' { "x" : 3.4 , "y" : 1.2 , "z" : 8.3 } ');
|
|
135
141
|
|
|
136
142
|
console.log("a11: " + JSON.stringify(a11));
|
|
137
143
|
|
|
138
144
|
const a12 = JSON.parse<InnerObj<ObjWithBracketString>>('{"obj":{"data":"hello} world"}}');
|
|
139
145
|
|
|
140
|
-
console.log("a12: " + JSON.stringify(a12))
|
|
141
|
-
|
|
146
|
+
console.log("a12: " + JSON.stringify(a12));
|
|
142
147
|
|
|
143
|
-
|
|
144
|
-
class NullableObj {
|
|
145
|
-
bar: Bar | null = null;
|
|
146
|
-
}
|
|
148
|
+
const a13 = JSON.stringify<JSON.Obj>(new JSON.Obj());
|
|
147
149
|
|
|
148
|
-
|
|
149
|
-
class Bar {
|
|
150
|
-
value: string = "";
|
|
151
|
-
}
|
|
150
|
+
console.log("a13: " + a13);
|
package/bench.js
CHANGED
|
@@ -34,9 +34,7 @@ const vec = {
|
|
|
34
34
|
let data;
|
|
35
35
|
|
|
36
36
|
const bench = new Bench({ time: 1000 })
|
|
37
|
-
.add("serialize vec3", () =>
|
|
38
|
-
data = JSON.stringify(vec)
|
|
39
|
-
)
|
|
37
|
+
.add("serialize vec3", () => (data = JSON.stringify(vec)))
|
|
40
38
|
.add("deserialize vec3", () => {
|
|
41
39
|
data = JSON.parse('{"x":3,"y":1,"z":8}');
|
|
42
40
|
})
|
|
@@ -44,7 +42,7 @@ const bench = new Bench({ time: 1000 })
|
|
|
44
42
|
data = JSON.stringify("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~`!@#$%^&*()-_=+{[}]|\\:;\"'?/>.<,'\"}");
|
|
45
43
|
})
|
|
46
44
|
.add("deserialize alphabet string", () => {
|
|
47
|
-
data = JSON.parse('"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~`!@#$%^&*()-_=+{[}]|\\\\:;\\"\'?/>.<,\'\\"}"')
|
|
45
|
+
data = JSON.parse('"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~`!@#$%^&*()-_=+{[}]|\\\\:;\\"\'?/>.<,\'\\"}"');
|
|
48
46
|
}) /*
|
|
49
47
|
.add("parse float", () => {
|
|
50
48
|
data = JSON.parse("1.2345")
|
package/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { JSON } from "./assembly/index";
|
|
1
|
+
export { JSON } from "./assembly/index";
|
package/lib/as-bs.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
|
|
|
5
5
|
*/
|
|
6
6
|
export namespace bs {
|
|
7
7
|
/** Current buffer pointer. */ // @ts-ignore
|
|
8
|
-
export let buffer: ArrayBuffer = new ArrayBuffer(32)
|
|
8
|
+
export let buffer: ArrayBuffer = new ArrayBuffer(32); //__new(32, idof<ArrayBuffer>());
|
|
9
9
|
|
|
10
10
|
/** Current offset within the buffer. */
|
|
11
11
|
export let offset: usize = changetype<usize>(buffer);
|
|
@@ -28,10 +28,7 @@ export namespace bs {
|
|
|
28
28
|
const deltaBytes = nextPowerOf2(size + 64);
|
|
29
29
|
bufferSize += deltaBytes;
|
|
30
30
|
// @ts-ignore: exists
|
|
31
|
-
const newPtr = changetype<ArrayBuffer>(__renew(
|
|
32
|
-
changetype<usize>(buffer),
|
|
33
|
-
bufferSize
|
|
34
|
-
));
|
|
31
|
+
const newPtr = changetype<ArrayBuffer>(__renew(changetype<usize>(buffer), bufferSize));
|
|
35
32
|
offset = offset + changetype<usize>(newPtr) - changetype<usize>(buffer);
|
|
36
33
|
buffer = newPtr;
|
|
37
34
|
}
|
|
@@ -49,10 +46,7 @@ export namespace bs {
|
|
|
49
46
|
const deltaBytes = nextPowerOf2(size);
|
|
50
47
|
bufferSize += deltaBytes;
|
|
51
48
|
// @ts-ignore: exists
|
|
52
|
-
const newPtr = changetype<ArrayBuffer>(__renew(
|
|
53
|
-
changetype<usize>(buffer),
|
|
54
|
-
bufferSize
|
|
55
|
-
));
|
|
49
|
+
const newPtr = changetype<ArrayBuffer>(__renew(changetype<usize>(buffer), bufferSize));
|
|
56
50
|
offset = offset + changetype<usize>(newPtr) - changetype<usize>(buffer);
|
|
57
51
|
buffer = newPtr;
|
|
58
52
|
}
|
|
@@ -70,10 +64,7 @@ export namespace bs {
|
|
|
70
64
|
const deltaBytes = nextPowerOf2(size + 64);
|
|
71
65
|
bufferSize += deltaBytes;
|
|
72
66
|
// @ts-ignore
|
|
73
|
-
const newPtr = changetype<ArrayBuffer>(__renew(
|
|
74
|
-
changetype<usize>(buffer),
|
|
75
|
-
bufferSize
|
|
76
|
-
));
|
|
67
|
+
const newPtr = changetype<ArrayBuffer>(__renew(changetype<usize>(buffer), bufferSize));
|
|
77
68
|
// if (buffer != newPtr) console.log(" Old: " + changetype<usize>(buffer).toString() + "\n New: " + changetype<usize>(newPtr).toString());
|
|
78
69
|
offset = offset + changetype<usize>(newPtr) - changetype<usize>(buffer);
|
|
79
70
|
buffer = newPtr;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-as",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"author": "Jairus Tanaka",
|
|
5
5
|
"description": "The only JSON library you'll need for AssemblyScript. SIMD enabled",
|
|
6
6
|
"types": "assembly/index.ts",
|
|
@@ -44,7 +44,9 @@
|
|
|
44
44
|
"lekiano",
|
|
45
45
|
"Florian Guitton",
|
|
46
46
|
"Matt Johnson-Pint",
|
|
47
|
-
"Tomáš Hromada"
|
|
47
|
+
"Tomáš Hromada",
|
|
48
|
+
"Loredana Cirstea",
|
|
49
|
+
"Accipiter Nisus"
|
|
48
50
|
],
|
|
49
51
|
"keywords": [
|
|
50
52
|
"assemblyscript",
|
|
@@ -65,4 +67,4 @@
|
|
|
65
67
|
"@JairusSW:registry": "https://npm.pkg.github.com"
|
|
66
68
|
},
|
|
67
69
|
"type": "module"
|
|
68
|
-
}
|
|
70
|
+
}
|
package/run-tests.sh
CHANGED
|
@@ -7,7 +7,7 @@ for file in ./assembly/__tests__/*.spec.ts; do
|
|
|
7
7
|
output="./build/${filename%.ts}.wasm"
|
|
8
8
|
|
|
9
9
|
start_time=$(date +%s%3N)
|
|
10
|
-
npx asc "$file" --transform ./transform -o "$output" || { echo "Tests failed"; exit 1; }
|
|
10
|
+
npx asc "$file" --transform ./transform -o "$output" --enable simd || { echo "Tests failed"; exit 1; }
|
|
11
11
|
end_time=$(date +%s%3N)
|
|
12
12
|
|
|
13
13
|
build_time=$((end_time - start_time))
|
package/transform/lib/index.js
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import { Node } from "assemblyscript/dist/assemblyscript.js";
|
|
2
2
|
import { Transform } from "assemblyscript/dist/transform.js";
|
|
3
3
|
import { Visitor } from "./visitor.js";
|
|
4
|
-
import { SimpleParser, toString } from "./util.js";
|
|
4
|
+
import { isStdlib, SimpleParser, toString } from "./util.js";
|
|
5
5
|
import * as path from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
import { Property, PropertyFlags, Schema } from "./types.js";
|
|
8
8
|
import { getClasses, getImportedClass } from "./linker.js";
|
|
9
9
|
let indent = " ";
|
|
10
10
|
class JSONTransform extends Visitor {
|
|
11
|
+
program;
|
|
12
|
+
baseDir;
|
|
11
13
|
parser;
|
|
12
14
|
schemas = [];
|
|
13
15
|
schema;
|
|
14
16
|
sources = new Set();
|
|
15
17
|
imports = [];
|
|
16
18
|
topStatements = [];
|
|
19
|
+
simdStatements = [];
|
|
17
20
|
visitClassDeclaration(node) {
|
|
18
21
|
if (!node.decorators?.length)
|
|
19
22
|
return;
|
|
@@ -29,8 +32,8 @@ class JSONTransform extends Visitor {
|
|
|
29
32
|
if (process.env["JSON_DEBUG"])
|
|
30
33
|
console.log("Created schema: " + this.schema.name + " in file " + node.range.source.normalizedPath);
|
|
31
34
|
const members = [...node.members.filter((v) => v.kind === 54 && v.flags !== 32 && v.flags !== 512 && v.flags !== 1024 && !v.decorators?.some((decorator) => decorator.name.text === "omit"))];
|
|
32
|
-
const serializers = [...
|
|
33
|
-
const deserializers = [...
|
|
35
|
+
const serializers = [...node.members.filter((v) => v.kind === 58 && v.decorators && v.decorators.some((e) => e.name.text.toLowerCase() === "serializer"))];
|
|
36
|
+
const deserializers = [...node.members.filter((v) => v.kind === 58 && v.decorators && v.decorators.some((e) => e.name.text.toLowerCase() === "deserializer"))];
|
|
34
37
|
if (serializers.length > 1)
|
|
35
38
|
throwError("Multiple serializers detected for class " + node.name.text + " but schemas can only have one serializer!", serializers[1].range);
|
|
36
39
|
if (deserializers.length > 1)
|
|
@@ -51,7 +54,7 @@ class JSONTransform extends Visitor {
|
|
|
51
54
|
let SERIALIZER = "";
|
|
52
55
|
SERIALIZER += " __SERIALIZE_CUSTOM(ptr: usize): void {\n";
|
|
53
56
|
SERIALIZER += " const data = this." + serializer.name.text + "(changetype<" + this.schema.name + ">(ptr));\n";
|
|
54
|
-
SERIALIZER +=
|
|
57
|
+
SERIALIZER += ' if (isNullable(data) && changetype<usize>(data) == <usize>0) throw new Error("Could not serialize data using custom serializer!");\n';
|
|
55
58
|
SERIALIZER += " const dataSize = data.length << 1;\n";
|
|
56
59
|
SERIALIZER += " memory.copy(bs.offset, changetype<usize>(data), dataSize);\n";
|
|
57
60
|
SERIALIZER += " bs.offset += dataSize;\n";
|
|
@@ -78,7 +81,7 @@ class JSONTransform extends Visitor {
|
|
|
78
81
|
let DESERIALIZER = "";
|
|
79
82
|
DESERIALIZER += " __DESERIALIZE_CUSTOM(data: string): " + this.schema.name + " {\n";
|
|
80
83
|
DESERIALIZER += " const d = this." + deserializer.name.text + "(data)";
|
|
81
|
-
DESERIALIZER +=
|
|
84
|
+
DESERIALIZER += ' if (isNullable(d) && changetype<usize>(d) == <usize>0) throw new Error("Could not deserialize data using custom deserializer!");\n';
|
|
82
85
|
DESERIALIZER += " return d;\n";
|
|
83
86
|
DESERIALIZER += " }\n";
|
|
84
87
|
if (process.env["JSON_DEBUG"])
|
|
@@ -217,12 +220,13 @@ class JSONTransform extends Visitor {
|
|
|
217
220
|
else if (member.type == "string" || member.type == "String") {
|
|
218
221
|
INITIALIZE += ` this.${member.name} = "";\n`;
|
|
219
222
|
}
|
|
223
|
+
const SIMD_ENABLED = this.program.options.hasFeature(16);
|
|
220
224
|
if (!isRegular && !member.flags.has(PropertyFlags.OmitIf) && !member.flags.has(PropertyFlags.OmitNull))
|
|
221
225
|
isRegular = true;
|
|
222
226
|
if (isRegular && isPure) {
|
|
223
227
|
const keyPart = (isFirst ? "{" : ",") + aliasName + ":";
|
|
224
228
|
this.schema.byteSize += keyPart.length << 1;
|
|
225
|
-
SERIALIZE += this.getStores(keyPart)
|
|
229
|
+
SERIALIZE += this.getStores(keyPart, SIMD_ENABLED)
|
|
226
230
|
.map((v) => indent + v + "\n")
|
|
227
231
|
.join("");
|
|
228
232
|
SERIALIZE += indent + `JSON.__serialize<${member.type}>(load<${member.type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
@@ -232,7 +236,7 @@ class JSONTransform extends Visitor {
|
|
|
232
236
|
else if (isRegular && !isPure) {
|
|
233
237
|
const keyPart = (isFirst ? "" : ",") + aliasName + ":";
|
|
234
238
|
this.schema.byteSize += keyPart.length << 1;
|
|
235
|
-
SERIALIZE += this.getStores(keyPart)
|
|
239
|
+
SERIALIZE += this.getStores(keyPart, SIMD_ENABLED)
|
|
236
240
|
.map((v) => indent + v + "\n")
|
|
237
241
|
.join("");
|
|
238
242
|
SERIALIZE += indent + `JSON.__serialize<${member.type}>(load<${member.type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
@@ -245,7 +249,7 @@ class JSONTransform extends Visitor {
|
|
|
245
249
|
indentInc();
|
|
246
250
|
const keyPart = aliasName + ":";
|
|
247
251
|
this.schema.byteSize += keyPart.length << 1;
|
|
248
|
-
SERIALIZE += this.getStores(keyPart)
|
|
252
|
+
SERIALIZE += this.getStores(keyPart, SIMD_ENABLED)
|
|
249
253
|
.map((v) => indent + v + "\n")
|
|
250
254
|
.join("");
|
|
251
255
|
SERIALIZE += indent + `JSON.__serialize<${member.type}>(load<${member.type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
@@ -269,7 +273,7 @@ class JSONTransform extends Visitor {
|
|
|
269
273
|
SERIALIZE += indent + `if (${toString(member.flags.get(PropertyFlags.OmitIf))}) {\n`;
|
|
270
274
|
}
|
|
271
275
|
indentInc();
|
|
272
|
-
SERIALIZE += this.getStores(aliasName + ":")
|
|
276
|
+
SERIALIZE += this.getStores(aliasName + ":", SIMD_ENABLED)
|
|
273
277
|
.map((v) => indent + v + "\n")
|
|
274
278
|
.join("");
|
|
275
279
|
SERIALIZE += indent + `JSON.__serialize<${member.type}>(load<${member.type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
@@ -317,7 +321,9 @@ class JSONTransform extends Visitor {
|
|
|
317
321
|
for (let i = 0; i < memberGroup.length; i++) {
|
|
318
322
|
const member = memberGroup[i];
|
|
319
323
|
const memberName = member.alias || member.name;
|
|
320
|
-
const dst = this.schemas.find(v => v.name == member.type)
|
|
324
|
+
const dst = this.schemas.find(v => v.name == member.type)
|
|
325
|
+
? "load<usize>(ptr + offsetof<this>(\"" + member.name + "\"))"
|
|
326
|
+
: "0";
|
|
321
327
|
if (memberLen == 2) {
|
|
322
328
|
DESERIALIZE += `${indent} case ${memberName.charCodeAt(0)}: { // ${memberName}\n`;
|
|
323
329
|
DESERIALIZE += `${indent} store<${member.type}>(ptr, JSON.__deserialize<${member.type}>(valStart, valEnd, ${dst}), offsetof<this>(${JSON.stringify(member.name)}));\n`;
|
|
@@ -416,19 +422,17 @@ class JSONTransform extends Visitor {
|
|
|
416
422
|
}
|
|
417
423
|
addRequiredImports(node) {
|
|
418
424
|
const filePath = fileURLToPath(import.meta.url);
|
|
419
|
-
const baseDir = path.resolve(filePath,
|
|
420
|
-
const nodePath = path.resolve(
|
|
425
|
+
const baseDir = path.resolve(filePath, "..", "..", "..");
|
|
426
|
+
const nodePath = path.resolve(this.baseDir, node.range.source.normalizedPath);
|
|
421
427
|
const bsImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "bs" || d.name.text == "bs"));
|
|
422
428
|
const jsonImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "JSON" || d.name.text == "JSON"));
|
|
423
|
-
let bsPath = path.posix.join(...
|
|
424
|
-
let jsonPath = path.posix.join(...
|
|
429
|
+
let bsPath = path.posix.join(...path.relative(path.dirname(nodePath), path.join(baseDir, "lib", "as-bs")).split(path.sep)).replace(/^.*node_modules\/json-as/, "json-as");
|
|
430
|
+
let jsonPath = path.posix.join(...path.relative(path.dirname(nodePath), path.join(baseDir, "assembly", "index.ts")).split(path.sep)).replace(/^.*node_modules\/json-as/, "json-as");
|
|
425
431
|
if (!bsImport) {
|
|
426
432
|
if (node.normalizedPath.startsWith("~")) {
|
|
427
433
|
bsPath = "json-as/lib/as-bs";
|
|
428
434
|
}
|
|
429
|
-
const replaceNode = Node.createImportStatement([
|
|
430
|
-
Node.createImportDeclaration(Node.createIdentifierExpression("bs", node.range, false), null, node.range)
|
|
431
|
-
], Node.createStringLiteralExpression(bsPath, node.range), node.range);
|
|
435
|
+
const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("bs", node.range, false), null, node.range)], Node.createStringLiteralExpression(bsPath, node.range), node.range);
|
|
432
436
|
this.topStatements.push(replaceNode);
|
|
433
437
|
if (process.env["JSON_DEBUG"])
|
|
434
438
|
console.log("Added as-bs import: " + toString(replaceNode) + "\n");
|
|
@@ -437,9 +441,7 @@ class JSONTransform extends Visitor {
|
|
|
437
441
|
if (node.normalizedPath.startsWith("~")) {
|
|
438
442
|
jsonPath = "json-as/assembly/index.ts";
|
|
439
443
|
}
|
|
440
|
-
const replaceNode = Node.createImportStatement([
|
|
441
|
-
Node.createImportDeclaration(Node.createIdentifierExpression("JSON", node.range, false), null, node.range)
|
|
442
|
-
], Node.createStringLiteralExpression(jsonPath, node.range), node.range);
|
|
444
|
+
const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("JSON", node.range, false), null, node.range)], Node.createStringLiteralExpression(jsonPath, node.range), node.range);
|
|
443
445
|
this.topStatements.push(replaceNode);
|
|
444
446
|
if (process.env["JSON_DEBUG"])
|
|
445
447
|
console.log("Added json-as import: " + toString(replaceNode) + "\n");
|
|
@@ -450,6 +452,14 @@ class JSONTransform extends Visitor {
|
|
|
450
452
|
const sizes = strToNum(data, simd);
|
|
451
453
|
let offset = 0;
|
|
452
454
|
for (const [size, num] of sizes) {
|
|
455
|
+
if (size == "v128" && simd) {
|
|
456
|
+
let index = this.simdStatements.findIndex((v) => v.includes(num));
|
|
457
|
+
let name = "SIMD_" + (index == -1 ? this.simdStatements.length : index);
|
|
458
|
+
if (index && !this.simdStatements.includes(`const ${name} = ${num};`))
|
|
459
|
+
this.simdStatements.push(`const ${name} = ${num};`);
|
|
460
|
+
out.push("store<v128>(bs.offset, " + name + ", " + offset + "); // " + data.slice(offset >> 1, (offset >> 1) + 8));
|
|
461
|
+
offset += 16;
|
|
462
|
+
}
|
|
453
463
|
if (size == "u64") {
|
|
454
464
|
out.push("store<u64>(bs.offset, " + num + ", " + offset + "); // " + data.slice(offset >> 1, (offset >> 1) + 4));
|
|
455
465
|
offset += 8;
|
|
@@ -467,36 +477,8 @@ class JSONTransform extends Visitor {
|
|
|
467
477
|
return out;
|
|
468
478
|
}
|
|
469
479
|
isValidType(type, node) {
|
|
470
|
-
const validTypes = [
|
|
471
|
-
|
|
472
|
-
"u8",
|
|
473
|
-
"i8",
|
|
474
|
-
"u16",
|
|
475
|
-
"i16",
|
|
476
|
-
"u32",
|
|
477
|
-
"i32",
|
|
478
|
-
"u64",
|
|
479
|
-
"i64",
|
|
480
|
-
"f32",
|
|
481
|
-
"f64",
|
|
482
|
-
"bool",
|
|
483
|
-
"boolean",
|
|
484
|
-
"Date",
|
|
485
|
-
"JSON.Value",
|
|
486
|
-
"JSON.Obj",
|
|
487
|
-
"JSON.Raw",
|
|
488
|
-
"Value",
|
|
489
|
-
"Obj",
|
|
490
|
-
"Raw",
|
|
491
|
-
...this.schemas.map((v) => v.name)
|
|
492
|
-
];
|
|
493
|
-
const baseTypes = [
|
|
494
|
-
"Array",
|
|
495
|
-
"Map",
|
|
496
|
-
"Set",
|
|
497
|
-
"JSON.Box",
|
|
498
|
-
"Box"
|
|
499
|
-
];
|
|
480
|
+
const validTypes = ["string", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean", "Date", "JSON.Value", "JSON.Obj", "JSON.Raw", "Value", "Obj", "Raw", ...this.schemas.map((v) => v.name)];
|
|
481
|
+
const baseTypes = ["Array", "Map", "Set", "JSON.Box", "Box"];
|
|
500
482
|
if (node && node.isGeneric && node.typeParameters)
|
|
501
483
|
validTypes.push(...node.typeParameters.map((v) => v.name.text));
|
|
502
484
|
if (type.endsWith("| null")) {
|
|
@@ -514,19 +496,35 @@ class JSONTransform extends Visitor {
|
|
|
514
496
|
export default class Transformer extends Transform {
|
|
515
497
|
afterParse(parser) {
|
|
516
498
|
const transformer = new JSONTransform();
|
|
517
|
-
const sources = parser.sources
|
|
518
|
-
|
|
519
|
-
const
|
|
520
|
-
if (
|
|
499
|
+
const sources = parser.sources
|
|
500
|
+
.filter((source) => {
|
|
501
|
+
const p = source.internalPath;
|
|
502
|
+
if (p.startsWith("~lib/rt") || p.startsWith("~lib/performance") || p.startsWith("~lib/wasi_") || p.startsWith("~lib/shared/")) {
|
|
503
|
+
return false;
|
|
504
|
+
}
|
|
505
|
+
return !isStdlib(source);
|
|
506
|
+
})
|
|
507
|
+
.sort((a, b) => {
|
|
508
|
+
if (a.sourceKind >= 2 && b.sourceKind <= 1) {
|
|
521
509
|
return -1;
|
|
522
510
|
}
|
|
523
|
-
else if (a
|
|
511
|
+
else if (a.sourceKind <= 1 && b.sourceKind >= 2) {
|
|
512
|
+
return 1;
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
return 0;
|
|
516
|
+
}
|
|
517
|
+
})
|
|
518
|
+
.sort((a, b) => {
|
|
519
|
+
if (a.sourceKind === 1) {
|
|
524
520
|
return 1;
|
|
525
521
|
}
|
|
526
522
|
else {
|
|
527
523
|
return 0;
|
|
528
524
|
}
|
|
529
525
|
});
|
|
526
|
+
transformer.baseDir = path.join(process.cwd(), this.baseDir);
|
|
527
|
+
transformer.program = this.program;
|
|
530
528
|
transformer.parser = parser;
|
|
531
529
|
for (const source of sources) {
|
|
532
530
|
transformer.imports = [];
|
|
@@ -536,6 +534,11 @@ export default class Transformer extends Transform {
|
|
|
536
534
|
source.statements.unshift(...transformer.topStatements);
|
|
537
535
|
transformer.topStatements = [];
|
|
538
536
|
}
|
|
537
|
+
if (transformer.simdStatements.length) {
|
|
538
|
+
for (const simd of transformer.simdStatements)
|
|
539
|
+
source.statements.unshift(SimpleParser.parseTopLevelStatement(simd));
|
|
540
|
+
}
|
|
541
|
+
transformer.simdStatements = [];
|
|
539
542
|
}
|
|
540
543
|
const schemas = transformer.schemas;
|
|
541
544
|
for (const schema of schemas) {
|