json-as 1.1.16 → 1.1.18
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 +8 -0
- package/README.md +1 -1
- package/assembly/__tests__/namespace.spec.ts +63 -0
- package/assembly/index.ts +1 -1
- package/assembly/test.tmp.ts +18 -23
- package/assembly/test.ts +0 -2
- package/package.json +5 -5
- package/run-bench.as.sh +1 -1
- package/run-tests.sh +17 -13
- package/transform/lib/index.js +47 -54
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/types.js +103 -2
- package/transform/lib/types.js.map +1 -1
- package/transform/src/index.ts +51 -54
- package/transform/src/types.ts +182 -4
- package/transform/src/linkers/classes.ts +0 -50
package/transform/src/index.ts
CHANGED
|
@@ -4,22 +4,20 @@ 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, Src } from "./types.js";
|
|
8
|
-
import {
|
|
9
|
-
import { existsSync, writeFileSync } from "fs";
|
|
7
|
+
import { Property, PropertyFlags, Schema, Src, SourceSet } from "./types.js";
|
|
8
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
10
9
|
import { CustomTransform } from "./linkers/custom.js";
|
|
11
10
|
|
|
12
11
|
let indent = " ";
|
|
13
12
|
|
|
14
13
|
let id = 0;
|
|
15
14
|
|
|
16
|
-
const WRITE = process.env["JSON_WRITE"];
|
|
17
|
-
const rawValue = process.env["JSON_DEBUG"];
|
|
15
|
+
const WRITE = process.env["JSON_WRITE"]?.trim();
|
|
16
|
+
const rawValue = process.env["JSON_DEBUG"]?.trim();
|
|
18
17
|
|
|
19
18
|
const DEBUG = rawValue === "true" ? 1 : rawValue === "false" || rawValue === "" ? 0 : isNaN(Number(rawValue)) ? 0 : Number(rawValue);
|
|
20
19
|
|
|
21
20
|
const STRICT = process.env["JSON_STRICT"] && process.env["JSON_STRICT"] == "true";
|
|
22
|
-
|
|
23
21
|
export class JSONTransform extends Visitor {
|
|
24
22
|
static SN: JSONTransform = new JSONTransform();
|
|
25
23
|
|
|
@@ -28,10 +26,8 @@ export class JSONTransform extends Visitor {
|
|
|
28
26
|
public parser!: Parser;
|
|
29
27
|
public schemas: Map<string, Schema[]> = new Map<string, Schema[]>();
|
|
30
28
|
public schema!: Schema;
|
|
31
|
-
public
|
|
32
|
-
public sources: Map<string, Src> = new Map<string, Src>();
|
|
29
|
+
public sources: SourceSet = new SourceSet();
|
|
33
30
|
public imports: ImportStatement[] = [];
|
|
34
|
-
|
|
35
31
|
public simdStatements: string[] = [];
|
|
36
32
|
|
|
37
33
|
private visitedClasses: Set<string> = new Set<string>();
|
|
@@ -47,6 +43,7 @@ export class JSONTransform extends Visitor {
|
|
|
47
43
|
throw new Error("Class " + node.name.text + " is missing an @json or @serializable decorator in " + node.range.source.internalPath);
|
|
48
44
|
this.visitClassDeclaration(node);
|
|
49
45
|
}
|
|
46
|
+
|
|
50
47
|
visitClassDeclaration(node: ClassDeclaration): void {
|
|
51
48
|
if (!node.decorators?.length) return;
|
|
52
49
|
|
|
@@ -58,13 +55,11 @@ export class JSONTransform extends Visitor {
|
|
|
58
55
|
)
|
|
59
56
|
return;
|
|
60
57
|
|
|
61
|
-
const source = node.range.source;
|
|
62
|
-
if (!this.sources.has(source.internalPath)) {
|
|
63
|
-
this.src = new Src(source);
|
|
64
|
-
this.sources.set(source.internalPath, this.src);
|
|
65
|
-
} else this.src = this.sources.get(source.internalPath);
|
|
58
|
+
const source = this.sources.get(node.range.source);
|
|
66
59
|
|
|
67
|
-
|
|
60
|
+
const fullClassPath = source.getFullPath(node);
|
|
61
|
+
|
|
62
|
+
if (this.visitedClasses.has(fullClassPath)) return;
|
|
68
63
|
if (!this.schemas.has(source.internalPath)) this.schemas.set(source.internalPath, []);
|
|
69
64
|
|
|
70
65
|
const members: FieldDeclaration[] = [...(node.members.filter((v) => v.kind === NodeKind.FieldDeclaration && v.flags !== CommonFlags.Static && v.flags !== CommonFlags.Private && v.flags !== CommonFlags.Protected && !v.decorators?.some((decorator) => (<IdentifierExpression>decorator.name).text === "omit")) as FieldDeclaration[])];
|
|
@@ -73,10 +68,11 @@ export class JSONTransform extends Visitor {
|
|
|
73
68
|
|
|
74
69
|
const schema = new Schema();
|
|
75
70
|
schema.node = node;
|
|
76
|
-
schema.name = node
|
|
71
|
+
schema.name = source.getQualifiedName(node);
|
|
77
72
|
|
|
78
73
|
if (node.extendsType) {
|
|
79
|
-
const extendsName = node
|
|
74
|
+
const extendsName = source.resolveExtendsName(node);
|
|
75
|
+
|
|
80
76
|
if (!schema.parent) {
|
|
81
77
|
const depSearch = schema.deps.find((v) => v.name == extendsName);
|
|
82
78
|
if (depSearch) {
|
|
@@ -84,31 +80,32 @@ export class JSONTransform extends Visitor {
|
|
|
84
80
|
if (!schema.deps.some((v) => v.name == depSearch.name)) schema.deps.push(depSearch);
|
|
85
81
|
schema.parent = depSearch;
|
|
86
82
|
} else {
|
|
87
|
-
const internalSearch = getClass(extendsName
|
|
83
|
+
const internalSearch = source.getClass(extendsName);
|
|
88
84
|
if (internalSearch) {
|
|
89
85
|
if (DEBUG > 0) console.log("Found " + extendsName + " internally from " + source.internalPath);
|
|
90
|
-
if (!this.visitedClasses.has(
|
|
86
|
+
if (!this.visitedClasses.has(source.getFullPath(internalSearch))) {
|
|
91
87
|
this.visitClassDeclarationRef(internalSearch);
|
|
92
88
|
this.schemas.get(internalSearch.range.source.internalPath).push(this.schema);
|
|
93
89
|
this.visitClassDeclaration(node);
|
|
94
90
|
return;
|
|
95
91
|
}
|
|
96
|
-
const schem = this.schemas.get(internalSearch.range.source.internalPath)?.find((s) => s.name ==
|
|
92
|
+
const schem = this.schemas.get(internalSearch.range.source.internalPath)?.find((s) => s.name == extendsName);
|
|
97
93
|
if (!schem) throw new Error("Could not find schema for " + internalSearch.name.text + " in " + internalSearch.range.source.internalPath);
|
|
98
94
|
schema.deps.push(schem);
|
|
99
95
|
schema.parent = schem;
|
|
100
96
|
} else {
|
|
101
|
-
const externalSearch = getImportedClass(extendsName,
|
|
97
|
+
const externalSearch = source.getImportedClass(extendsName, this.parser);
|
|
102
98
|
if (externalSearch) {
|
|
103
99
|
if (DEBUG > 0) console.log("Found " + externalSearch.name.text + " externally from " + source.internalPath);
|
|
104
|
-
|
|
100
|
+
const externalSource = this.sources.get(externalSearch.range.source);
|
|
101
|
+
if (!this.visitedClasses.has(externalSource.getFullPath(externalSearch))) {
|
|
105
102
|
this.visitClassDeclarationRef(externalSearch);
|
|
106
|
-
this.schemas.get(
|
|
103
|
+
this.schemas.get(externalSource.internalPath).push(this.schema);
|
|
107
104
|
this.visitClassDeclaration(node);
|
|
108
105
|
return;
|
|
109
106
|
}
|
|
110
|
-
const schem = this.schemas.get(
|
|
111
|
-
if (!schem) throw new Error("Could not find schema for " + externalSearch.name.text + " in " +
|
|
107
|
+
const schem = this.schemas.get(externalSource.internalPath)?.find((s) => s.name == extendsName);
|
|
108
|
+
if (!schem) throw new Error("Could not find schema for " + externalSearch.name.text + " in " + externalSource.internalPath);
|
|
112
109
|
schema.deps.push(schem);
|
|
113
110
|
schema.parent = schem;
|
|
114
111
|
}
|
|
@@ -127,7 +124,7 @@ export class JSONTransform extends Visitor {
|
|
|
127
124
|
|
|
128
125
|
const getUnknownTypes = (type: string, types: string[] = []): string[] => {
|
|
129
126
|
type = stripNull(type);
|
|
130
|
-
type =
|
|
127
|
+
type = source.aliases.find((v) => stripNull(v.name) == type)?.getBaseType() || type;
|
|
131
128
|
if (type.startsWith("Array<")) {
|
|
132
129
|
return getUnknownTypes(type.slice(6, -1));
|
|
133
130
|
} else if (type.startsWith("Map<")) {
|
|
@@ -158,35 +155,36 @@ export class JSONTransform extends Visitor {
|
|
|
158
155
|
schema.deps.push(depSearch);
|
|
159
156
|
}
|
|
160
157
|
} else {
|
|
161
|
-
const internalSearch = getClass(unknownType
|
|
158
|
+
const internalSearch = source.getClass(unknownType);
|
|
162
159
|
if (internalSearch) {
|
|
163
160
|
if (DEBUG > 0) console.log("Found " + unknownType + " internally from " + source.internalPath);
|
|
164
|
-
if (!this.visitedClasses.has(
|
|
161
|
+
if (!this.visitedClasses.has(source.getFullPath(internalSearch))) {
|
|
165
162
|
this.visitClassDeclarationRef(internalSearch);
|
|
166
|
-
const internalSchema = this.schemas.get(internalSearch.range.source.internalPath)?.find((s) => s.name ==
|
|
163
|
+
const internalSchema = this.schemas.get(internalSearch.range.source.internalPath)?.find((s) => s.name == unknownType);
|
|
167
164
|
// if (internalSchema.custom) mem.custom = true;
|
|
168
165
|
schema.deps.push(internalSchema);
|
|
169
166
|
this.schemas.get(internalSearch.range.source.internalPath).push(this.schema);
|
|
170
167
|
this.visitClassDeclaration(node);
|
|
171
168
|
return;
|
|
172
169
|
}
|
|
173
|
-
const schem = this.schemas.get(internalSearch.range.source.internalPath)?.find((s) => s.name ==
|
|
170
|
+
const schem = this.schemas.get(internalSearch.range.source.internalPath)?.find((s) => s.name == unknownType);
|
|
174
171
|
if (!schem) throw new Error("Could not find schema for " + internalSearch.name.text + " in " + internalSearch.range.source.internalPath);
|
|
175
172
|
schema.deps.push(schem);
|
|
176
173
|
} else {
|
|
177
|
-
const externalSearch = getImportedClass(unknownType,
|
|
174
|
+
const externalSearch = source.getImportedClass(unknownType, this.parser);
|
|
178
175
|
if (externalSearch) {
|
|
179
176
|
if (DEBUG > 0) console.log("Found " + externalSearch.name.text + " externally from " + source.internalPath);
|
|
180
|
-
|
|
177
|
+
const externalSource = this.sources.get(externalSearch.range.source);
|
|
178
|
+
if (!this.visitedClasses.has(externalSource.getFullPath(externalSearch))) {
|
|
181
179
|
this.visitClassDeclarationRef(externalSearch);
|
|
182
|
-
const externalSchema = this.schemas.get(
|
|
180
|
+
const externalSchema = this.schemas.get(externalSource.internalPath)?.find((s) => s.name == unknownType);
|
|
183
181
|
schema.deps.push(externalSchema);
|
|
184
|
-
this.schemas.get(
|
|
182
|
+
this.schemas.get(externalSource.internalPath).push(this.schema);
|
|
185
183
|
this.visitClassDeclaration(node);
|
|
186
184
|
return;
|
|
187
185
|
}
|
|
188
|
-
const schem = this.schemas.get(
|
|
189
|
-
if (!schem) throw new Error("Could not find schema for " + externalSearch.name.text + " in " +
|
|
186
|
+
const schem = this.schemas.get(externalSource.internalPath)?.find((s) => s.name == unknownType);
|
|
187
|
+
if (!schem) throw new Error("Could not find schema for " + externalSearch.name.text + " in " + externalSource.internalPath);
|
|
190
188
|
schema.deps.push(schem);
|
|
191
189
|
}
|
|
192
190
|
}
|
|
@@ -196,7 +194,7 @@ export class JSONTransform extends Visitor {
|
|
|
196
194
|
|
|
197
195
|
this.schemas.get(source.internalPath).push(schema);
|
|
198
196
|
this.schema = schema;
|
|
199
|
-
this.visitedClasses.add(
|
|
197
|
+
this.visitedClasses.add(fullClassPath);
|
|
200
198
|
|
|
201
199
|
let SERIALIZE = "__SERIALIZE(ptr: usize): void {\n";
|
|
202
200
|
let INITIALIZE = "@inline __INITIALIZE(): this {\n";
|
|
@@ -258,7 +256,7 @@ export class JSONTransform extends Visitor {
|
|
|
258
256
|
for (const member of members) {
|
|
259
257
|
if (!member.type) throwError("Fields must be strongly typed", node.range);
|
|
260
258
|
let type = toString(member.type!);
|
|
261
|
-
type =
|
|
259
|
+
type = source.aliases.find((v) => stripNull(v.name) == stripNull(type))?.getBaseType() || type;
|
|
262
260
|
|
|
263
261
|
const name = member.name;
|
|
264
262
|
const value = member.initializer ? toString(member.initializer!) : null;
|
|
@@ -335,8 +333,8 @@ export class JSONTransform extends Visitor {
|
|
|
335
333
|
const realName = member.name;
|
|
336
334
|
const isLast = i == this.schema.members.length - 1;
|
|
337
335
|
|
|
338
|
-
if (member.value
|
|
339
|
-
if (
|
|
336
|
+
if (member.value) {
|
|
337
|
+
if (member.value != "null" && member.value != "0" && member.value != "0.0" && member.value != "false") {
|
|
340
338
|
INITIALIZE += ` store<${member.type}>(changetype<usize>(this), ${member.value}, offsetof<this>(${JSON.stringify(member.name)}));\n`;
|
|
341
339
|
}
|
|
342
340
|
} else if (member.generic) {
|
|
@@ -1060,7 +1058,7 @@ export class JSONTransform extends Visitor {
|
|
|
1060
1058
|
generateEmptyMethods(node: ClassDeclaration): void {
|
|
1061
1059
|
let SERIALIZE_EMPTY = "@inline __SERIALIZE(ptr: usize): void {\n bs.proposeSize(4);\n store<u32>(bs.offset, 8192123);\n bs.offset += 4;\n}";
|
|
1062
1060
|
let INITIALIZE_EMPTY = "@inline __INITIALIZE(): this {\n return this;\n}";
|
|
1063
|
-
let DESERIALIZE_EMPTY = "@inline __DESERIALIZE<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): __JSON_T {\n return
|
|
1061
|
+
let DESERIALIZE_EMPTY = "@inline __DESERIALIZE<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): __JSON_T {\n return out;\n}";
|
|
1064
1062
|
|
|
1065
1063
|
if (DEBUG > 0) {
|
|
1066
1064
|
console.log(SERIALIZE_EMPTY);
|
|
@@ -1115,12 +1113,20 @@ export class JSONTransform extends Visitor {
|
|
|
1115
1113
|
this.baseCWD = this.baseCWD.replaceAll("/", path.sep);
|
|
1116
1114
|
|
|
1117
1115
|
const baseDir = path.resolve(fileURLToPath(import.meta.url), "..", "..", "..");
|
|
1118
|
-
const pkgPath = path.join(this.baseCWD, "node_modules");
|
|
1119
1116
|
let fromPath = node.range.source.normalizedPath.replaceAll("/", path.sep);
|
|
1120
1117
|
|
|
1118
|
+
const isLib = path.dirname(baseDir).endsWith("node_modules");
|
|
1119
|
+
|
|
1120
|
+
if (!isLib && !this.parser.sources.some((s) => s.normalizedPath.startsWith("assembly/index"))) {
|
|
1121
|
+
const newPath = "./assembly/index.ts";
|
|
1122
|
+
this.parser.parseFile(readFileSync(path.join(...newPath.split("/"))).toString(), newPath, false);
|
|
1123
|
+
} else if (isLib && !this.parser.sources.some((s) => s.normalizedPath.startsWith("~lib/json-as/assembly/index"))) {
|
|
1124
|
+
const newPath = "~lib/json-as/assembly/index.ts";
|
|
1125
|
+
this.parser.parseFile(readFileSync(path.join(...newPath.split("/"))).toString(), newPath, false);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1121
1128
|
// console.log("baseCWD", this.baseCWD);
|
|
1122
1129
|
// console.log("baseDir", baseDir);
|
|
1123
|
-
// console.log("pkgPath: ", pkgPath);
|
|
1124
1130
|
|
|
1125
1131
|
fromPath = fromPath.startsWith("~lib") ? fromPath.slice(5) : path.join(this.baseCWD, fromPath);
|
|
1126
1132
|
|
|
@@ -1131,8 +1137,8 @@ export class JSONTransform extends Visitor {
|
|
|
1131
1137
|
|
|
1132
1138
|
let baseRel = path.posix.join(...path.relative(path.dirname(fromPath), path.join(baseDir)).split(path.sep));
|
|
1133
1139
|
|
|
1134
|
-
if (baseRel.endsWith("
|
|
1135
|
-
baseRel = "json-as" + baseRel.slice(baseRel.indexOf("
|
|
1140
|
+
if (baseRel.endsWith("json-as")) {
|
|
1141
|
+
baseRel = "json-as" + baseRel.slice(baseRel.indexOf("json-as") + 7);
|
|
1136
1142
|
} else if (!baseRel.startsWith(".") && !baseRel.startsWith("/") && !baseRel.startsWith("json-as")) {
|
|
1137
1143
|
baseRel = "./" + baseRel;
|
|
1138
1144
|
}
|
|
@@ -1400,15 +1406,6 @@ function isBoolean(type: string): boolean {
|
|
|
1400
1406
|
return type == "bool" || type == "boolean";
|
|
1401
1407
|
}
|
|
1402
1408
|
|
|
1403
|
-
function isStruct(type: string): boolean {
|
|
1404
|
-
type = stripNull(type);
|
|
1405
|
-
const schema = JSONTransform.SN.schema;
|
|
1406
|
-
if (schema.name == type) return true;
|
|
1407
|
-
const depSearch = schema.deps.some((v) => v.name == type);
|
|
1408
|
-
if (depSearch) return true;
|
|
1409
|
-
return false;
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
1409
|
function isString(type: string) {
|
|
1413
1410
|
return stripNull(type) == "string" || stripNull(type) == "String";
|
|
1414
1411
|
}
|
package/transform/src/types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ClassDeclaration, Expression, FieldDeclaration, Source } from "assemblyscript/dist/assemblyscript.js";
|
|
1
|
+
import { ClassDeclaration, Expression, FieldDeclaration, Source, NodeKind, Node, NamespaceDeclaration, DeclarationStatement, TypeName, Parser, ImportStatement, CommonFlags } from "assemblyscript/dist/assemblyscript.js";
|
|
2
2
|
import { TypeAlias } from "./linkers/alias.js";
|
|
3
|
-
import {
|
|
3
|
+
import { stripNull } from "./index.js";
|
|
4
4
|
|
|
5
5
|
export enum PropertyFlags {
|
|
6
6
|
OmitNull,
|
|
@@ -75,14 +75,192 @@ export class Schema {
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
export class SourceSet {
|
|
79
|
+
private sources: Record<string, Src> = {};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get a stored source from the set, or create a new one and store it if it
|
|
83
|
+
* didn't exist.
|
|
84
|
+
* @param source AssemblyScript Source
|
|
85
|
+
* @returns Source object
|
|
86
|
+
*/
|
|
87
|
+
get(source: Source): Src {
|
|
88
|
+
let src = this.sources[source.internalPath];
|
|
89
|
+
if (!src) {
|
|
90
|
+
src = new Src(source, this);
|
|
91
|
+
this.sources[source.internalPath] = src;
|
|
92
|
+
}
|
|
93
|
+
return src;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
78
97
|
export class Src {
|
|
79
98
|
public internalPath: string;
|
|
99
|
+
public normalizedPath: string;
|
|
80
100
|
public schemas: Schema[];
|
|
81
101
|
public aliases: TypeAlias[];
|
|
82
|
-
public imports: Schema[];
|
|
83
102
|
public exports: Schema[];
|
|
84
|
-
|
|
103
|
+
private nodeMap: Map<Node, NamespaceDeclaration[]> = new Map<Node, NamespaceDeclaration[]>();
|
|
104
|
+
private classes: Record<string, ClassDeclaration> = {};
|
|
105
|
+
private imports: ImportStatement[] = [];
|
|
106
|
+
|
|
107
|
+
constructor(
|
|
108
|
+
source: Source,
|
|
109
|
+
private sourceSet: SourceSet,
|
|
110
|
+
) {
|
|
85
111
|
this.internalPath = source.internalPath;
|
|
112
|
+
this.normalizedPath = source.normalizedPath;
|
|
86
113
|
this.aliases = TypeAlias.getAliases(source);
|
|
114
|
+
this.traverse(source.statements, []);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Traverse source nodes and finds all classes and imports, and which namespaces they exist under.
|
|
119
|
+
* @param nodes Nodes to traverse.
|
|
120
|
+
* @param path The current path of namespace declarations leading to the nodes.
|
|
121
|
+
*/
|
|
122
|
+
private traverse(nodes: Node[], path: NamespaceDeclaration[]) {
|
|
123
|
+
for (let node of nodes) {
|
|
124
|
+
switch (node.kind) {
|
|
125
|
+
case NodeKind.NamespaceDeclaration:
|
|
126
|
+
const namespaceDeclaration = node as NamespaceDeclaration;
|
|
127
|
+
this.traverse(namespaceDeclaration.members, [...path, namespaceDeclaration]);
|
|
128
|
+
break;
|
|
129
|
+
case NodeKind.ClassDeclaration:
|
|
130
|
+
const classDeclaration = node as ClassDeclaration;
|
|
131
|
+
this.classes[this.qualifiedName(classDeclaration, path)] = classDeclaration;
|
|
132
|
+
break;
|
|
133
|
+
case NodeKind.Import:
|
|
134
|
+
const importStatement = node as ImportStatement;
|
|
135
|
+
this.imports.push(importStatement);
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
this.nodeMap.set(node, path);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get the qualified name (eg. "Namespace.BaseObject") for a class.
|
|
144
|
+
* @param node Class declaration.
|
|
145
|
+
* @returns Qualified name
|
|
146
|
+
*/
|
|
147
|
+
getQualifiedName(node: DeclarationStatement): string {
|
|
148
|
+
return this.qualifiedName(node, this.nodeMap.get(node));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get a class declaration by its qualified name.
|
|
153
|
+
* @param qualifiedName Qualified named (eg. "Namespace.BaseObject")
|
|
154
|
+
* @returns Class declaration or null if not found.
|
|
155
|
+
*/
|
|
156
|
+
getClass(qualifiedName: string): ClassDeclaration | null {
|
|
157
|
+
return this.classes[qualifiedName] || null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get imported class from other sources in the parser.
|
|
162
|
+
* @param qualifiedName Qualified name of class.
|
|
163
|
+
* @param parser AssemblyScript parser.
|
|
164
|
+
* @returns Class declaration or null if not found.
|
|
165
|
+
*/
|
|
166
|
+
getImportedClass(qualifiedName: string, parser: Parser): ClassDeclaration | null {
|
|
167
|
+
for (const stmt of this.imports) {
|
|
168
|
+
const externalSource = parser.sources.filter((src) => src.internalPath != this.internalPath).find((src) => src.internalPath == stmt.internalPath);
|
|
169
|
+
if (!externalSource) continue;
|
|
170
|
+
|
|
171
|
+
const source = this.sourceSet.get(externalSource);
|
|
172
|
+
const classDeclaration = source.getClass(qualifiedName);
|
|
173
|
+
if (classDeclaration && classDeclaration.flags & CommonFlags.Export) {
|
|
174
|
+
return classDeclaration;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Gets a unique path string to the node by combining the internalPath with
|
|
182
|
+
* the qualified name of the node.
|
|
183
|
+
* @param node DeclarationStatement
|
|
184
|
+
*/
|
|
185
|
+
getFullPath(node: DeclarationStatement): string {
|
|
186
|
+
return this.internalPath + "/" + this.getQualifiedName(node);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Resolved the qualified name of the extended class for a class
|
|
191
|
+
* declaration.
|
|
192
|
+
* @param classDeclaration Class declaration that extends another class.
|
|
193
|
+
* @returns Qualified name of the extended class, or empty string if not extending any class.
|
|
194
|
+
*/
|
|
195
|
+
resolveExtendsName(classDeclaration: ClassDeclaration): string {
|
|
196
|
+
const parents = this.nodeMap.get(classDeclaration);
|
|
197
|
+
if (!classDeclaration.extendsType || !parents) {
|
|
198
|
+
return "";
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const name = classDeclaration.extendsType.name.identifier.text;
|
|
202
|
+
const extendsName = this.getIdentifier(classDeclaration.extendsType.name);
|
|
203
|
+
|
|
204
|
+
// Reverse walk to find first class or namespace that matches the first part
|
|
205
|
+
// of type name.
|
|
206
|
+
for (let i = parents.length - 1; i >= 0; i--) {
|
|
207
|
+
const parent = parents[i];
|
|
208
|
+
for (let node of parent.members) {
|
|
209
|
+
if (name == this.getNamespaceOrClassName(node)) {
|
|
210
|
+
// Add namespace path to the extendsName.
|
|
211
|
+
return (
|
|
212
|
+
parents
|
|
213
|
+
.slice(0, i + 1)
|
|
214
|
+
.map((p) => p.name.text)
|
|
215
|
+
.join(".") +
|
|
216
|
+
"." +
|
|
217
|
+
extendsName
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// No matching class or namespace found. Just use the extendsName.
|
|
223
|
+
return extendsName;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Get the qualified name (eg "Namespace.BaseObject") of a class.
|
|
228
|
+
* @param node Class declaration.
|
|
229
|
+
* @param parents Array of namespace parents.
|
|
230
|
+
* @returns Qualified name
|
|
231
|
+
*/
|
|
232
|
+
private qualifiedName(node: DeclarationStatement, parents: NamespaceDeclaration[]): string {
|
|
233
|
+
return parents?.length ? parents.map((p) => p.name.text).join(".") + "." + node.name.text : node.name.text;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Checks if the node is either a namespace or class, and returns the simple
|
|
238
|
+
* name of the node.
|
|
239
|
+
* @param node Node to check
|
|
240
|
+
* @returns Name of namespace or class, or empty string if other type of node.
|
|
241
|
+
*/
|
|
242
|
+
private getNamespaceOrClassName(node: Node): string {
|
|
243
|
+
switch (node.kind) {
|
|
244
|
+
case NodeKind.NamespaceDeclaration:
|
|
245
|
+
return (node as DeclarationStatement).name.text;
|
|
246
|
+
case NodeKind.ClassDeclaration:
|
|
247
|
+
return (node as DeclarationStatement).name.text;
|
|
248
|
+
}
|
|
249
|
+
return "";
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Get the full name (eg. "Namespace.Base") of a type name such as an
|
|
254
|
+
* extendedType.
|
|
255
|
+
* @param typeName Type name
|
|
256
|
+
* @returns Full name
|
|
257
|
+
*/
|
|
258
|
+
private getIdentifier(typeName: TypeName): string {
|
|
259
|
+
let names = [];
|
|
260
|
+
while (typeName) {
|
|
261
|
+
names.push(typeName.identifier.text);
|
|
262
|
+
typeName = typeName.next;
|
|
263
|
+
}
|
|
264
|
+
return names.join(".");
|
|
87
265
|
}
|
|
88
266
|
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { ClassDeclaration, CommonFlags, NodeKind, Parser, Source } from "assemblyscript/dist/assemblyscript.js";
|
|
2
|
-
import { Visitor } from "../visitor.js";
|
|
3
|
-
import { getImports } from "./imports.js";
|
|
4
|
-
|
|
5
|
-
export function getImportedClass(name: string, source: Source, parser: Parser): ClassDeclaration | null {
|
|
6
|
-
for (const stmt of getImports(source)) {
|
|
7
|
-
const externalSource = parser.sources.filter((src) => src.internalPath != source.internalPath).find((src) => src.internalPath == stmt.internalPath);
|
|
8
|
-
if (!externalSource) continue;
|
|
9
|
-
|
|
10
|
-
const classDeclaration = ClassGetter.getClass(name, externalSource);
|
|
11
|
-
if (!classDeclaration) continue;
|
|
12
|
-
if (!(classDeclaration.flags & CommonFlags.Export)) continue;
|
|
13
|
-
return classDeclaration;
|
|
14
|
-
}
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
class ClassGetter extends Visitor {
|
|
19
|
-
static SN: ClassGetter = new ClassGetter();
|
|
20
|
-
|
|
21
|
-
private classes: ClassDeclaration[] = [];
|
|
22
|
-
|
|
23
|
-
visitClassDeclaration(node: ClassDeclaration): void {
|
|
24
|
-
this.classes.push(node);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// visitTypeName(node: TypeName, ref?: Node | null): void {}
|
|
28
|
-
// visitParameter(node: ParameterNode, ref?: Node | null): void {}
|
|
29
|
-
// visitFunctionTypeNode(node: FunctionTypeNode, ref?: Node | null): void {}
|
|
30
|
-
// visitNamedTypeNode(node: NamedTypeNode, ref?: Node | null): void {}
|
|
31
|
-
|
|
32
|
-
static getClass(name: string, source: Source): ClassDeclaration | null {
|
|
33
|
-
return ClassGetter.getClasses(source).find((c) => c.name.text == name) || null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
static getClasses(source: Source): ClassDeclaration[] {
|
|
37
|
-
// ClassGetter.SN.classes = [];
|
|
38
|
-
// ClassGetter.SN.visit(source);
|
|
39
|
-
// return ClassGetter.SN.classes;
|
|
40
|
-
return source.statements.filter((stmt) => stmt.kind == NodeKind.ClassDeclaration) as ClassDeclaration[];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function getClasses(source: Source): ClassDeclaration[] {
|
|
45
|
-
return ClassGetter.getClasses(source);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function getClass(name: string, source: Source): ClassDeclaration | null {
|
|
49
|
-
return ClassGetter.getClass(name, source);
|
|
50
|
-
}
|