@eventra_dev/eventra-cli 0.1.31 → 0.1.32
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/callResolver.js +56 -25
- package/dist/engine/languageService.js +36 -11
- package/dist/engine/scanner.js +74 -71
- package/dist/utils/universal.js +73 -21
- package/package.json +1 -1
- package/src/engine/callResolver.ts +61 -28
- package/src/engine/languageService.ts +50 -16
- package/src/engine/scanner.ts +83 -94
- package/src/utils/universal.ts +90 -21
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
2
|
|
|
3
|
+
// HELPERS
|
|
3
4
|
function isFunctionLike(
|
|
4
5
|
node: ts.Node
|
|
5
6
|
): node is ts.FunctionLikeDeclaration {
|
|
@@ -12,40 +13,39 @@ function isFunctionLike(
|
|
|
12
13
|
);
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
// symbol → function
|
|
15
17
|
function resolveFromSymbol(
|
|
16
18
|
symbol: ts.Symbol,
|
|
17
19
|
checker: ts.TypeChecker,
|
|
18
20
|
visited = new Set<ts.Symbol>(),
|
|
19
21
|
depth = 0
|
|
20
22
|
): ts.FunctionLikeDeclaration | null {
|
|
23
|
+
if (!symbol) return null;
|
|
21
24
|
if (visited.has(symbol)) return null;
|
|
22
|
-
if (depth >
|
|
25
|
+
if (depth > 10) return null;
|
|
23
26
|
|
|
24
27
|
visited.add(symbol);
|
|
25
28
|
|
|
26
|
-
// unwrap
|
|
29
|
+
// Alias unwrap (import/export)
|
|
27
30
|
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// re-export support
|
|
33
|
-
if ((symbol as any).exports) {
|
|
34
|
-
for (const exp of (symbol as any).exports.values()) {
|
|
35
|
-
const resolved = resolveFromSymbol(exp, checker, visited, depth + 1);
|
|
36
|
-
if (resolved) return resolved;
|
|
37
|
-
}
|
|
31
|
+
try {
|
|
32
|
+
const aliased = checker.getAliasedSymbol(symbol);
|
|
33
|
+
return resolveFromSymbol(aliased, checker, visited, depth + 1);
|
|
34
|
+
} catch {}
|
|
38
35
|
}
|
|
39
36
|
|
|
37
|
+
// Declarations
|
|
40
38
|
const decls = symbol.getDeclarations() ?? [];
|
|
41
39
|
|
|
42
40
|
for (const decl of decls) {
|
|
43
|
-
|
|
41
|
+
/**
|
|
42
|
+
* direct function
|
|
43
|
+
*/
|
|
44
44
|
if (isFunctionLike(decl)) {
|
|
45
45
|
return decl;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
// VARIABLE → FUNCTION
|
|
48
|
+
// VARIABLE → FUNCTION const fn = () => {}
|
|
49
49
|
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
50
50
|
if (isFunctionLike(decl.initializer)) {
|
|
51
51
|
return decl.initializer;
|
|
@@ -63,7 +63,12 @@ function resolveFromSymbol(
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
//
|
|
66
|
+
// CLASS METHOD
|
|
67
|
+
if (ts.isMethodDeclaration(decl)) {
|
|
68
|
+
return decl;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// interface / type method
|
|
67
72
|
if (ts.isMethodSignature(decl)) {
|
|
68
73
|
const parent = decl.parent;
|
|
69
74
|
|
|
@@ -71,14 +76,10 @@ function resolveFromSymbol(
|
|
|
71
76
|
ts.isInterfaceDeclaration(parent) ||
|
|
72
77
|
ts.isTypeLiteralNode(parent)
|
|
73
78
|
) {
|
|
74
|
-
const name = decl.name.getText();
|
|
75
|
-
|
|
76
79
|
const type = checker.getTypeAtLocation(parent);
|
|
77
80
|
const props = type.getProperties();
|
|
78
81
|
|
|
79
82
|
for (const prop of props) {
|
|
80
|
-
if (prop.name !== name) continue;
|
|
81
|
-
|
|
82
83
|
const resolved = resolveFromSymbol(
|
|
83
84
|
prop,
|
|
84
85
|
checker,
|
|
@@ -91,10 +92,24 @@ function resolveFromSymbol(
|
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
// fallback recursion
|
|
94
|
-
const
|
|
95
|
-
if (
|
|
95
|
+
const inner = checker.getSymbolAtLocation(decl);
|
|
96
|
+
if (inner && inner !== symbol) {
|
|
96
97
|
const resolved = resolveFromSymbol(
|
|
97
|
-
|
|
98
|
+
inner,
|
|
99
|
+
checker,
|
|
100
|
+
visited,
|
|
101
|
+
depth + 1
|
|
102
|
+
);
|
|
103
|
+
if (resolved) return resolved;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Exports (re-export)
|
|
108
|
+
const exports = (symbol as any).exports;
|
|
109
|
+
if (exports) {
|
|
110
|
+
for (const exp of exports.values()) {
|
|
111
|
+
const resolved = resolveFromSymbol(
|
|
112
|
+
exp,
|
|
98
113
|
checker,
|
|
99
114
|
visited,
|
|
100
115
|
depth + 1
|
|
@@ -106,17 +121,19 @@ function resolveFromSymbol(
|
|
|
106
121
|
return null;
|
|
107
122
|
}
|
|
108
123
|
|
|
124
|
+
// MAIN FUNCTION
|
|
109
125
|
export function resolveFunctionFromCall(
|
|
110
126
|
expr: ts.Expression,
|
|
111
127
|
checker: ts.TypeChecker
|
|
112
128
|
): ts.FunctionLikeDeclaration | null {
|
|
113
|
-
|
|
114
|
-
// tracker.track
|
|
129
|
+
// obj.method()
|
|
115
130
|
if (ts.isPropertyAccessExpression(expr)) {
|
|
116
131
|
let symbol = checker.getSymbolAtLocation(expr.name);
|
|
117
132
|
|
|
118
133
|
if (symbol && (symbol.flags & ts.SymbolFlags.Alias)) {
|
|
119
|
-
|
|
134
|
+
try {
|
|
135
|
+
symbol = checker.getAliasedSymbol(symbol);
|
|
136
|
+
} catch {}
|
|
120
137
|
}
|
|
121
138
|
|
|
122
139
|
if (symbol) {
|
|
@@ -125,7 +142,7 @@ export function resolveFunctionFromCall(
|
|
|
125
142
|
}
|
|
126
143
|
}
|
|
127
144
|
|
|
128
|
-
//
|
|
145
|
+
// obj["method"]()
|
|
129
146
|
if (ts.isElementAccessExpression(expr)) {
|
|
130
147
|
const symbol = checker.getSymbolAtLocation(expr.argumentExpression);
|
|
131
148
|
|
|
@@ -135,7 +152,7 @@ export function resolveFunctionFromCall(
|
|
|
135
152
|
}
|
|
136
153
|
}
|
|
137
154
|
|
|
138
|
-
//
|
|
155
|
+
// Call signatures
|
|
139
156
|
const type = checker.getTypeAtLocation(expr);
|
|
140
157
|
const signatures = type.getCallSignatures();
|
|
141
158
|
|
|
@@ -157,7 +174,23 @@ export function resolveFunctionFromCall(
|
|
|
157
174
|
}
|
|
158
175
|
}
|
|
159
176
|
|
|
160
|
-
// fallback
|
|
177
|
+
// Identifier fallback
|
|
178
|
+
if (ts.isIdentifier(expr)) {
|
|
179
|
+
let symbol = checker.getSymbolAtLocation(expr);
|
|
180
|
+
|
|
181
|
+
if (symbol && (symbol.flags & ts.SymbolFlags.Alias)) {
|
|
182
|
+
try {
|
|
183
|
+
symbol = checker.getAliasedSymbol(symbol);
|
|
184
|
+
} catch {}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (symbol) {
|
|
188
|
+
const resolved = resolveFromSymbol(symbol, checker);
|
|
189
|
+
if (resolved) return resolved;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// LAST fallback
|
|
161
194
|
const symbol = checker.getSymbolAtLocation(expr);
|
|
162
195
|
if (symbol) {
|
|
163
196
|
return resolveFromSymbol(symbol, checker);
|
|
@@ -7,9 +7,10 @@ export class TSService {
|
|
|
7
7
|
private fileNames = new Set<string>();
|
|
8
8
|
private service: ts.LanguageService;
|
|
9
9
|
|
|
10
|
-
private compilerOptions: ts.CompilerOptions;
|
|
11
|
-
private baseUrl: string;
|
|
12
|
-
private paths: Record<string, string[]>;
|
|
10
|
+
private readonly compilerOptions: ts.CompilerOptions;
|
|
11
|
+
private readonly baseUrl: string;
|
|
12
|
+
private readonly paths: Record<string, string[]>;
|
|
13
|
+
|
|
13
14
|
private usage = new Map<string, number>();
|
|
14
15
|
private tick = 0;
|
|
15
16
|
private MAX_FILES = 2000;
|
|
@@ -23,6 +24,7 @@ export class TSService {
|
|
|
23
24
|
|
|
24
25
|
let compilerOptions: ts.CompilerOptions = {
|
|
25
26
|
allowJs: true,
|
|
27
|
+
allowNonTsExtensions: true,
|
|
26
28
|
jsx: ts.JsxEmit.React,
|
|
27
29
|
jsxImportSource: "react",
|
|
28
30
|
moduleResolution: ts.ModuleResolutionKind.Node16,
|
|
@@ -60,7 +62,17 @@ export class TSService {
|
|
|
60
62
|
this.paths = paths;
|
|
61
63
|
|
|
62
64
|
const host: ts.LanguageServiceHost = {
|
|
63
|
-
getScriptFileNames: () =>
|
|
65
|
+
getScriptFileNames: () => {
|
|
66
|
+
if (this.fileNames.size === 0) {
|
|
67
|
+
return ts.sys.readDirectory(
|
|
68
|
+
this.root,
|
|
69
|
+
[".ts", ".tsx", ".js", ".jsx"],
|
|
70
|
+
undefined,
|
|
71
|
+
undefined
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
return Array.from(this.fileNames);
|
|
75
|
+
},
|
|
64
76
|
|
|
65
77
|
getScriptVersion: (file) => {
|
|
66
78
|
file = this.normalize(file);
|
|
@@ -69,13 +81,29 @@ export class TSService {
|
|
|
69
81
|
|
|
70
82
|
getScriptSnapshot: (file) => {
|
|
71
83
|
file = this.normalize(file);
|
|
72
|
-
|
|
73
84
|
const f = this.files.get(file);
|
|
74
85
|
if (f) {
|
|
75
86
|
this.touch(file);
|
|
76
87
|
return ts.ScriptSnapshot.fromString(f.content);
|
|
77
88
|
}
|
|
89
|
+
if (file.endsWith(".tsx")) {
|
|
90
|
+
const original = file.replace(/\.tsx$/, "");
|
|
91
|
+
|
|
92
|
+
if (fs.existsSync(original)) {
|
|
93
|
+
const content = fs.readFileSync(original, "utf-8");
|
|
94
|
+
|
|
95
|
+
this.files.set(file, {
|
|
96
|
+
content,
|
|
97
|
+
version: 1,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
this.fileNames.add(file);
|
|
101
|
+
this.touch(file);
|
|
102
|
+
this.evictIfNeeded();
|
|
78
103
|
|
|
104
|
+
return ts.ScriptSnapshot.fromString(content);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
79
107
|
try {
|
|
80
108
|
if (fs.existsSync(file)) {
|
|
81
109
|
const content = fs.readFileSync(file, "utf-8");
|
|
@@ -93,16 +121,22 @@ export class TSService {
|
|
|
93
121
|
}
|
|
94
122
|
} catch {}
|
|
95
123
|
|
|
96
|
-
// fallback
|
|
97
124
|
return ts.ScriptSnapshot.fromString("");
|
|
98
125
|
},
|
|
99
|
-
|
|
100
126
|
getCurrentDirectory: () => this.root,
|
|
101
127
|
getCompilationSettings: () => this.compilerOptions,
|
|
102
128
|
getDefaultLibFileName: (opts) =>
|
|
103
129
|
ts.getDefaultLibFilePath(opts),
|
|
104
|
-
fileExists:
|
|
105
|
-
|
|
130
|
+
fileExists: (file) => {
|
|
131
|
+
file = this.normalize(file);
|
|
132
|
+
return this.files.has(file) || ts.sys.fileExists(file);
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
readFile: (file) => {
|
|
136
|
+
file = this.normalize(file);
|
|
137
|
+
return this.files.get(file)?.content ?? ts.sys.readFile(file);
|
|
138
|
+
},
|
|
139
|
+
|
|
106
140
|
readDirectory: ts.sys.readDirectory,
|
|
107
141
|
};
|
|
108
142
|
|
|
@@ -122,7 +156,7 @@ export class TSService {
|
|
|
122
156
|
private evictIfNeeded() {
|
|
123
157
|
if (this.fileNames.size <= this.MAX_FILES) return;
|
|
124
158
|
|
|
125
|
-
let
|
|
159
|
+
let oldest: string | null = null;
|
|
126
160
|
let oldestTick = Infinity;
|
|
127
161
|
|
|
128
162
|
for (const f of this.fileNames) {
|
|
@@ -130,20 +164,20 @@ export class TSService {
|
|
|
130
164
|
|
|
131
165
|
if (t < oldestTick) {
|
|
132
166
|
oldestTick = t;
|
|
133
|
-
|
|
167
|
+
oldest = f;
|
|
134
168
|
}
|
|
135
169
|
}
|
|
136
170
|
|
|
137
|
-
if (
|
|
138
|
-
this.files.delete(
|
|
139
|
-
this.fileNames.delete(
|
|
140
|
-
this.usage.delete(
|
|
171
|
+
if (oldest) {
|
|
172
|
+
this.files.delete(oldest);
|
|
173
|
+
this.fileNames.delete(oldest);
|
|
174
|
+
this.usage.delete(oldest);
|
|
141
175
|
}
|
|
142
176
|
}
|
|
143
177
|
|
|
144
178
|
private ensureProgram() {
|
|
145
179
|
try {
|
|
146
|
-
this.service.getProgram();
|
|
180
|
+
this.service.getProgram()?.getTypeChecker();
|
|
147
181
|
} catch {}
|
|
148
182
|
}
|
|
149
183
|
|
package/src/engine/scanner.ts
CHANGED
|
@@ -173,15 +173,13 @@ export function scanSource(
|
|
|
173
173
|
config: EventraConfig,
|
|
174
174
|
visited = new Set<string>(),
|
|
175
175
|
inheritedParamMap?: Map<string, ts.Expression>,
|
|
176
|
-
wrapperCache
|
|
176
|
+
wrapperCache = new Map<string, string | null>()
|
|
177
177
|
): ScanResult {
|
|
178
|
-
wrapperCache = wrapperCache ?? new Map();
|
|
179
|
-
|
|
180
178
|
const events = new Set<string>();
|
|
181
179
|
const detectedFunctionWrappers = new Set<string>();
|
|
182
180
|
const detectedComponentWrappers = new Map<string, string>();
|
|
183
181
|
|
|
184
|
-
if (visited.
|
|
182
|
+
if (visited.has(source.fileName) || visited.size > 200) {
|
|
185
183
|
return { events, detectedFunctionWrappers, detectedComponentWrappers };
|
|
186
184
|
}
|
|
187
185
|
|
|
@@ -189,76 +187,58 @@ export function scanSource(
|
|
|
189
187
|
|
|
190
188
|
function visit(node: ts.Node) {
|
|
191
189
|
// JSX WRAPPERS
|
|
192
|
-
if (
|
|
193
|
-
ts.isJsxSelfClosingElement(node) ||
|
|
194
|
-
ts.isJsxOpeningElement(node)
|
|
195
|
-
) {
|
|
190
|
+
if (ts.isJsxSelfClosingElement(node) || ts.isJsxOpeningElement(node)) {
|
|
196
191
|
const tagName = getJsxTagName(node.tagName);
|
|
197
192
|
|
|
198
193
|
// skip html
|
|
199
|
-
if (
|
|
194
|
+
if (tagName[0] === tagName[0].toLowerCase()) {
|
|
200
195
|
ts.forEachChild(node, visit);
|
|
201
196
|
return;
|
|
202
197
|
}
|
|
203
198
|
|
|
204
|
-
let wrapper = config.wrappers.find(
|
|
205
|
-
(w) => w.name === tagName
|
|
206
|
-
);
|
|
199
|
+
let wrapper = config.wrappers.find(w => w.name === tagName);
|
|
207
200
|
|
|
201
|
+
// AUTO DETECT
|
|
208
202
|
if (!wrapper) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
203
|
+
if (wrapperCache.has(tagName)) {
|
|
204
|
+
const cached = wrapperCache.get(tagName);
|
|
205
|
+
if (cached) wrapper = { name: tagName, prop: cached };
|
|
206
|
+
} else {
|
|
207
|
+
let symbol = checker.getSymbolAtLocation(node.tagName);
|
|
212
208
|
|
|
213
|
-
|
|
214
|
-
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
209
|
+
if (symbol && (symbol.flags & ts.SymbolFlags.Alias)) {
|
|
215
210
|
symbol = checker.getAliasedSymbol(symbol);
|
|
216
211
|
}
|
|
217
212
|
|
|
218
|
-
symbol
|
|
219
|
-
resolveExportedSymbol(symbol, checker) ?? symbol;
|
|
220
|
-
|
|
221
|
-
cacheKey = checker.getFullyQualifiedName(symbol);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (wrapperCache?.has(cacheKey)) {
|
|
225
|
-
const cached = wrapperCache.get(cacheKey);
|
|
226
|
-
if (cached) {
|
|
227
|
-
wrapper = { name: tagName, prop: cached };
|
|
228
|
-
}
|
|
229
|
-
} else if (symbol) {
|
|
230
|
-
let detected: string | null = null;
|
|
213
|
+
if (symbol) {
|
|
214
|
+
symbol = resolveExportedSymbol(symbol, checker) ?? symbol;
|
|
231
215
|
|
|
232
|
-
|
|
233
|
-
|
|
216
|
+
for (const decl of symbol.getDeclarations() ?? []) {
|
|
217
|
+
let fn: ts.FunctionLikeDeclaration | null = null;
|
|
234
218
|
|
|
235
|
-
|
|
219
|
+
if (ts.isFunctionDeclaration(decl)) fn = decl;
|
|
236
220
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
221
|
+
if (
|
|
222
|
+
ts.isVariableDeclaration(decl) &&
|
|
223
|
+
decl.initializer &&
|
|
224
|
+
(ts.isArrowFunction(decl.initializer) ||
|
|
225
|
+
ts.isFunctionExpression(decl.initializer))
|
|
226
|
+
) {
|
|
227
|
+
fn = decl.initializer;
|
|
228
|
+
}
|
|
245
229
|
|
|
246
|
-
|
|
230
|
+
if (!fn) continue;
|
|
247
231
|
|
|
248
|
-
|
|
232
|
+
const prop = findTrackedPropName(fn, checker);
|
|
233
|
+
wrapperCache.set(tagName, prop ?? null);
|
|
249
234
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
235
|
+
if (prop) {
|
|
236
|
+
wrapper = { name: tagName, prop };
|
|
237
|
+
detectedComponentWrappers.set(tagName, prop);
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
253
240
|
}
|
|
254
241
|
}
|
|
255
|
-
|
|
256
|
-
wrapperCache?.set(cacheKey, detected);
|
|
257
|
-
|
|
258
|
-
if (detected) {
|
|
259
|
-
wrapper = { name: tagName, prop: detected };
|
|
260
|
-
detectedComponentWrappers.set(tagName, detected);
|
|
261
|
-
}
|
|
262
242
|
}
|
|
263
243
|
}
|
|
264
244
|
|
|
@@ -268,25 +248,21 @@ export function scanSource(
|
|
|
268
248
|
|
|
269
249
|
const name = getJsxAttrName(attr.name);
|
|
270
250
|
if (name !== wrapper.prop) continue;
|
|
251
|
+
|
|
271
252
|
if (!attr.initializer) continue;
|
|
272
253
|
|
|
273
254
|
if (ts.isStringLiteral(attr.initializer)) {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
255
|
+
const v = attr.initializer.text;
|
|
256
|
+
if (isValidEvent(v)) events.add(v);
|
|
277
257
|
}
|
|
278
258
|
|
|
279
259
|
if (ts.isJsxExpression(attr.initializer)) {
|
|
280
260
|
const expr = attr.initializer.expression;
|
|
281
261
|
if (!expr) continue;
|
|
282
262
|
|
|
283
|
-
const res = resolveNodeValue(
|
|
284
|
-
expr,
|
|
285
|
-
checker,
|
|
286
|
-
inheritedParamMap
|
|
287
|
-
);
|
|
263
|
+
const res = resolveNodeValue(expr, checker, inheritedParamMap);
|
|
288
264
|
|
|
289
|
-
res.values.forEach(
|
|
265
|
+
res.values.forEach(v => {
|
|
290
266
|
if (isValidEvent(v)) events.add(v);
|
|
291
267
|
});
|
|
292
268
|
}
|
|
@@ -297,40 +273,56 @@ export function scanSource(
|
|
|
297
273
|
return;
|
|
298
274
|
}
|
|
299
275
|
|
|
300
|
-
// FUNCTION
|
|
276
|
+
// FUNCTION CALLS
|
|
301
277
|
if (ts.isCallExpression(node)) {
|
|
302
|
-
|
|
278
|
+
let trackParamIndex: number | null = null;
|
|
279
|
+
let isTracking = false;
|
|
280
|
+
|
|
281
|
+
const callName = getCallName(node.expression);
|
|
282
|
+
|
|
283
|
+
// direct .track()
|
|
284
|
+
if (
|
|
285
|
+
ts.isPropertyAccessExpression(node.expression) &&
|
|
286
|
+
node.expression.name.text === "track"
|
|
287
|
+
) {
|
|
288
|
+
isTracking = true;
|
|
289
|
+
trackParamIndex = 0;
|
|
290
|
+
}
|
|
303
291
|
|
|
304
|
-
|
|
305
|
-
|
|
292
|
+
// config wrapper
|
|
293
|
+
const manualWrapper = config.functionWrappers.find(
|
|
294
|
+
w => w.name === callName
|
|
306
295
|
);
|
|
307
296
|
|
|
297
|
+
if (manualWrapper) {
|
|
298
|
+
isTracking = true;
|
|
299
|
+
trackParamIndex = 0;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// resolve function → check body
|
|
308
303
|
const resolvedFn = resolveFunctionFromCall(
|
|
309
304
|
node.expression,
|
|
310
305
|
checker
|
|
311
306
|
);
|
|
312
307
|
|
|
313
|
-
|
|
314
|
-
|
|
308
|
+
if (resolvedFn) {
|
|
309
|
+
const idx = findTrackParamIndex(resolvedFn);
|
|
315
310
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
311
|
+
if (idx !== null) {
|
|
312
|
+
isTracking = true;
|
|
313
|
+
trackParamIndex = idx;
|
|
314
|
+
|
|
315
|
+
if (!manualWrapper && callName !== "track") {
|
|
316
|
+
detectedFunctionWrappers.add(callName);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
324
320
|
|
|
325
321
|
if (!isTracking) {
|
|
326
322
|
ts.forEachChild(node, visit);
|
|
327
323
|
return;
|
|
328
324
|
}
|
|
329
325
|
|
|
330
|
-
if (!isKnownWrapper && isAutoWrapper && name !== "track") {
|
|
331
|
-
detectedFunctionWrappers.add(name);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
326
|
const paramMap = new Map(inheritedParamMap ?? []);
|
|
335
327
|
|
|
336
328
|
if (resolvedFn && ts.isFunctionLike(resolvedFn)) {
|
|
@@ -344,22 +336,19 @@ export function scanSource(
|
|
|
344
336
|
});
|
|
345
337
|
}
|
|
346
338
|
|
|
347
|
-
if (
|
|
348
|
-
const
|
|
339
|
+
if (trackParamIndex !== null && node.arguments[trackParamIndex]) {
|
|
340
|
+
const res = resolveNodeValue(
|
|
341
|
+
node.arguments[trackParamIndex],
|
|
342
|
+
checker,
|
|
343
|
+
paramMap
|
|
344
|
+
);
|
|
349
345
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
checker,
|
|
354
|
-
paramMap
|
|
355
|
-
);
|
|
356
|
-
|
|
357
|
-
res.values.forEach((v) => {
|
|
358
|
-
if (isValidEvent(v)) events.add(v);
|
|
359
|
-
});
|
|
360
|
-
}
|
|
346
|
+
res.values.forEach(v => {
|
|
347
|
+
if (isValidEvent(v)) events.add(v);
|
|
348
|
+
});
|
|
361
349
|
}
|
|
362
350
|
|
|
351
|
+
// CROSS FILE
|
|
363
352
|
if (resolvedFn) {
|
|
364
353
|
const sf = resolvedFn.getSourceFile();
|
|
365
354
|
|
|
@@ -373,7 +362,7 @@ export function scanSource(
|
|
|
373
362
|
wrapperCache
|
|
374
363
|
);
|
|
375
364
|
|
|
376
|
-
res.events.forEach(
|
|
365
|
+
res.events.forEach(e => events.add(e));
|
|
377
366
|
}
|
|
378
367
|
}
|
|
379
368
|
}
|