@eventra_dev/eventra-cli 0.1.29 → 0.1.31
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 +0 -1
- package/dist/engine/engine.js +7 -4
- package/dist/engine/functionAnalyzer.js +15 -50
- package/dist/engine/resolver.js +57 -138
- package/dist/engine/scanner.js +205 -54
- package/dist/utils/config.js +0 -1
- package/dist/utils/processFile.js +3 -3
- package/dist/utils/universal.js +91 -94
- package/package.json +1 -1
- package/src/engine/engine.ts +26 -7
- package/src/engine/functionAnalyzer.ts +14 -54
- package/src/engine/resolver.ts +83 -184
- package/src/engine/scanner.ts +263 -75
- package/src/types.ts +6 -1
- package/src/utils/config.ts +0 -1
- package/src/utils/processFile.ts +3 -3
- package/src/utils/universal.ts +108 -119
- package/tests/run.ts +0 -1
- package/dist/engine/trackingDetector.js +0 -68
- package/src/engine/trackingDetector.ts +0 -94
package/README.md
CHANGED
package/dist/engine/engine.js
CHANGED
|
@@ -14,6 +14,7 @@ const boundary_1 = require("./boundary");
|
|
|
14
14
|
class EventraEngine {
|
|
15
15
|
ts;
|
|
16
16
|
graph;
|
|
17
|
+
wrapperCache = new Map();
|
|
17
18
|
fileResults = new Map();
|
|
18
19
|
fileHash = new Map();
|
|
19
20
|
constructor(root) {
|
|
@@ -54,14 +55,15 @@ class EventraEngine {
|
|
|
54
55
|
if (!source || !checker) {
|
|
55
56
|
return this.empty();
|
|
56
57
|
}
|
|
57
|
-
//
|
|
58
|
+
// update graph
|
|
58
59
|
this.graph.update(file, source);
|
|
59
|
-
const res = (0, scanner_1.scanSource)(source, checker, config);
|
|
60
|
+
const res = (0, scanner_1.scanSource)(source, checker, config, new Set(), undefined, this.wrapperCache);
|
|
60
61
|
this.fileResults.set(file, res);
|
|
61
62
|
return res;
|
|
62
63
|
}
|
|
63
64
|
// UPDATE FILE (incremental)
|
|
64
65
|
updateFile(file, content, config) {
|
|
66
|
+
this.wrapperCache.clear();
|
|
65
67
|
file = this.normalize(file);
|
|
66
68
|
const res = this.scanFile(file, content, config);
|
|
67
69
|
const dependents = this.graph.getAllDependentsDeep(file);
|
|
@@ -89,7 +91,7 @@ class EventraEngine {
|
|
|
89
91
|
if (!source || !checker)
|
|
90
92
|
continue;
|
|
91
93
|
this.graph.update(abs, source);
|
|
92
|
-
const r = (0, scanner_1.scanSource)(source, checker, config);
|
|
94
|
+
const r = (0, scanner_1.scanSource)(source, checker, config, new Set(), undefined, this.wrapperCache);
|
|
93
95
|
this.fileResults.set(abs, r);
|
|
94
96
|
}
|
|
95
97
|
return res;
|
|
@@ -104,6 +106,7 @@ class EventraEngine {
|
|
|
104
106
|
}
|
|
105
107
|
// REMOVE FILE
|
|
106
108
|
removeFile(file, config) {
|
|
109
|
+
this.wrapperCache.clear();
|
|
107
110
|
file = this.normalize(file);
|
|
108
111
|
const dependents = this.graph.getAllDependentsDeep(file);
|
|
109
112
|
this.ts.removeFile(file);
|
|
@@ -138,7 +141,7 @@ class EventraEngine {
|
|
|
138
141
|
wrappers: [],
|
|
139
142
|
functionWrappers: [],
|
|
140
143
|
sync: { include: [], exclude: [] },
|
|
141
|
-
});
|
|
144
|
+
}, new Set(), undefined, this.wrapperCache);
|
|
142
145
|
this.fileResults.set(abs, r);
|
|
143
146
|
}
|
|
144
147
|
}
|
|
@@ -10,25 +10,11 @@ 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
|
-
}
|
|
18
13
|
}
|
|
19
14
|
});
|
|
20
15
|
let result = null;
|
|
21
|
-
function
|
|
22
|
-
//
|
|
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
|
|
16
|
+
function check(arg) {
|
|
17
|
+
// identifier
|
|
32
18
|
if (typescript_1.default.isIdentifier(arg)) {
|
|
33
19
|
const idx = paramIndex.get(arg.text);
|
|
34
20
|
if (idx !== undefined) {
|
|
@@ -36,12 +22,7 @@ function findTrackParamIndex(fn) {
|
|
|
36
22
|
return true;
|
|
37
23
|
}
|
|
38
24
|
}
|
|
39
|
-
//
|
|
40
|
-
if (typescript_1.default.isStringLiteral(arg)) {
|
|
41
|
-
result = 0;
|
|
42
|
-
return true;
|
|
43
|
-
}
|
|
44
|
-
// template `${name}`
|
|
25
|
+
// template
|
|
45
26
|
if (typescript_1.default.isTemplateExpression(arg)) {
|
|
46
27
|
for (const span of arg.templateSpans) {
|
|
47
28
|
if (typescript_1.default.isIdentifier(span.expression)) {
|
|
@@ -52,49 +33,33 @@ function findTrackParamIndex(fn) {
|
|
|
52
33
|
}
|
|
53
34
|
}
|
|
54
35
|
}
|
|
55
|
-
result = 0;
|
|
56
|
-
return true;
|
|
57
36
|
}
|
|
58
37
|
// object { event: name }
|
|
59
38
|
if (typescript_1.default.isObjectLiteralExpression(arg)) {
|
|
60
39
|
for (const prop of arg.properties) {
|
|
61
40
|
if (!typescript_1.default.isPropertyAssignment(prop))
|
|
62
41
|
continue;
|
|
63
|
-
const
|
|
64
|
-
if (["event", "name", "type"].includes(
|
|
65
|
-
return
|
|
42
|
+
const key = prop.name.getText();
|
|
43
|
+
if (["event", "name", "type"].includes(key)) {
|
|
44
|
+
return check(prop.initializer);
|
|
66
45
|
}
|
|
67
46
|
}
|
|
68
47
|
}
|
|
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
48
|
return false;
|
|
77
49
|
}
|
|
78
50
|
function visit(node) {
|
|
79
51
|
if (result !== null)
|
|
80
52
|
return;
|
|
81
53
|
if (typescript_1.default.isCallExpression(node)) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
if (isTrackCall) {
|
|
94
|
-
for (const arg of node.arguments) {
|
|
95
|
-
if (checkArg(arg))
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
54
|
+
const expr = node.expression;
|
|
55
|
+
const isTrack = (typescript_1.default.isIdentifier(expr) && expr.text === "track") ||
|
|
56
|
+
(typescript_1.default.isPropertyAccessExpression(expr) &&
|
|
57
|
+
expr.name.text === "track");
|
|
58
|
+
if (!isTrack)
|
|
59
|
+
return;
|
|
60
|
+
for (const arg of node.arguments) {
|
|
61
|
+
if (check(arg))
|
|
62
|
+
return;
|
|
98
63
|
}
|
|
99
64
|
}
|
|
100
65
|
typescript_1.default.forEachChild(node, visit);
|
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
|
-
// PARAM
|
|
14
|
+
// PARAM MAP (wrapper args)
|
|
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
|
}
|
|
@@ -19,36 +19,19 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
19
19
|
if (typescript_1.default.isStringLiteral(node)) {
|
|
20
20
|
return { values: [node.text], dynamic: false };
|
|
21
21
|
}
|
|
22
|
-
// ARRAY
|
|
23
|
-
if (typescript_1.default.isArrayLiteralExpression(node)) {
|
|
24
|
-
const values = [];
|
|
25
|
-
for (const el of node.elements) {
|
|
26
|
-
const res = resolveNodeValue(el, checker, paramMap, seen);
|
|
27
|
-
if (res.values.length) {
|
|
28
|
-
values.push(...res.values);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return {
|
|
32
|
-
values: [...new Set(values)],
|
|
33
|
-
dynamic: true
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
22
|
// TEMPLATE
|
|
37
23
|
if (typescript_1.default.isTemplateExpression(node)) {
|
|
38
24
|
let results = node.head.text ? [node.head.text] : [""];
|
|
39
25
|
for (const span of node.templateSpans) {
|
|
40
26
|
const res = resolveNodeValue(span.expression, checker, paramMap, seen);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
else {
|
|
45
|
-
results = results.map(r => r + "*");
|
|
46
|
-
}
|
|
27
|
+
results = results.flatMap(r => res.values.length
|
|
28
|
+
? res.values.map(v => r + v)
|
|
29
|
+
: [r + "*"]);
|
|
47
30
|
results = results.map(r => r + span.literal.text);
|
|
48
31
|
}
|
|
49
32
|
return { values: results, dynamic: true };
|
|
50
33
|
}
|
|
51
|
-
// CONDITIONAL
|
|
34
|
+
// CONDITIONAL (a ? b : c)
|
|
52
35
|
if (typescript_1.default.isConditionalExpression(node)) {
|
|
53
36
|
const a = resolveNodeValue(node.whenTrue, checker, paramMap, seen);
|
|
54
37
|
const b = resolveNodeValue(node.whenFalse, checker, paramMap, seen);
|
|
@@ -57,23 +40,57 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
57
40
|
dynamic: true,
|
|
58
41
|
};
|
|
59
42
|
}
|
|
43
|
+
// OBJECT → берём ВСЕ значения (без привязки к ключам)
|
|
44
|
+
if (typescript_1.default.isObjectLiteralExpression(node)) {
|
|
45
|
+
const values = [];
|
|
46
|
+
for (const prop of node.properties) {
|
|
47
|
+
if (!typescript_1.default.isPropertyAssignment(prop))
|
|
48
|
+
continue;
|
|
49
|
+
const res = resolveNodeValue(prop.initializer, checker, paramMap, seen);
|
|
50
|
+
values.push(...res.values);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
values: [...new Set(values)],
|
|
54
|
+
dynamic: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// ARRAY
|
|
58
|
+
if (typescript_1.default.isArrayLiteralExpression(node)) {
|
|
59
|
+
const values = [];
|
|
60
|
+
for (const el of node.elements) {
|
|
61
|
+
const res = resolveNodeValue(el, checker, paramMap, seen);
|
|
62
|
+
values.push(...res.values);
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
values: [...new Set(values)],
|
|
66
|
+
dynamic: true,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// BINARY CONCAT
|
|
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
|
+
}
|
|
60
82
|
// IDENTIFIER
|
|
61
83
|
if (typescript_1.default.isIdentifier(node)) {
|
|
62
84
|
let symbol = checker.getSymbolAtLocation(node);
|
|
63
85
|
if (!symbol)
|
|
64
86
|
return { values: [], dynamic: true };
|
|
65
|
-
|
|
87
|
+
symbol = (0, exportResolver_1.resolveExportedSymbol)(symbol, checker) ?? symbol;
|
|
88
|
+
// const VAR = "click"
|
|
66
89
|
for (const decl of symbol.getDeclarations() ?? []) {
|
|
67
90
|
if (typescript_1.default.isVariableDeclaration(decl) && decl.initializer) {
|
|
68
91
|
return resolveNodeValue(decl.initializer, checker, paramMap, seen);
|
|
69
92
|
}
|
|
70
|
-
|
|
71
|
-
// unwrap export
|
|
72
|
-
symbol = (0, exportResolver_1.resolveExportedSymbol)(symbol, checker) ?? symbol;
|
|
73
|
-
if (symbol.flags & typescript_1.default.SymbolFlags.Alias) {
|
|
74
|
-
symbol = checker.getAliasedSymbol(symbol);
|
|
75
|
-
}
|
|
76
|
-
for (const decl of symbol.getDeclarations() ?? []) {
|
|
93
|
+
// enum
|
|
77
94
|
if (typescript_1.default.isEnumMember(decl) && decl.initializer) {
|
|
78
95
|
if (typescript_1.default.isStringLiteral(decl.initializer)) {
|
|
79
96
|
return {
|
|
@@ -83,29 +100,9 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
83
100
|
}
|
|
84
101
|
}
|
|
85
102
|
}
|
|
86
|
-
const type = checker.getTypeAtLocation(node);
|
|
87
|
-
// UNION
|
|
88
|
-
if (type.isUnion()) {
|
|
89
|
-
const values = [];
|
|
90
|
-
for (const t of type.types) {
|
|
91
|
-
if (t.flags & typescript_1.default.TypeFlags.StringLiteral) {
|
|
92
|
-
values.push(t.value);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (values.length) {
|
|
96
|
-
return { values, dynamic: false };
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
// STRING LITERAL TYPE
|
|
100
|
-
if (type.flags & typescript_1.default.TypeFlags.StringLiteral) {
|
|
101
|
-
return {
|
|
102
|
-
values: [type.value],
|
|
103
|
-
dynamic: false
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
103
|
return { values: [], dynamic: true };
|
|
107
104
|
}
|
|
108
|
-
// PROPERTY ACCESS
|
|
105
|
+
// PROPERTY ACCESS (ENUM / CONST)
|
|
109
106
|
if (typescript_1.default.isPropertyAccessExpression(node)) {
|
|
110
107
|
const symbol = checker.getSymbolAtLocation(node);
|
|
111
108
|
if (symbol) {
|
|
@@ -124,96 +121,18 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
124
121
|
}
|
|
125
122
|
}
|
|
126
123
|
}
|
|
127
|
-
|
|
128
|
-
if (typeof constantValue === "string") {
|
|
129
|
-
return { values: [constantValue], dynamic: false };
|
|
130
|
-
}
|
|
131
|
-
const type = checker.getTypeAtLocation(node);
|
|
132
|
-
if (type.flags & typescript_1.default.TypeFlags.StringLiteral) {
|
|
133
|
-
return {
|
|
134
|
-
values: [type.value],
|
|
135
|
-
dynamic: false,
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
// object literal resolve
|
|
139
|
-
if (typescript_1.default.isIdentifier(node.expression)) {
|
|
140
|
-
const objSymbol = checker.getSymbolAtLocation(node.expression);
|
|
141
|
-
if (objSymbol) {
|
|
142
|
-
for (const decl of objSymbol.getDeclarations() ?? []) {
|
|
143
|
-
if (typescript_1.default.isVariableDeclaration(decl) &&
|
|
144
|
-
decl.initializer &&
|
|
145
|
-
typescript_1.default.isObjectLiteralExpression(decl.initializer)) {
|
|
146
|
-
for (const prop of decl.initializer.properties) {
|
|
147
|
-
if (!typescript_1.default.isPropertyAssignment(prop))
|
|
148
|
-
continue;
|
|
149
|
-
const name = prop.name.getText();
|
|
150
|
-
if (name === node.name.text) {
|
|
151
|
-
return resolveNodeValue(prop.initializer, checker, paramMap, seen);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
// fallback
|
|
159
|
-
return resolveNodeValue(node.name, checker, paramMap, seen);
|
|
160
|
-
}
|
|
161
|
-
// ARRAY ACCESS
|
|
162
|
-
if (typescript_1.default.isElementAccessExpression(node)) {
|
|
163
|
-
const obj = resolveNodeValue(node.expression, checker, paramMap, seen);
|
|
164
|
-
if (!node.argumentExpression) {
|
|
165
|
-
return { values: obj.values, dynamic: true };
|
|
166
|
-
}
|
|
167
|
-
const index = resolveNodeValue(node.argumentExpression, checker, paramMap, seen);
|
|
168
|
-
if (index.values.length === 1) {
|
|
169
|
-
const i = Number(index.values[0]);
|
|
170
|
-
if (!Number.isNaN(i) && obj.values[i] !== undefined) {
|
|
171
|
-
return {
|
|
172
|
-
values: [obj.values[i]],
|
|
173
|
-
dynamic: false,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
return obj.values.length
|
|
178
|
-
? { values: obj.values, dynamic: true }
|
|
179
|
-
: { values: [], dynamic: true };
|
|
124
|
+
return { values: [], dynamic: true };
|
|
180
125
|
}
|
|
181
|
-
//
|
|
182
|
-
if (typescript_1.default.
|
|
126
|
+
// CALL → unwrap args
|
|
127
|
+
if (typescript_1.default.isCallExpression(node)) {
|
|
183
128
|
const values = [];
|
|
184
|
-
for (const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const name = prop.name.getText();
|
|
188
|
-
if (["event", "name", "type"].includes(name)) {
|
|
189
|
-
const res = resolveNodeValue(prop.initializer, checker, paramMap, seen);
|
|
190
|
-
values.push(...res.values);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return {
|
|
194
|
-
values: [...new Set(values)],
|
|
195
|
-
dynamic: true
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
// BINARY ("btn_" + name)
|
|
199
|
-
if (typescript_1.default.isBinaryExpression(node)) {
|
|
200
|
-
if (node.operatorToken.kind === typescript_1.default.SyntaxKind.PlusToken) {
|
|
201
|
-
const left = resolveNodeValue(node.left, checker, paramMap, seen);
|
|
202
|
-
const right = resolveNodeValue(node.right, checker, paramMap, seen);
|
|
203
|
-
if (!left.values.length) {
|
|
204
|
-
return { values: [], dynamic: true };
|
|
205
|
-
}
|
|
206
|
-
return {
|
|
207
|
-
values: left.values.flatMap(l => right.values.length
|
|
208
|
-
? right.values.map(r => l + r)
|
|
209
|
-
: [l + "*"]),
|
|
210
|
-
dynamic: true,
|
|
211
|
-
};
|
|
129
|
+
for (const arg of node.arguments) {
|
|
130
|
+
const res = resolveNodeValue(arg, checker, paramMap, seen);
|
|
131
|
+
values.push(...res.values);
|
|
212
132
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
return { values: [], dynamic: true };
|
|
133
|
+
return values.length
|
|
134
|
+
? { values, dynamic: true }
|
|
135
|
+
: { values: [], dynamic: true };
|
|
217
136
|
}
|
|
218
137
|
return { values: [], dynamic: true };
|
|
219
138
|
}
|