json-as 1.1.10 → 1.1.12
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 +18 -1
- package/README.md +1 -1
- package/assembly/__tests__/generics.spec.ts +40 -0
- package/assembly/__tests__/types.spec.ts +26 -0
- package/package.json +2 -3
- package/transform/lib/index.js +132 -106
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/linkers/alias.js +49 -0
- package/transform/lib/linkers/alias.js.map +1 -0
- package/transform/lib/{linker.js → linkers/classes.js} +6 -20
- package/transform/lib/linkers/classes.js.map +1 -0
- package/transform/lib/linkers/custom.js +32 -0
- package/transform/lib/linkers/custom.js.map +1 -0
- package/transform/lib/linkers/imports.js +17 -0
- package/transform/lib/linkers/imports.js.map +1 -0
- package/transform/lib/types.js +13 -0
- package/transform/lib/types.js.map +1 -1
- package/transform/src/index.ts +199 -184
- package/transform/src/linkers/alias.ts +59 -0
- package/transform/src/{linker.ts → linkers/classes.ts} +13 -25
- package/transform/src/linkers/custom.ts +32 -0
- package/transform/src/linkers/imports.ts +22 -0
- package/transform/src/types.ts +15 -1
- package/transform/tsconfig.json +1 -1
- package/transform/lib/linker.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
## 2025-05-
|
|
3
|
+
## 2025-05-29 - 1.1.2
|
|
4
|
+
|
|
5
|
+
- fix: add helpful warning on unknown or unaccessible types in fields
|
|
6
|
+
- feat: support deserialization of class generics
|
|
7
|
+
- fix: add support for numerical generics
|
|
8
|
+
- tests: add proper testing for generics
|
|
9
|
+
- feat: support type aliases with a custom type resolver/linker
|
|
10
|
+
- chore: add other linkers to tsconfig and clean up
|
|
11
|
+
- feat: add type alias resolving
|
|
12
|
+
|
|
13
|
+
## 2025-05-28 - 1.1.11
|
|
14
|
+
|
|
15
|
+
- fix: class resolving should only search top level statements for class declarations
|
|
16
|
+
- fix: add helpful error if class is missing an @json decorator
|
|
17
|
+
- fix: properly calculate relative path when json-as is a library
|
|
18
|
+
- fix: add proper null check when resolving imported classes
|
|
19
|
+
|
|
20
|
+
## 2025-05-28 - 1.1.10
|
|
4
21
|
|
|
5
22
|
- feat: add more debug levels (1 = print transform code, 2 = print keys/values at runtime)
|
|
6
23
|
- feat: add write out feature (`JSON_WRITE=path-to-file.ts`) which writes out generated code
|
package/README.md
CHANGED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { JSON } from "..";
|
|
2
|
+
import { describe, expect } from "./lib";
|
|
3
|
+
|
|
4
|
+
@json
|
|
5
|
+
class GenericTest<T> {
|
|
6
|
+
public foo: T;
|
|
7
|
+
|
|
8
|
+
constructor(foo: T) {
|
|
9
|
+
this.foo = foo;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@json
|
|
14
|
+
class Vec3 {
|
|
15
|
+
public x!: i32;
|
|
16
|
+
public y!: i32;
|
|
17
|
+
public z!: i32;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe("Should serialize generics", () => {
|
|
21
|
+
expect(JSON.stringify(new GenericTest<string>("bar"))).toBe('{"foo":"bar"}');
|
|
22
|
+
expect(JSON.stringify(new GenericTest<i32>(42))).toBe('{"foo":42}');
|
|
23
|
+
expect(JSON.stringify(new GenericTest<boolean>(true))).toBe('{"foo":true}');
|
|
24
|
+
expect(JSON.stringify(new GenericTest<Vec3>({ x: 1, y: 2, z: 3 }))).toBe('{"foo":{"x":1,"y":2,"z":3}}');
|
|
25
|
+
expect(JSON.stringify(new GenericTest<string[]>(["item1", "item2"]))).toBe('{"foo":["item1","item2"]}');
|
|
26
|
+
expect(JSON.stringify(new GenericTest<Vec3[]>([{ x: 1, y: 2, z: 3 }, { x: 4, y: 5, z: 6 }]))).toBe('{"foo":[{"x":1,"y":2,"z":3},{"x":4,"y":5,"z":6}]}');
|
|
27
|
+
expect(JSON.stringify(new GenericTest<i32[]>([1, 2, 3]))).toBe('{"foo":[1,2,3]}');
|
|
28
|
+
expect(JSON.stringify(new GenericTest<boolean[]>([true, false, true]))).toBe('{"foo":[true,false,true]}');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("Should deserialize generics", () => {
|
|
32
|
+
expect(JSON.parse<GenericTest<string>>('{"foo":"bar"}').foo).toBe("bar");
|
|
33
|
+
expect(JSON.parse<GenericTest<i32>>('{"foo":42}').foo.toString()).toBe("42");
|
|
34
|
+
expect(JSON.parse<GenericTest<boolean>>('{"foo":true}').foo).toBe(true);
|
|
35
|
+
expect(JSON.stringify(JSON.parse<GenericTest<Vec3>>('{"foo":{"x":1,"y":2,"z":3}}'))).toBe('{"foo":{"x":1,"y":2,"z":3}}');
|
|
36
|
+
expect(JSON.stringify(JSON.parse<GenericTest<string[]>>('{"foo":["item1","item2"]}'))).toBe('{"foo":["item1","item2"]}');
|
|
37
|
+
expect(JSON.stringify(JSON.parse<GenericTest<Vec3[]>>('{"foo":[{"x":1,"y":2,"z":3},{"x":4,"y":5,"z":6}]}'))).toBe('{"foo":[{"x":1,"y":2,"z":3},{"x":4,"y":5,"z":6}]}');
|
|
38
|
+
expect(JSON.stringify(JSON.parse<GenericTest<i32[]>>('{"foo":[1,2,3]}'))).toBe('{"foo":[1,2,3]}');
|
|
39
|
+
expect(JSON.stringify(JSON.parse<GenericTest<boolean[]>>('{"foo":[true,false,true]}'))).toBe('{"foo":[true,false,true]}');
|
|
40
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { JSON } from "..";
|
|
2
|
+
import { describe, expect } from "./lib";
|
|
3
|
+
|
|
4
|
+
type StringAlias = string;
|
|
5
|
+
type StringAlias1 = StringAlias;
|
|
6
|
+
type StringAlias2 = StringAlias1;
|
|
7
|
+
type StringAlias3 = StringAlias2;
|
|
8
|
+
type StringAlias4 = StringAlias3;
|
|
9
|
+
|
|
10
|
+
@json
|
|
11
|
+
class Alias {
|
|
12
|
+
public foo: StringAlias4 = "";
|
|
13
|
+
constructor(foo: StringAlias2) {
|
|
14
|
+
this.foo = foo;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const alias = new Alias("bar");
|
|
19
|
+
|
|
20
|
+
describe("Should serialize with type aliases", () => {
|
|
21
|
+
expect(JSON.stringify(alias)).toBe('{"foo":"bar"}');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe("Should deserialize with type aliases", () => {
|
|
25
|
+
expect(JSON.stringify(JSON.parse<Alias>('{"foo":"bar"}'))).toBe('{"foo":"bar"}');
|
|
26
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-as",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.12",
|
|
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",
|
|
@@ -19,8 +19,7 @@
|
|
|
19
19
|
"test": "bash ./run-tests.sh",
|
|
20
20
|
"bench:as": "bash ./run-bench.as.sh",
|
|
21
21
|
"bench:js": "bash ./run-bench.js.sh",
|
|
22
|
-
"build:test": "rm -rf ./build/ && JSON_DEBUG=1 asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
|
|
23
|
-
"build:test:simd": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --optimizeLevel 3 --shrinkLevel 0 --enable simd --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
|
|
22
|
+
"build:test": "rm -rf ./build/ && JSON_DEBUG=1 JSON_WRITE=assembly/test.ts asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
|
|
24
23
|
"test:wasmtime": "wasmtime ./build/test.wasm",
|
|
25
24
|
"test:wasmer": "wasmer ./build/test.wasm",
|
|
26
25
|
"build:transform": "tsc -p ./transform",
|
package/transform/lib/index.js
CHANGED
|
@@ -4,9 +4,10 @@ import { Visitor } from "./visitor.js";
|
|
|
4
4
|
import { isStdlib, removeExtension, SimpleParser, toString } from "./util.js";
|
|
5
5
|
import * as path from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
|
-
import { Property, PropertyFlags, Schema } from "./types.js";
|
|
8
|
-
import { getClass, getImportedClass } from "./
|
|
7
|
+
import { Property, PropertyFlags, Schema, Src } from "./types.js";
|
|
8
|
+
import { getClass, getImportedClass } from "./linkers/classes.js";
|
|
9
9
|
import { existsSync, writeFileSync } from "fs";
|
|
10
|
+
import { CustomTransform } from "./linkers/custom.js";
|
|
10
11
|
let indent = " ";
|
|
11
12
|
let id = 0;
|
|
12
13
|
const WRITE = process.env["JSON_WRITE"];
|
|
@@ -19,35 +20,6 @@ const DEBUG = rawValue === "true"
|
|
|
19
20
|
? 0
|
|
20
21
|
: Number(rawValue);
|
|
21
22
|
const STRICT = process.env["JSON_STRICT"] && process.env["JSON_STRICT"] == "true";
|
|
22
|
-
class CustomTransform extends Visitor {
|
|
23
|
-
static SN = new CustomTransform();
|
|
24
|
-
modify = false;
|
|
25
|
-
visitCallExpression(node) {
|
|
26
|
-
super.visit(node.args, node);
|
|
27
|
-
if (node.expression.kind != 21 || node.expression.property.text != "stringify")
|
|
28
|
-
return;
|
|
29
|
-
if (node.expression.expression.kind != 6 || node.expression.expression.text != "JSON")
|
|
30
|
-
return;
|
|
31
|
-
if (this.modify) {
|
|
32
|
-
node.expression.expression = Node.createPropertyAccessExpression(Node.createIdentifierExpression("JSON", node.expression.range), Node.createIdentifierExpression("internal", node.expression.range), node.expression.range);
|
|
33
|
-
}
|
|
34
|
-
this.modify = true;
|
|
35
|
-
}
|
|
36
|
-
static visit(node, ref = null) {
|
|
37
|
-
if (!node)
|
|
38
|
-
return;
|
|
39
|
-
CustomTransform.SN.modify = true;
|
|
40
|
-
CustomTransform.SN.visit(node, ref);
|
|
41
|
-
CustomTransform.SN.modify = false;
|
|
42
|
-
}
|
|
43
|
-
static hasCall(node) {
|
|
44
|
-
if (!node)
|
|
45
|
-
return;
|
|
46
|
-
CustomTransform.SN.modify = false;
|
|
47
|
-
CustomTransform.SN.visit(node);
|
|
48
|
-
return CustomTransform.SN.modify;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
23
|
class JSONTransform extends Visitor {
|
|
52
24
|
static SN = new JSONTransform();
|
|
53
25
|
program;
|
|
@@ -55,11 +27,20 @@ class JSONTransform extends Visitor {
|
|
|
55
27
|
parser;
|
|
56
28
|
schemas = new Map();
|
|
57
29
|
schema;
|
|
58
|
-
|
|
30
|
+
src;
|
|
31
|
+
sources = new Map();
|
|
59
32
|
imports = [];
|
|
60
|
-
topStatements = [];
|
|
61
33
|
simdStatements = [];
|
|
62
34
|
visitedClasses = new Set();
|
|
35
|
+
visitClassDeclarationRef(node) {
|
|
36
|
+
if (!node.decorators?.length ||
|
|
37
|
+
!node.decorators.some((decorator) => {
|
|
38
|
+
const name = decorator.name.text;
|
|
39
|
+
return name === "json" || name === "serializable";
|
|
40
|
+
}))
|
|
41
|
+
throw new Error("Class " + node.name.text + " is missing an @json or @serializable decorator in " + node.range.source.internalPath);
|
|
42
|
+
this.visitClassDeclaration(node);
|
|
43
|
+
}
|
|
63
44
|
visitClassDeclaration(node) {
|
|
64
45
|
if (!node.decorators?.length)
|
|
65
46
|
return;
|
|
@@ -68,10 +49,17 @@ class JSONTransform extends Visitor {
|
|
|
68
49
|
return name === "json" || name === "serializable";
|
|
69
50
|
}))
|
|
70
51
|
return;
|
|
71
|
-
|
|
52
|
+
const source = node.range.source;
|
|
53
|
+
if (!this.sources.has(source.internalPath)) {
|
|
54
|
+
this.src = new Src(source);
|
|
55
|
+
this.sources.set(source.internalPath, this.src);
|
|
56
|
+
}
|
|
57
|
+
else
|
|
58
|
+
this.src = this.sources.get(source.internalPath);
|
|
59
|
+
if (this.visitedClasses.has(source.internalPath + node.name.text))
|
|
72
60
|
return;
|
|
73
|
-
if (!this.schemas.has(
|
|
74
|
-
this.schemas.set(
|
|
61
|
+
if (!this.schemas.has(source.internalPath))
|
|
62
|
+
this.schemas.set(source.internalPath, []);
|
|
75
63
|
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"))];
|
|
76
64
|
const serializers = [...node.members.filter((v) => v.kind === 58 && v.decorators && v.decorators.some((e) => e.name.text.toLowerCase() === "serializer"))];
|
|
77
65
|
const deserializers = [...node.members.filter((v) => v.kind === 58 && v.decorators && v.decorators.some((e) => e.name.text.toLowerCase() === "deserializer"))];
|
|
@@ -84,31 +72,44 @@ class JSONTransform extends Visitor {
|
|
|
84
72
|
const depSearch = schema.deps.find((v) => v.name == extendsName);
|
|
85
73
|
if (depSearch) {
|
|
86
74
|
if (DEBUG > 0)
|
|
87
|
-
console.log("Found " + extendsName + " in dependencies of " +
|
|
88
|
-
schema.deps.
|
|
75
|
+
console.log("Found " + extendsName + " in dependencies of " + source.internalPath);
|
|
76
|
+
if (!schema.deps.some(v => v.name == depSearch.name))
|
|
77
|
+
schema.deps.push(depSearch);
|
|
89
78
|
schema.parent = depSearch;
|
|
90
79
|
}
|
|
91
80
|
else {
|
|
92
|
-
const internalSearch = getClass(extendsName,
|
|
81
|
+
const internalSearch = getClass(extendsName, source);
|
|
93
82
|
if (internalSearch) {
|
|
94
83
|
if (DEBUG > 0)
|
|
95
|
-
console.log("Found " + extendsName + " internally from " +
|
|
96
|
-
this.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
84
|
+
console.log("Found " + extendsName + " internally from " + source.internalPath);
|
|
85
|
+
if (!this.visitedClasses.has(internalSearch.range.source.internalPath + internalSearch.name.text)) {
|
|
86
|
+
this.visitClassDeclarationRef(internalSearch);
|
|
87
|
+
this.schemas.get(internalSearch.range.source.internalPath).push(this.schema);
|
|
88
|
+
this.visitClassDeclaration(node);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const schem = this.schemas.get(internalSearch.range.source.internalPath)?.find(s => s.name == internalSearch.name.text);
|
|
92
|
+
if (!schem)
|
|
93
|
+
throw new Error("Could not find schema for " + internalSearch.name.text + " in " + internalSearch.range.source.internalPath);
|
|
94
|
+
schema.deps.push(schem);
|
|
95
|
+
schema.parent = schem;
|
|
101
96
|
}
|
|
102
97
|
else {
|
|
103
|
-
const externalSearch = getImportedClass(extendsName,
|
|
98
|
+
const externalSearch = getImportedClass(extendsName, source, this.parser);
|
|
104
99
|
if (externalSearch) {
|
|
105
100
|
if (DEBUG > 0)
|
|
106
|
-
console.log("Found " + externalSearch.name.text + " externally from " +
|
|
107
|
-
this.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
101
|
+
console.log("Found " + externalSearch.name.text + " externally from " + source.internalPath);
|
|
102
|
+
if (!this.visitedClasses.has(externalSearch.range.source.internalPath + externalSearch.name.text)) {
|
|
103
|
+
this.visitClassDeclarationRef(externalSearch);
|
|
104
|
+
this.schemas.get(externalSearch.range.source.internalPath).push(this.schema);
|
|
105
|
+
this.visitClassDeclaration(node);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const schem = this.schemas.get(externalSearch.range.source.internalPath)?.find(s => s.name == externalSearch.name.text);
|
|
109
|
+
if (!schem)
|
|
110
|
+
throw new Error("Could not find schema for " + externalSearch.name.text + " in " + externalSearch.range.source.internalPath);
|
|
111
|
+
schema.deps.push(schem);
|
|
112
|
+
schema.parent = schem;
|
|
112
113
|
}
|
|
113
114
|
}
|
|
114
115
|
}
|
|
@@ -124,6 +125,7 @@ class JSONTransform extends Visitor {
|
|
|
124
125
|
}
|
|
125
126
|
const getUnknownTypes = (type, types = []) => {
|
|
126
127
|
type = stripNull(type);
|
|
128
|
+
type = this.src.aliases.find(v => stripNull(v.name) == type)?.getBaseType() || type;
|
|
127
129
|
if (type.startsWith("Array<")) {
|
|
128
130
|
return getUnknownTypes(type.slice(6, -1));
|
|
129
131
|
}
|
|
@@ -153,42 +155,56 @@ class JSONTransform extends Visitor {
|
|
|
153
155
|
const depSearch = schema.deps.find((v) => v.name == unknownType);
|
|
154
156
|
if (depSearch) {
|
|
155
157
|
if (DEBUG > 0)
|
|
156
|
-
console.log("Found " + unknownType + " in dependencies of " +
|
|
157
|
-
schema.deps.
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
const internalSearch = getClass(unknownType, node.range.source);
|
|
161
|
-
if (internalSearch) {
|
|
162
|
-
if (DEBUG > 0)
|
|
163
|
-
console.log("Found " + unknownType + " internally from " + node.range.source.internalPath);
|
|
164
|
-
this.visitClassDeclaration(internalSearch);
|
|
165
|
-
this.schemas.get(node.range.source.internalPath).push(this.schema);
|
|
166
|
-
schema.deps.push(this.schema);
|
|
167
|
-
this.schema = schema;
|
|
158
|
+
console.log("Found " + unknownType + " in dependencies of " + source.internalPath);
|
|
159
|
+
if (!schema.deps.some(v => v.name == depSearch.name))
|
|
160
|
+
schema.deps.push(depSearch);
|
|
168
161
|
}
|
|
169
162
|
else {
|
|
170
|
-
const
|
|
171
|
-
if (
|
|
163
|
+
const internalSearch = getClass(unknownType, source);
|
|
164
|
+
if (internalSearch) {
|
|
172
165
|
if (DEBUG > 0)
|
|
173
|
-
console.log("Found " +
|
|
174
|
-
this.
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
166
|
+
console.log("Found " + unknownType + " internally from " + source.internalPath);
|
|
167
|
+
if (!this.visitedClasses.has(internalSearch.range.source.internalPath + internalSearch.name.text)) {
|
|
168
|
+
this.visitClassDeclarationRef(internalSearch);
|
|
169
|
+
this.schemas.get(internalSearch.range.source.internalPath).push(this.schema);
|
|
170
|
+
this.visitClassDeclaration(node);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const schem = this.schemas.get(internalSearch.range.source.internalPath)?.find(s => s.name == internalSearch.name.text);
|
|
174
|
+
if (!schem)
|
|
175
|
+
throw new Error("Could not find schema for " + internalSearch.name.text + " in " + internalSearch.range.source.internalPath);
|
|
176
|
+
schema.deps.push(schem);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
const externalSearch = getImportedClass(unknownType, source, this.parser);
|
|
180
|
+
if (externalSearch) {
|
|
181
|
+
if (DEBUG > 0)
|
|
182
|
+
console.log("Found " + externalSearch.name.text + " externally from " + source.internalPath);
|
|
183
|
+
if (!this.visitedClasses.has(externalSearch.range.source.internalPath + externalSearch.name.text)) {
|
|
184
|
+
this.visitClassDeclarationRef(externalSearch);
|
|
185
|
+
this.schemas.get(externalSearch.range.source.internalPath).push(this.schema);
|
|
186
|
+
this.visitClassDeclaration(node);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const schem = this.schemas.get(externalSearch.range.source.internalPath)?.find(s => s.name == externalSearch.name.text);
|
|
190
|
+
if (!schem)
|
|
191
|
+
throw new Error("Could not find schema for " + externalSearch.name.text + " in " + externalSearch.range.source.internalPath);
|
|
192
|
+
schema.deps.push(schem);
|
|
193
|
+
}
|
|
178
194
|
}
|
|
179
195
|
}
|
|
180
196
|
}
|
|
181
197
|
}
|
|
182
|
-
this.schemas.get(
|
|
198
|
+
this.schemas.get(source.internalPath).push(schema);
|
|
183
199
|
this.schema = schema;
|
|
184
|
-
this.visitedClasses.add(
|
|
200
|
+
this.visitedClasses.add(source.internalPath + node.name.text);
|
|
185
201
|
let SERIALIZE = "__SERIALIZE(ptr: usize): void {\n";
|
|
186
202
|
let INITIALIZE = "@inline __INITIALIZE(): this {\n";
|
|
187
203
|
let DESERIALIZE = "__DESERIALIZE<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): __JSON_T {\n";
|
|
188
204
|
let DESERIALIZE_CUSTOM = "";
|
|
189
205
|
let SERIALIZE_CUSTOM = "";
|
|
190
206
|
if (DEBUG > 0)
|
|
191
|
-
console.log("Created schema: " + this.schema.name + " in file " +
|
|
207
|
+
console.log("Created schema: " + this.schema.name + " in file " + source.normalizedPath + (this.schema.deps.length ? " with dependencies:\n " + this.schema.deps.map((v) => v.name).join("\n ") : ""));
|
|
192
208
|
if (serializers.length > 1)
|
|
193
209
|
throwError("Multiple serializers detected for class " + node.name.text + " but schemas can only have one serializer!", serializers[1].range);
|
|
194
210
|
if (deserializers.length > 1)
|
|
@@ -241,7 +257,8 @@ class JSONTransform extends Visitor {
|
|
|
241
257
|
for (const member of members) {
|
|
242
258
|
if (!member.type)
|
|
243
259
|
throwError("Fields must be strongly typed", node.range);
|
|
244
|
-
|
|
260
|
+
let type = toString(member.type);
|
|
261
|
+
type = this.src.aliases.find(v => stripNull(v.name) == stripNull(type))?.getBaseType() || type;
|
|
245
262
|
const name = member.name;
|
|
246
263
|
const value = member.initializer ? toString(member.initializer) : null;
|
|
247
264
|
if (type.startsWith("(") && type.includes("=>"))
|
|
@@ -396,21 +413,34 @@ class JSONTransform extends Visitor {
|
|
|
396
413
|
object: [],
|
|
397
414
|
};
|
|
398
415
|
for (const member of this.schema.members) {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
416
|
+
const type = stripNull(member.type);
|
|
417
|
+
if (node.isGeneric && node.typeParameters.some((p) => stripNull(p.name.text) == type)) {
|
|
418
|
+
member.generic = true;
|
|
402
419
|
sortedMembers.string.push(member);
|
|
403
|
-
else if (isBoolean(member.type) || member.type.startsWith("JSON.Box<bool"))
|
|
404
|
-
sortedMembers.boolean.push(member);
|
|
405
|
-
else if (isPrimitive(member.type) || member.type.startsWith("JSON.Box<"))
|
|
406
420
|
sortedMembers.number.push(member);
|
|
407
|
-
else if (isArray(member.type))
|
|
408
|
-
sortedMembers.array.push(member);
|
|
409
|
-
else
|
|
410
421
|
sortedMembers.object.push(member);
|
|
422
|
+
sortedMembers.array.push(member);
|
|
423
|
+
sortedMembers.boolean.push(member);
|
|
424
|
+
sortedMembers.null.push(member);
|
|
425
|
+
}
|
|
426
|
+
else {
|
|
427
|
+
if (member.node.type.isNullable)
|
|
428
|
+
sortedMembers.null.push(member);
|
|
429
|
+
if (isString(type) || type == "JSON.Raw")
|
|
430
|
+
sortedMembers.string.push(member);
|
|
431
|
+
else if (isBoolean(type) || type.startsWith("JSON.Box<bool"))
|
|
432
|
+
sortedMembers.boolean.push(member);
|
|
433
|
+
else if (isPrimitive(type) || type.startsWith("JSON.Box<"))
|
|
434
|
+
sortedMembers.number.push(member);
|
|
435
|
+
else if (isArray(type))
|
|
436
|
+
sortedMembers.array.push(member);
|
|
437
|
+
else if (isStruct(type, source))
|
|
438
|
+
sortedMembers.object.push(member);
|
|
439
|
+
else
|
|
440
|
+
throw new Error("Could not determine type " + type + " for member " + member.name + " in class " + this.schema.name);
|
|
441
|
+
}
|
|
411
442
|
}
|
|
412
443
|
indent = "";
|
|
413
|
-
let shouldGroup = false;
|
|
414
444
|
DESERIALIZE += indent + " let keyStart: usize = 0;\n";
|
|
415
445
|
DESERIALIZE += indent + " let keyEnd: usize = 0;\n";
|
|
416
446
|
DESERIALIZE += indent + " let isKey = false;\n";
|
|
@@ -539,7 +569,7 @@ class JSONTransform extends Visitor {
|
|
|
539
569
|
generateConsts(group);
|
|
540
570
|
const first = group[0];
|
|
541
571
|
const fName = first.alias || first.name;
|
|
542
|
-
DESERIALIZE += indent + " if (" + getComparision(fName) + ") { // " + fName + "\n";
|
|
572
|
+
DESERIALIZE += indent + " if (" + (first.generic ? "isString<" + first.type + ">() && " : "") + getComparision(fName) + ") { // " + fName + "\n";
|
|
543
573
|
DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), JSON.__deserialize<" + first.type + ">(lastIndex, srcStart + 2), offsetof<this>(" + JSON.stringify(first.name) + "));\n";
|
|
544
574
|
DESERIALIZE += indent + " srcStart += 4;\n";
|
|
545
575
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
@@ -548,7 +578,7 @@ class JSONTransform extends Visitor {
|
|
|
548
578
|
for (let i = 1; i < group.length; i++) {
|
|
549
579
|
const mem = group[i];
|
|
550
580
|
const memName = mem.alias || mem.name;
|
|
551
|
-
DESERIALIZE += indent + " else if (" + getComparision(memName) + ") { // " + memName + "\n";
|
|
581
|
+
DESERIALIZE += indent + " else if (" + (mem.generic ? "isString<" + mem.type + ">() && " : "") + getComparision(memName) + ") { // " + memName + "\n";
|
|
552
582
|
DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), JSON.__deserialize<" + mem.type + ">(lastIndex, srcStart + 2), offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
|
|
553
583
|
DESERIALIZE += indent + " srcStart += 4;\n";
|
|
554
584
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
@@ -587,7 +617,7 @@ class JSONTransform extends Visitor {
|
|
|
587
617
|
generateConsts(group);
|
|
588
618
|
const first = group[0];
|
|
589
619
|
const fName = first.alias || first.name;
|
|
590
|
-
DESERIALIZE += indent + " if (" + getComparision(fName) + ") { // " + fName + "\n";
|
|
620
|
+
DESERIALIZE += indent + " if (" + (first.generic ? "(isInteger<" + first.type + ">() || isFloat<" + first.type + ">()) && " : "") + getComparision(fName) + ") { // " + fName + "\n";
|
|
591
621
|
DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), JSON.__deserialize<" + first.type + ">(lastIndex, srcStart), offsetof<this>(" + JSON.stringify(first.name) + "));\n";
|
|
592
622
|
DESERIALIZE += indent + " srcStart += 2;\n";
|
|
593
623
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
@@ -596,7 +626,7 @@ class JSONTransform extends Visitor {
|
|
|
596
626
|
for (let i = 1; i < group.length; i++) {
|
|
597
627
|
const mem = group[i];
|
|
598
628
|
const memName = mem.alias || mem.name;
|
|
599
|
-
DESERIALIZE += indent + " else if (" + getComparision(memName) + ") { // " + memName + "\n";
|
|
629
|
+
DESERIALIZE += indent + " else if (" + (mem.generic ? "(isInteger<" + mem.type + ">() || isFloat<" + mem.type + ">()) && " : "") + getComparision(memName) + ") { // " + memName + "\n";
|
|
600
630
|
DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), JSON.__deserialize<" + mem.type + ">(lastIndex, srcStart), offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
|
|
601
631
|
DESERIALIZE += indent + " srcStart += 2;\n";
|
|
602
632
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
@@ -642,7 +672,7 @@ class JSONTransform extends Visitor {
|
|
|
642
672
|
generateConsts(group);
|
|
643
673
|
const first = group[0];
|
|
644
674
|
const fName = first.alias || first.name;
|
|
645
|
-
DESERIALIZE += indent + " if (" + getComparision(fName) + ") { // " + fName + "\n";
|
|
675
|
+
DESERIALIZE += indent + " if (" + (first.generic ? "isDefined(out.__DESERIALIZE) &&" : "") + getComparision(fName) + ") { // " + fName + "\n";
|
|
646
676
|
DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), JSON.__deserialize<" + first.type + ">(lastIndex, srcStart), offsetof<this>(" + JSON.stringify(first.name) + "));\n";
|
|
647
677
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
648
678
|
DESERIALIZE += indent + " break;\n";
|
|
@@ -650,7 +680,7 @@ class JSONTransform extends Visitor {
|
|
|
650
680
|
for (let i = 1; i < group.length; i++) {
|
|
651
681
|
const mem = group[i];
|
|
652
682
|
const memName = mem.alias || mem.name;
|
|
653
|
-
DESERIALIZE += indent + " else if (" + getComparision(memName) + ") { // " + memName + "\n";
|
|
683
|
+
DESERIALIZE += indent + " else if (" + (mem.generic ? "isDefined(out.__DESERIALIZE) &&" : "") + getComparision(memName) + ") { // " + memName + "\n";
|
|
654
684
|
DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), JSON.__deserialize<" + mem.type + ">(lastIndex, srcStart), offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
|
|
655
685
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
656
686
|
DESERIALIZE += indent + " break;\n";
|
|
@@ -696,7 +726,7 @@ class JSONTransform extends Visitor {
|
|
|
696
726
|
generateConsts(group);
|
|
697
727
|
const first = group[0];
|
|
698
728
|
const fName = first.alias || first.name;
|
|
699
|
-
DESERIALIZE += indent + " if (" + getComparision(fName) + ") { // " + fName + "\n";
|
|
729
|
+
DESERIALIZE += indent + " if (" + (first.generic ? "isArray<" + first.type + ">() && " : "") + getComparision(fName) + ") { // " + fName + "\n";
|
|
700
730
|
DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), JSON.__deserialize<" + first.type + ">(lastIndex, srcStart), offsetof<this>(" + JSON.stringify(first.name) + "));\n";
|
|
701
731
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
702
732
|
DESERIALIZE += indent + " break;\n";
|
|
@@ -704,7 +734,7 @@ class JSONTransform extends Visitor {
|
|
|
704
734
|
for (let i = 1; i < group.length; i++) {
|
|
705
735
|
const mem = group[i];
|
|
706
736
|
const memName = mem.alias || mem.name;
|
|
707
|
-
DESERIALIZE += indent + " else if (" + getComparision(memName) + ") { // " + memName + "\n";
|
|
737
|
+
DESERIALIZE += indent + " else if (" + (mem.generic ? "isArray" + mem.type + ">() && " : "") + getComparision(memName) + ") { // " + memName + "\n";
|
|
708
738
|
DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), JSON.__deserialize<" + mem.type + ">(lastIndex, srcStart), offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
|
|
709
739
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
710
740
|
DESERIALIZE += indent + " break;\n";
|
|
@@ -740,7 +770,7 @@ class JSONTransform extends Visitor {
|
|
|
740
770
|
generateConsts(group);
|
|
741
771
|
const first = group[0];
|
|
742
772
|
const fName = first.alias || first.name;
|
|
743
|
-
DESERIALIZE += indent + " if (" + getComparision(fName) + ") { // " + fName + "\n";
|
|
773
|
+
DESERIALIZE += indent + " if (" + (first.generic ? "isBoolean<" + first.type + ">() && " : "") + getComparision(fName) + ") { // " + fName + "\n";
|
|
744
774
|
DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), true, offsetof<this>(" + JSON.stringify(first.name) + "));\n";
|
|
745
775
|
DESERIALIZE += indent + " srcStart += 2;\n";
|
|
746
776
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
@@ -749,7 +779,7 @@ class JSONTransform extends Visitor {
|
|
|
749
779
|
for (let i = 1; i < group.length; i++) {
|
|
750
780
|
const mem = group[i];
|
|
751
781
|
const memName = mem.alias || mem.name;
|
|
752
|
-
DESERIALIZE += indent + " else if (" + getComparision(memName) + ") { // " + memName + "\n";
|
|
782
|
+
DESERIALIZE += indent + " else if (" + (mem.generic ? "isBoolean<" + mem.type + ">() && " : "") + getComparision(memName) + ") { // " + memName + "\n";
|
|
753
783
|
DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), true, offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
|
|
754
784
|
DESERIALIZE += indent + " srcStart += 2;\n";
|
|
755
785
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
@@ -784,7 +814,7 @@ class JSONTransform extends Visitor {
|
|
|
784
814
|
generateConsts(group);
|
|
785
815
|
const first = group[0];
|
|
786
816
|
const fName = first.alias || first.name;
|
|
787
|
-
DESERIALIZE += indent + " if (" + getComparision(fName) + ") { // " + fName + "\n";
|
|
817
|
+
DESERIALIZE += indent + " if (" + (first.generic ? "isBoolean<" + first.type + ">() && " : "") + getComparision(fName) + ") { // " + fName + "\n";
|
|
788
818
|
DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), false, offsetof<this>(" + JSON.stringify(first.name) + "));\n";
|
|
789
819
|
DESERIALIZE += indent + " srcStart += 2;\n";
|
|
790
820
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
@@ -793,7 +823,7 @@ class JSONTransform extends Visitor {
|
|
|
793
823
|
for (let i = 1; i < group.length; i++) {
|
|
794
824
|
const mem = group[i];
|
|
795
825
|
const memName = mem.alias || mem.name;
|
|
796
|
-
DESERIALIZE += indent + " else if (" + getComparision(memName) + ") { // " + memName + "\n";
|
|
826
|
+
DESERIALIZE += indent + " else if (" + (mem.generic ? "isBoolean<" + mem.type + ">() && " : "") + getComparision(memName) + ") { // " + memName + "\n";
|
|
797
827
|
DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), false, offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
|
|
798
828
|
DESERIALIZE += indent + " srcStart += 2;\n";
|
|
799
829
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
@@ -830,8 +860,8 @@ class JSONTransform extends Visitor {
|
|
|
830
860
|
generateConsts(group);
|
|
831
861
|
const first = group[0];
|
|
832
862
|
const fName = first.alias || first.name;
|
|
833
|
-
DESERIALIZE += indent + " if (" + getComparision(fName) + ") { // " + fName + "\n";
|
|
834
|
-
DESERIALIZE += indent + " store<
|
|
863
|
+
DESERIALIZE += indent + " if (" + (first.generic ? "isNullable<" + first.type + ">() && " : "") + getComparision(fName) + ") { // " + fName + "\n";
|
|
864
|
+
DESERIALIZE += indent + " store<usize>(changetype<usize>(out), 0, offsetof<this>(" + JSON.stringify(first.name) + "));\n";
|
|
835
865
|
DESERIALIZE += indent + " srcStart += 2;\n";
|
|
836
866
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
837
867
|
DESERIALIZE += indent + " break;\n";
|
|
@@ -839,8 +869,8 @@ class JSONTransform extends Visitor {
|
|
|
839
869
|
for (let i = 1; i < group.length; i++) {
|
|
840
870
|
const mem = group[i];
|
|
841
871
|
const memName = mem.alias || mem.name;
|
|
842
|
-
DESERIALIZE += indent + " else if (" + getComparision(memName) + ") { // " + memName + "\n";
|
|
843
|
-
DESERIALIZE += indent + " store<
|
|
872
|
+
DESERIALIZE += indent + " else if (" + (mem.generic ? "isNullable<" + mem.type + ">() && " : "") + getComparision(memName) + ") { // " + memName + "\n";
|
|
873
|
+
DESERIALIZE += indent + " store<usize>(changetype<usize>(out), 0, offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
|
|
844
874
|
DESERIALIZE += indent + " srcStart += 2;\n";
|
|
845
875
|
DESERIALIZE += indent + " keyStart = 0;\n";
|
|
846
876
|
DESERIALIZE += indent + " break;\n";
|
|
@@ -936,7 +966,7 @@ class JSONTransform extends Visitor {
|
|
|
936
966
|
? existsSync(path.join(pkgPath, fromPath.slice(5, fromPath.indexOf("/", 5))))
|
|
937
967
|
? path.join(pkgPath, fromPath.slice(5))
|
|
938
968
|
: fromPath
|
|
939
|
-
: path.join(
|
|
969
|
+
: path.join(this.baseCWD, fromPath);
|
|
940
970
|
const bsImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "bs" || d.name.text == "bs"));
|
|
941
971
|
const jsonImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "JSON" || d.name.text == "JSON"));
|
|
942
972
|
let bsRel = removeExtension(path.posix.join(...path
|
|
@@ -1063,10 +1093,6 @@ export default class Transformer extends Transform {
|
|
|
1063
1093
|
transformer.imports = [];
|
|
1064
1094
|
transformer.currentSource = source;
|
|
1065
1095
|
transformer.visit(source);
|
|
1066
|
-
if (transformer.topStatements.length) {
|
|
1067
|
-
source.statements.unshift(...transformer.topStatements);
|
|
1068
|
-
transformer.topStatements = [];
|
|
1069
|
-
}
|
|
1070
1096
|
if (transformer.simdStatements.length) {
|
|
1071
1097
|
for (const simd of transformer.simdStatements)
|
|
1072
1098
|
source.statements.unshift(SimpleParser.parseTopLevelStatement(simd));
|