@eventra_dev/eventra-cli 0.1.29 → 0.1.30

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.
@@ -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 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
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
- // string literal
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 name = prop.name.getText();
64
- if (["event", "name", "type"].includes(name)) {
65
- return checkArg(prop.initializer);
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
- let isTrackCall = false;
83
- if (typescript_1.default.isPropertyAccessExpression(node.expression)) {
84
- if (node.expression.name.text === "track") {
85
- isTrackCall = true;
86
- }
87
- }
88
- if (typescript_1.default.isIdentifier(node.expression)) {
89
- if (node.expression.text === "track") {
90
- isTrackCall = true;
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);
@@ -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 MAPPING
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
- if (res.values.length) {
42
- results = results.flatMap(r => res.values.map(v => r + v));
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
- // INLINE FIRST
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
- const constantValue = checker.getConstantValue(node);
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
- // OBJECT
182
- if (typescript_1.default.isObjectLiteralExpression(node)) {
126
+ // CALL → unwrap args
127
+ if (typescript_1.default.isCallExpression(node)) {
183
128
  const values = [];
184
- for (const prop of node.properties) {
185
- if (!typescript_1.default.isPropertyAssignment(prop))
186
- continue;
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
- // CALL → dynamic
215
- if (typescript_1.default.isCallExpression(node)) {
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
  }
@@ -7,10 +7,8 @@ exports.scanSource = scanSource;
7
7
  const typescript_1 = __importDefault(require("typescript"));
8
8
  const resolver_1 = require("./resolver");
9
9
  const callResolver_1 = require("./callResolver");
10
- const exportResolver_1 = require("./exportResolver");
11
10
  const functionAnalyzer_1 = require("./functionAnalyzer");
12
11
  const boundary_1 = require("./boundary");
13
- const trackingDetector_1 = require("./trackingDetector");
14
12
  function getCallName(expr) {
15
13
  if (typescript_1.default.isIdentifier(expr))
16
14
  return expr.text;
@@ -25,31 +23,7 @@ function isValidEvent(v) {
25
23
  !v.includes(" ") &&
26
24
  /^[a-zA-Z0-9._:-]+$/.test(v));
27
25
  }
28
- function resolveFunctionDeep(expr, checker) {
29
- let fn = (0, callResolver_1.resolveFunctionFromCall)(expr, checker);
30
- if (fn)
31
- return fn;
32
- let symbol = checker.getSymbolAtLocation(expr);
33
- if (!symbol)
34
- return null;
35
- if (symbol.flags & typescript_1.default.SymbolFlags.Alias) {
36
- symbol = checker.getAliasedSymbol(symbol);
37
- }
38
- const resolvedSymbol = (0, exportResolver_1.resolveExportedSymbol)(symbol, checker) ?? symbol;
39
- for (const decl of resolvedSymbol.getDeclarations() ?? []) {
40
- if (typescript_1.default.isFunctionDeclaration(decl)) {
41
- return decl;
42
- }
43
- if (typescript_1.default.isVariableDeclaration(decl) &&
44
- decl.initializer &&
45
- (typescript_1.default.isArrowFunction(decl.initializer) ||
46
- typescript_1.default.isFunctionExpression(decl.initializer))) {
47
- return decl.initializer;
48
- }
49
- }
50
- return null;
51
- }
52
- function scanSource(source, checker, config, visited = new Set(), depth = 0, inheritedParamMap) {
26
+ function scanSource(source, checker, config, visited = new Set(), inheritedParamMap) {
53
27
  const events = new Set();
54
28
  const detectedFunctionWrappers = new Set();
55
29
  const detectedComponentWrappers = new Map();
@@ -58,42 +32,24 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
58
32
  }
59
33
  visited.add(source.fileName);
60
34
  function visit(node) {
61
- // CALL EXPRESSIONS
62
35
  if (typescript_1.default.isCallExpression(node)) {
63
36
  const name = getCallName(node.expression);
64
37
  const isKnownWrapper = config.functionWrappers.some(w => w.name === name);
65
- const isTrackingByType = (0, trackingDetector_1.isTrackingCall)(node, checker);
66
- const resolvedFn = resolveFunctionDeep(node.expression, checker);
67
- const isAutoWrapper = resolvedFn && (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn) !== null;
68
- let isTracking = isKnownWrapper ||
69
- isTrackingByType ||
70
- name.startsWith("$") ||
38
+ const resolvedFn = (0, callResolver_1.resolveFunctionFromCall)(node.expression, checker);
39
+ const isAutoWrapper = !!resolvedFn && (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn) !== null;
40
+ const isTracking = name === "track" ||
41
+ isKnownWrapper ||
71
42
  (isAutoWrapper &&
72
43
  resolvedFn &&
73
- resolvedFn.getSourceFile &&
74
44
  !(0, boundary_1.isExternalFile)(resolvedFn.getSourceFile().fileName));
75
- if (!isTracking) {
76
- if (typescript_1.default.isPropertyAccessExpression(node.expression) &&
77
- node.expression.name.text === "track") {
78
- isTracking = true;
79
- }
80
- else if (typescript_1.default.isIdentifier(node.expression) &&
81
- node.expression.text === "track") {
82
- isTracking = true;
83
- }
84
- }
85
45
  if (!isTracking) {
86
46
  typescript_1.default.forEachChild(node, visit);
87
47
  return;
88
48
  }
89
- // DETECT WRAPPER
90
- if (!isKnownWrapper &&
91
- isAutoWrapper &&
92
- !isTrackingByType &&
93
- !name.startsWith("track")) {
49
+ // авто-детект wrapper
50
+ if (!isKnownWrapper && isAutoWrapper && name !== "track") {
94
51
  detectedFunctionWrappers.add(name);
95
52
  }
96
- // PARAM MAP
97
53
  const paramMap = new Map(inheritedParamMap ?? []);
98
54
  if (resolvedFn && typescript_1.default.isFunctionLike(resolvedFn)) {
99
55
  resolvedFn.parameters.forEach((param, i) => {
@@ -105,22 +61,23 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
105
61
  }
106
62
  });
107
63
  }
108
- // STRICT EVENT RESOLVE
64
+ // ✅ ТОЛЬКО правильный аргумент
109
65
  if (resolvedFn) {
110
66
  const idx = (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn);
111
67
  if (idx !== null && node.arguments[idx]) {
112
68
  const res = (0, resolver_1.resolveNodeValue)(node.arguments[idx], checker, paramMap);
113
- res.values.forEach(v => {
114
- if (isValidEvent(v))
69
+ for (const v of res.values) {
70
+ if (isValidEvent(v)) {
115
71
  events.add(v);
116
- });
72
+ }
73
+ }
117
74
  }
118
75
  }
119
- // CROSS-FILE
76
+ // CROSS FILE
120
77
  if (resolvedFn) {
121
- const sf = resolvedFn.getSourceFile?.();
122
- if (sf && !visited.has(sf.fileName)) {
123
- const res = scanSource(sf, checker, config, visited, depth + 1, paramMap);
78
+ const sf = resolvedFn.getSourceFile();
79
+ if (!visited.has(sf.fileName)) {
80
+ const res = scanSource(sf, checker, config, visited, paramMap);
124
81
  res.events.forEach(e => events.add(e));
125
82
  }
126
83
  }
@@ -5,64 +5,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.isTrackingCall = isTrackingCall;
7
7
  const typescript_1 = __importDefault(require("typescript"));
8
- function isStringLike(type) {
9
- return ((type.flags & typescript_1.default.TypeFlags.StringLike) !== 0 ||
10
- (type.flags & typescript_1.default.TypeFlags.StringLiteral) !== 0);
11
- }
12
- function hasTrackLikeSignature(type, checker) {
13
- const sigs = type.getCallSignatures();
14
- for (const sig of sigs) {
15
- const params = sig.getParameters();
16
- if (!params.length)
17
- continue;
18
- const t = checker.getTypeOfSymbolAtLocation(params[0], params[0].valueDeclaration);
19
- if (isStringLike(t)) {
20
- return true;
21
- }
22
- }
23
- return false;
24
- }
25
- function isEventraLikeType(type, checker) {
26
- const props = type.getProperties();
27
- for (const prop of props) {
28
- const decl = prop.valueDeclaration ?? prop.declarations?.[0];
29
- if (!decl)
30
- continue;
31
- const t = checker.getTypeOfSymbolAtLocation(prop, decl);
32
- if (hasTrackLikeSignature(t, checker)) {
33
- return true;
34
- }
35
- }
36
- return false;
37
- }
38
- function isTrackingCall(node, checker) {
8
+ function isTrackingCall(node) {
39
9
  const expr = node.expression;
40
- // fn(...)
41
10
  if (typescript_1.default.isIdentifier(expr)) {
42
- const type = checker.getTypeAtLocation(expr);
43
- if (hasTrackLikeSignature(type, checker)) {
44
- return true;
45
- }
11
+ return expr.text === "track";
46
12
  }
47
- // obj.method(...)
48
13
  if (typescript_1.default.isPropertyAccessExpression(expr)) {
49
- const objType = checker.getTypeAtLocation(expr.expression);
50
- // объект похож на tracker
51
- if (isEventraLikeType(objType, checker)) {
52
- return true;
53
- }
54
- // fallback
55
- const methodType = checker.getTypeAtLocation(expr.name);
56
- if (hasTrackLikeSignature(methodType, checker)) {
57
- return true;
58
- }
59
- }
60
- // obj["track"](...)
61
- if (typescript_1.default.isElementAccessExpression(expr)) {
62
- const objType = checker.getTypeAtLocation(expr.expression);
63
- if (isEventraLikeType(objType, checker)) {
64
- return true;
65
- }
14
+ return expr.name.text === "track";
66
15
  }
67
16
  return false;
68
17
  }