@eventra_dev/eventra-cli 0.3.4 → 0.3.5
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.
|
@@ -0,0 +1,76 @@
|
|
|
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.analyzeFileRecursive = analyzeFileRecursive;
|
|
7
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
+
const propagationAnalyzer_1 = require("../scanner/analyzer/propagationAnalyzer");
|
|
9
|
+
const extractor_1 = require("../extractor/extractor");
|
|
10
|
+
async function analyzeFileRecursive(sourceFile, config, wrapperRegistry, evaluationCache, resolvedCallCache, returnPropagationCache, resolvedExportCache) {
|
|
11
|
+
const checker = wrapperRegistry["checker"];
|
|
12
|
+
const sinks = [];
|
|
13
|
+
const wrappers = [];
|
|
14
|
+
const trackCalls = [];
|
|
15
|
+
// Support empty functionWrappers
|
|
16
|
+
const wrapperNames = new Set(config.functionWrappers?.map(w => w.name) ?? []);
|
|
17
|
+
function visit(node, parentFunction) {
|
|
18
|
+
// Detect calls to configured wrapper functions
|
|
19
|
+
if (typescript_1.default.isCallExpression(node)) {
|
|
20
|
+
const callName = getCallName(node.expression);
|
|
21
|
+
if (wrapperNames.has(callName)) {
|
|
22
|
+
// Track this wrapper call
|
|
23
|
+
sinks.push({ call: node, trackedArguments: [{ index: 0, propertyPath: [] }] });
|
|
24
|
+
trackCalls.push({
|
|
25
|
+
node,
|
|
26
|
+
sourceFile,
|
|
27
|
+
trackedArguments: node.arguments.filter(typescript_1.default.isExpression)
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Detect and analyze function declarations / expressions / methods
|
|
32
|
+
if (typescript_1.default.isFunctionDeclaration(node) ||
|
|
33
|
+
typescript_1.default.isFunctionExpression(node) ||
|
|
34
|
+
typescript_1.default.isArrowFunction(node) ||
|
|
35
|
+
typescript_1.default.isMethodDeclaration(node)) {
|
|
36
|
+
const localSinks = sinks.filter(s => isNodeInside(s.call, node));
|
|
37
|
+
const wrapper = (0, propagationAnalyzer_1.analyzeWrapperPropagation)(node, checker, localSinks);
|
|
38
|
+
if (wrapper) {
|
|
39
|
+
wrappers.push(wrapper);
|
|
40
|
+
wrapperRegistry.set(wrapper);
|
|
41
|
+
}
|
|
42
|
+
// Recurse into function body
|
|
43
|
+
if (node.body) {
|
|
44
|
+
typescript_1.default.forEachChild(node.body, child => visit(child, node));
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// Recurse into child nodes
|
|
49
|
+
typescript_1.default.forEachChild(node, child => visit(child, parentFunction));
|
|
50
|
+
}
|
|
51
|
+
visit(sourceFile);
|
|
52
|
+
// Extract events from tracked calls and wrapper metadata
|
|
53
|
+
return (0, extractor_1.extractEvents)({
|
|
54
|
+
fileName: sourceFile.fileName,
|
|
55
|
+
sourceFile,
|
|
56
|
+
sinks,
|
|
57
|
+
trackCalls,
|
|
58
|
+
wrappers,
|
|
59
|
+
}, checker, config, evaluationCache, resolvedExportCache, resolvedCallCache, returnPropagationCache, wrapperRegistry);
|
|
60
|
+
}
|
|
61
|
+
function isNodeInside(child, fn) {
|
|
62
|
+
let current = child;
|
|
63
|
+
while (current) {
|
|
64
|
+
if (current === fn)
|
|
65
|
+
return true;
|
|
66
|
+
current = current.parent;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
function getCallName(expr) {
|
|
71
|
+
if (typescript_1.default.isIdentifier(expr))
|
|
72
|
+
return expr.text;
|
|
73
|
+
if (typescript_1.default.isPropertyAccessExpression(expr) || typescript_1.default.isPropertyAccessChain(expr))
|
|
74
|
+
return expr.name.text;
|
|
75
|
+
return "";
|
|
76
|
+
}
|
|
@@ -14,9 +14,8 @@ const resolvedCallCache_1 = require("../analysis/cache/resolvedCallCache");
|
|
|
14
14
|
const resolvedExportCache_1 = require("../analysis/cache/resolvedExportCache");
|
|
15
15
|
const returnPropagationCache_1 = require("../analysis/cache/returnPropagationCache");
|
|
16
16
|
const symbolInvalidation_1 = require("../analysis/cache/symbolInvalidation");
|
|
17
|
-
const scanner_1 = require("../analysis/scanner/scanner");
|
|
18
|
-
const extractor_1 = require("../analysis/extractor/extractor");
|
|
19
17
|
const wrapperRegistry_1 = require("../analysis/symbols/wrapperRegistry");
|
|
18
|
+
const recursiveWrapperAnalyzer_1 = require("../analysis/engine/recursiveWrapperAnalyzer");
|
|
20
19
|
const EMPTY_RESULT = () => ({
|
|
21
20
|
events: new Set(),
|
|
22
21
|
detectedFunctionWrappers: new Set(),
|
|
@@ -63,7 +62,7 @@ class EventraEngine {
|
|
|
63
62
|
}
|
|
64
63
|
// RE-ANALYZE
|
|
65
64
|
for (const file of affected) {
|
|
66
|
-
this.analyzeFile(file, this.lastConfig);
|
|
65
|
+
await this.analyzeFile(file, this.lastConfig);
|
|
67
66
|
}
|
|
68
67
|
});
|
|
69
68
|
}
|
|
@@ -109,19 +108,6 @@ class EventraEngine {
|
|
|
109
108
|
}
|
|
110
109
|
this.importGraph.updateFile(normalized, imports);
|
|
111
110
|
}
|
|
112
|
-
analyzeFile(fileName, config) {
|
|
113
|
-
const normalized = this.normalize(fileName);
|
|
114
|
-
const source = this.compiler.getSourceFile(normalized);
|
|
115
|
-
if (!source) {
|
|
116
|
-
this.fileResults.delete(normalized);
|
|
117
|
-
return EMPTY_RESULT();
|
|
118
|
-
}
|
|
119
|
-
const checker = this.compiler.getChecker();
|
|
120
|
-
const index = (0, scanner_1.scanSource)(source, checker, this.wrapperRegistry);
|
|
121
|
-
const result = (0, extractor_1.extractEvents)(index, checker, config, this.evaluationCache, this.resolvedExportCache, this.resolvedCallCache, this.returnPropagationCache, this.wrapperRegistry);
|
|
122
|
-
this.fileResults.set(normalized, result);
|
|
123
|
-
return result;
|
|
124
|
-
}
|
|
125
111
|
async preloadFile(fileName, content) {
|
|
126
112
|
if (!this.isPreloading) {
|
|
127
113
|
throw new Error("preload phase not active");
|
|
@@ -135,9 +121,9 @@ class EventraEngine {
|
|
|
135
121
|
const normalized = this.normalize(fileName);
|
|
136
122
|
await this.scheduler.enqueue(normalized, content);
|
|
137
123
|
}
|
|
138
|
-
scanFile(fileName, config) {
|
|
124
|
+
async scanFile(fileName, config) {
|
|
139
125
|
this.lastConfig = config;
|
|
140
|
-
return this.analyzeFile(fileName, config);
|
|
126
|
+
return await this.analyzeFile(fileName, config);
|
|
141
127
|
}
|
|
142
128
|
async removeFile(fileName, config) {
|
|
143
129
|
const normalized = this.normalize(fileName);
|
|
@@ -152,9 +138,20 @@ class EventraEngine {
|
|
|
152
138
|
if (file === normalized) {
|
|
153
139
|
continue;
|
|
154
140
|
}
|
|
155
|
-
this.analyzeFile(file, nextConfig);
|
|
141
|
+
await this.analyzeFile(file, nextConfig);
|
|
156
142
|
}
|
|
157
143
|
}
|
|
144
|
+
async analyzeFile(fileName, config) {
|
|
145
|
+
const normalized = this.normalize(fileName);
|
|
146
|
+
const source = this.compiler.getSourceFile(normalized);
|
|
147
|
+
if (!source) {
|
|
148
|
+
this.fileResults.delete(normalized);
|
|
149
|
+
return EMPTY_RESULT();
|
|
150
|
+
}
|
|
151
|
+
const result = await (0, recursiveWrapperAnalyzer_1.analyzeFileRecursive)(source, config, this.wrapperRegistry, this.evaluationCache, this.resolvedCallCache, this.returnPropagationCache, this.resolvedExportCache);
|
|
152
|
+
this.fileResults.set(normalized, result);
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
158
155
|
getAllEvents() {
|
|
159
156
|
const events = new Set();
|
|
160
157
|
for (const result of this.fileResults.values()) {
|
|
@@ -60,7 +60,7 @@ async function scanProject(config) {
|
|
|
60
60
|
const results = new Map();
|
|
61
61
|
for (const file of toScan) {
|
|
62
62
|
try {
|
|
63
|
-
const result = engine.scanFile((0, getVirtualFile_1.getVirtualFile)(file), config);
|
|
63
|
+
const result = await engine.scanFile((0, getVirtualFile_1.getVirtualFile)(file), config);
|
|
64
64
|
results.set(file, result);
|
|
65
65
|
}
|
|
66
66
|
catch {
|