@eventra_dev/eventra-cli 0.1.30 → 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 CHANGED
@@ -170,7 +170,6 @@ eventra send
170
170
  "events": [],
171
171
  "wrappers": [],
172
172
  "functionWrappers": [],
173
- "aliases": {},
174
173
  "sync": {
175
174
  "include": ["**/*.{ts,tsx,js,jsx,vue,svelte,astro}"],
176
175
  "exclude": ["node_modules", "dist", ".next", ".git"]
@@ -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
- // обновляем graph
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
  }
@@ -8,7 +8,24 @@ const typescript_1 = __importDefault(require("typescript"));
8
8
  const resolver_1 = require("./resolver");
9
9
  const callResolver_1 = require("./callResolver");
10
10
  const functionAnalyzer_1 = require("./functionAnalyzer");
11
+ const exportResolver_1 = require("./exportResolver");
11
12
  const boundary_1 = require("./boundary");
13
+ // UTILS
14
+ function getJsxAttrName(name) {
15
+ if (typescript_1.default.isIdentifier(name))
16
+ return name.text;
17
+ if (typescript_1.default.isJsxNamespacedName(name))
18
+ return name.name.text;
19
+ return "";
20
+ }
21
+ function getJsxTagName(tag) {
22
+ if (typescript_1.default.isIdentifier(tag))
23
+ return tag.text;
24
+ if (typescript_1.default.isPropertyAccessExpression(tag)) {
25
+ return tag.name.text;
26
+ }
27
+ return "";
28
+ }
12
29
  function getCallName(expr) {
13
30
  if (typescript_1.default.isIdentifier(expr))
14
31
  return expr.text;
@@ -23,7 +40,104 @@ function isValidEvent(v) {
23
40
  !v.includes(" ") &&
24
41
  /^[a-zA-Z0-9._:-]+$/.test(v));
25
42
  }
