@eventra_dev/eventra-cli 0.1.4 → 0.1.6
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/dist/engine/engine.js +5 -1
- package/dist/engine/exportResolver.js +34 -0
- package/dist/engine/graph.js +41 -21
- package/dist/engine/languageService.js +22 -2
- package/dist/engine/resolver.js +2 -0
- package/package.json +1 -1
- package/src/engine/engine.ts +10 -1
- package/src/engine/exportResolver.ts +39 -0
- package/src/engine/graph.ts +43 -24
- package/src/engine/languageService.ts +28 -6
- package/src/engine/resolver.ts +3 -0
package/dist/engine/engine.js
CHANGED
|
@@ -7,14 +7,17 @@ const graph_1 = require("./graph");
|
|
|
7
7
|
const hash_1 = require("./hash");
|
|
8
8
|
class EventraEngine {
|
|
9
9
|
ts;
|
|
10
|
-
graph
|
|
10
|
+
graph;
|
|
11
11
|
fileEvents = new Map();
|
|
12
12
|
fileHash = new Map();
|
|
13
13
|
constructor(root) {
|
|
14
14
|
this.ts = new languageService_1.TSService(root);
|
|
15
|
+
const { baseUrl, paths } = this.ts.getModuleResolutionConfig();
|
|
16
|
+
this.graph = new graph_1.DependencyGraph(baseUrl, paths);
|
|
15
17
|
}
|
|
16
18
|
scanFile(file, content) {
|
|
17
19
|
const h = (0, hash_1.hash)(content);
|
|
20
|
+
// cache
|
|
18
21
|
if (this.fileHash.get(file) === h) {
|
|
19
22
|
return this.fileEvents.get(file) ?? new Set();
|
|
20
23
|
}
|
|
@@ -24,6 +27,7 @@ class EventraEngine {
|
|
|
24
27
|
const checker = this.ts.getChecker();
|
|
25
28
|
if (!source || !checker)
|
|
26
29
|
return new Set();
|
|
30
|
+
// обновляем graph
|
|
27
31
|
this.graph.update(file, source);
|
|
28
32
|
const events = (0, scanner_1.scanSource)(source, checker);
|
|
29
33
|
this.fileEvents.set(file, events);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolveExportedSymbol = resolveExportedSymbol;
|
|
7
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
+
function resolveExportedSymbol(symbol, checker, visited = new Set()) {
|
|
9
|
+
if (visited.has(symbol))
|
|
10
|
+
return null;
|
|
11
|
+
visited.add(symbol);
|
|
12
|
+
if (symbol.flags & typescript_1.default.SymbolFlags.Alias) {
|
|
13
|
+
const aliased = checker.getAliasedSymbol(symbol);
|
|
14
|
+
return resolveExportedSymbol(aliased, checker, visited);
|
|
15
|
+
}
|
|
16
|
+
if (symbol.getDeclarations()?.length) {
|
|
17
|
+
return symbol;
|
|
18
|
+
}
|
|
19
|
+
const declarations = symbol.getDeclarations() ?? [];
|
|
20
|
+
for (const decl of declarations) {
|
|
21
|
+
const source = decl.getSourceFile();
|
|
22
|
+
const moduleSymbol = checker.getSymbolAtLocation(source);
|
|
23
|
+
if (!moduleSymbol)
|
|
24
|
+
continue;
|
|
25
|
+
const exports = checker.getExportsOfModule(moduleSymbol);
|
|
26
|
+
for (const exp of exports) {
|
|
27
|
+
const resolved = resolveExportedSymbol(exp, checker, visited);
|
|
28
|
+
if (resolved?.getDeclarations()?.length) {
|
|
29
|
+
return resolved;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return symbol;
|
|
34
|
+
}
|
package/dist/engine/graph.js
CHANGED
|
@@ -8,15 +8,48 @@ const typescript_1 = __importDefault(require("typescript"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
10
10
|
class DependencyGraph {
|
|
11
|
+
baseUrl;
|
|
12
|
+
paths;
|
|
11
13
|
reverse = new Map();
|
|
12
14
|
exports = new Map();
|
|
15
|
+
constructor(baseUrl, paths) {
|
|
16
|
+
this.baseUrl = baseUrl;
|
|
17
|
+
this.paths = paths;
|
|
18
|
+
}
|
|
13
19
|
normalize(file) {
|
|
14
20
|
return path_1.default.resolve(file);
|
|
15
21
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
// TS-like resolver
|
|
23
|
+
resolveModule(module, from) {
|
|
24
|
+
// relative
|
|
25
|
+
if (module.startsWith(".")) {
|
|
26
|
+
const abs = path_1.default.resolve(path_1.default.dirname(from), module);
|
|
27
|
+
return this.resolveFile(abs);
|
|
28
|
+
}
|
|
29
|
+
// paths mapping
|
|
30
|
+
for (const key in this.paths) {
|
|
31
|
+
const pattern = key.replace("*", "(.*)");
|
|
32
|
+
const regex = new RegExp("^" + pattern + "$");
|
|
33
|
+
const match = module.match(regex);
|
|
34
|
+
if (!match)
|
|
35
|
+
continue;
|
|
36
|
+
const wildcard = match[1] || "";
|
|
37
|
+
for (const target of this.paths[key]) {
|
|
38
|
+
const replaced = target.replace("*", wildcard);
|
|
39
|
+
const abs = path_1.default.resolve(this.baseUrl, replaced);
|
|
40
|
+
const resolved = this.resolveFile(abs);
|
|
41
|
+
if (resolved)
|
|
42
|
+
return resolved;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// baseUrl fallback
|
|
46
|
+
const abs = path_1.default.resolve(this.baseUrl, module);
|
|
47
|
+
const resolved = this.resolveFile(abs);
|
|
48
|
+
if (resolved)
|
|
49
|
+
return resolved;
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
resolveFile(base) {
|
|
20
53
|
const tryFiles = [
|
|
21
54
|
base,
|
|
22
55
|
base + ".ts",
|
|
@@ -32,7 +65,7 @@ class DependencyGraph {
|
|
|
32
65
|
return this.normalize(f);
|
|
33
66
|
}
|
|
34
67
|
}
|
|
35
|
-
return
|
|
68
|
+
return null;
|
|
36
69
|
}
|
|
37
70
|
update(file, source) {
|
|
38
71
|
const normalizedFile = this.normalize(file);
|
|
@@ -41,7 +74,7 @@ class DependencyGraph {
|
|
|
41
74
|
// IMPORT
|
|
42
75
|
if (typescript_1.default.isImportDeclaration(stmt)) {
|
|
43
76
|
const module = stmt.moduleSpecifier.getText().replace(/['"]/g, "");
|
|
44
|
-
const resolved = this.
|
|
77
|
+
const resolved = this.resolveModule(module, normalizedFile);
|
|
45
78
|
if (!resolved)
|
|
46
79
|
continue;
|
|
47
80
|
if (!this.reverse.has(resolved)) {
|
|
@@ -49,10 +82,10 @@ class DependencyGraph {
|
|
|
49
82
|
}
|
|
50
83
|
this.reverse.get(resolved).add(normalizedFile);
|
|
51
84
|
}
|
|
52
|
-
// EXPORT
|
|
85
|
+
// EXPORT *
|
|
53
86
|
if (typescript_1.default.isExportDeclaration(stmt) && stmt.moduleSpecifier) {
|
|
54
87
|
const module = stmt.moduleSpecifier.getText().replace(/['"]/g, "");
|
|
55
|
-
const resolved = this.
|
|
88
|
+
const resolved = this.resolveModule(module, normalizedFile);
|
|
56
89
|
if (!resolved)
|
|
57
90
|
continue;
|
|
58
91
|
if (!this.exports.has(normalizedFile)) {
|
|
@@ -66,19 +99,6 @@ class DependencyGraph {
|
|
|
66
99
|
}
|
|
67
100
|
}
|
|
68
101
|
}
|
|
69
|
-
getAllRelated(file, visited = new Set()) {
|
|
70
|
-
const normalized = this.normalize(file);
|
|
71
|
-
if (visited.has(normalized))
|
|
72
|
-
return visited;
|
|
73
|
-
visited.add(normalized);
|
|
74
|
-
const deps = this.exports.get(normalized);
|
|
75
|
-
if (!deps)
|
|
76
|
-
return visited;
|
|
77
|
-
for (const dep of deps) {
|
|
78
|
-
this.getAllRelated(dep, visited);
|
|
79
|
-
}
|
|
80
|
-
return visited;
|
|
81
|
-
}
|
|
82
102
|
getDependents(file) {
|
|
83
103
|
return [...(this.reverse.get(this.normalize(file)) ?? [])];
|
|
84
104
|
}
|
|
@@ -6,11 +6,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.TSService = void 0;
|
|
7
7
|
const typescript_1 = __importDefault(require("typescript"));
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
9
10
|
class TSService {
|
|
10
11
|
root;
|
|
11
12
|
files = new Map();
|
|
12
13
|
fileNames = new Set();
|
|
13
14
|
service;
|
|
15
|
+
compilerOptions = {};
|
|
16
|
+
baseUrl = "";
|
|
17
|
+
paths = {};
|
|
14
18
|
constructor(root) {
|
|
15
19
|
this.root = root;
|
|
16
20
|
const configPath = typescript_1.default.findConfigFile(root, typescript_1.default.sys.fileExists, "tsconfig.json");
|
|
@@ -29,9 +33,19 @@ class TSService {
|
|
|
29
33
|
...compilerOptions,
|
|
30
34
|
...parsed.options,
|
|
31
35
|
};
|
|
36
|
+
this.paths = parsed.options.paths || {};
|
|
37
|
+
this.baseUrl = parsed.options.baseUrl
|
|
38
|
+
? path_1.default.resolve(root, parsed.options.baseUrl)
|
|
39
|
+
: root;
|
|
32
40
|
}
|
|
41
|
+
else {
|
|
42
|
+
this.baseUrl = root;
|
|
43
|
+
}
|
|
44
|
+
this.compilerOptions = compilerOptions;
|
|
33
45
|
const host = {
|
|
34
|
-
getScriptFileNames: () =>
|
|
46
|
+
getScriptFileNames: () => {
|
|
47
|
+
return [...new Set(this.fileNames)].sort((a, b) => a.localeCompare(b));
|
|
48
|
+
},
|
|
35
49
|
getScriptVersion: (file) => this.files.get(file)?.version.toString() ?? "0",
|
|
36
50
|
getScriptSnapshot: (file) => {
|
|
37
51
|
const f = this.files.get(file);
|
|
@@ -44,7 +58,7 @@ class TSService {
|
|
|
44
58
|
return undefined;
|
|
45
59
|
},
|
|
46
60
|
getCurrentDirectory: () => this.root,
|
|
47
|
-
getCompilationSettings: () => compilerOptions,
|
|
61
|
+
getCompilationSettings: () => this.compilerOptions,
|
|
48
62
|
getDefaultLibFileName: (opts) => typescript_1.default.getDefaultLibFilePath(opts),
|
|
49
63
|
readFile: typescript_1.default.sys.readFile,
|
|
50
64
|
fileExists: typescript_1.default.sys.fileExists,
|
|
@@ -69,5 +83,11 @@ class TSService {
|
|
|
69
83
|
getSourceFile(file) {
|
|
70
84
|
return this.getProgram()?.getSourceFile(file);
|
|
71
85
|
}
|
|
86
|
+
getModuleResolutionConfig() {
|
|
87
|
+
return {
|
|
88
|
+
baseUrl: this.baseUrl,
|
|
89
|
+
paths: this.paths,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
72
92
|
}
|
|
73
93
|
exports.TSService = TSService;
|
package/dist/engine/resolver.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.resolveNodeValue = resolveNodeValue;
|
|
7
7
|
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
+
const exportResolver_1 = require("./exportResolver");
|
|
8
9
|
function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
9
10
|
if (seen.has(node))
|
|
10
11
|
return null;
|
|
@@ -36,6 +37,7 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
36
37
|
let symbol = checker.getSymbolAtLocation(node);
|
|
37
38
|
if (!symbol)
|
|
38
39
|
return null;
|
|
40
|
+
symbol = (0, exportResolver_1.resolveExportedSymbol)(symbol, checker) ?? symbol;
|
|
39
41
|
if (symbol.flags & typescript_1.default.SymbolFlags.Alias) {
|
|
40
42
|
symbol = checker.getAliasedSymbol(symbol);
|
|
41
43
|
}
|
package/package.json
CHANGED
package/src/engine/engine.ts
CHANGED
|
@@ -5,23 +5,28 @@ import { hash } from "./hash";
|
|
|
5
5
|
|
|
6
6
|
export class EventraEngine {
|
|
7
7
|
private ts: TSService;
|
|
8
|
-
private graph
|
|
8
|
+
private graph: DependencyGraph;
|
|
9
9
|
|
|
10
10
|
private fileEvents = new Map<string, Set<string>>();
|
|
11
11
|
private fileHash = new Map<string, string>();
|
|
12
12
|
|
|
13
13
|
constructor(root: string) {
|
|
14
14
|
this.ts = new TSService(root);
|
|
15
|
+
|
|
16
|
+
const { baseUrl, paths } = this.ts.getModuleResolutionConfig();
|
|
17
|
+
this.graph = new DependencyGraph(baseUrl, paths);
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
scanFile(file: string, content: string) {
|
|
18
21
|
const h = hash(content);
|
|
19
22
|
|
|
23
|
+
// cache
|
|
20
24
|
if (this.fileHash.get(file) === h) {
|
|
21
25
|
return this.fileEvents.get(file) ?? new Set();
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
this.fileHash.set(file, h);
|
|
29
|
+
|
|
25
30
|
this.ts.updateFile(file, content);
|
|
26
31
|
|
|
27
32
|
const source = this.ts.getSourceFile(file);
|
|
@@ -29,7 +34,9 @@ export class EventraEngine {
|
|
|
29
34
|
|
|
30
35
|
if (!source || !checker) return new Set();
|
|
31
36
|
|
|
37
|
+
// обновляем graph
|
|
32
38
|
this.graph.update(file, source);
|
|
39
|
+
|
|
33
40
|
const events = scanSource(source, checker);
|
|
34
41
|
|
|
35
42
|
this.fileEvents.set(file, events);
|
|
@@ -39,6 +46,7 @@ export class EventraEngine {
|
|
|
39
46
|
|
|
40
47
|
updateFile(file: string, content: string) {
|
|
41
48
|
const events = this.scanFile(file, content);
|
|
49
|
+
|
|
42
50
|
const dependents = this.graph.getDependents(file);
|
|
43
51
|
|
|
44
52
|
for (const dep of dependents) {
|
|
@@ -48,6 +56,7 @@ export class EventraEngine {
|
|
|
48
56
|
if (!source || !checker) continue;
|
|
49
57
|
|
|
50
58
|
const ev = scanSource(source, checker);
|
|
59
|
+
|
|
51
60
|
this.fileEvents.set(dep, ev);
|
|
52
61
|
}
|
|
53
62
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
|
|
3
|
+
export function resolveExportedSymbol(
|
|
4
|
+
symbol: ts.Symbol,
|
|
5
|
+
checker: ts.TypeChecker,
|
|
6
|
+
visited = new Set<ts.Symbol>()
|
|
7
|
+
): ts.Symbol | null {
|
|
8
|
+
|
|
9
|
+
if (visited.has(symbol)) return null;
|
|
10
|
+
visited.add(symbol);
|
|
11
|
+
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
12
|
+
const aliased = checker.getAliasedSymbol(symbol);
|
|
13
|
+
return resolveExportedSymbol(aliased, checker, visited);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (symbol.getDeclarations()?.length) {
|
|
17
|
+
return symbol;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const declarations = symbol.getDeclarations() ?? [];
|
|
21
|
+
|
|
22
|
+
for (const decl of declarations) {
|
|
23
|
+
const source = decl.getSourceFile();
|
|
24
|
+
const moduleSymbol = checker.getSymbolAtLocation(source);
|
|
25
|
+
|
|
26
|
+
if (!moduleSymbol) continue;
|
|
27
|
+
|
|
28
|
+
const exports = checker.getExportsOfModule(moduleSymbol);
|
|
29
|
+
|
|
30
|
+
for (const exp of exports) {
|
|
31
|
+
const resolved = resolveExportedSymbol(exp, checker, visited);
|
|
32
|
+
if (resolved?.getDeclarations()?.length) {
|
|
33
|
+
return resolved;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return symbol;
|
|
39
|
+
}
|
package/src/engine/graph.ts
CHANGED
|
@@ -6,15 +6,51 @@ export class DependencyGraph {
|
|
|
6
6
|
private reverse = new Map<string, Set<string>>();
|
|
7
7
|
private exports = new Map<string, Set<string>>();
|
|
8
8
|
|
|
9
|
+
constructor(
|
|
10
|
+
private baseUrl: string,
|
|
11
|
+
private paths: Record<string, string[]>
|
|
12
|
+
) {}
|
|
13
|
+
|
|
9
14
|
private normalize(file: string) {
|
|
10
15
|
return path.resolve(file);
|
|
11
16
|
}
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
// TS-like resolver
|
|
19
|
+
private resolveModule(module: string, from: string): string | null {
|
|
20
|
+
// relative
|
|
21
|
+
if (module.startsWith(".")) {
|
|
22
|
+
const abs = path.resolve(path.dirname(from), module);
|
|
23
|
+
return this.resolveFile(abs);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// paths mapping
|
|
27
|
+
for (const key in this.paths) {
|
|
28
|
+
const pattern = key.replace("*", "(.*)");
|
|
29
|
+
const regex = new RegExp("^" + pattern + "$");
|
|
30
|
+
const match = module.match(regex);
|
|
31
|
+
|
|
32
|
+
if (!match) continue;
|
|
33
|
+
|
|
34
|
+
const wildcard = match[1] || "";
|
|
35
|
+
|
|
36
|
+
for (const target of this.paths[key]) {
|
|
37
|
+
const replaced = target.replace("*", wildcard);
|
|
38
|
+
const abs = path.resolve(this.baseUrl, replaced);
|
|
39
|
+
|
|
40
|
+
const resolved = this.resolveFile(abs);
|
|
41
|
+
if (resolved) return resolved;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// baseUrl fallback
|
|
46
|
+
const abs = path.resolve(this.baseUrl, module);
|
|
47
|
+
const resolved = this.resolveFile(abs);
|
|
48
|
+
if (resolved) return resolved;
|
|
15
49
|
|
|
16
|
-
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
17
52
|
|
|
53
|
+
private resolveFile(base: string): string | null {
|
|
18
54
|
const tryFiles = [
|
|
19
55
|
base,
|
|
20
56
|
base + ".ts",
|
|
@@ -32,7 +68,7 @@ export class DependencyGraph {
|
|
|
32
68
|
}
|
|
33
69
|
}
|
|
34
70
|
|
|
35
|
-
return
|
|
71
|
+
return null;
|
|
36
72
|
}
|
|
37
73
|
|
|
38
74
|
update(file: string, source: ts.SourceFile) {
|
|
@@ -44,8 +80,8 @@ export class DependencyGraph {
|
|
|
44
80
|
// IMPORT
|
|
45
81
|
if (ts.isImportDeclaration(stmt)) {
|
|
46
82
|
const module = stmt.moduleSpecifier.getText().replace(/['"]/g, "");
|
|
47
|
-
const resolved = this.resolveImport(normalizedFile, module);
|
|
48
83
|
|
|
84
|
+
const resolved = this.resolveModule(module, normalizedFile);
|
|
49
85
|
if (!resolved) continue;
|
|
50
86
|
|
|
51
87
|
if (!this.reverse.has(resolved)) {
|
|
@@ -55,11 +91,11 @@ export class DependencyGraph {
|
|
|
55
91
|
this.reverse.get(resolved)!.add(normalizedFile);
|
|
56
92
|
}
|
|
57
93
|
|
|
58
|
-
// EXPORT
|
|
94
|
+
// EXPORT *
|
|
59
95
|
if (ts.isExportDeclaration(stmt) && stmt.moduleSpecifier) {
|
|
60
96
|
const module = stmt.moduleSpecifier.getText().replace(/['"]/g, "");
|
|
61
|
-
const resolved = this.resolveImport(normalizedFile, module);
|
|
62
97
|
|
|
98
|
+
const resolved = this.resolveModule(module, normalizedFile);
|
|
63
99
|
if (!resolved) continue;
|
|
64
100
|
|
|
65
101
|
if (!this.exports.has(normalizedFile)) {
|
|
@@ -77,23 +113,6 @@ export class DependencyGraph {
|
|
|
77
113
|
}
|
|
78
114
|
}
|
|
79
115
|
|
|
80
|
-
getAllRelated(file: string, visited = new Set<string>()): Set<string> {
|
|
81
|
-
const normalized = this.normalize(file);
|
|
82
|
-
|
|
83
|
-
if (visited.has(normalized)) return visited;
|
|
84
|
-
visited.add(normalized);
|
|
85
|
-
|
|
86
|
-
const deps = this.exports.get(normalized);
|
|
87
|
-
|
|
88
|
-
if (!deps) return visited;
|
|
89
|
-
|
|
90
|
-
for (const dep of deps) {
|
|
91
|
-
this.getAllRelated(dep, visited);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return visited;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
116
|
getDependents(file: string) {
|
|
98
117
|
return [...(this.reverse.get(this.normalize(file)) ?? [])];
|
|
99
118
|
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
2
|
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
3
4
|
|
|
4
5
|
export class TSService {
|
|
5
6
|
private files = new Map<string, { version: number; content: string }>();
|
|
6
7
|
private fileNames = new Set<string>();
|
|
7
8
|
private service: ts.LanguageService;
|
|
8
9
|
|
|
10
|
+
private readonly compilerOptions: ts.CompilerOptions = {};
|
|
11
|
+
private readonly baseUrl: string = "";
|
|
12
|
+
private readonly paths: Record<string, string[]> = {};
|
|
13
|
+
|
|
9
14
|
constructor(private root: string) {
|
|
10
15
|
const configPath = ts.findConfigFile(
|
|
11
16
|
root,
|
|
@@ -23,10 +28,7 @@ export class TSService {
|
|
|
23
28
|
};
|
|
24
29
|
|
|
25
30
|
if (configPath) {
|
|
26
|
-
const configFile = ts.readConfigFile(
|
|
27
|
-
configPath,
|
|
28
|
-
ts.sys.readFile
|
|
29
|
-
);
|
|
31
|
+
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
30
32
|
|
|
31
33
|
const parsed = ts.parseJsonConfigFileContent(
|
|
32
34
|
configFile.config,
|
|
@@ -38,10 +40,23 @@ export class TSService {
|
|
|
38
40
|
...compilerOptions,
|
|
39
41
|
...parsed.options,
|
|
40
42
|
};
|
|
43
|
+
|
|
44
|
+
this.paths = parsed.options.paths || {};
|
|
45
|
+
this.baseUrl = parsed.options.baseUrl
|
|
46
|
+
? path.resolve(root, parsed.options.baseUrl)
|
|
47
|
+
: root;
|
|
48
|
+
} else {
|
|
49
|
+
this.baseUrl = root;
|
|
41
50
|
}
|
|
42
51
|
|
|
52
|
+
this.compilerOptions = compilerOptions;
|
|
53
|
+
|
|
43
54
|
const host: ts.LanguageServiceHost = {
|
|
44
|
-
getScriptFileNames: () =>
|
|
55
|
+
getScriptFileNames: () => {
|
|
56
|
+
return [...new Set(this.fileNames)].sort((a, b) =>
|
|
57
|
+
a.localeCompare(b)
|
|
58
|
+
);
|
|
59
|
+
},
|
|
45
60
|
|
|
46
61
|
getScriptVersion: (file) =>
|
|
47
62
|
this.files.get(file)?.version.toString() ?? "0",
|
|
@@ -63,7 +78,7 @@ export class TSService {
|
|
|
63
78
|
},
|
|
64
79
|
|
|
65
80
|
getCurrentDirectory: () => this.root,
|
|
66
|
-
getCompilationSettings: () => compilerOptions,
|
|
81
|
+
getCompilationSettings: () => this.compilerOptions,
|
|
67
82
|
getDefaultLibFileName: (opts) =>
|
|
68
83
|
ts.getDefaultLibFilePath(opts),
|
|
69
84
|
|
|
@@ -97,4 +112,11 @@ export class TSService {
|
|
|
97
112
|
getSourceFile(file: string) {
|
|
98
113
|
return this.getProgram()?.getSourceFile(file);
|
|
99
114
|
}
|
|
115
|
+
|
|
116
|
+
getModuleResolutionConfig() {
|
|
117
|
+
return {
|
|
118
|
+
baseUrl: this.baseUrl,
|
|
119
|
+
paths: this.paths,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
100
122
|
}
|
package/src/engine/resolver.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
+
import {resolveExportedSymbol} from "./exportResolver";
|
|
2
3
|
|
|
3
4
|
export type ResolveResult = {
|
|
4
5
|
values: string[];
|
|
@@ -53,6 +54,8 @@ export function resolveNodeValue(
|
|
|
53
54
|
let symbol = checker.getSymbolAtLocation(node);
|
|
54
55
|
if (!symbol) return null;
|
|
55
56
|
|
|
57
|
+
symbol = resolveExportedSymbol(symbol, checker) ?? symbol;
|
|
58
|
+
|
|
56
59
|
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
57
60
|
symbol = checker.getAliasedSymbol(symbol);
|
|
58
61
|
}
|