@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.
@@ -7,10 +7,25 @@ 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");
11
+ const exportResolver_1 = require("./exportResolver");
12
12
  const boundary_1 = require("./boundary");
13
- const trackingDetector_1 = require("./trackingDetector");
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
+ }
14
29
  function getCallName(expr) {
15
30
  if (typescript_1.default.isIdentifier(expr))
16
31
  return expr.text;
@@ -25,31 +40,104 @@ function isValidEvent(v) {
25
40
  !v.includes(" ") &&
26
41
  /^[a-zA-Z0-9._:-]+$/.test(v));
27
42
  }
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);
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, "*");
37
61
  }
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;
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
+ }
42
89
  }
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;
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
+ }
48
131
  }
132
+ typescript_1.default.forEachChild(node, visit);
49
133
  }
50
- return null;
134
+ if (fn.body)
135
+ visit(fn.body);
136
+ return result;
51
137
  }
52
- function scanSource(source, checker, config, visited = new Set(), depth = 0, inheritedParamMap) {
138
+ // MAIN SCANNER
139
+ function scanSource(source, checker, config, visited = new Set(), inheritedParamMap, wrapperCache) {
140
+ wrapperCache = wrapperCache ?? new Map();
53
141
  const events = new Set();
54
142
  const detectedFunctionWrappers = new Set();
55
143
  const detectedComponentWrappers = new Map();
@@ -58,42 +146,107 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
58
146
  }
59
147
  visited.add(source.fileName);
60
148
  function visit(node) {
61
- // CALL EXPRESSIONS
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
62
233
  if (typescript_1.default.isCallExpression(node)) {
63
234
  const name = getCallName(node.expression);
64
- 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("$") ||
235
+ const isKnownWrapper = config.functionWrappers.some((w) => w.name === name);
236
+ const resolvedFn = (0, callResolver_1.resolveFunctionFromCall)(node.expression, checker);
237
+ const isAutoWrapper = !!resolvedFn && (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn) !== null;
238
+ const isTracking = name === "track" ||
239
+ isKnownWrapper ||
71
240
  (isAutoWrapper &&
72
241
  resolvedFn &&
73
- resolvedFn.getSourceFile &&
74
242
  !(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
243
  if (!isTracking) {
86
244
  typescript_1.default.forEachChild(node, visit);
87
245
  return;
88
246
  }
89
- // DETECT WRAPPER
90
- if (!isKnownWrapper &&
91
- isAutoWrapper &&
92
- !isTrackingByType &&
93
- !name.startsWith("track")) {
247
+ if (!isKnownWrapper && isAutoWrapper && name !== "track") {
94
248
  detectedFunctionWrappers.add(name);
95
249
  }
96
- // PARAM MAP
97
250
  const paramMap = new Map(inheritedParamMap ?? []);
98
251
  if (resolvedFn && typescript_1.default.isFunctionLike(resolvedFn)) {
99
252
  resolvedFn.parameters.forEach((param, i) => {
@@ -105,23 +258,21 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
105
258
  }
106
259
  });
107
260
  }
108
- // STRICT EVENT RESOLVE
109
261
  if (resolvedFn) {
110
262
  const idx = (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn);
111
263
  if (idx !== null && node.arguments[idx]) {
112
264
  const res = (0, resolver_1.resolveNodeValue)(node.arguments[idx], checker, paramMap);
113
- res.values.forEach(v => {
265
+ res.values.forEach((v) => {
114
266
  if (isValidEvent(v))
115
267
  events.add(v);
116
268
  });
117
269
  }
118
270
  }
119
- // CROSS-FILE
120
271
  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);
124
- res.events.forEach(e => events.add(e));
272
+ const sf = resolvedFn.getSourceFile();
273
+ if (!visited.has(sf.fileName)) {
274
+ const res = scanSource(sf, checker, config, visited, paramMap, wrapperCache);
275
+ res.events.forEach((e) => events.add(e));
125
276
  }
126
277
  }
127
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,135 +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
- // Strip comments (HTML + JS)
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
- // Extract JS expressions inside {}
16
- function extractJS(input) {
14
+ // TRACK FILTER
15
+ function looksLikeTracking(code) {
16
+ return /\btrack\w*\s*\(/.test(code);
17
+ }
18
+ // SAFE {} PARSER
19
+ function extractBracedExpressions(input) {
17
20
  const result = [];
18
- let i = 0;
19
- const len = input.length;
20
- let inString = null;
21
- let escape = false;
22
- while (i < len) {
23
- const ch = input[i];
24
- if (inString) {
25
- if (escape)
26
- escape = false;
27
- else if (ch === "\\")
28
- escape = true;
29
- else if (ch === inString)
30
- inString = null;
31
- i++;
32
- continue;
33
- }
34
- if (ch === '"' || ch === "'" || ch === "`") {
35
- inString = ch;
36
- i++;
37
- continue;
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++;
38
29
  }
39
- if (ch === "{") {
40
- let depth = 1;
41
- let j = i + 1;
42
- while (j < len && depth > 0) {
43
- if (input[j] === "{")
44
- depth++;
45
- else if (input[j] === "}")
46
- depth--;
47
- j++;
48
- }
49
- if (depth === 0) {
50
- const expr = input.slice(i + 1, j - 1).trim();
51
- if (expr && /[a-zA-Z0-9_$]\s*\(/.test(expr)) {
30
+ else if (char === "}") {
31
+ depth--;
32
+ if (depth === 0 && start !== -1) {
33
+ const expr = input.slice(start, i);
34
+ if (looksLikeTracking(expr)) {
52
35
  result.push(expr);
53
36
  }
54
- i = j;
55
- continue;
37
+ start = -1;
56
38
  }
57
39
  }
58
- i++;
59
40
  }
60
41
  return result;
61
42
  }
62
- // Extract inline HTML handlers
63
- function extractInlineHandlers(input) {
43
+ // HTML handlers
44
+ function extractHTMLHandlers(input) {
45
+ const result = [];
46
+ const regex = /\bon\w+\s*=\s*["']([^"']+)["']/g;
47
+ for (const m of input.matchAll(regex)) {
48
+ if (looksLikeTracking(m[1])) {
49
+ result.push(m[1]);
50
+ }
51
+ }
52
+ return result;
53
+ }
54
+ // VUE handlers
55
+ function extractVueHandlers(input) {
64
56
  const result = [];
65
- const matches = input.matchAll(/\bon\w+\s*=\s*["']([^"']+)["']/g);
66
- for (const m of matches) {
67
- const code = m[1];
68
- if (/[a-zA-Z0-9_$]\s*\(/.test(code)) {
69
- result.push(code);
57
+ const regex = /(?:@|v-on:)[\w:-]+\s*=\s*["']([^"']+)["']/g;
58
+ for (const m of input.matchAll(regex)) {
59
+ if (looksLikeTracking(m[1])) {
60
+ result.push(m[1]);
70
61
  }
71
62
  }
72
63
  return result;
73
64
  }
74
- // Extract dynamic imports
65
+ // SVELTE handlers
66
+ function extractSvelteHandlers(input) {
67
+ const result = [];
68
+ const regex = /\bon:[\w]+\s*=\s*{([^}]+)}/g;
69
+ for (const m of input.matchAll(regex)) {
70
+ if (looksLikeTracking(m[1])) {
71
+ result.push(m[1]);
72
+ }
73
+ }
74
+ return result;
75
+ }
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]);
94
+ }
95
+ }
96
+ const noScripts = input.replace(scriptRegex, "");
97
+ return { scripts, deps, noScripts };
98
+ }
99
+ // DYNAMIC IMPORTS
75
100
  function extractDynamicImports(input, file) {
76
101
  const deps = [];
77
- const calls = [];
78
- const matches = input.matchAll(/import\(\s*["'](.+?)["']\s*\)/g);
79
- for (const m of matches) {
102
+ const regex = /import\(\s*["'](.+?)["']\s*\)/g;
103
+ for (const m of input.matchAll(regex)) {
80
104
  const mod = m[1];
81
105
  const resolved = mod.startsWith("/")
82
106
  ? path_1.default.resolve(process.cwd(), "." + mod)
83
107
  : path_1.default.resolve(path_1.default.dirname(file), mod);
84
108
  deps.push(resolved);
85
- calls.push(`import("${mod}")`);
86
109
  }
87
- return { deps, calls };
110
+ return deps;
88
111
  }
89
- // Filter only probable tracking-related code
90
- function isProbablyTracking(code) {
91
- return /track|event|analytics/i.test(code);
92
- }
93
- // UNIVERSAL PARSER
112
+ // MAIN
94
113
  function parseUniversal(content, file) {
95
114
  const parts = [];
96
115
  const deps = [];
97
116
  const clean = stripComments(content);
98
- // ASTRO FRONTMATTER
117
+ /* ---------- ASTRO FRONTMATTER ---------- */
99
118
  const fm = clean.match(/^---([\s\S]*?)---/);
100
119
  if (fm?.[1]) {
101
120
  parts.push(fm[1]);
102
121
  }
103
- // <script src="">
104
- const scriptSrc = clean.matchAll(/<script\b[^>]*?\bsrc=["'](.+?)["'][^>]*>/g);
105
- for (const s of scriptSrc) {
106
- const src = s[1];
107
- const resolved = src.startsWith("/")
108
- ? path_1.default.resolve(process.cwd(), "." + src)
109
- : path_1.default.resolve(path_1.default.dirname(file), src);
110
- deps.push(resolved);
111
- }
112
- // INLINE <script>
113
- const scripts = clean.matchAll(/<script\b([^>]*)>([\s\S]*?)<\/script>/g);
114
- for (const m of scripts) {
115
- const attrs = m[1];
116
- if (/type=["']application\/json/.test(attrs))
117
- continue;
118
- if (m[2].trim()) {
119
- parts.push(m[2]);
120
- }
121
- }
122
- // REMOVE SCRIPTS → TEMPLATE PART
123
- const noScripts = clean.replace(/<script[\s\S]*?<\/script>/g, "");
124
- // INLINE HANDLERS
125
- parts.push(...extractInlineHandlers(noScripts).filter(isProbablyTracking));
126
- // DYNAMIC IMPORTS
127
- const dyn = extractDynamicImports(clean, file);
128
- deps.push(...dyn.deps);
129
- parts.push(...dyn.calls.filter(isProbablyTracking));
130
- // EXPRESSIONS
131
- const extracted = extractJS(clean);
132
- for (const e of extracted) {
133
- if (isProbablyTracking(e)) {
134
- parts.push(e + ";");
135
- }
136
- }
122
+ /* ---------- SCRIPTS ---------- */
123
+ const { scripts, deps: scriptDeps, noScripts } = extractScripts(clean, file);
124
+ parts.push(...scripts);
125
+ deps.push(...scriptDeps);
126
+ /* ---------- HANDLERS ---------- */
127
+ parts.push(...extractHTMLHandlers(noScripts));
128
+ parts.push(...extractVueHandlers(noScripts));
129
+ parts.push(...extractSvelteHandlers(noScripts));
130
+ /* ---------- JSX / TEMPLATE ---------- */
131
+ parts.push(...extractBracedExpressions(clean));
132
+ /* ---------- IMPORTS ---------- */
133
+ deps.push(...extractDynamicImports(clean, file));
137
134
  return {
138
135
  code: [...new Set(parts)].join("\n"),
139
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.29",
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);