26
- function scanSource(source, checker, config, visited = new Set(), inheritedParamMap) {
43
+ // COMPONENT ANALYSIS
44
+ function getComponentPropsMap(fn) {
45
+ const map = new Map();
46
+ const firstParam = fn.parameters[0];
47
+ if (!firstParam)
48
+ return map;
49
+ // ({ event }) => ...
50
+ if (typescript_1.default.isObjectBindingPattern(firstParam.name)) {
51
+ for (const el of firstParam.name.elements) {
52
+ if (!typescript_1.default.isBindingElement(el))
53
+ continue;
54
+ const propName = el.propertyName?.getText() || el.name.getText();
55
+ map.set(el.name.getText(), propName);
56
+ }
57
+ }
58
+ // (props) => props.event
59
+ if (typescript_1.default.isIdentifier(firstParam.name)) {
60
+ map.set(firstParam.name.text, "*");
61
+ }
62
+ return map;
63
+ }
64
+ function findTrackedPropName(fn, checker) {
65
+ const propMap = getComponentPropsMap(fn);
66
+ let result = null;
67
+ function resolveIdentifierToProp(node) {
68
+ const mapped = propMap.get(node.text);
69
+ if (mapped && mapped !== "*")
70
+ return mapped;
71
+ const symbol = checker.getSymbolAtLocation(node);
72
+ if (!symbol)
73
+ return null;
74
+ for (const decl of symbol.getDeclarations() ?? []) {
75
+ // const e = props.event
76
+ if (typescript_1.default.isVariableDeclaration(decl) &&
77
+ decl.initializer &&
78
+ typescript_1.default.isPropertyAccessExpression(decl.initializer)) {
79
+ return decl.initializer.name.text;
80
+ }
81
+ // const e = event
82
+ if (typescript_1.default.isVariableDeclaration(decl) &&
83
+ decl.initializer &&
84
+ typescript_1.default.isIdentifier(decl.initializer)) {
85
+ const inner = propMap.get(decl.initializer.text);
86
+ if (inner)
87
+ return inner;
88
+ }
89
+ }
90
+ return null;
91
+ }
92
+ function visit(node) {
93
+ if (result)
94
+ return;
95
+ if (typescript_1.default.isCallExpression(node)) {
96
+ const expr = node.expression;
97
+ const isTrack = (typescript_1.default.isIdentifier(expr) && expr.text === "track") ||
98
+ (typescript_1.default.isPropertyAccessExpression(expr) &&
99
+ expr.name.text === "track");
100
+ if (!isTrack) {
101
+ typescript_1.default.forEachChild(node, visit);
102
+ return;
103
+ }
104
+ for (const arg of node.arguments) {
105
+ // track(event)
106
+ if (typescript_1.default.isIdentifier(arg)) {
107
+ const prop = resolveIdentifierToProp(arg);
108
+ if (prop) {
109
+ result = prop;
110
+ return;
111
+ }
112
+ }
113
+ // track(props.a.b.event)
114
+ if (typescript_1.default.isPropertyAccessExpression(arg)) {
115
+ let current = arg;
116
+ while (typescript_1.default.isPropertyAccessExpression(current)) {
117
+ result = current.name.text;
118
+ return;
119
+ }
120
+ }
121
+ // track(fn())
122
+ if (typescript_1.default.isCallExpression(arg)) {
123
+ const inner = (0, callResolver_1.resolveFunctionFromCall)(arg.expression, checker);
124
+ if (inner?.body) {
125
+ visit(inner.body);
126
+ if (result)
127
+ return;
128
+ }
129
+ }
130
+ }
131
+ }
132
+ typescript_1.default.forEachChild(node, visit);
133
+ }
134
+ if (fn.body)
135
+ visit(fn.body);
136
+ return result;
137
+ }
138
+ // MAIN SCANNER
139
+ function scanSource(source, checker, config, visited = new Set(), inheritedParamMap, wrapperCache) {
140
+ wrapperCache = wrapperCache ?? new Map();
27
141
  const events = new Set();
28
142
  const detectedFunctionWrappers = new Set();
29
143
  const detectedComponentWrappers = new Map();
@@ -32,9 +146,93 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
32
146
  }
33
147
  visited.add(source.fileName);
34
148
  function visit(node) {
149
+ // JSX WRAPPERS
150
+ if (typescript_1.default.isJsxSelfClosingElement(node) ||
151
+ typescript_1.default.isJsxOpeningElement(node)) {
152
+ const tagName = getJsxTagName(node.tagName);
153
+ // skip html
154
+ if (!tagName || tagName[0] === tagName[0].toLowerCase()) {
155
+ typescript_1.default.forEachChild(node, visit);
156
+ return;
157
+ }
158
+ let wrapper = config.wrappers.find((w) => w.name === tagName);
159
+ if (!wrapper) {
160
+ let symbol = checker.getSymbolAtLocation(node.tagName);
161
+ let cacheKey = tagName;
162
+ if (symbol) {
163
+ if (symbol.flags & typescript_1.default.SymbolFlags.Alias) {
164
+ symbol = checker.getAliasedSymbol(symbol);
165
+ }
166
+ symbol =
167
+ (0, exportResolver_1.resolveExportedSymbol)(symbol, checker) ?? symbol;
168
+ cacheKey = checker.getFullyQualifiedName(symbol);
169
+ }
170
+ if (wrapperCache?.has(cacheKey)) {
171
+ const cached = wrapperCache.get(cacheKey);
172
+ if (cached) {
173
+ wrapper = { name: tagName, prop: cached };
174
+ }
175
+ }
176
+ else if (symbol) {
177
+ let detected = null;
178
+ for (const decl of symbol.getDeclarations() ?? []) {
179
+ let fn = null;
180
+ if (typescript_1.default.isFunctionDeclaration(decl))
181
+ fn = decl;
182
+ if (typescript_1.default.isVariableDeclaration(decl) &&
183
+ decl.initializer &&
184
+ (typescript_1.default.isArrowFunction(decl.initializer) ||
185
+ typescript_1.default.isFunctionExpression(decl.initializer))) {
186
+ fn = decl.initializer;
187
+ }
188
+ if (!fn)
189
+ continue;
190
+ const prop = findTrackedPropName(fn, checker);
191
+ if (prop) {
192
+ detected = prop;
193
+ break;
194
+ }
195
+ }
196
+ wrapperCache?.set(cacheKey, detected);
197
+ if (detected) {
198
+ wrapper = { name: tagName, prop: detected };
199
+ detectedComponentWrappers.set(tagName, detected);
200
+ }
201
+ }
202
+ }
203
+ if (wrapper) {
204
+ for (const attr of node.attributes.properties) {
205
+ if (!typescript_1.default.isJsxAttribute(attr))
206
+ continue;
207
+ const name = getJsxAttrName(attr.name);
208
+ if (name !== wrapper.prop)
209
+ continue;
210
+ if (!attr.initializer)
211
+ continue;
212
+ if (typescript_1.default.isStringLiteral(attr.initializer)) {
213
+ if (isValidEvent(attr.initializer.text)) {
214
+ events.add(attr.initializer.text);
215
+ }
216
+ }
217
+ if (typescript_1.default.isJsxExpression(attr.initializer)) {
218
+ const expr = attr.initializer.expression;
219
+ if (!expr)
220
+ continue;
221
+ const res = (0, resolver_1.resolveNodeValue)(expr, checker, inheritedParamMap);
222
+ res.values.forEach((v) => {
223
+ if (isValidEvent(v))
224
+ events.add(v);
225
+ });
226
+ }
227
+ }
228
+ }
229
+ typescript_1.default.forEachChild(node, visit);
230
+ return;
231
+ }
232
+ // FUNCTION TRACKING
35
233
  if (typescript_1.default.isCallExpression(node)) {
36
234
  const name = getCallName(node.expression);
37
- const isKnownWrapper = config.functionWrappers.some(w => w.name === name);
235
+ const isKnownWrapper = config.functionWrappers.some((w) => w.name === name);
38
236
  const resolvedFn = (0, callResolver_1.resolveFunctionFromCall)(node.expression, checker);
39
237
  const isAutoWrapper = !!resolvedFn && (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn) !== null;
40
238
  const isTracking = name === "track" ||
@@ -46,7 +244,6 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
46
244
  typescript_1.default.forEachChild(node, visit);
47
245
  return;
48
246
  }
49
- // авто-детект wrapper
50
247
  if (!isKnownWrapper && isAutoWrapper && name !== "track") {
51
248
  detectedFunctionWrappers.add(name);
52
249
  }
@@ -61,24 +258,21 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
61
258
  }
62
259
  });
63
260
  }
64
- // ✅ ТОЛЬКО правильный аргумент
65
261
  if (resolvedFn) {
66
262
  const idx = (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn);
67
263
  if (idx !== null && node.arguments[idx]) {
68
264
  const res = (0, resolver_1.resolveNodeValue)(node.arguments[idx], checker, paramMap);
69
- for (const v of res.values) {
70
- if (isValidEvent(v)) {
265
+ res.values.forEach((v) => {
266
+ if (isValidEvent(v))
71
267
  events.add(v);
72
- }
73
- }
268
+ });
74
269
  }
75
270
  }
76
- // CROSS FILE
77
271
  if (resolvedFn) {
78
272
  const sf = resolvedFn.getSourceFile();
79
273
  if (!visited.has(sf.fileName)) {
80
- const res = scanSource(sf, checker, config, visited, paramMap);
81
- res.events.forEach(e => events.add(e));
274
+ const res = scanSource(sf, checker, config, visited, paramMap, wrapperCache);
275
+ res.events.forEach((e) => events.add(e));
82
276
  }
83
277
  }
84
278
  }
