@eventra_dev/eventra-cli 0.1.25 → 0.1.27
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/README.md +62 -50
- package/dist/commands/watch.js +41 -23
- package/dist/engine/callResolver.js +52 -4
- package/dist/engine/engine.js +63 -31
- package/dist/engine/exportResolver.js +16 -4
- package/dist/engine/functionAnalyzer.js +66 -13
- package/dist/engine/graph.js +40 -4
- package/dist/engine/languageService.js +83 -20
- package/dist/engine/resolver.js +29 -21
- package/dist/engine/scanner.js +57 -46
- package/dist/engine/trackingDetector.js +68 -0
- package/dist/utils/processFile.js +0 -9
- package/dist/utils/universal.js +25 -87
- package/package.json +1 -1
- package/src/commands/watch.ts +45 -25
- package/src/engine/callResolver.ts +77 -6
- package/src/engine/engine.ts +77 -32
- package/src/engine/exportResolver.ts +22 -5
- package/src/engine/functionAnalyzer.ts +76 -16
- package/src/engine/graph.ts +45 -6
- package/src/engine/languageService.ts +100 -29
- package/src/engine/resolver.ts +36 -27
- package/src/engine/scanner.ts +72 -50
- package/src/engine/trackingDetector.ts +94 -0
- package/src/types.ts +0 -3
- package/src/utils/processFile.ts +0 -9
- package/src/utils/universal.ts +26 -102
|
@@ -10,19 +10,81 @@ function findTrackParamIndex(fn) {
|
|
|
10
10
|
fn.parameters.forEach((p, i) => {
|
|
11
11
|
if (typescript_1.default.isIdentifier(p.name)) {
|
|
12
12
|
paramIndex.set(p.name.text, i);
|
|
13
|
+
// default param: (name = "x")
|
|
14
|
+
if (p.initializer && typescript_1.default.isStringLiteral(p.initializer)) {
|
|
15
|
+
if (i === 0)
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
13
18
|
}
|
|
14
19
|
});
|
|
15
20
|
let result = null;
|
|
21
|
+
function unwrap(node) {
|
|
22
|
+
// as / parentheses
|
|
23
|
+
while (typescript_1.default.isAsExpression(node) ||
|
|
24
|
+
typescript_1.default.isParenthesizedExpression(node)) {
|
|
25
|
+
node = node.expression;
|
|
26
|
+
}
|
|
27
|
+
return node;
|
|
28
|
+
}
|
|
29
|
+
function checkArg(arg) {
|
|
30
|
+
arg = unwrap(arg);
|
|
31
|
+
// identifier → param
|
|
32
|
+
if (typescript_1.default.isIdentifier(arg)) {
|
|
33
|
+
const idx = paramIndex.get(arg.text);
|
|
34
|
+
if (idx !== undefined) {
|
|
35
|
+
result = idx;
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// string literal
|
|
40
|
+
if (typescript_1.default.isStringLiteral(arg)) {
|
|
41
|
+
result = 0;
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
// template `${name}`
|
|
45
|
+
if (typescript_1.default.isTemplateExpression(arg)) {
|
|
46
|
+
for (const span of arg.templateSpans) {
|
|
47
|
+
if (typescript_1.default.isIdentifier(span.expression)) {
|
|
48
|
+
const idx = paramIndex.get(span.expression.text);
|
|
49
|
+
if (idx !== undefined) {
|
|
50
|
+
result = idx;
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
result = 0;
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
// object { event: name }
|
|
59
|
+
if (typescript_1.default.isObjectLiteralExpression(arg)) {
|
|
60
|
+
for (const prop of arg.properties) {
|
|
61
|
+
if (!typescript_1.default.isPropertyAssignment(prop))
|
|
62
|
+
continue;
|
|
63
|
+
const name = prop.name.getText();
|
|
64
|
+
if (["event", "name", "type"].includes(name)) {
|
|
65
|
+
return checkArg(prop.initializer);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// call: String(name)
|
|
70
|
+
if (typescript_1.default.isCallExpression(arg)) {
|
|
71
|
+
for (const inner of arg.arguments) {
|
|
72
|
+
if (checkArg(inner))
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
16
78
|
function visit(node) {
|
|
79
|
+
if (result !== null)
|
|
80
|
+
return;
|
|
17
81
|
if (typescript_1.default.isCallExpression(node)) {
|
|
18
82
|
let isTrackCall = false;
|
|
19
83
|
if (typescript_1.default.isPropertyAccessExpression(node.expression)) {
|
|
20
|
-
|
|
21
|
-
if (method === "track") {
|
|
84
|
+
if (node.expression.name.text === "track") {
|
|
22
85
|
isTrackCall = true;
|
|
23
86
|
}
|
|
24
87
|
}
|
|
25
|
-
// fallback
|
|
26
88
|
if (typescript_1.default.isIdentifier(node.expression)) {
|
|
27
89
|
if (node.expression.text === "track") {
|
|
28
90
|
isTrackCall = true;
|
|
@@ -30,17 +92,8 @@ function findTrackParamIndex(fn) {
|
|
|
30
92
|
}
|
|
31
93
|
if (isTrackCall) {
|
|
32
94
|
for (const arg of node.arguments) {
|
|
33
|
-
if (
|
|
34
|
-
const idx = paramIndex.get(arg.text);
|
|
35
|
-
if (idx !== undefined) {
|
|
36
|
-
result = idx;
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (typescript_1.default.isStringLiteral(arg)) {
|
|
41
|
-
result = 0;
|
|
95
|
+
if (checkArg(arg))
|
|
42
96
|
return;
|
|
43
|
-
}
|
|
44
97
|
}
|
|
45
98
|
}
|
|
46
99
|
}
|
package/dist/engine/graph.js
CHANGED
|
@@ -18,13 +18,16 @@ class DependencyGraph {
|
|
|
18
18
|
this.paths = paths;
|
|
19
19
|
}
|
|
20
20
|
normalize(file) {
|
|
21
|
-
return path_1.default.resolve(file);
|
|
21
|
+
return path_1.default.resolve(file).replace(/\\/g, "/");
|
|
22
22
|
}
|
|
23
|
+
// MODULE RESOLVE
|
|
23
24
|
resolveModule(module, from) {
|
|
25
|
+
// relative import
|
|
24
26
|
if (module.startsWith(".")) {
|
|
25
27
|
const abs = path_1.default.resolve(path_1.default.dirname(from), module);
|
|
26
28
|
return this.resolveFile(abs);
|
|
27
29
|
}
|
|
30
|
+
// tsconfig paths
|
|
28
31
|
for (const key in this.paths) {
|
|
29
32
|
const pattern = key.replace(/\*/g, "(.*)");
|
|
30
33
|
const regex = new RegExp("^" + pattern + "$");
|
|
@@ -43,9 +46,19 @@ class DependencyGraph {
|
|
|
43
46
|
return resolved;
|
|
44
47
|
}
|
|
45
48
|
}
|
|
49
|
+
// node resolution (safe)
|
|
50
|
+
try {
|
|
51
|
+
const resolved = require.resolve(module, {
|
|
52
|
+
paths: [path_1.default.dirname(from)],
|
|
53
|
+
});
|
|
54
|
+
return this.normalize(resolved);
|
|
55
|
+
}
|
|
56
|
+
catch { }
|
|
57
|
+
// fallback
|
|
46
58
|
const abs = path_1.default.resolve(this.baseUrl, module);
|
|
47
59
|
return this.resolveFile(abs);
|
|
48
60
|
}
|
|
61
|
+
// FILE RESOLVE
|
|
49
62
|
resolveFile(base) {
|
|
50
63
|
if (this.fileCache.has(base)) {
|
|
51
64
|
return this.fileCache.get(base);
|
|
@@ -56,6 +69,12 @@ class DependencyGraph {
|
|
|
56
69
|
base + ".tsx",
|
|
57
70
|
base + ".js",
|
|
58
71
|
base + ".jsx",
|
|
72
|
+
base + ".mjs",
|
|
73
|
+
base + ".cjs",
|
|
74
|
+
base + ".d.ts",
|
|
75
|
+
base + ".vue",
|
|
76
|
+
base + ".svelte",
|
|
77
|
+
base + ".astro",
|
|
59
78
|
path_1.default.join(base, "index.ts"),
|
|
60
79
|
path_1.default.join(base, "index.tsx"),
|
|
61
80
|
path_1.default.join(base, "index.js"),
|
|
@@ -70,12 +89,22 @@ class DependencyGraph {
|
|
|
70
89
|
this.fileCache.set(base, null);
|
|
71
90
|
return null;
|
|
72
91
|
}
|
|
92
|
+
// UPDATE GRAPH
|
|
73
93
|
update(file, source) {
|
|
74
94
|
const normalizedFile = this.normalize(file);
|
|
95
|
+
for (const deps of this.reverse.values()) {
|
|
96
|
+
deps.delete(normalizedFile);
|
|
97
|
+
}
|
|
75
98
|
this.exports.set(normalizedFile, new Set());
|
|
76
99
|
for (const stmt of source.statements) {
|
|
100
|
+
// IMPORT
|
|
77
101
|
if (typescript_1.default.isImportDeclaration(stmt)) {
|
|
78
|
-
|
|
102
|
+
// ignore import type
|
|
103
|
+
if (stmt.importClause?.importKind === "type")
|
|
104
|
+
continue;
|
|
105
|
+
const module = stmt.moduleSpecifier
|
|
106
|
+
.getText()
|
|
107
|
+
.replace(/['"]/g, "");
|
|
79
108
|
const resolved = this.resolveModule(module, normalizedFile);
|
|
80
109
|
if (!resolved)
|
|
81
110
|
continue;
|
|
@@ -84,8 +113,13 @@ class DependencyGraph {
|
|
|
84
113
|
}
|
|
85
114
|
this.reverse.get(resolved).add(normalizedFile);
|
|
86
115
|
}
|
|
87
|
-
|
|
88
|
-
|
|
116
|
+
// EXPORT (re-export)
|
|
117
|
+
if (typescript_1.default.isExportDeclaration(stmt)) {
|
|
118
|
+
if (!stmt.moduleSpecifier)
|
|
119
|
+
continue;
|
|
120
|
+
const module = stmt.moduleSpecifier
|
|
121
|
+
.getText()
|
|
122
|
+
.replace(/['"]/g, "");
|
|
89
123
|
const resolved = this.resolveModule(module, normalizedFile);
|
|
90
124
|
if (!resolved)
|
|
91
125
|
continue;
|
|
@@ -97,6 +131,7 @@ class DependencyGraph {
|
|
|
97
131
|
}
|
|
98
132
|
}
|
|
99
133
|
}
|
|
134
|
+
// DEPENDENTS
|
|
100
135
|
getAllDependentsDeep(file) {
|
|
101
136
|
const start = this.normalize(file);
|
|
102
137
|
const visited = new Set();
|
|
@@ -116,6 +151,7 @@ class DependencyGraph {
|
|
|
116
151
|
walk(start);
|
|
117
152
|
return [...result];
|
|
118
153
|
}
|
|
154
|
+
// REMOVE
|
|
119
155
|
remove(file) {
|
|
120
156
|
const normalized = this.normalize(file);
|
|
121
157
|
this.reverse.delete(normalized);
|
|
@@ -12,20 +12,27 @@ class TSService {
|
|
|
12
12
|
files = new Map();
|
|
13
13
|
fileNames = new Set();
|
|
14
14
|
service;
|
|
15
|
-
compilerOptions
|
|
16
|
-
baseUrl
|
|
17
|
-
paths
|
|
15
|
+
compilerOptions;
|
|
16
|
+
baseUrl;
|
|
17
|
+
paths;
|
|
18
|
+
usage = new Map();
|
|
19
|
+
tick = 0;
|
|
20
|
+
MAX_FILES = 2000;
|
|
18
21
|
constructor(root) {
|
|
19
22
|
this.root = root;
|
|
20
23
|
const configPath = typescript_1.default.findConfigFile(root, typescript_1.default.sys.fileExists, "tsconfig.json");
|
|
21
24
|
let compilerOptions = {
|
|
22
25
|
allowJs: true,
|
|
23
|
-
jsx: typescript_1.default.JsxEmit.
|
|
26
|
+
jsx: typescript_1.default.JsxEmit.React,
|
|
27
|
+
jsxImportSource: "react",
|
|
24
28
|
moduleResolution: typescript_1.default.ModuleResolutionKind.Node16,
|
|
25
29
|
target: typescript_1.default.ScriptTarget.ESNext,
|
|
26
30
|
esModuleInterop: true,
|
|
27
31
|
allowSyntheticDefaultImports: true,
|
|
32
|
+
skipLibCheck: true,
|
|
28
33
|
};
|
|
34
|
+
let baseUrl = root;
|
|
35
|
+
let paths = {};
|
|
29
36
|
if (configPath) {
|
|
30
37
|
const configFile = typescript_1.default.readConfigFile(configPath, typescript_1.default.sys.readFile);
|
|
31
38
|
const parsed = typescript_1.default.parseJsonConfigFileContent(configFile.config, typescript_1.default.sys, root);
|
|
@@ -33,46 +40,104 @@ class TSService {
|
|
|
33
40
|
...compilerOptions,
|
|
34
41
|
...parsed.options,
|
|
35
42
|
};
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
paths = parsed.options.paths || {};
|
|
44
|
+
baseUrl = parsed.options.baseUrl
|
|
38
45
|
? path_1.default.resolve(root, parsed.options.baseUrl)
|
|
39
46
|
: root;
|
|
40
47
|
}
|
|
41
|
-
else {
|
|
42
|
-
this.baseUrl = root;
|
|
43
|
-
}
|
|
44
48
|
this.compilerOptions = compilerOptions;
|
|
49
|
+
this.baseUrl = baseUrl;
|
|
50
|
+
this.paths = paths;
|
|
45
51
|
const host = {
|
|
46
|
-
getScriptFileNames: () =>
|
|
47
|
-
|
|
52
|
+
getScriptFileNames: () => Array.from(this.fileNames),
|
|
53
|
+
getScriptVersion: (file) => {
|
|
54
|
+
file = this.normalize(file);
|
|
55
|
+
return this.files.get(file)?.version.toString() ?? "0";
|
|
48
56
|
},
|
|
49
|
-
getScriptVersion: (file) => this.files.get(file)?.version.toString() ?? "0",
|
|
50
57
|
getScriptSnapshot: (file) => {
|
|
58
|
+
file = this.normalize(file);
|
|
51
59
|
const f = this.files.get(file);
|
|
52
60
|
if (f) {
|
|
61
|
+
this.touch(file);
|
|
53
62
|
return typescript_1.default.ScriptSnapshot.fromString(f.content);
|
|
54
63
|
}
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
try {
|
|
65
|
+
if (fs_1.default.existsSync(file)) {
|
|
66
|
+
const content = fs_1.default.readFileSync(file, "utf-8");
|
|
67
|
+
this.files.set(file, {
|
|
68
|
+
content,
|
|
69
|
+
version: 1,
|
|
70
|
+
});
|
|
71
|
+
this.fileNames.add(file);
|
|
72
|
+
this.touch(file);
|
|
73
|
+
this.evictIfNeeded();
|
|
74
|
+
return typescript_1.default.ScriptSnapshot.fromString(content);
|
|
75
|
+
}
|
|
57
76
|
}
|
|
58
|
-
|
|
77
|
+
catch { }
|
|
78
|
+
// fallback
|
|
79
|
+
return typescript_1.default.ScriptSnapshot.fromString("");
|
|
59
80
|
},
|
|
60
81
|
getCurrentDirectory: () => this.root,
|
|
61
82
|
getCompilationSettings: () => this.compilerOptions,
|
|
62
83
|
getDefaultLibFileName: (opts) => typescript_1.default.getDefaultLibFilePath(opts),
|
|
63
|
-
readFile: typescript_1.default.sys.readFile,
|
|
64
84
|
fileExists: typescript_1.default.sys.fileExists,
|
|
85
|
+
readFile: typescript_1.default.sys.readFile,
|
|
65
86
|
readDirectory: typescript_1.default.sys.readDirectory,
|
|
66
87
|
};
|
|
67
88
|
this.service = typescript_1.default.createLanguageService(host);
|
|
68
89
|
}
|
|
90
|
+
// INTERNAL
|
|
91
|
+
normalize(file) {
|
|
92
|
+
return path_1.default.resolve(file).replace(/\\/g, "/");
|
|
93
|
+
}
|
|
94
|
+
touch(file) {
|
|
95
|
+
this.tick++;
|
|
96
|
+
this.usage.set(file, this.tick);
|
|
97
|
+
}
|
|
98
|
+
evictIfNeeded() {
|
|
99
|
+
if (this.fileNames.size <= this.MAX_FILES)
|
|
100
|
+
return;
|
|
101
|
+
let oldestFile = null;
|
|
102
|
+
let oldestTick = Infinity;
|
|
103
|
+
for (const f of this.fileNames) {
|
|
104
|
+
const t = this.usage.get(f) ?? 0;
|
|
105
|
+
if (t < oldestTick) {
|
|
106
|
+
oldestTick = t;
|
|
107
|
+
oldestFile = f;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (oldestFile) {
|
|
111
|
+
this.files.delete(oldestFile);
|
|
112
|
+
this.fileNames.delete(oldestFile);
|
|
113
|
+
this.usage.delete(oldestFile);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
ensureProgram() {
|
|
117
|
+
try {
|
|
118
|
+
this.service.getProgram();
|
|
119
|
+
}
|
|
120
|
+
catch { }
|
|
121
|
+
}
|
|
122
|
+
// PUBLIC API
|
|
69
123
|
updateFile(file, content) {
|
|
124
|
+
file = this.normalize(file);
|
|
70
125
|
const prev = this.files.get(file);
|
|
71
126
|
this.files.set(file, {
|
|
72
127
|
content,
|
|
73
128
|
version: prev ? prev.version + 1 : 1,
|
|
74
129
|
});
|
|
75
130
|
this.fileNames.add(file);
|
|
131
|
+
this.touch(file);
|
|
132
|
+
this.evictIfNeeded();
|
|
133
|
+
this.ensureProgram();
|
|
134
|
+
}
|
|
135
|
+
removeFile(file) {
|
|
136
|
+
file = this.normalize(file);
|
|
137
|
+
this.files.delete(file);
|
|
138
|
+
this.fileNames.delete(file);
|
|
139
|
+
this.usage.delete(file);
|
|
140
|
+
this.ensureProgram();
|
|
76
141
|
}
|
|
77
142
|
getProgram() {
|
|
78
143
|
return this.service.getProgram();
|
|
@@ -81,15 +146,13 @@ class TSService {
|
|
|
81
146
|
return this.getProgram()?.getTypeChecker();
|
|
82
147
|
}
|
|
83
148
|
getSourceFile(file) {
|
|
149
|
+
file = this.normalize(file);
|
|
84
150
|
return this.getProgram()?.getSourceFile(file);
|
|
85
151
|
}
|
|
86
152
|
getFileContent(file) {
|
|
153
|
+
file = this.normalize(file);
|
|
87
154
|
return this.files.get(file)?.content;
|
|
88
155
|
}
|
|
89
|
-
removeFile(file) {
|
|
90
|
-
this.files.delete(file);
|
|
91
|
-
this.fileNames.delete(file);
|
|
92
|
-
}
|
|
93
156
|
getModuleResolutionConfig() {
|
|
94
157
|
return {
|
|
95
158
|
baseUrl: this.baseUrl,
|
package/dist/engine/resolver.js
CHANGED
|
@@ -11,7 +11,7 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
11
11
|
return { values: [], dynamic: true };
|
|
12
12
|
}
|
|
13
13
|
seen.add(node);
|
|
14
|
-
//
|
|
14
|
+
// PARAM MAPPING
|
|
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
|
}
|
|
@@ -28,11 +28,14 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
28
28
|
values.push(...res.values);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
return {
|
|
31
|
+
return {
|
|
32
|
+
values: [...new Set(values)],
|
|
33
|
+
dynamic: true
|
|
34
|
+
};
|
|
32
35
|
}
|
|
33
36
|
// TEMPLATE
|
|
34
37
|
if (typescript_1.default.isTemplateExpression(node)) {
|
|
35
|
-
let results = [node.head.text];
|
|
38
|
+
let results = node.head.text ? [node.head.text] : [""];
|
|
36
39
|
for (const span of node.templateSpans) {
|
|
37
40
|
const res = resolveNodeValue(span.expression, checker, paramMap, seen);
|
|
38
41
|
if (res.values.length) {
|
|
@@ -59,16 +62,18 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
59
62
|
let symbol = checker.getSymbolAtLocation(node);
|
|
60
63
|
if (!symbol)
|
|
61
64
|
return { values: [], dynamic: true };
|
|
65
|
+
// INLINE FIRST
|
|
66
|
+
for (const decl of symbol.getDeclarations() ?? []) {
|
|
67
|
+
if (typescript_1.default.isVariableDeclaration(decl) && decl.initializer) {
|
|
68
|
+
return resolveNodeValue(decl.initializer, checker, paramMap, seen);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
62
71
|
// unwrap export
|
|
63
72
|
symbol = (0, exportResolver_1.resolveExportedSymbol)(symbol, checker) ?? symbol;
|
|
64
73
|
if (symbol.flags & typescript_1.default.SymbolFlags.Alias) {
|
|
65
74
|
symbol = checker.getAliasedSymbol(symbol);
|
|
66
75
|
}
|
|
67
|
-
// inline variable
|
|
68
76
|
for (const decl of symbol.getDeclarations() ?? []) {
|
|
69
|
-
if (typescript_1.default.isVariableDeclaration(decl) && decl.initializer) {
|
|
70
|
-
return resolveNodeValue(decl.initializer, checker, paramMap, seen);
|
|
71
|
-
}
|
|
72
77
|
if (typescript_1.default.isEnumMember(decl) && decl.initializer) {
|
|
73
78
|
if (typescript_1.default.isStringLiteral(decl.initializer)) {
|
|
74
79
|
return {
|
|
@@ -78,12 +83,12 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
78
83
|
}
|
|
79
84
|
}
|
|
80
85
|
}
|
|
81
|
-
// UNION TYPES
|
|
82
86
|
const type = checker.getTypeAtLocation(node);
|
|
87
|
+
// UNION
|
|
83
88
|
if (type.isUnion()) {
|
|
84
89
|
const values = [];
|
|
85
90
|
for (const t of type.types) {
|
|
86
|
-
if (t.
|
|
91
|
+
if (t.flags & typescript_1.default.TypeFlags.StringLiteral) {
|
|
87
92
|
values.push(t.value);
|
|
88
93
|
}
|
|
89
94
|
}
|
|
@@ -91,13 +96,16 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
91
96
|
return { values, dynamic: false };
|
|
92
97
|
}
|
|
93
98
|
}
|
|
94
|
-
//
|
|
95
|
-
if (type.
|
|
96
|
-
return {
|
|
99
|
+
// STRING LITERAL TYPE
|
|
100
|
+
if (type.flags & typescript_1.default.TypeFlags.StringLiteral) {
|
|
101
|
+
return {
|
|
102
|
+
values: [type.value],
|
|
103
|
+
dynamic: false
|
|
104
|
+
};
|
|
97
105
|
}
|
|
98
106
|
return { values: [], dynamic: true };
|
|
99
107
|
}
|
|
100
|
-
// PROPERTY ACCESS
|
|
108
|
+
// PROPERTY ACCESS
|
|
101
109
|
if (typescript_1.default.isPropertyAccessExpression(node)) {
|
|
102
110
|
const symbol = checker.getSymbolAtLocation(node);
|
|
103
111
|
if (symbol) {
|
|
@@ -116,14 +124,12 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
116
124
|
}
|
|
117
125
|
}
|
|
118
126
|
}
|
|
119
|
-
// constant enum / readonly
|
|
120
127
|
const constantValue = checker.getConstantValue(node);
|
|
121
128
|
if (typeof constantValue === "string") {
|
|
122
129
|
return { values: [constantValue], dynamic: false };
|
|
123
130
|
}
|
|
124
|
-
// type fallback
|
|
125
131
|
const type = checker.getTypeAtLocation(node);
|
|
126
|
-
if (type.
|
|
132
|
+
if (type.flags & typescript_1.default.TypeFlags.StringLiteral) {
|
|
127
133
|
return {
|
|
128
134
|
values: [type.value],
|
|
129
135
|
dynamic: false,
|
|
@@ -149,16 +155,16 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
149
155
|
}
|
|
150
156
|
}
|
|
151
157
|
}
|
|
152
|
-
|
|
158
|
+
// fallback
|
|
159
|
+
return resolveNodeValue(node.name, checker, paramMap, seen);
|
|
153
160
|
}
|
|
154
|
-
// ARRAY ACCESS
|
|
161
|
+
// ARRAY ACCESS
|
|
155
162
|
if (typescript_1.default.isElementAccessExpression(node)) {
|
|
156
163
|
const obj = resolveNodeValue(node.expression, checker, paramMap, seen);
|
|
157
164
|
if (!node.argumentExpression) {
|
|
158
165
|
return { values: obj.values, dynamic: true };
|
|
159
166
|
}
|
|
160
167
|
const index = resolveNodeValue(node.argumentExpression, checker, paramMap, seen);
|
|
161
|
-
// if index known
|
|
162
168
|
if (index.values.length === 1) {
|
|
163
169
|
const i = Number(index.values[0]);
|
|
164
170
|
if (!Number.isNaN(i) && obj.values[i] !== undefined) {
|
|
@@ -168,7 +174,6 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
168
174
|
};
|
|
169
175
|
}
|
|
170
176
|
}
|
|
171
|
-
// fallback → dynamic
|
|
172
177
|
return obj.values.length
|
|
173
178
|
? { values: obj.values, dynamic: true }
|
|
174
179
|
: { values: [], dynamic: true };
|
|
@@ -185,7 +190,10 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
185
190
|
values.push(...res.values);
|
|
186
191
|
}
|
|
187
192
|
}
|
|
188
|
-
return {
|
|
193
|
+
return {
|
|
194
|
+
values: [...new Set(values)],
|
|
195
|
+
dynamic: true
|
|
196
|
+
};
|
|
189
197
|
}
|
|
190
198
|
// BINARY ("btn_" + name)
|
|
191
199
|
if (typescript_1.default.isBinaryExpression(node)) {
|