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 CHANGED
@@ -1,6 +1,23 @@
1
1
  # Change Log
2
2
 
3
- ## 2025-05-27 - 1.1.10
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
@@ -6,7 +6,7 @@
6
6
  ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
7
7
  █████ ███████ ██████ ██ ████ ██ ██ ███████
8
8
  </span>
9
- AssemblyScript - v1.1.10
9
+ AssemblyScript - v1.1.12
10
10
  </pre>
11
11
  </h6>
12
12
 
@@ -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.10",
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",
@@ -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 "./linker.js";
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
- sources = new Set();
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
- if (this.visitedClasses.has(node.range.source.internalPath + node.name.text))
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(node.range.source.internalPath))
74
- this.schemas.set(node.range.source.internalPath, []);
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 " + node.range.source.internalPath);
88
- schema.deps.push(depSearch);
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, node.range.source);
81
+ const internalSearch = getClass(extendsName, source);
93
82
  if (internalSearch) {
94
83
  if (DEBUG > 0)
95
- console.log("Found " + extendsName + " internally from " + node.range.source.internalPath);
96
- this.visitClassDeclaration(internalSearch);
97
- schema.deps.push(this.schema);
98
- this.schemas.get(node.range.source.internalPath).push(this.schema);
99
- schema.parent = this.schema;
100
- this.schema = schema;
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, node.range.source, this.parser);
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 " + node.range.source.internalPath);
107
- this.visitClassDeclaration(externalSearch);
108
- schema.deps.push(this.schema);
109
- this.schemas.get(node.range.source.internalPath).push(this.schema);
110
- schema.parent = this.schema;
111
- this.schema = schema;
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 " + node.range.source.internalPath);
157
- schema.deps.push(depSearch);
158
- continue;
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 externalSearch = getImportedClass(unknownType, node.range.source, this.parser);
171
- if (externalSearch) {
163
+ const internalSearch = getClass(unknownType, source);
164
+ if (internalSearch) {
172
165
  if (DEBUG > 0)
173
- console.log("Found " + externalSearch.name.text + " externally from " + node.range.source.internalPath);
174
- this.visitClassDeclaration(externalSearch);
175
- this.schemas.get(node.range.source.internalPath).push(this.schema);
176
- schema.deps.push(this.schema);
177
- this.schema = schema;
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(node.range.source.internalPath).push(schema);
198
+ this.schemas.get(source.internalPath).push(schema);
183
199
  this.schema = schema;
184
- this.visitedClasses.add(node.range.source.internalPath + node.name.text);
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 " + node.range.source.normalizedPath + (this.schema.deps.length ? " with dependencies:\n " + this.schema.deps.map((v) => v.name).join("\n ") : ""));
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
- const type = toString(member.type);
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
- if (member.type.endsWith(" | null"))
400
- sortedMembers.null.push(member);
401
- if (isString(member.type) || member.type == "JSON.Raw")
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<" + first.type + ">(changetype<usize>(out), null, offsetof<this>(" + JSON.stringify(first.name) + "));\n";
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<" + mem.type + ">(changetype<usize>(out), null, offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
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(baseDir, fromPath);
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));