@@ -17,7 +17,6 @@ function normalizeConfig(config) {
17
17
  endpoint: config.endpoint ?? "",
18
18
  wrappers: config.wrappers ?? [],
19
19
  functionWrappers: config.functionWrappers ?? [],
20
- aliases: config.aliases ?? {},
21
20
  sync: config.sync ?? {
22
21
  include: [
23
22
  "**/*.{ts,tsx,js,jsx,vue,svelte,astro}"
@@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.processFile = processFile;
4
4
  const universal_1 = require("./universal");
5
5
  function processFile(file, content) {
6
- const { code, deps } = (0, universal_1.parseUniversal)(content, file);
6
+ const parsed = (0, universal_1.parseUniversal)(content, file);
7
7
  return {
8
- content: code || "",
9
- deps: [...new Set(deps.filter(Boolean))],
8
+ content: parsed.code || "",
9
+ deps: [...new Set(parsed.deps.filter(Boolean))],
10
10
  };
11
11
  }
@@ -5,116 +5,132 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.parseUniversal = parseUniversal;
7
7
  const path_1 = __importDefault(require("path"));
8
- // Remove comments
8
+ // SAFE COMMENT STRIP
9
9
  function stripComments(input) {
10
10
  return input
11
11
  .replace(/<!--[\s\S]*?-->/g, "")
12
- .replace(/\/\*[\s\S]*?\*\//g, "")
13
- .replace(/\/\/.*$/gm, "");
12
+ .replace(/\/\*[\s\S]*?\*\//g, "");
14
13
  }
15
- // Basic filter
14
+ // TRACK FILTER
16
15
  function looksLikeTracking(code) {
17
- return /track/i.test(code);
16
+ return /\btrack\w*\s*\(/.test(code);
18
17
  }
19
- // HTML inline handlers (onclick="")
18
+ // SAFE {} PARSER
19
+ function extractBracedExpressions(input) {
20
+ const result = [];
21
+ let depth = 0;
22
+ let start = -1;
23
+ for (let i = 0; i < input.length; i++) {
24
+ const char = input[i];
25
+ if (char === "{") {
26
+ if (depth === 0)
27
+ start = i + 1;
28
+ depth++;
29
+ }
30
+ else if (char === "}") {
31
+ depth--;
32
+ if (depth === 0 && start !== -1) {
33
+ const expr = input.slice(start, i);
34
+ if (looksLikeTracking(expr)) {
35
+ result.push(expr);
36
+ }
37
+ start = -1;
38
+ }
39
+ }
40
+ }
41
+ return result;
42
+ }
43
+ // HTML handlers
20
44
  function extractHTMLHandlers(input) {
21
45
  const result = [];
22
- const matches = input.matchAll(/\bon\w+\s*=\s*["']([^"']+)["']/g);
23
- for (const m of matches) {
46
+ const regex = /\bon\w+\s*=\s*["']([^"']+)["']/g;
47
+ for (const m of input.matchAll(regex)) {
24
48
  if (looksLikeTracking(m[1])) {
25
49
  result.push(m[1]);
26
50
  }
27
51
  }
28
52
  return result;
29
53
  }
30
- // Vue handlers (@click / v-on)
54
+ // VUE handlers
31
55
  function extractVueHandlers(input) {
32
56
  const result = [];
33
- const matches = input.matchAll(/(?:@|v-on:)[\w:-]+\s*=\s*["']([^"']+)["']/g);
34
- for (const m of matches) {
57
+ const regex = /(?:@|v-on:)[\w:-]+\s*=\s*["']([^"']+)["']/g;
58
+ for (const m of input.matchAll(regex)) {
35
59
  if (looksLikeTracking(m[1])) {
36
60
  result.push(m[1]);
37
61
  }
38
62
  }
39
63
  return result;
40
64
  }
41
- // Svelte handlers (on:click)
65
+ // SVELTE handlers
42
66
  function extractSvelteHandlers(input) {
43
67
  const result = [];
44
- const matches = input.matchAll(/\bon:[\w]+\s*=\s*{([^}]+)}/g);
45
- for (const m of matches) {
68
+ const regex = /\bon:[\w]+\s*=\s*{([^}]+)}/g;
69
+ for (const m of input.matchAll(regex)) {
46
70
  if (looksLikeTracking(m[1])) {
47
71
  result.push(m[1]);
48
72
  }
49
73
  }
50
74
  return result;
51
75
  }
52
- // JSX / template { ... }
53
- function extractJSExpressions(input) {
54
- const result = [];
55
- const matches = input.matchAll(/\{([^}]+)\}/g);
56
- for (const m of matches) {
57
- if (looksLikeTracking(m[1])) {
58
- result.push(m[1]);
76
+ // SCRIPT EXTRACTION
77
+ function extractScripts(input, file) {
78
+ const scripts = [];
79
+ const deps = [];
80
+ // src scripts
81
+ const srcRegex = /<script\b[^>]*?\bsrc=["'](.+?)["'][^>]*>/g;
82
+ for (const m of input.matchAll(srcRegex)) {
83
+ const src = m[1];
84
+ const resolved = src.startsWith("/")
85
+ ? path_1.default.resolve(process.cwd(), "." + src)
86
+ : path_1.default.resolve(path_1.default.dirname(file), src);
87
+ deps.push(resolved);
88
+ }
89
+ // inline scripts
90
+ const scriptRegex = /<script\b[^>]*>([\s\S]*?)<\/script>/g;
91
+ for (const m of input.matchAll(scriptRegex)) {
92
+ if (m[1]?.trim()) {
93
+ scripts.push(m[1]);
59
94
  }
60
95
  }
61
- return result;
96
+ const noScripts = input.replace(scriptRegex, "");
97
+ return { scripts, deps, noScripts };
62
98
  }
63
- // dynamic import()
99
+ // DYNAMIC IMPORTS
64
100
  function extractDynamicImports(input, file) {
65
101
  const deps = [];
66
- const calls = [];
67
- const matches = input.matchAll(/import\(\s*["'](.+?)["']\s*\)/g);
68
- for (const m of matches) {
102
+ const regex = /import\(\s*["'](.+?)["']\s*\)/g;
103
+ for (const m of input.matchAll(regex)) {
69
104
  const mod = m[1];
70
105
  const resolved = mod.startsWith("/")
71
106
  ? path_1.default.resolve(process.cwd(), "." + mod)
72
107
  : path_1.default.resolve(path_1.default.dirname(file), mod);
73
108
  deps.push(resolved);
74
- if (looksLikeTracking(mod)) {
75
- calls.push(`import("${mod}")`);
76
- }
77
109
  }
78
- return { deps, calls };
110
+ return deps;
79
111
  }
80
- // UNIVERSAL PARSER
112
+ // MAIN
81
113
  function parseUniversal(content, file) {
82
114
  const parts = [];
83
115
  const deps = [];
84
116
  const clean = stripComments(content);
85
- // ASTRO FRONTMATTER
117
+ /* ---------- ASTRO FRONTMATTER ---------- */
86
118
  const fm = clean.match(/^---([\s\S]*?)---/);
87
119
  if (fm?.[1]) {
88
120
  parts.push(fm[1]);
89
121
  }
90
- // <script src="">
91
- const scriptSrc = clean.matchAll(/<script\b[^>]*?\bsrc=["'](.+?)["'][^>]*>/g);
92
- for (const s of scriptSrc) {
93
- const src = s[1];
94
- const resolved = src.startsWith("/")
95
- ? path_1.default.resolve(process.cwd(), "." + src)
96
- : path_1.default.resolve(path_1.default.dirname(file), src);
97
- deps.push(resolved);
98
- }
99
- // INLINE <script>
100
- const scripts = clean.matchAll(/<script\b([^>]*)>([\s\S]*?)<\/script>/g);
101
- for (const m of scripts) {
102
- if (m[2].trim()) {
103
- parts.push(m[2]);
104
- }
105
- }
106
- // TEMPLATE PART
107
- const noScripts = clean.replace(/<script[\s\S]*?<\/script>/g, "");
108
- // handlers
122
+ /* ---------- SCRIPTS ---------- */
123
+ const { scripts, deps: scriptDeps, noScripts } = extractScripts(clean, file);
124
+ parts.push(...scripts);
125
+ deps.push(...scriptDeps);
126
+ /* ---------- HANDLERS ---------- */
109
127
  parts.push(...extractHTMLHandlers(noScripts));
110
128
  parts.push(...extractVueHandlers(noScripts));
111
129
  parts.push(...extractSvelteHandlers(noScripts));
112
- // JSX / Astro / Vue expressions
113
- parts.push(...extractJSExpressions(clean));
114
- // dynamic imports
115
- const dyn = extractDynamicImports(clean, file);
116
- deps.push(...dyn.deps);
117
- parts.push(...dyn.calls);
130
+ /* ---------- JSX / TEMPLATE ---------- */
131
+ parts.push(...extractBracedExpressions(clean));
132
+ /* ---------- IMPORTS ---------- */
133
+ deps.push(...extractDynamicImports(clean, file));
118
134
  return {
119
135
  code: [...new Set(parts)].join("\n"),
120
136
  deps: [...new Set(deps.filter(Boolean))],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventra_dev/eventra-cli",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "description": "Eventra CLI",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -2,16 +2,16 @@ import path from "path";
2
2
  import fs from "fs";
3
3
 
4
4
  import { TSService } from "./languageService";
5
- import { ScanResult, scanSource } from "./scanner";
5
+ import { scanSource } from "./scanner";
6
6
  import { DependencyGraph } from "./graph";
7
7
  import { hash } from "./hash";
8
- import { EventraConfig } from "../types";
8
+ import {EventraConfig, ScanResult} from "../types";
9
9
  import { isExternalFile } from "./boundary";
10
10
 
11
11
  export class EventraEngine {
12
12
  private ts: TSService;
13
13
  private graph: DependencyGraph;
14
-
14
+ private wrapperCache = new Map<string, string | null>();
15
15
  private fileResults = new Map<string, ScanResult>();
16
16
  private fileHash = new Map<string, string>();
17
17
 
@@ -71,10 +71,17 @@ export class EventraEngine {
71
71
  return this.empty();
72
72
  }
73
73
 
74
- // обновляем graph
74
+ // update graph
75
75
  this.graph.update(file, source);
76
76
 
77
- const res = scanSource(source, checker, config);
77
+ const res = scanSource(
78
+ source,
79
+ checker,
80
+ config,
81
+ new Set(),
82
+ undefined,
83
+ this.wrapperCache
84
+ );
78
85
  this.fileResults.set(file, res);
79
86
 
80
87
  return res;
@@ -86,6 +93,7 @@ export class EventraEngine {
86
93
  content: string,
87
94
  config: EventraConfig
88
95
  ) {
96
+ this.wrapperCache.clear();
89
97
  file = this.normalize(file);
90
98
 
91
99
  const res = this.scanFile(file, content, config);
@@ -124,7 +132,14 @@ export class EventraEngine {
124
132
 
125
133
  this.graph.update(abs, source);
126
134
 
127
- const r = scanSource(source, checker, config);
135
+ const r = scanSource(
136
+ source,
137
+ checker,
138
+ config,
139
+ new Set(),
140
+ undefined,
141
+ this.wrapperCache
142
+ );
128
143
  this.fileResults.set(abs, r);
129
144
  }
130
145
 
@@ -144,6 +159,7 @@ export class EventraEngine {
144
159
 
145
160
  // REMOVE FILE
146
161
  removeFile(file: string, config?: EventraConfig) {
162
+ this.wrapperCache.clear();
147
163
  file = this.normalize(file);
148
164
 
149
165
  const dependents = this.graph.getAllDependentsDeep(file);
@@ -191,7 +207,10 @@ export class EventraEngine {
191
207
  wrappers: [],
192
208
  functionWrappers: [],
193
209
  sync: { include: [], exclude: [] },
194
- }
210
+ },
211
+ new Set(),
212
+ undefined,
213
+ this.wrapperCache
195
214
  );
196
215
 
197
216
  this.fileResults.set(abs, r);
@@ -2,9 +2,27 @@ import ts from "typescript";
2
2
  import { resolveNodeValue } from "./resolver";
3
3
  import { resolveFunctionFromCall } from "./callResolver";
4
4
  import { findTrackParamIndex } from "./functionAnalyzer";
5
- import { EventraConfig } from "../types";
5
+ import { resolveExportedSymbol } from "./exportResolver";
6
+ import { EventraConfig, ScanResult } from "../types";
6
7
  import { isExternalFile } from "./boundary";
7
8
 
9
+ // UTILS
10
+ function getJsxAttrName(name: ts.JsxAttributeName): string {
11
+ if (ts.isIdentifier(name)) return name.text;
12
+ if (ts.isJsxNamespacedName(name)) return name.name.text;
13
+ return "";
14
+ }
15
+
16
+ function getJsxTagName(tag: ts.JsxTagNameExpression): string {
17
+ if (ts.isIdentifier(tag)) return tag.text;
18
+
19
+ if (ts.isPropertyAccessExpression(tag)) {
20
+ return tag.name.text;
21
+ }
22
+
23
+ return "";
24
+ }
25
+
8
26
  function getCallName(expr: ts.Expression): string {
9
27
  if (ts.isIdentifier(expr)) return expr.text;
10
28
  if (ts.isPropertyAccessExpression(expr)) return expr.name.text;
@@ -21,19 +39,144 @@ function isValidEvent(v: string) {
21
39
  );
22
40
  }
23
41
 
24
- export type ScanResult = {
25
- events: Set<string>;
26
- detectedFunctionWrappers: Set<string>;
27
- detectedComponentWrappers: Map<string, string>;
28
- };
42
+ // COMPONENT ANALYSIS
43
+ function getComponentPropsMap(
44
+ fn: ts.FunctionLikeDeclaration
45
+ ): Map<string, string> {
46
+ const map = new Map<string, string>();
47
+ const firstParam = fn.parameters[0];
48
+ if (!firstParam) return map;
49
+
50
+ // ({ event }) => ...
51
+ if (ts.isObjectBindingPattern(firstParam.name)) {
52
+ for (const el of firstParam.name.elements) {
53
+ if (!ts.isBindingElement(el)) continue;
54
+
55
+ const propName =
56
+ el.propertyName?.getText() || el.name.getText();
57
+
58
+ map.set(el.name.getText(), propName);
59
+ }
60
+ }
29
61
 
62
+ // (props) => props.event
63
+ if (ts.isIdentifier(firstParam.name)) {
64
+ map.set(firstParam.name.text, "*");
65
+ }
66
+
67
+ return map;
68
+ }
69
+
70
+ function findTrackedPropName(
71
+ fn: ts.FunctionLikeDeclaration,
72
+ checker: ts.TypeChecker
73
+ ): string | null {
74
+ const propMap = getComponentPropsMap(fn);
75
+ let result: string | null = null;
76
+
77
+ function resolveIdentifierToProp(
78
+ node: ts.Identifier
79
+ ): string | null {
80
+ const mapped = propMap.get(node.text);
81
+ if (mapped && mapped !== "*") return mapped;
82
+
83
+ const symbol = checker.getSymbolAtLocation(node);
84
+ if (!symbol) return null;
85
+
86
+ for (const decl of symbol.getDeclarations() ?? []) {
87
+ // const e = props.event
88
+ if (
89
+ ts.isVariableDeclaration(decl) &&
90
+ decl.initializer &&
91
+ ts.isPropertyAccessExpression(decl.initializer)
92
+ ) {
93
+ return decl.initializer.name.text;
94
+ }
95
+
96
+ // const e = event
97
+ if (
98
+ ts.isVariableDeclaration(decl) &&
99
+ decl.initializer &&
100
+ ts.isIdentifier(decl.initializer)
101
+ ) {
102
+ const inner = propMap.get(decl.initializer.text);
103
+ if (inner) return inner;
104
+ }
105
+ }
106
+
107
+ return null;
108
+ }
109
+
110
+ function visit(node: ts.Node) {
111
+ if (result) return;
112
+
113
+ if (ts.isCallExpression(node)) {
114
+ const expr = node.expression;
115
+
116
+ const isTrack =
117
+ (ts.isIdentifier(expr) && expr.text === "track") ||
118
+ (ts.isPropertyAccessExpression(expr) &&
119
+ expr.name.text === "track");
120
+
121
+ if (!isTrack) {
122
+ ts.forEachChild(node, visit);
123
+ return;
124
+ }
125
+
126
+ for (const arg of node.arguments) {
127
+ // track(event)
128
+ if (ts.isIdentifier(arg)) {
129
+ const prop = resolveIdentifierToProp(arg);
130
+ if (prop) {
131
+ result = prop;
132
+ return;
133
+ }
134
+ }
135
+
136
+ // track(props.a.b.event)
137
+ if (ts.isPropertyAccessExpression(arg)) {
138
+ let current = arg;
139
+
140
+ while (ts.isPropertyAccessExpression(current)) {
141
+ result = current.name.text;
142
+ return;
143
+ }
144
+ }
145
+
146
+ // track(fn())
147
+ if (ts.isCallExpression(arg)) {
148
+ const inner = resolveFunctionFromCall(
149
+ arg.expression,
150
+ checker
151
+ );
152
+
153
+ if (inner?.body) {
154
+ visit(inner.body);
155
+ if (result) return;
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ ts.forEachChild(node, visit);
162
+ }
163
+
164
+ if (fn.body) visit(fn.body);
165
+
166
+ return result;
167
+ }
168
+
169
+ // MAIN SCANNER
30
170
  export function scanSource(
31
171
  source: ts.SourceFile,
32
172
  checker: ts.TypeChecker,
33
173
  config: EventraConfig,
34
174
  visited = new Set<string>(),
35
- inheritedParamMap?: Map<string, ts.Expression>
175
+ inheritedParamMap?: Map<string, ts.Expression>,
176
+ wrapperCache?: Map<string, string | null>
36
177
  ): ScanResult {
178
+ wrapperCache = wrapperCache ?? new Map();
179
+
37
180
  const events = new Set<string>();
38
181
  const detectedFunctionWrappers = new Set<string>();
39
182
  const detectedComponentWrappers = new Map<string, string>();
@@ -45,14 +188,127 @@ export function scanSource(
45
188
  visited.add(source.fileName);
46
189
 
47
190
  function visit(node: ts.Node) {
191
+ // JSX WRAPPERS
192
+ if (
193
+ ts.isJsxSelfClosingElement(node) ||
194
+ ts.isJsxOpeningElement(node)
195
+ ) {
196
+ const tagName = getJsxTagName(node.tagName);
197
+
198
+ // skip html
199
+ if (!tagName || tagName[0] === tagName[0].toLowerCase()) {
200
+ ts.forEachChild(node, visit);
201
+ return;
202
+ }
203
+
204
+ let wrapper = config.wrappers.find(
205
+ (w) => w.name === tagName
206
+ );
207
+
208
+ if (!wrapper) {
209
+ let symbol = checker.getSymbolAtLocation(node.tagName);
210
+
211
+ let cacheKey = tagName;
212
+
213
+ if (symbol) {
214
+ if (symbol.flags & ts.SymbolFlags.Alias) {
215
+ symbol = checker.getAliasedSymbol(symbol);
216
+ }
217
+
218
+ symbol =
219
+ resolveExportedSymbol(symbol, checker) ?? symbol;
220
+
221
+ cacheKey = checker.getFullyQualifiedName(symbol);
222
+ }
223
+
224
+ if (wrapperCache?.has(cacheKey)) {
225
+ const cached = wrapperCache.get(cacheKey);
226
+ if (cached) {
227
+ wrapper = { name: tagName, prop: cached };
228
+ }
229
+ } else if (symbol) {
230
+ let detected: string | null = null;
231
+
232
+ for (const decl of symbol.getDeclarations() ?? []) {
233
+ let fn: ts.FunctionLikeDeclaration | null = null;
234
+
235
+ if (ts.isFunctionDeclaration(decl)) fn = decl;
236
+
237
+ if (
238
+ ts.isVariableDeclaration(decl) &&
239
+ decl.initializer &&
240
+ (ts.isArrowFunction(decl.initializer) ||
241
+ ts.isFunctionExpression(decl.initializer))
242
+ ) {
243
+ fn = decl.initializer;
244
+ }
245
+
246
+ if (!fn) continue;
247
+
248
+ const prop = findTrackedPropName(fn, checker);
249
+
250
+ if (prop) {
251
+ detected = prop;
252
+ break;
253
+ }
254
+ }
255
+
256
+ wrapperCache?.set(cacheKey, detected);
257
+
258
+ if (detected) {
259
+ wrapper = { name: tagName, prop: detected };
260
+ detectedComponentWrappers.set(tagName, detected);
261
+ }
262
+ }
263
+ }
264
+
265
+ if (wrapper) {
266
+ for (const attr of node.attributes.properties) {
267
+ if (!ts.isJsxAttribute(attr)) continue;
268
+
269
+ const name = getJsxAttrName(attr.name);
270
+ if (name !== wrapper.prop) continue;
271
+ if (!attr.initializer) continue;
272
+
273
+ if (ts.isStringLiteral(attr.initializer)) {
274
+ if (isValidEvent(attr.initializer.text)) {
275
+ events.add(attr.initializer.text);
276
+ }
277
+ }
278
+
279
+ if (ts.isJsxExpression(attr.initializer)) {
280
+ const expr = attr.initializer.expression;
281
+ if (!expr) continue;
282
+
283
+ const res = resolveNodeValue(
284
+ expr,
285
+ checker,
286
+ inheritedParamMap
287
+ );
288
+
289
+ res.values.forEach((v) => {
290
+ if (isValidEvent(v)) events.add(v);
291
+ });
292
+ }
293
+ }
294
+ }
295
+
296
+ ts.forEachChild(node, visit);
297
+ return;
298
+ }
299
+
300
+ // FUNCTION TRACKING
48
301
  if (ts.isCallExpression(node)) {
49
302
  const name = getCallName(node.expression);
50
303
 
51
304
  const isKnownWrapper = config.functionWrappers.some(
52
- w => w.name === name
305
+ (w) => w.name === name
53
306
  );
54
307
 
55
- const resolvedFn = resolveFunctionFromCall(node.expression, checker);
308
+ const resolvedFn = resolveFunctionFromCall(
309
+ node.expression,
310
+ checker
311
+ );
56
312
 
57
313
  const isAutoWrapper =
58
314
  !!resolvedFn && findTrackParamIndex(resolvedFn) !== null;
@@ -62,14 +318,15 @@ export function scanSource(
62
318
  isKnownWrapper ||
63
319
  (isAutoWrapper &&
64
320
  resolvedFn &&
65
- !isExternalFile(resolvedFn.getSourceFile().fileName));
321
+ !isExternalFile(
322
+ resolvedFn.getSourceFile().fileName
323
+ ));
66
324
 
67
325
  if (!isTracking) {
68
326
  ts.forEachChild(node, visit);
69
327
  return;
70
328
  }
71
329
 
72
- // авто-детект wrapper
73
330
  if (!isKnownWrapper && isAutoWrapper && name !== "track") {
74
331
  detectedFunctionWrappers.add(name);
75
332
  }
@@ -87,7 +344,6 @@ export function scanSource(
87
344
  });
88
345
  }
89
346
 
90
- // ✅ ТОЛЬКО правильный аргумент
91
347
  if (resolvedFn) {
92
348
  const idx = findTrackParamIndex(resolvedFn);
93
349
 
@@ -98,15 +354,12 @@ export function scanSource(
98
354
  paramMap
99
355
  );
100
356
 
101
- for (const v of res.values) {
102
- if (isValidEvent(v)) {
103
- events.add(v);
104
- }
105
- }
357
+ res.values.forEach((v) => {
358
+ if (isValidEvent(v)) events.add(v);
359
+ });
106
360
  }
107
361
  }
108
362
 
109
- // CROSS FILE
110
363
  if (resolvedFn) {
111
364
  const sf = resolvedFn.getSourceFile();
112
365
 
@@ -116,10 +369,11 @@ export function scanSource(
116
369
  checker,
117
370
  config,
118
371
  visited,
119
- paramMap
372
+ paramMap,
373
+ wrapperCache
120
374
  );
121
375
 
122
- res.events.forEach(e => events.add(e));
376
+ res.events.forEach((e) => events.add(e));
123
377
  }
124
378
  }
125
379
  }
package/src/types.ts CHANGED
@@ -1,5 +1,11 @@
1
1
  export type ScanMode = "strict" | "hybrid" | "discovery";
2
2
 
3
+ export type ScanResult = {
4
+ events: Set<string>;
5
+ detectedFunctionWrappers: Set<string>;
6
+ detectedComponentWrappers: Map<string, string>;
7
+ };
8
+
3
9
  export type ParseResult = {
4
10
  code: string;
5
11
  deps: string[];
@@ -22,7 +28,6 @@ export type EventraConfig = {
22
28
  mode?: ScanMode;
23
29
  wrappers: ComponentWrapper[];
24
30
  functionWrappers: FunctionWrapper[];
25
- aliases?: Record<string, string>;
26
31
  sync: {
27
32
  include: string[];
28
33
  exclude: string[];
@@ -13,7 +13,6 @@ export function normalizeConfig(
13
13
  endpoint: config.endpoint ?? "",
14
14
  wrappers: config.wrappers ?? [],
15
15
  functionWrappers: config.functionWrappers ?? [],
16
- aliases: config.aliases ?? {},
17
16
  sync: config.sync ?? {
18
17
  include: [
19
18
  "**/*.{ts,tsx,js,jsx,vue,svelte,astro}"
@@ -1,10 +1,10 @@
1
1
  import { parseUniversal } from "./universal";
2
2
 
3
3
  export function processFile(file: string, content: string) {
4
- const { code, deps } = parseUniversal(content, file);
4
+ const parsed = parseUniversal(content, file);
5
5
 
6
6
  return {
7
- content: code || "",
8
- deps: [...new Set(deps.filter(Boolean))],
7
+ content: parsed.code || "",
8
+ deps: [...new Set(parsed.deps.filter(Boolean))],
9
9
  };
10
10
  }
@@ -1,28 +1,53 @@
1
1
  import path from "path";
2
2
  import { ParseResult } from "../types";
3
3
 
4
- // Remove comments
4
+ // SAFE COMMENT STRIP
5
5
  function stripComments(input: string): string {
6
6
  return input
7
7
  .replace(/<!--[\s\S]*?-->/g, "")
8
- .replace(/\/\*[\s\S]*?\*\//g, "")
9
- .replace(/\/\/.*$/gm, "");
8
+ .replace(/\/\*[\s\S]*?\*\//g, "");
10
9
  }
11
10
 
12
- // Basic filter
11
+ // TRACK FILTER
13
12
  function looksLikeTracking(code: string) {
14
- return /track/i.test(code);
13
+ return /\btrack\w*\s*\(/.test(code);
15
14
  }
16
15
 
17
- // HTML inline handlers (onclick="")
16
+ // SAFE {} PARSER
17
+ function extractBracedExpressions(input: string): string[] {
18
+ const result: string[] = [];
19
+
20
+ let depth = 0;
21
+ let start = -1;
22
+
23
+ for (let i = 0; i < input.length; i++) {
24
+ const char = input[i];
25
+
26
+ if (char === "{") {
27
+ if (depth === 0) start = i + 1;
28
+ depth++;
29
+ } else if (char === "}") {
30
+ depth--;
31
+ if (depth === 0 && start !== -1) {
32
+ const expr = input.slice(start, i);
33
+ if (looksLikeTracking(expr)) {
34
+ result.push(expr);
35
+ }
36
+ start = -1;
37
+ }
38
+ }
39
+ }
40
+
41
+ return result;
42
+ }
43
+
44
+ // HTML handlers
18
45
  function extractHTMLHandlers(input: string): string[] {
19
46
  const result: string[] = [];
20
47
 
21
- const matches = input.matchAll(
22
- /\bon\w+\s*=\s*["']([^"']+)["']/g
23
- );
48
+ const regex = /\bon\w+\s*=\s*["']([^"']+)["']/g;
24
49
 
25
- for (const m of matches) {
50
+ for (const m of input.matchAll(regex)) {
26
51
  if (looksLikeTracking(m[1])) {
27
52
  result.push(m[1]);
28
53
  }
@@ -31,15 +56,13 @@ function extractHTMLHandlers(input: string): string[] {
31
56
  return result;
32
57
  }
33
58
 
34
- // Vue handlers (@click / v-on)
59
+ // VUE handlers
35
60
  function extractVueHandlers(input: string): string[] {
36
61
  const result: string[] = [];
37
62
 
38
- const matches = input.matchAll(
39
- /(?:@|v-on:)[\w:-]+\s*=\s*["']([^"']+)["']/g
40
- );
63
+ const regex = /(?:@|v-on:)[\w:-]+\s*=\s*["']([^"']+)["']/g;
41
64
 
42
- for (const m of matches) {
65
+ for (const m of input.matchAll(regex)) {
43
66
  if (looksLikeTracking(m[1])) {
44
67
  result.push(m[1]);
45
68
  }
@@ -48,15 +71,13 @@ function extractVueHandlers(input: string): string[] {
48
71
  return result;
49
72
  }
50
73
 
51
- // Svelte handlers (on:click)
74
+ // SVELTE handlers
52
75
  function extractSvelteHandlers(input: string): string[] {
53
76
  const result: string[] = [];
54
77
 
55
- const matches = input.matchAll(
56
- /\bon:[\w]+\s*=\s*{([^}]+)}/g
57
- );
78
+ const regex = /\bon:[\w]+\s*=\s*{([^}]+)}/g;
58
79
 
59
- for (const m of matches) {
80
+ for (const m of input.matchAll(regex)) {
60
81
  if (looksLikeTracking(m[1])) {
61
82
  result.push(m[1]);
62
83
  }
@@ -65,34 +86,47 @@ function extractSvelteHandlers(input: string): string[] {
65
86
  return result;
66
87
  }
67
88
 
68
- // JSX / template { ... }
69
- function extractJSExpressions(input: string): string[] {
70
- const result: string[] = [];
89
+ // SCRIPT EXTRACTION
90
+ function extractScripts(input: string, file: string) {
91
+ const scripts: string[] = [];
92
+ const deps: string[] = [];
71
93
 
72
- const matches = input.matchAll(/\{([^}]+)\}/g);
94
+ // src scripts
95
+ const srcRegex =
96
+ /<script\b[^>]*?\bsrc=["'](.+?)["'][^>]*>/g;
73
97
 
74
- for (const m of matches) {
75
- if (looksLikeTracking(m[1])) {
76
- result.push(m[1]);
98
+ for (const m of input.matchAll(srcRegex)) {
99
+ const src = m[1];
100
+
101
+ const resolved = src.startsWith("/")
102
+ ? path.resolve(process.cwd(), "." + src)
103
+ : path.resolve(path.dirname(file), src);
104
+
105
+ deps.push(resolved);
106
+ }
107
+
108
+ // inline scripts
109
+ const scriptRegex =
110
+ /<script\b[^>]*>([\s\S]*?)<\/script>/g;
111
+
112
+ for (const m of input.matchAll(scriptRegex)) {
113
+ if (m[1]?.trim()) {
114
+ scripts.push(m[1]);
77
115
  }
78
116
  }
79
117
 
80
- return result;
118
+ const noScripts = input.replace(scriptRegex, "");
119
+
120
+ return { scripts, deps, noScripts };
81
121
  }
82
122
 
83
- // dynamic import()
84
- function extractDynamicImports(
85
- input: string,
86
- file: string
87
- ): { deps: string[]; calls: string[] } {
123
+ // DYNAMIC IMPORTS
124
+ function extractDynamicImports(input: string, file: string) {
88
125
  const deps: string[] = [];
89
- const calls: string[] = [];
90
126
 
91
- const matches = input.matchAll(
92
- /import\(\s*["'](.+?)["']\s*\)/g
93
- );
127
+ const regex = /import\(\s*["'](.+?)["']\s*\)/g;
94
128
 
95
- for (const m of matches) {
129
+ for (const m of input.matchAll(regex)) {
96
130
  const mod = m[1];
97
131
 
98
132
  const resolved = mod.startsWith("/")
@@ -100,16 +134,12 @@ function extractDynamicImports(
100
134
  : path.resolve(path.dirname(file), mod);
101
135
 
102
136
  deps.push(resolved);
103
-
104
- if (looksLikeTracking(mod)) {
105
- calls.push(`import("${mod}")`);
106
- }
107
137
  }
108
138
 
109
- return { deps, calls };
139
+ return deps;
110
140
  }
111
141
 
112
- // UNIVERSAL PARSER
142
+ // MAIN
113
143
  export function parseUniversal(
114
144
  content: string,
115
145
  file: string
@@ -119,56 +149,29 @@ export function parseUniversal(
119
149
 
120
150
  const clean = stripComments(content);
121
151
 
122
- // ASTRO FRONTMATTER
152
+ /* ---------- ASTRO FRONTMATTER ---------- */
123
153
  const fm = clean.match(/^---([\s\S]*?)---/);
124
154
  if (fm?.[1]) {
125
155
  parts.push(fm[1]);
126
156
  }
127
157
 
128
- // <script src="">
129
- const scriptSrc = clean.matchAll(
130
- /<script\b[^>]*?\bsrc=["'](.+?)["'][^>]*>/g
131
- );
132
-
133
- for (const s of scriptSrc) {
134
- const src = s[1];
135
-
136
- const resolved = src.startsWith("/")
137
- ? path.resolve(process.cwd(), "." + src)
138
- : path.resolve(path.dirname(file), src);
139
-
140
- deps.push(resolved);
141
- }
142
-
143
- // INLINE <script>
144
- const scripts = clean.matchAll(
145
- /<script\b([^>]*)>([\s\S]*?)<\/script>/g
146
- );
147
-
148
- for (const m of scripts) {
149
- if (m[2].trim()) {
150
- parts.push(m[2]);
151
- }
152
- }
158
+ /* ---------- SCRIPTS ---------- */
159
+ const { scripts, deps: scriptDeps, noScripts } =
160
+ extractScripts(clean, file);
153
161
 
154
- // TEMPLATE PART
155
- const noScripts = clean.replace(
156
- /<script[\s\S]*?<\/script>/g,
157
- ""
158
- );
162
+ parts.push(...scripts);
163
+ deps.push(...scriptDeps);
159
164
 
160
- // handlers
165
+ /* ---------- HANDLERS ---------- */
161
166
  parts.push(...extractHTMLHandlers(noScripts));
162
167
  parts.push(...extractVueHandlers(noScripts));
163
168
  parts.push(...extractSvelteHandlers(noScripts));
164
169
 
165
- // JSX / Astro / Vue expressions
166
- parts.push(...extractJSExpressions(clean));
170
+ /* ---------- JSX / TEMPLATE ---------- */
171
+ parts.push(...extractBracedExpressions(clean));
167
172
 
168
- // dynamic imports
169
- const dyn = extractDynamicImports(clean, file);
170
- deps.push(...dyn.deps);
171
- parts.push(...dyn.calls);
173
+ /* ---------- IMPORTS ---------- */
174
+ deps.push(...extractDynamicImports(clean, file));
172
175
 
173
176
  return {
174
177
  code: [...new Set(parts)].join("\n"),
package/tests/run.ts CHANGED
@@ -40,7 +40,6 @@ function ensureTestConfig(dir: string) {
40
40
  events: [],
41
41
  wrappers: [],
42
42
  functionWrappers: [],
43
- aliases: {},
44
43
  sync: {
45
44
  include: [
46
45
  "**/*.{ts,tsx,js,jsx,vue,svelte,astro}"
@@ -1,17 +0,0 @@
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.isTrackingCall = isTrackingCall;
7
- const typescript_1 = __importDefault(require("typescript"));
8
- function isTrackingCall(node) {
9
- const expr = node.expression;
10
- if (typescript_1.default.isIdentifier(expr)) {
11
- return expr.text === "track";
12
- }
13
- if (typescript_1.default.isPropertyAccessExpression(expr)) {
14
- return expr.name.text === "track";
15
- }
16
- return false;
17
- }
@@ -1,17 +0,0 @@
1
- import ts from "typescript";
2
-
3
- export function isTrackingCall(
4
- node: ts.CallExpression
5
- ): boolean {
6
- const expr = node.expression;
7
-
8
- if (ts.isIdentifier(expr)) {
9
- return expr.text === "track";
10
- }
11
-
12
- if (ts.isPropertyAccessExpression(expr)) {
13
- return expr.name.text === "track";
14
- }
15
-
16
- return false;
17
- }