@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
|
@@ -8,31 +8,13 @@ export function findTrackParamIndex(
|
|
|
8
8
|
fn.parameters.forEach((p, i) => {
|
|
9
9
|
if (ts.isIdentifier(p.name)) {
|
|
10
10
|
paramIndex.set(p.name.text, i);
|
|
11
|
-
|
|
12
|
-
// default param: (name = "x")
|
|
13
|
-
if (p.initializer && ts.isStringLiteral(p.initializer)) {
|
|
14
|
-
if (i === 0) return 0;
|
|
15
|
-
}
|
|
16
11
|
}
|
|
17
12
|
});
|
|
18
13
|
|
|
19
14
|
let result: number | null = null;
|
|
20
15
|
|
|
21
|
-
function
|
|
22
|
-
//
|
|
23
|
-
while (
|
|
24
|
-
ts.isAsExpression(node) ||
|
|
25
|
-
ts.isParenthesizedExpression(node)
|
|
26
|
-
) {
|
|
27
|
-
node = node.expression;
|
|
28
|
-
}
|
|
29
|
-
return node;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function checkArg(arg: ts.Expression) {
|
|
33
|
-
arg = unwrap(arg);
|
|
34
|
-
|
|
35
|
-
// identifier → param
|
|
16
|
+
function check(arg: ts.Expression): boolean {
|
|
17
|
+
// identifier
|
|
36
18
|
if (ts.isIdentifier(arg)) {
|
|
37
19
|
const idx = paramIndex.get(arg.text);
|
|
38
20
|
if (idx !== undefined) {
|
|
@@ -41,13 +23,7 @@ export function findTrackParamIndex(
|
|
|
41
23
|
}
|
|
42
24
|
}
|
|
43
25
|
|
|
44
|
-
//
|
|
45
|
-
if (ts.isStringLiteral(arg)) {
|
|
46
|
-
result = 0;
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// template `${name}`
|
|
26
|
+
// template
|
|
51
27
|
if (ts.isTemplateExpression(arg)) {
|
|
52
28
|
for (const span of arg.templateSpans) {
|
|
53
29
|
if (ts.isIdentifier(span.expression)) {
|
|
@@ -58,8 +34,6 @@ export function findTrackParamIndex(
|
|
|
58
34
|
}
|
|
59
35
|
}
|
|
60
36
|
}
|
|
61
|
-
result = 0;
|
|
62
|
-
return true;
|
|
63
37
|
}
|
|
64
38
|
|
|
65
39
|
// object { event: name }
|
|
@@ -67,21 +41,14 @@ export function findTrackParamIndex(
|
|
|
67
41
|
for (const prop of arg.properties) {
|
|
68
42
|
if (!ts.isPropertyAssignment(prop)) continue;
|
|
69
43
|
|
|
70
|
-
const
|
|
44
|
+
const key = prop.name.getText();
|
|
71
45
|
|
|
72
|
-
if (["event", "name", "type"].includes(
|
|
73
|
-
return
|
|
46
|
+
if (["event", "name", "type"].includes(key)) {
|
|
47
|
+
return check(prop.initializer);
|
|
74
48
|
}
|
|
75
49
|
}
|
|
76
50
|
}
|
|
77
51
|
|
|
78
|
-
// call: String(name)
|
|
79
|
-
if (ts.isCallExpression(arg)) {
|
|
80
|
-
for (const inner of arg.arguments) {
|
|
81
|
-
if (checkArg(inner)) return true;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
52
|
return false;
|
|
86
53
|
}
|
|
87
54
|
|
|
@@ -89,24 +56,17 @@ export function findTrackParamIndex(
|
|
|
89
56
|
if (result !== null) return;
|
|
90
57
|
|
|
91
58
|
if (ts.isCallExpression(node)) {
|
|
92
|
-
|
|
59
|
+
const expr = node.expression;
|
|
93
60
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
61
|
+
const isTrack =
|
|
62
|
+
(ts.isIdentifier(expr) && expr.text === "track") ||
|
|
63
|
+
(ts.isPropertyAccessExpression(expr) &&
|
|
64
|
+
expr.name.text === "track");
|
|
99
65
|
|
|
100
|
-
if (
|
|
101
|
-
if (node.expression.text === "track") {
|
|
102
|
-
isTrackCall = true;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
66
|
+
if (!isTrack) return;
|
|
105
67
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (checkArg(arg)) return;
|
|
109
|
-
}
|
|
68
|
+
for (const arg of node.arguments) {
|
|
69
|
+
if (check(arg)) return;
|
|
110
70
|
}
|
|
111
71
|
}
|
|
112
72
|
|
package/src/engine/resolver.ts
CHANGED
|
@@ -12,13 +12,12 @@ export function resolveNodeValue(
|
|
|
12
12
|
paramMap?: Map<string, ts.Expression>,
|
|
13
13
|
seen = new Set<ts.Node>()
|
|
14
14
|
): ResolveResult {
|
|
15
|
-
|
|
16
15
|
if (seen.has(node)) {
|
|
17
16
|
return { values: [], dynamic: true };
|
|
18
17
|
}
|
|
19
18
|
seen.add(node);
|
|
20
19
|
|
|
21
|
-
// PARAM
|
|
20
|
+
// PARAM MAP (wrapper args)
|
|
22
21
|
if (ts.isIdentifier(node) && paramMap?.has(node.text)) {
|
|
23
22
|
return resolveNodeValue(
|
|
24
23
|
paramMap.get(node.text)!,
|
|
@@ -33,37 +32,23 @@ export function resolveNodeValue(
|
|
|
33
32
|
return { values: [node.text], dynamic: false };
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
// ARRAY
|
|
37
|
-
if (ts.isArrayLiteralExpression(node)) {
|
|
38
|
-
const values: string[] = [];
|
|
39
|
-
|
|
40
|
-
for (const el of node.elements) {
|
|
41
|
-
const res = resolveNodeValue(el, checker, paramMap, seen);
|
|
42
|
-
if (res.values.length) {
|
|
43
|
-
values.push(...res.values);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
values: [...new Set(values)],
|
|
49
|
-
dynamic: true
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
35
|
// TEMPLATE
|
|
54
36
|
if (ts.isTemplateExpression(node)) {
|
|
55
37
|
let results = node.head.text ? [node.head.text] : [""];
|
|
56
38
|
|
|
57
39
|
for (const span of node.templateSpans) {
|
|
58
|
-
const res = resolveNodeValue(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
40
|
+
const res = resolveNodeValue(
|
|
41
|
+
span.expression,
|
|
42
|
+
checker,
|
|
43
|
+
paramMap,
|
|
44
|
+
seen
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
results = results.flatMap(r =>
|
|
48
|
+
res.values.length
|
|
49
|
+
? res.values.map(v => r + v)
|
|
50
|
+
: [r + "*"]
|
|
51
|
+
);
|
|
67
52
|
|
|
68
53
|
results = results.map(r => r + span.literal.text);
|
|
69
54
|
}
|
|
@@ -71,7 +56,7 @@ export function resolveNodeValue(
|
|
|
71
56
|
return { values: results, dynamic: true };
|
|
72
57
|
}
|
|
73
58
|
|
|
74
|
-
// CONDITIONAL
|
|
59
|
+
// CONDITIONAL (a ? b : c)
|
|
75
60
|
if (ts.isConditionalExpression(node)) {
|
|
76
61
|
const a = resolveNodeValue(node.whenTrue, checker, paramMap, seen);
|
|
77
62
|
const b = resolveNodeValue(node.whenFalse, checker, paramMap, seen);
|
|
@@ -82,12 +67,69 @@ export function resolveNodeValue(
|
|
|
82
67
|
};
|
|
83
68
|
}
|
|
84
69
|
|
|
70
|
+
// OBJECT → берём ВСЕ значения (без привязки к ключам)
|
|
71
|
+
if (ts.isObjectLiteralExpression(node)) {
|
|
72
|
+
const values: string[] = [];
|
|
73
|
+
|
|
74
|
+
for (const prop of node.properties) {
|
|
75
|
+
if (!ts.isPropertyAssignment(prop)) continue;
|
|
76
|
+
|
|
77
|
+
const res = resolveNodeValue(
|
|
78
|
+
prop.initializer,
|
|
79
|
+
checker,
|
|
80
|
+
paramMap,
|
|
81
|
+
seen
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
values.push(...res.values);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
values: [...new Set(values)],
|
|
89
|
+
dynamic: true,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ARRAY
|
|
94
|
+
if (ts.isArrayLiteralExpression(node)) {
|
|
95
|
+
const values: string[] = [];
|
|
96
|
+
|
|
97
|
+
for (const el of node.elements) {
|
|
98
|
+
const res = resolveNodeValue(el, checker, paramMap, seen);
|
|
99
|
+
values.push(...res.values);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
values: [...new Set(values)],
|
|
104
|
+
dynamic: true,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// BINARY CONCAT
|
|
109
|
+
if (ts.isBinaryExpression(node)) {
|
|
110
|
+
if (node.operatorToken.kind === ts.SyntaxKind.PlusToken) {
|
|
111
|
+
const left = resolveNodeValue(node.left, checker, paramMap, seen);
|
|
112
|
+
const right = resolveNodeValue(node.right, checker, paramMap, seen);
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
values: left.values.flatMap(l =>
|
|
116
|
+
right.values.length
|
|
117
|
+
? right.values.map(r => l + r)
|
|
118
|
+
: [l + "*"]
|
|
119
|
+
),
|
|
120
|
+
dynamic: true,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
85
125
|
// IDENTIFIER
|
|
86
126
|
if (ts.isIdentifier(node)) {
|
|
87
127
|
let symbol = checker.getSymbolAtLocation(node);
|
|
88
128
|
if (!symbol) return { values: [], dynamic: true };
|
|
89
129
|
|
|
90
|
-
|
|
130
|
+
symbol = resolveExportedSymbol(symbol, checker) ?? symbol;
|
|
131
|
+
|
|
132
|
+
// const VAR = "click"
|
|
91
133
|
for (const decl of symbol.getDeclarations() ?? []) {
|
|
92
134
|
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
93
135
|
return resolveNodeValue(
|
|
@@ -97,16 +139,8 @@ export function resolveNodeValue(
|
|
|
97
139
|
seen
|
|
98
140
|
);
|
|
99
141
|
}
|
|
100
|
-
}
|
|
101
142
|
|
|
102
|
-
|
|
103
|
-
symbol = resolveExportedSymbol(symbol, checker) ?? symbol;
|
|
104
|
-
|
|
105
|
-
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
106
|
-
symbol = checker.getAliasedSymbol(symbol);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
for (const decl of symbol.getDeclarations() ?? []) {
|
|
143
|
+
// enum
|
|
110
144
|
if (ts.isEnumMember(decl) && decl.initializer) {
|
|
111
145
|
if (ts.isStringLiteral(decl.initializer)) {
|
|
112
146
|
return {
|
|
@@ -117,37 +151,11 @@ export function resolveNodeValue(
|
|
|
117
151
|
}
|
|
118
152
|
}
|
|
119
153
|
|
|
120
|
-
const type = checker.getTypeAtLocation(node);
|
|
121
|
-
|
|
122
|
-
// UNION
|
|
123
|
-
if (type.isUnion()) {
|
|
124
|
-
const values: string[] = [];
|
|
125
|
-
|
|
126
|
-
for (const t of type.types) {
|
|
127
|
-
if (t.flags & ts.TypeFlags.StringLiteral) {
|
|
128
|
-
values.push((t as ts.StringLiteralType).value);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (values.length) {
|
|
133
|
-
return { values, dynamic: false };
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// STRING LITERAL TYPE
|
|
138
|
-
if (type.flags & ts.TypeFlags.StringLiteral) {
|
|
139
|
-
return {
|
|
140
|
-
values: [(type as ts.StringLiteralType).value],
|
|
141
|
-
dynamic: false
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
154
|
return { values: [], dynamic: true };
|
|
146
155
|
}
|
|
147
156
|
|
|
148
|
-
// PROPERTY ACCESS
|
|
157
|
+
// PROPERTY ACCESS (ENUM / CONST)
|
|
149
158
|
if (ts.isPropertyAccessExpression(node)) {
|
|
150
|
-
|
|
151
159
|
const symbol = checker.getSymbolAtLocation(node);
|
|
152
160
|
|
|
153
161
|
if (symbol) {
|
|
@@ -169,130 +177,21 @@ export function resolveNodeValue(
|
|
|
169
177
|
}
|
|
170
178
|
}
|
|
171
179
|
|
|
172
|
-
|
|
173
|
-
if (typeof constantValue === "string") {
|
|
174
|
-
return { values: [constantValue], dynamic: false };
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const type = checker.getTypeAtLocation(node);
|
|
178
|
-
|
|
179
|
-
if (type.flags & ts.TypeFlags.StringLiteral) {
|
|
180
|
-
return {
|
|
181
|
-
values: [(type as ts.StringLiteralType).value],
|
|
182
|
-
dynamic: false,
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// object literal resolve
|
|
187
|
-
if (ts.isIdentifier(node.expression)) {
|
|
188
|
-
const objSymbol = checker.getSymbolAtLocation(node.expression);
|
|
189
|
-
|
|
190
|
-
if (objSymbol) {
|
|
191
|
-
for (const decl of objSymbol.getDeclarations() ?? []) {
|
|
192
|
-
if (
|
|
193
|
-
ts.isVariableDeclaration(decl) &&
|
|
194
|
-
decl.initializer &&
|
|
195
|
-
ts.isObjectLiteralExpression(decl.initializer)
|
|
196
|
-
) {
|
|
197
|
-
for (const prop of decl.initializer.properties) {
|
|
198
|
-
if (!ts.isPropertyAssignment(prop)) continue;
|
|
199
|
-
|
|
200
|
-
const name = prop.name.getText();
|
|
201
|
-
|
|
202
|
-
if (name === node.name.text) {
|
|
203
|
-
return resolveNodeValue(
|
|
204
|
-
prop.initializer,
|
|
205
|
-
checker,
|
|
206
|
-
paramMap,
|
|
207
|
-
seen
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// fallback
|
|
217
|
-
return resolveNodeValue(node.name, checker, paramMap, seen);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// ARRAY ACCESS
|
|
221
|
-
if (ts.isElementAccessExpression(node)) {
|
|
222
|
-
const obj = resolveNodeValue(node.expression, checker, paramMap, seen);
|
|
223
|
-
|
|
224
|
-
if (!node.argumentExpression) {
|
|
225
|
-
return { values: obj.values, dynamic: true };
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const index = resolveNodeValue(
|
|
229
|
-
node.argumentExpression,
|
|
230
|
-
checker,
|
|
231
|
-
paramMap,
|
|
232
|
-
seen
|
|
233
|
-
);
|
|
234
|
-
|
|
235
|
-
if (index.values.length === 1) {
|
|
236
|
-
const i = Number(index.values[0]);
|
|
237
|
-
|
|
238
|
-
if (!Number.isNaN(i) && obj.values[i] !== undefined) {
|
|
239
|
-
return {
|
|
240
|
-
values: [obj.values[i]],
|
|
241
|
-
dynamic: false,
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return obj.values.length
|
|
247
|
-
? { values: obj.values, dynamic: true }
|
|
248
|
-
: { values: [], dynamic: true };
|
|
180
|
+
return { values: [], dynamic: true };
|
|
249
181
|
}
|
|
250
182
|
|
|
251
|
-
//
|
|
252
|
-
if (ts.
|
|
183
|
+
// CALL → unwrap args
|
|
184
|
+
if (ts.isCallExpression(node)) {
|
|
253
185
|
const values: string[] = [];
|
|
254
186
|
|
|
255
|
-
for (const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const name = prop.name.getText();
|
|
259
|
-
|
|
260
|
-
if (["event", "name", "type"].includes(name)) {
|
|
261
|
-
const res = resolveNodeValue(prop.initializer, checker, paramMap, seen);
|
|
262
|
-
values.push(...res.values);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return {
|
|
267
|
-
values: [...new Set(values)],
|
|
268
|
-
dynamic: true
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// BINARY ("btn_" + name)
|
|
273
|
-
if (ts.isBinaryExpression(node)) {
|
|
274
|
-
if (node.operatorToken.kind === ts.SyntaxKind.PlusToken) {
|
|
275
|
-
const left = resolveNodeValue(node.left, checker, paramMap, seen);
|
|
276
|
-
const right = resolveNodeValue(node.right, checker, paramMap, seen);
|
|
277
|
-
|
|
278
|
-
if (!left.values.length) {
|
|
279
|
-
return { values: [], dynamic: true };
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return {
|
|
283
|
-
values: left.values.flatMap(l =>
|
|
284
|
-
right.values.length
|
|
285
|
-
? right.values.map(r => l + r)
|
|
286
|
-
: [l + "*"]
|
|
287
|
-
),
|
|
288
|
-
dynamic: true,
|
|
289
|
-
};
|
|
187
|
+
for (const arg of node.arguments) {
|
|
188
|
+
const res = resolveNodeValue(arg, checker, paramMap, seen);
|
|
189
|
+
values.push(...res.values);
|
|
290
190
|
}
|
|
291
|
-
}
|
|
292
191
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
192
|
+
return values.length
|
|
193
|
+
? { values, dynamic: true }
|
|
194
|
+
: { values: [], dynamic: true };
|
|
296
195
|
}
|
|
297
196
|
|
|
298
197
|
return { values: [], dynamic: true };
|