@eventra_dev/eventra-cli 0.1.32 → 0.1.34
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/ARCHITECTURE.md +88 -0
- package/dist/engine/callResolver.js +32 -131
- package/dist/engine/languageService.js +7 -38
- package/dist/engine/resolver.js +88 -77
- package/dist/engine/scanner.js +123 -201
- package/package.json +1 -1
- package/src/engine/callResolver.ts +24 -159
- package/src/engine/languageService.ts +22 -52
- package/src/engine/resolver.ts +99 -120
- package/src/engine/scanner.ts +128 -262
package/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Eventra CLI Architecture
|
|
2
|
+
|
|
3
|
+
## High-Level Flow
|
|
4
|
+
|
|
5
|
+
FILES → parseUniversal → TSService → scanSource → Engine → CLI
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Diagram
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
+-------------------+
|
|
13
|
+
| Source Files |
|
|
14
|
+
+---------+---------+
|
|
15
|
+
|
|
|
16
|
+
v
|
|
17
|
+
+-------------------+
|
|
18
|
+
| parseUniversal |
|
|
19
|
+
| (normalize input) |
|
|
20
|
+
+---------+---------+
|
|
21
|
+
|
|
|
22
|
+
v
|
|
23
|
+
+-------------------+
|
|
24
|
+
| TSService |
|
|
25
|
+
| (AST + Types) |
|
|
26
|
+
+---------+---------+
|
|
27
|
+
|
|
|
28
|
+
v
|
|
29
|
+
+-------------------+
|
|
30
|
+
| scanSource |
|
|
31
|
+
| (core analyzer) |
|
|
32
|
+
+----+------+-------+
|
|
33
|
+
| |
|
|
34
|
+
| |
|
|
35
|
+
v v
|
|
36
|
+
+----------------+----------------+
|
|
37
|
+
| |
|
|
38
|
+
+-------------------+ +-----------------------+
|
|
39
|
+
| Function Wrappers | | Component Wrappers |
|
|
40
|
+
+-------------------+ +-----------------------+
|
|
41
|
+
| |
|
|
42
|
+
+---------------+-----------------+
|
|
43
|
+
|
|
|
44
|
+
v
|
|
45
|
+
+-------------------+
|
|
46
|
+
| resolveNodeValue |
|
|
47
|
+
| (extract values) |
|
|
48
|
+
+---------+---------+
|
|
49
|
+
|
|
|
50
|
+
v
|
|
51
|
+
+-------------------+
|
|
52
|
+
| EventraEngine |
|
|
53
|
+
| (orchestration) |
|
|
54
|
+
+---------+---------+
|
|
55
|
+
|
|
|
56
|
+
v
|
|
57
|
+
+-------------------+
|
|
58
|
+
| CLI (sync/check) |
|
|
59
|
+
+-------------------+
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Modules
|
|
65
|
+
|
|
66
|
+
### Parser
|
|
67
|
+
Extracts JS from any framework (Vue, Svelte, Astro, HTML).
|
|
68
|
+
|
|
69
|
+
### TSService
|
|
70
|
+
Provides TypeScript AST and type resolution.
|
|
71
|
+
|
|
72
|
+
### Scanner
|
|
73
|
+
Finds:
|
|
74
|
+
- track() calls
|
|
75
|
+
- wrappers
|
|
76
|
+
- values
|
|
77
|
+
|
|
78
|
+
### Engine
|
|
79
|
+
Handles:
|
|
80
|
+
- caching
|
|
81
|
+
- dependency graph
|
|
82
|
+
- incremental updates
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Goal
|
|
87
|
+
|
|
88
|
+
Static analytics extraction without runtime.
|
|
@@ -5,153 +5,54 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.resolveFunctionFromCall = resolveFunctionFromCall;
|
|
7
7
|
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
-
|
|
9
|
-
function isFunctionLike(node) {
|
|
8
|
+
function isFn(node) {
|
|
10
9
|
return (typescript_1.default.isFunctionDeclaration(node) ||
|
|
11
10
|
typescript_1.default.isMethodDeclaration(node) ||
|
|
12
|
-
typescript_1.default.isConstructorDeclaration(node) ||
|
|
13
11
|
typescript_1.default.isFunctionExpression(node) ||
|
|
14
12
|
typescript_1.default.isArrowFunction(node));
|
|
15
13
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (!symbol)
|
|
14
|
+
function resolveFromSymbol(symbol, checker, seen = new Set()) {
|
|
15
|
+
if (seen.has(symbol))
|
|
19
16
|
return null;
|
|
20
|
-
|
|
21
|
-
return null;
|
|
22
|
-
if (depth > 10)
|
|
23
|
-
return null;
|
|
24
|
-
visited.add(symbol);
|
|
25
|
-
// Alias unwrap (import/export)
|
|
17
|
+
seen.add(symbol);
|
|
26
18
|
if (symbol.flags & typescript_1.default.SymbolFlags.Alias) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return decl;
|
|
41
|
-
}
|
|
42
|
-
// VARIABLE → FUNCTION const fn = () => {}
|
|
43
|
-
if (typescript_1.default.isVariableDeclaration(decl) && decl.initializer) {
|
|
44
|
-
if (isFunctionLike(decl.initializer)) {
|
|
45
|
-
return decl.initializer;
|
|
46
|
-
}
|
|
47
|
-
const innerSymbol = checker.getSymbolAtLocation(decl.initializer);
|
|
48
|
-
if (innerSymbol && innerSymbol !== symbol) {
|
|
49
|
-
const resolved = resolveFromSymbol(innerSymbol, checker, visited, depth + 1);
|
|
50
|
-
if (resolved)
|
|
51
|
-
return resolved;
|
|
19
|
+
return resolveFromSymbol(checker.getAliasedSymbol(symbol), checker, seen);
|
|
20
|
+
}
|
|
21
|
+
for (const d of symbol.getDeclarations() ?? []) {
|
|
22
|
+
if (isFn(d))
|
|
23
|
+
return d;
|
|
24
|
+
if (typescript_1.default.isVariableDeclaration(d) && d.initializer) {
|
|
25
|
+
if (isFn(d.initializer))
|
|
26
|
+
return d.initializer;
|
|
27
|
+
const s = checker.getSymbolAtLocation(d.initializer);
|
|
28
|
+
if (s) {
|
|
29
|
+
const r = resolveFromSymbol(s, checker, seen);
|
|
30
|
+
if (r)
|
|
31
|
+
return r;
|
|
52
32
|
}
|
|
53
33
|
}
|
|
54
|
-
// CLASS METHOD
|
|
55
|
-
if (typescript_1.default.isMethodDeclaration(decl)) {
|
|
56
|
-
return decl;
|
|
57
|
-
}
|
|
58
|
-
// interface / type method
|
|
59
|
-
if (typescript_1.default.isMethodSignature(decl)) {
|
|
60
|
-
const parent = decl.parent;
|
|
61
|
-
if (typescript_1.default.isInterfaceDeclaration(parent) ||
|
|
62
|
-
typescript_1.default.isTypeLiteralNode(parent)) {
|
|
63
|
-
const type = checker.getTypeAtLocation(parent);
|
|
64
|
-
const props = type.getProperties();
|
|
65
|
-
for (const prop of props) {
|
|
66
|
-
const resolved = resolveFromSymbol(prop, checker, visited, depth + 1);
|
|
67
|
-
if (resolved)
|
|
68
|
-
return resolved;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
// fallback recursion
|
|
73
|
-
const inner = checker.getSymbolAtLocation(decl);
|
|
74
|
-
if (inner && inner !== symbol) {
|
|
75
|
-
const resolved = resolveFromSymbol(inner, checker, visited, depth + 1);
|
|
76
|
-
if (resolved)
|
|
77
|
-
return resolved;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
// Exports (re-export)
|
|
81
|
-
const exports = symbol.exports;
|
|
82
|
-
if (exports) {
|
|
83
|
-
for (const exp of exports.values()) {
|
|
84
|
-
const resolved = resolveFromSymbol(exp, checker, visited, depth + 1);
|
|
85
|
-
if (resolved)
|
|
86
|
-
return resolved;
|
|
87
|
-
}
|
|
88
34
|
}
|
|
89
35
|
return null;
|
|
90
36
|
}
|
|
91
|
-
// MAIN FUNCTION
|
|
92
37
|
function resolveFunctionFromCall(expr, checker) {
|
|
93
|
-
//
|
|
38
|
+
// foo.bar()
|
|
94
39
|
if (typescript_1.default.isPropertyAccessExpression(expr)) {
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
catch { }
|
|
101
|
-
}
|
|
102
|
-
if (symbol) {
|
|
103
|
-
const resolved = resolveFromSymbol(symbol, checker);
|
|
104
|
-
if (resolved)
|
|
105
|
-
return resolved;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
// obj["method"]()
|
|
109
|
-
if (typescript_1.default.isElementAccessExpression(expr)) {
|
|
110
|
-
const symbol = checker.getSymbolAtLocation(expr.argumentExpression);
|
|
111
|
-
if (symbol) {
|
|
112
|
-
const resolved = resolveFromSymbol(symbol, checker);
|
|
113
|
-
if (resolved)
|
|
114
|
-
return resolved;
|
|
40
|
+
const s = checker.getSymbolAtLocation(expr.name);
|
|
41
|
+
if (s) {
|
|
42
|
+
const r = resolveFromSymbol(s, checker);
|
|
43
|
+
if (r)
|
|
44
|
+
return r;
|
|
115
45
|
}
|
|
116
46
|
}
|
|
117
|
-
//
|
|
47
|
+
// direct call
|
|
118
48
|
const type = checker.getTypeAtLocation(expr);
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (typescript_1.default.isMethodSignature(decl)) {
|
|
128
|
-
const symbol = checker.getSymbolAtLocation(decl.name);
|
|
129
|
-
if (symbol) {
|
|
130
|
-
const resolved = resolveFromSymbol(symbol, checker);
|
|
131
|
-
if (resolved)
|
|
132
|
-
return resolved;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
// Identifier fallback
|
|
137
|
-
if (typescript_1.default.isIdentifier(expr)) {
|
|
138
|
-
let symbol = checker.getSymbolAtLocation(expr);
|
|
139
|
-
if (symbol && (symbol.flags & typescript_1.default.SymbolFlags.Alias)) {
|
|
140
|
-
try {
|
|
141
|
-
symbol = checker.getAliasedSymbol(symbol);
|
|
142
|
-
}
|
|
143
|
-
catch { }
|
|
144
|
-
}
|
|
145
|
-
if (symbol) {
|
|
146
|
-
const resolved = resolveFromSymbol(symbol, checker);
|
|
147
|
-
if (resolved)
|
|
148
|
-
return resolved;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
// LAST fallback
|
|
152
|
-
const symbol = checker.getSymbolAtLocation(expr);
|
|
153
|
-
if (symbol) {
|
|
154
|
-
return resolveFromSymbol(symbol, checker);
|
|
155
|
-
}
|
|
49
|
+
for (const sig of type.getCallSignatures()) {
|
|
50
|
+
const d = sig.getDeclaration();
|
|
51
|
+
if (d && isFn(d))
|
|
52
|
+
return d;
|
|
53
|
+
}
|
|
54
|
+
const s = checker.getSymbolAtLocation(expr);
|
|
55
|
+
if (s)
|
|
56
|
+
return resolveFromSymbol(s, checker);
|
|
156
57
|
return null;
|
|
157
58
|
}
|
|
@@ -15,9 +15,6 @@ class TSService {
|
|
|
15
15
|
compilerOptions;
|
|
16
16
|
baseUrl;
|
|
17
17
|
paths;
|
|
18
|
-
usage = new Map();
|
|
19
|
-
tick = 0;
|
|
20
|
-
MAX_FILES = 2000;
|
|
21
18
|
constructor(root) {
|
|
22
19
|
this.root = root;
|
|
23
20
|
const configPath = typescript_1.default.findConfigFile(root, typescript_1.default.sys.fileExists, "tsconfig.json");
|
|
@@ -49,11 +46,12 @@ class TSService {
|
|
|
49
46
|
this.compilerOptions = compilerOptions;
|
|
50
47
|
this.baseUrl = baseUrl;
|
|
51
48
|
this.paths = paths;
|
|
49
|
+
const allFiles = typescript_1.default.sys.readDirectory(root, [".ts", ".tsx", ".js", ".jsx"], undefined, undefined);
|
|
50
|
+
for (const f of allFiles) {
|
|
51
|
+
this.fileNames.add(this.normalize(f));
|
|
52
|
+
}
|
|
52
53
|
const host = {
|
|
53
54
|
getScriptFileNames: () => {
|
|
54
|
-
if (this.fileNames.size === 0) {
|
|
55
|
-
return typescript_1.default.sys.readDirectory(this.root, [".ts", ".tsx", ".js", ".jsx"], undefined, undefined);
|
|
56
|
-
}
|
|
57
55
|
return Array.from(this.fileNames);
|
|
58
56
|
},
|
|
59
57
|
getScriptVersion: (file) => {
|
|
@@ -62,11 +60,12 @@ class TSService {
|
|
|
62
60
|
},
|
|
63
61
|
getScriptSnapshot: (file) => {
|
|
64
62
|
file = this.normalize(file);
|
|
63
|
+
// из памяти
|
|
65
64
|
const f = this.files.get(file);
|
|
66
65
|
if (f) {
|
|
67
|
-
this.touch(file);
|
|
68
66
|
return typescript_1.default.ScriptSnapshot.fromString(f.content);
|
|
69
67
|
}
|
|
68
|
+
// virtual TSX (vue/svelte/astro)
|
|
70
69
|
if (file.endsWith(".tsx")) {
|
|
71
70
|
const original = file.replace(/\.tsx$/, "");
|
|
72
71
|
if (fs_1.default.existsSync(original)) {
|
|
@@ -76,8 +75,6 @@ class TSService {
|
|
|
76
75
|
version: 1,
|
|
77
76
|
});
|
|
78
77
|
this.fileNames.add(file);
|
|
79
|
-
this.touch(file);
|
|
80
|
-
this.evictIfNeeded();
|
|
81
78
|
return typescript_1.default.ScriptSnapshot.fromString(content);
|
|
82
79
|
}
|
|
83
80
|
}
|
|
@@ -89,8 +86,6 @@ class TSService {
|
|
|
89
86
|
version: 1,
|
|
90
87
|
});
|
|
91
88
|
this.fileNames.add(file);
|
|
92
|
-
this.touch(file);
|
|
93
|
-
this.evictIfNeeded();
|
|
94
89
|
return typescript_1.default.ScriptSnapshot.fromString(content);
|
|
95
90
|
}
|
|
96
91
|
}
|
|
@@ -112,35 +107,12 @@ class TSService {
|
|
|
112
107
|
};
|
|
113
108
|
this.service = typescript_1.default.createLanguageService(host);
|
|
114
109
|
}
|
|
115
|
-
// INTERNAL
|
|
116
110
|
normalize(file) {
|
|
117
111
|
return path_1.default.resolve(file).replace(/\\/g, "/");
|
|
118
112
|
}
|
|
119
|
-
touch(file) {
|
|
120
|
-
this.tick++;
|
|
121
|
-
this.usage.set(file, this.tick);
|
|
122
|
-
}
|
|
123
|
-
evictIfNeeded() {
|
|
124
|
-
if (this.fileNames.size <= this.MAX_FILES)
|
|
125
|
-
return;
|
|
126
|
-
let oldest = null;
|
|
127
|
-
let oldestTick = Infinity;
|
|
128
|
-
for (const f of this.fileNames) {
|
|
129
|
-
const t = this.usage.get(f) ?? 0;
|
|
130
|
-
if (t < oldestTick) {
|
|
131
|
-
oldestTick = t;
|
|
132
|
-
oldest = f;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
if (oldest) {
|
|
136
|
-
this.files.delete(oldest);
|
|
137
|
-
this.fileNames.delete(oldest);
|
|
138
|
-
this.usage.delete(oldest);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
113
|
ensureProgram() {
|
|
142
114
|
try {
|
|
143
|
-
this.service.getProgram()
|
|
115
|
+
this.service.getProgram();
|
|
144
116
|
}
|
|
145
117
|
catch { }
|
|
146
118
|
}
|
|
@@ -153,15 +125,12 @@ class TSService {
|
|
|
153
125
|
version: prev ? prev.version + 1 : 1,
|
|
154
126
|
});
|
|
155
127
|
this.fileNames.add(file);
|
|
156
|
-
this.touch(file);
|
|
157
|
-
this.evictIfNeeded();
|
|
158
128
|
this.ensureProgram();
|
|
159
129
|
}
|
|
160
130
|
removeFile(file) {
|
|
161
131
|
file = this.normalize(file);
|
|
162
132
|
this.files.delete(file);
|
|
163
133
|
this.fileNames.delete(file);
|
|
164
|
-
this.usage.delete(file);
|
|
165
134
|
this.ensureProgram();
|
|
166
135
|
}
|
|
167
136
|
getProgram() {
|
package/dist/engine/resolver.js
CHANGED
|
@@ -6,32 +6,30 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.resolveNodeValue = resolveNodeValue;
|
|
7
7
|
const typescript_1 = __importDefault(require("typescript"));
|
|
8
8
|
const exportResolver_1 = require("./exportResolver");
|
|
9
|
+
const callResolver_1 = require("./callResolver");
|
|
9
10
|
function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
10
|
-
if (seen.has(node))
|
|
11
|
+
if (seen.has(node))
|
|
11
12
|
return { values: [], dynamic: true };
|
|
12
|
-
}
|
|
13
13
|
seen.add(node);
|
|
14
|
-
//
|
|
14
|
+
// param passthrough
|
|
15
15
|
if (typescript_1.default.isIdentifier(node) && paramMap?.has(node.text)) {
|
|
16
16
|
return resolveNodeValue(paramMap.get(node.text), checker, paramMap, seen);
|
|
17
17
|
}
|
|
18
|
-
//
|
|
18
|
+
// string
|
|
19
19
|
if (typescript_1.default.isStringLiteral(node)) {
|
|
20
20
|
return { values: [node.text], dynamic: false };
|
|
21
21
|
}
|
|
22
|
-
//
|
|
22
|
+
// template
|
|
23
23
|
if (typescript_1.default.isTemplateExpression(node)) {
|
|
24
24
|
let results = node.head.text ? [node.head.text] : [""];
|
|
25
25
|
for (const span of node.templateSpans) {
|
|
26
|
-
const
|
|
27
|
-
results = results.flatMap(
|
|
28
|
-
|
|
29
|
-
: [r + "*"]);
|
|
30
|
-
results = results.map(r => r + span.literal.text);
|
|
26
|
+
const r = resolveNodeValue(span.expression, checker, paramMap, seen);
|
|
27
|
+
results = results.flatMap(s => r.values.length ? r.values.map(v => s + v) : [s + "*"]);
|
|
28
|
+
results = results.map(s => s + span.literal.text);
|
|
31
29
|
}
|
|
32
30
|
return { values: results, dynamic: true };
|
|
33
31
|
}
|
|
34
|
-
//
|
|
32
|
+
// ternary
|
|
35
33
|
if (typescript_1.default.isConditionalExpression(node)) {
|
|
36
34
|
const a = resolveNodeValue(node.whenTrue, checker, paramMap, seen);
|
|
37
35
|
const b = resolveNodeValue(node.whenFalse, checker, paramMap, seen);
|
|
@@ -40,99 +38,112 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
40
38
|
dynamic: true,
|
|
41
39
|
};
|
|
42
40
|
}
|
|
43
|
-
//
|
|
41
|
+
// object (event/name priority)
|
|
44
42
|
if (typescript_1.default.isObjectLiteralExpression(node)) {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
for (const p of node.properties) {
|
|
44
|
+
if (typescript_1.default.isPropertyAssignment(p)) {
|
|
45
|
+
const key = p.name.getText();
|
|
46
|
+
if (key === "event" || key === "name") {
|
|
47
|
+
return resolveNodeValue(p.initializer, checker, paramMap, seen);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const vals = [];
|
|
52
|
+
for (const p of node.properties) {
|
|
53
|
+
if (!typescript_1.default.isPropertyAssignment(p))
|
|
48
54
|
continue;
|
|
49
|
-
const
|
|
50
|
-
|
|
55
|
+
const r = resolveNodeValue(p.initializer, checker, paramMap, seen);
|
|
56
|
+
vals.push(...r.values);
|
|
51
57
|
}
|
|
52
|
-
return {
|
|
53
|
-
values: [...new Set(values)],
|
|
54
|
-
dynamic: true,
|
|
55
|
-
};
|
|
58
|
+
return { values: [...new Set(vals)], dynamic: true };
|
|
56
59
|
}
|
|
57
|
-
//
|
|
60
|
+
// array
|
|
58
61
|
if (typescript_1.default.isArrayLiteralExpression(node)) {
|
|
59
|
-
const
|
|
62
|
+
const vals = [];
|
|
60
63
|
for (const el of node.elements) {
|
|
61
|
-
const
|
|
62
|
-
|
|
64
|
+
const r = resolveNodeValue(el, checker, paramMap, seen);
|
|
65
|
+
vals.push(...r.values);
|
|
63
66
|
}
|
|
67
|
+
return { values: [...new Set(vals)], dynamic: true };
|
|
68
|
+
}
|
|
69
|
+
// concat
|
|
70
|
+
if (typescript_1.default.isBinaryExpression(node) &&
|
|
71
|
+
node.operatorToken.kind === typescript_1.default.SyntaxKind.PlusToken) {
|
|
72
|
+
const l = resolveNodeValue(node.left, checker, paramMap, seen);
|
|
73
|
+
const r = resolveNodeValue(node.right, checker, paramMap, seen);
|
|
64
74
|
return {
|
|
65
|
-
values:
|
|
75
|
+
values: l.values.flatMap(a => r.values.length ? r.values.map(b => a + b) : [a + "*"]),
|
|
66
76
|
dynamic: true,
|
|
67
77
|
};
|
|
68
78
|
}
|
|
69
|
-
//
|
|
70
|
-
if (typescript_1.default.isBinaryExpression(node)) {
|
|
71
|
-
if (node.operatorToken.kind === typescript_1.default.SyntaxKind.PlusToken) {
|
|
72
|
-
const left = resolveNodeValue(node.left, checker, paramMap, seen);
|
|
73
|
-
const right = resolveNodeValue(node.right, checker, paramMap, seen);
|
|
74
|
-
return {
|
|
75
|
-
values: left.values.flatMap(l => right.values.length
|
|
76
|
-
? right.values.map(r => l + r)
|
|
77
|
-
: [l + "*"]),
|
|
78
|
-
dynamic: true,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
// IDENTIFIER
|
|
79
|
+
// identifier (const / enum)
|
|
83
80
|
if (typescript_1.default.isIdentifier(node)) {
|
|
84
|
-
let
|
|
85
|
-
if (!
|
|
81
|
+
let s = checker.getSymbolAtLocation(node);
|
|
82
|
+
if (!s)
|
|
86
83
|
return { values: [], dynamic: true };
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return resolveNodeValue(decl.initializer, checker, paramMap, seen);
|
|
84
|
+
s = (0, exportResolver_1.resolveExportedSymbol)(s, checker) ?? s;
|
|
85
|
+
for (const d of s.getDeclarations() ?? []) {
|
|
86
|
+
if (typescript_1.default.isVariableDeclaration(d) && d.initializer) {
|
|
87
|
+
return resolveNodeValue(d.initializer, checker, paramMap, seen);
|
|
92
88
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (typescript_1.default.isStringLiteral(decl.initializer)) {
|
|
96
|
-
return {
|
|
97
|
-
values: [decl.initializer.text],
|
|
98
|
-
dynamic: false,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
89
|
+
if (typescript_1.default.isEnumMember(d) && d.initializer && typescript_1.default.isStringLiteral(d.initializer)) {
|
|
90
|
+
return { values: [d.initializer.text], dynamic: false };
|
|
101
91
|
}
|
|
102
92
|
}
|
|
103
93
|
return { values: [], dynamic: true };
|
|
104
94
|
}
|
|
105
|
-
// PROPERTY ACCESS (
|
|
95
|
+
// PROPERTY ACCESS (OBJECT + ENUM)
|
|
106
96
|
if (typescript_1.default.isPropertyAccessExpression(node)) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (typescript_1.default.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
97
|
+
const obj = node.expression;
|
|
98
|
+
const prop = node.name.text;
|
|
99
|
+
// object literal lookup
|
|
100
|
+
if (typescript_1.default.isIdentifier(obj)) {
|
|
101
|
+
const sym = checker.getSymbolAtLocation(obj);
|
|
102
|
+
if (sym) {
|
|
103
|
+
const s = (0, exportResolver_1.resolveExportedSymbol)(sym, checker) ?? sym;
|
|
104
|
+
for (const d of s.getDeclarations() ?? []) {
|
|
105
|
+
if (typescript_1.default.isVariableDeclaration(d) &&
|
|
106
|
+
d.initializer &&
|
|
107
|
+
typescript_1.default.isObjectLiteralExpression(d.initializer)) {
|
|
108
|
+
for (const p of d.initializer.properties) {
|
|
109
|
+
if (typescript_1.default.isPropertyAssignment(p) &&
|
|
110
|
+
p.name.getText() === prop) {
|
|
111
|
+
return resolveNodeValue(p.initializer, checker, paramMap, seen);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
120
114
|
}
|
|
121
115
|
}
|
|
122
116
|
}
|
|
123
117
|
}
|
|
118
|
+
// enum fallback
|
|
119
|
+
const sym = checker.getSymbolAtLocation(node);
|
|
120
|
+
if (sym) {
|
|
121
|
+
let s = (0, exportResolver_1.resolveExportedSymbol)(sym, checker) ?? sym;
|
|
122
|
+
if (s.flags & typescript_1.default.SymbolFlags.Alias)
|
|
123
|
+
s = checker.getAliasedSymbol(s);
|
|
124
|
+
for (const d of s.getDeclarations() ?? []) {
|
|
125
|
+
if (typescript_1.default.isEnumMember(d) && d.initializer && typescript_1.default.isStringLiteral(d.initializer)) {
|
|
126
|
+
return { values: [d.initializer.text], dynamic: false };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
124
130
|
return { values: [], dynamic: true };
|
|
125
131
|
}
|
|
126
|
-
// CALL
|
|
132
|
+
// CALL (unwrap + dive into wrapper body)
|
|
127
133
|
if (typescript_1.default.isCallExpression(node)) {
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
134
|
+
const vals = [];
|
|
135
|
+
// args
|
|
136
|
+
for (const a of node.arguments) {
|
|
137
|
+
const r = resolveNodeValue(a, checker, paramMap, seen);
|
|
138
|
+
vals.push(...r.values);
|
|
139
|
+
}
|
|
140
|
+
// dive into called function (wrapper support)
|
|
141
|
+
const fn = (0, callResolver_1.resolveFunctionFromCall)(node.expression, checker);
|
|
142
|
+
if (fn?.body) {
|
|
143
|
+
const r = resolveNodeValue(fn.body, checker, paramMap, seen);
|
|
144
|
+
vals.push(...r.values);
|
|
132
145
|
}
|
|
133
|
-
return values
|
|
134
|
-
? { values, dynamic: true }
|
|
135
|
-
: { values: [], dynamic: true };
|
|
146
|
+
return { values: [...new Set(vals)], dynamic: true };
|
|
136
147
|
}
|
|
137
148
|
return { values: [], dynamic: true };
|
|
138
149
|
}
|