@eventra_dev/eventra-cli 0.1.9 → 0.1.10

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.
@@ -25,11 +25,21 @@ async function sync() {
25
25
  const engine = new engine_1.EventraEngine(process.cwd());
26
26
  const detectedFn = new Set();
27
27
  const detectedCmp = new Map();
28
+ const fileCache = [];
28
29
  for (const file of files) {
29
30
  try {
30
31
  const raw = await promises_1.default.readFile(file, "utf-8");
31
32
  const { content, virtualFile } = (0, processFile_1.processFile)(file, raw);
32
- const res = engine.scanFile(virtualFile, content, config);
33
+ fileCache.push({ file: virtualFile, content });
34
+ engine["ts"].updateFile(virtualFile, content);
35
+ }
36
+ catch {
37
+ // ignore
38
+ }
39
+ }
40
+ for (const { file, content } of fileCache) {
41
+ try {
42
+ const res = engine.scanFile(file, content, config);
33
43
  for (const w of res.detectedFunctionWrappers) {
34
44
  detectedFn.add(w);
35
45
  }
@@ -48,9 +48,6 @@ class TSService {
48
48
  },
49
49
  getScriptVersion: (file) => this.files.get(file)?.version.toString() ?? "0",
50
50
  getScriptSnapshot: (file) => {
51
- if (!this.fileNames.has(file)) {
52
- return undefined;
53
- }
54
51
  const f = this.files.get(file);
55
52
  if (f) {
56
53
  return typescript_1.default.ScriptSnapshot.fromString(f.content);
@@ -37,8 +37,10 @@ function isPropUsedInTracking(fn, prop) {
37
37
  function visit(node) {
38
38
  if (typescript_1.default.isCallExpression(node)) {
39
39
  const name = getCallName(node.expression);
40
- if (!TRACKING_NAMES.has(name))
40
+ if (!TRACKING_NAMES.has(name)) {
41
+ typescript_1.default.forEachChild(node, visit);
41
42
  return;
43
+ }
42
44
  for (const arg of node.arguments) {
43
45
  if ((typescript_1.default.isIdentifier(arg) && arg.text === prop) ||
44
46
  (typescript_1.default.isPropertyAccessExpression(arg) &&
@@ -65,22 +67,40 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
65
67
  if (typescript_1.default.isCallExpression(node)) {
66
68
  const name = getCallName(node.expression);
67
69
  const isKnownWrapper = config.functionWrappers.some(w => w.name === name);
68
- const fn = (0, callResolver_1.resolveFunctionFromCall)(node.expression, checker);
69
- const isAutoWrapper = fn && (0, functionAnalyzer_1.findTrackParamIndex)(fn) !== null;
70
+ let resolvedFn = (0, callResolver_1.resolveFunctionFromCall)(node.expression, checker);
71
+ // fallback: tracker.track(...)
72
+ if (!resolvedFn && typescript_1.default.isPropertyAccessExpression(node.expression)) {
73
+ const symbol = checker.getSymbolAtLocation(node.expression.name);
74
+ if (symbol) {
75
+ const decls = symbol.getDeclarations();
76
+ if (decls?.length) {
77
+ const d = decls[0];
78
+ if (typescript_1.default.isMethodDeclaration(d) ||
79
+ typescript_1.default.isFunctionDeclaration(d) ||
80
+ typescript_1.default.isFunctionExpression(d) ||
81
+ typescript_1.default.isArrowFunction(d)) {
82
+ resolvedFn = d;
83
+ }
84
+ }
85
+ }
86
+ }
87
+ const isAutoWrapper = resolvedFn && (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn) !== null;
70
88
  const isTracking = isKnownWrapper ||
71
89
  TRACKING_NAMES.has(name) ||
72
90
  (isAutoWrapper &&
73
- fn &&
74
- !(0, boundary_1.isExternalFile)(fn.getSourceFile().fileName));
75
- if (!isTracking)
91
+ resolvedFn &&
92
+ !(0, boundary_1.isExternalFile)(resolvedFn.getSourceFile().fileName));
93
+ if (!isTracking) {
94
+ typescript_1.default.forEachChild(node, visit);
76
95
  return;
96
+ }
77
97
  if (!isKnownWrapper && isAutoWrapper && !TRACKING_NAMES.has(name)) {
78
98
  detectedFunctionWrappers.add(name);
79
99
  }
80
- // paramMap
100
+ // paramMap (chain support)
81
101
  const paramMap = new Map(inheritedParamMap ?? []);
82
- if (fn && typescript_1.default.isFunctionLike(fn)) {
83
- fn.parameters.forEach((param, i) => {
102
+ if (resolvedFn && typescript_1.default.isFunctionLike(resolvedFn)) {
103
+ resolvedFn.parameters.forEach((param, i) => {
84
104
  const arg = node.arguments[i];
85
105
  if (!arg)
86
106
  return;
@@ -90,8 +110,8 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
90
110
  });
91
111
  }
92
112
  let handled = false;
93
- if (fn) {
94
- const idx = (0, functionAnalyzer_1.findTrackParamIndex)(fn);
113
+ if (resolvedFn) {
114
+ const idx = (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn);
95
115
  if (idx !== null && node.arguments[idx]) {
96
116
  const res = (0, resolver_1.resolveNodeValue)(node.arguments[idx], checker, paramMap);
97
117
  res?.values.forEach(v => {
@@ -101,7 +121,6 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
101
121
  handled = true;
102
122
  }
103
123
  }
104
- // fallback
105
124
  if (!handled) {
106
125
  for (const arg of node.arguments) {
107
126
  const res = (0, resolver_1.resolveNodeValue)(arg, checker, paramMap);
@@ -111,9 +130,9 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
111
130
  });
112
131
  }
113
132
  }
114
- // cross-file WITH paramMap
115
- if (fn) {
116
- const sf = fn.getSourceFile();
133
+ // cross-file with paramMap
134
+ if (resolvedFn) {
135
+ const sf = resolvedFn.getSourceFile();
117
136
  if (!visited.has(sf.fileName)) {
118
137
  const res = scanSource(sf, checker, config, visited, depth + 1, paramMap);
119
138
  res.events.forEach(e => events.add(e));
@@ -133,8 +152,10 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
133
152
  if (symbol && (symbol.flags & typescript_1.default.SymbolFlags.Alias)) {
134
153
  symbol = checker.getAliasedSymbol(symbol);
135
154
  }
136
- if (!symbol)
155
+ if (!symbol) {
156
+ typescript_1.default.forEachChild(node, visit);
137
157
  return;
158
+ }
138
159
  const tagName = typescript_1.default.isPropertyAccessExpression(node.tagName)
139
160
  ? node.tagName.name.getText()
140
161
  : node.tagName.getText();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventra_dev/eventra-cli",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Eventra CLI",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -26,13 +26,24 @@ export async function sync() {
26
26
  const detectedFn = new Set<string>();
27
27
  const detectedCmp = new Map<string, string>();
28
28
 
29
+ const fileCache: { file: string; content: string }[] = [];
30
+
29
31
  for (const file of files) {
30
32
  try {
31
33
  const raw = await fs.readFile(file, "utf-8");
32
-
33
34
  const { content, virtualFile } = processFile(file, raw);
34
35
 
35
- const res = engine.scanFile(virtualFile, content, config);
36
+ fileCache.push({ file: virtualFile, content });
37
+
38
+ engine["ts"].updateFile(virtualFile, content);
39
+ } catch {
40
+ // ignore
41
+ }
42
+ }
43
+
44
+ for (const { file, content } of fileCache) {
45
+ try {
46
+ const res = engine.scanFile(file, content, config);
36
47
 
37
48
  for (const w of res.detectedFunctionWrappers) {
38
49
  detectedFn.add(w);
@@ -62,10 +62,6 @@ export class TSService {
62
62
  this.files.get(file)?.version.toString() ?? "0",
63
63
 
64
64
  getScriptSnapshot: (file) => {
65
- if (!this.fileNames.has(file)) {
66
- return undefined;
67
- }
68
-
69
65
  const f = this.files.get(file);
70
66
 
71
67
  if (f) {
@@ -40,7 +40,10 @@ function isPropUsedInTracking(
40
40
  if (ts.isCallExpression(node)) {
41
41
  const name = getCallName(node.expression);
42
42
 
43
- if (!TRACKING_NAMES.has(name)) return;
43
+ if (!TRACKING_NAMES.has(name)) {
44
+ ts.forEachChild(node, visit);
45
+ return;
46
+ }
44
47
 
45
48
  for (const arg of node.arguments) {
46
49
  if (
@@ -93,29 +96,54 @@ export function scanSource(
93
96
  w => w.name === name
94
97
  );
95
98
 
96
- const fn = resolveFunctionFromCall(node.expression, checker);
99
+ let resolvedFn = resolveFunctionFromCall(node.expression, checker);
100
+
101
+ // fallback: tracker.track(...)
102
+ if (!resolvedFn && ts.isPropertyAccessExpression(node.expression)) {
103
+ const symbol = checker.getSymbolAtLocation(node.expression.name);
104
+
105
+ if (symbol) {
106
+ const decls = symbol.getDeclarations();
107
+
108
+ if (decls?.length) {
109
+ const d = decls[0];
110
+
111
+ if (
112
+ ts.isMethodDeclaration(d) ||
113
+ ts.isFunctionDeclaration(d) ||
114
+ ts.isFunctionExpression(d) ||
115
+ ts.isArrowFunction(d)
116
+ ) {
117
+ resolvedFn = d;
118
+ }
119
+ }
120
+ }
121
+ }
97
122
 
98
123
  const isAutoWrapper =
99
- fn && findTrackParamIndex(fn) !== null;
124
+ resolvedFn && findTrackParamIndex(resolvedFn) !== null;
100
125
 
101
126
  const isTracking =
102
127
  isKnownWrapper ||
103
128
  TRACKING_NAMES.has(name) ||
104
129
  (isAutoWrapper &&
105
- fn &&
106
- !isExternalFile(fn.getSourceFile().fileName));
130
+ resolvedFn &&
131
+ !isExternalFile(resolvedFn.getSourceFile().fileName));
107
132
 
108
- if (!isTracking) return;
133
+ if (!isTracking) {
134
+ ts.forEachChild(node, visit);
135
+ return;
136
+ }
109
137
 
110
138
  if (!isKnownWrapper && isAutoWrapper && !TRACKING_NAMES.has(name)) {
111
139
  detectedFunctionWrappers.add(name);
112
140
  }
113
141
 
114
- // paramMap
142
+ // paramMap (chain support)
115
143
  const paramMap = new Map(inheritedParamMap ?? []);
116
144
 
117
- if (fn && ts.isFunctionLike(fn)) {
118
- fn.parameters.forEach((param, i) => {
145
+ if (resolvedFn && ts.isFunctionLike(resolvedFn)) {
146
+ resolvedFn.parameters.forEach((param, i) => {
119
147
  const arg = node.arguments[i];
120
148
  if (!arg) return;
121
149
 
@@ -127,8 +155,8 @@ export function scanSource(
127
155
 
128
156
  let handled = false;
129
157
 
130
- if (fn) {
131
- const idx = findTrackParamIndex(fn);
158
+ if (resolvedFn) {
159
+ const idx = findTrackParamIndex(resolvedFn);
132
160
 
133
161
  if (idx !== null && node.arguments[idx]) {
134
162
  const res = resolveNodeValue(
@@ -145,7 +173,6 @@ export function scanSource(
145
173
  }
146
174
  }
147
175
 
148
- // fallback
149
176
  if (!handled) {
150
177
  for (const arg of node.arguments) {
151
178
  const res = resolveNodeValue(arg, checker, paramMap);
@@ -156,9 +183,9 @@ export function scanSource(
156
183
  }
157
184
  }
158
185
 
159
- // cross-file WITH paramMap
160
- if (fn) {
161
- const sf = fn.getSourceFile();
186
+ // cross-file with paramMap
187
+ if (resolvedFn) {
188
+ const sf = resolvedFn.getSourceFile();
162
189
 
163
190
  if (!visited.has(sf.fileName)) {
164
191
  const res = scanSource(
@@ -195,7 +222,10 @@ export function scanSource(
195
222
  symbol = checker.getAliasedSymbol(symbol);
196
223
  }
197
224
 
198
- if (!symbol) return;
225
+ if (!symbol) {
226
+ ts.forEachChild(node, visit);
227
+ return;
228
+ }
199
229
 
200
230
  const tagName =
201
231
  ts.isPropertyAccessExpression(node.tagName)
@@ -209,6 +239,7 @@ export function scanSource(
209
239
 
210
240
  if (ts.isVariableDeclaration(decl) && decl.initializer) {
211
241
  const init = decl.initializer;
242
+
212
243
  if (
213
244
  ts.isArrowFunction(init) ||
214
245
  ts.isFunctionExpression(init)