@eventra_dev/eventra-cli 0.1.25 → 0.1.26

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.
@@ -13,6 +13,9 @@ const config_1 = require("../utils/config");
13
13
  const engine_1 = require("../engine/engine");
14
14
  const processFile_1 = require("../utils/processFile");
15
15
  const getVirtualFile_1 = require("../utils/getVirtualFile");
16
+ function normalize(file) {
17
+ return path_1.default.resolve(file).replace(/\\/g, "/");
18
+ }
16
19
  async function watch() {
17
20
  const config = await (0, config_1.loadConfig)();
18
21
  if (!config)
@@ -29,28 +32,29 @@ async function watch() {
29
32
  // COLLECT + CACHE
30
33
  for (const file of files) {
31
34
  try {
32
- const raw = await promises_1.default.readFile(file, "utf-8");
35
+ const abs = normalize(file);
36
+ const raw = await promises_1.default.readFile(abs, "utf-8");
33
37
  if (raw.length > 2_000_000)
34
- continue; // safeguard
35
- const parsed = (0, processFile_1.processFile)(file, raw);
36
- cache.set(file, parsed);
37
- toScan.add(file);
38
+ continue;
39
+ const parsed = (0, processFile_1.processFile)(abs, raw);
40
+ cache.set(abs, parsed);
41
+ toScan.add(abs);
38
42
  for (const dep of parsed.deps) {
39
- const absDep = path_1.default.resolve(dep);
40
- toScan.add(absDep);
43
+ toScan.add(normalize(dep));
41
44
  }
42
45
  }
43
46
  catch {
44
47
  console.log(chalk_1.default.gray(`skip: ${file}`));
45
48
  }
46
49
  }
47
- // PRELOAD (TS PROGRAM)
50
+ // PRELOAD
48
51
  for (const file of toScan) {
49
52
  try {
50
53
  let parsed = cache.get(file);
51
54
  if (!parsed) {
52
55
  const raw = await promises_1.default.readFile(file, "utf-8");
53
56
  parsed = (0, processFile_1.processFile)(file, raw);
57
+ cache.set(file, parsed);
54
58
  }
55
59
  const virtual = (0, getVirtualFile_1.getVirtualFile)(file);
56
60
  engine.preloadFile?.(virtual, parsed.content);
@@ -68,7 +72,7 @@ async function watch() {
68
72
  const virtual = (0, getVirtualFile_1.getVirtualFile)(file);
69
73
  engine.scanFile(virtual, parsed.content, config);
70
74
  for (const dep of parsed.deps) {
71
- watchedDeps.add(path_1.default.resolve(dep));
75
+ watchedDeps.add(normalize(dep));
72
76
  }
73
77
  }
74
78
  catch { }
@@ -94,19 +98,33 @@ async function watch() {
94
98
  const parsed = (0, processFile_1.processFile)(item.real, raw);
95
99
  cache.set(item.real, parsed);
96
100
  engine.updateFile(item.virtual, parsed.content, config);
97
- // DEPS
101
+ // DEPENDENCY DIFF
102
+ const nextDeps = new Set();
98
103
  for (const dep of parsed.deps) {
99
- const absDep = path_1.default.resolve(dep);
100
- if (!watchedDeps.has(absDep)) {
101
- watcher.add(absDep);
102
- watchedDeps.add(absDep);
104
+ nextDeps.add(normalize(dep));
105
+ }
106
+ // add new deps
107
+ for (const dep of nextDeps) {
108
+ if (!watchedDeps.has(dep)) {
109
+ watcher.add(dep);
110
+ watchedDeps.add(dep);
103
111
  }
112
+ }
113
+ // remove old deps
114
+ for (const dep of [...watchedDeps]) {
115
+ if (!nextDeps.has(dep)) {
116
+ watcher.unwatch(dep);
117
+ watchedDeps.delete(dep);
118
+ }
119
+ }
120
+ // preload deps
121
+ for (const dep of nextDeps) {
104
122
  try {
105
- const depRaw = await promises_1.default.readFile(absDep, "utf-8");
106
- const depParsed = (0, processFile_1.processFile)(absDep, depRaw);
107
- cache.set(absDep, depParsed);
108
- const depVirtual = (0, getVirtualFile_1.getVirtualFile)(absDep);
109
- engine.updateFile(depVirtual, depParsed.content, config);
123
+ const raw = await promises_1.default.readFile(dep, "utf-8");
124
+ const parsedDep = (0, processFile_1.processFile)(dep, raw);
125
+ cache.set(dep, parsedDep);
126
+ const virtual = (0, getVirtualFile_1.getVirtualFile)(dep);
127
+ engine.updateFile(virtual, parsedDep.content, config);
110
128
  }
111
129
  catch { }
112
130
  }
@@ -130,13 +148,13 @@ async function watch() {
130
148
  };
131
149
  // SCHEDULER
132
150
  const schedule = (file) => {
133
- const abs = path_1.default.resolve(file);
151
+ const abs = normalize(file);
134
152
  const virtual = (0, getVirtualFile_1.getVirtualFile)(abs);
135
153
  console.log(chalk_1.default.gray(`change: ${file}`));
136
154
  queued.set(abs, { real: abs, virtual });
137
155
  if (timer)
138
156
  clearTimeout(timer);
139
- timer = setTimeout(run, 250);
157
+ timer = setTimeout(run, 200);
140
158
  };
141
159
  // WATCHER
142
160
  const watcher = chokidar_1.default.watch(config.sync.include, {
@@ -148,7 +166,7 @@ async function watch() {
148
166
  .on("add", schedule)
149
167
  .on("change", schedule)
150
168
  .on("unlink", async (file) => {
151
- const abs = path_1.default.resolve(file);
169
+ const abs = normalize(file);
152
170
  console.log(chalk_1.default.gray(`remove: ${file}`));
153
171
  const virtual = (0, getVirtualFile_1.getVirtualFile)(abs);
154
172
  engine.removeFile(virtual, config);
@@ -162,7 +180,7 @@ async function watch() {
162
180
  .on("error", (err) => {
163
181
  console.error(chalk_1.default.red("Watcher error:"), err);
164
182
  });
165
- // WATCH DEPS
183
+ // WATCH DEPS INIT
166
184
  for (const dep of watchedDeps) {
167
185
  watcher.add(dep);
168
186
  }
@@ -23,15 +23,37 @@ function resolveFromSymbol(symbol, checker, visited = new Set(), depth = 0) {
23
23
  const aliased = checker.getAliasedSymbol(symbol);
24
24
  return resolveFromSymbol(aliased, checker, visited, depth + 1);
25
25
  }
26
+ // re-export support
27
+ if (symbol.exports) {
28
+ for (const exp of symbol.exports.values()) {
29
+ const resolved = resolveFromSymbol(exp, checker, visited, depth + 1);
30
+ if (resolved)
31
+ return resolved;
32
+ }
33
+ }
26
34
  const decls = symbol.getDeclarations() ?? [];
27
35
  for (const decl of decls) {
36
+ // direct function
28
37
  if (isFunctionLike(decl)) {
29
38
  return decl;
30
39
  }
31
- // MethodSignature
40
+ // VARIABLE → FUNCTION
41
+ if (typescript_1.default.isVariableDeclaration(decl) && decl.initializer) {
42
+ if (isFunctionLike(decl.initializer)) {
43
+ return decl.initializer;
44
+ }
45
+ const innerSymbol = checker.getSymbolAtLocation(decl.initializer);
46
+ if (innerSymbol && innerSymbol !== symbol) {
47
+ const resolved = resolveFromSymbol(innerSymbol, checker, visited, depth + 1);
48
+ if (resolved)
49
+ return resolved;
50
+ }
51
+ }
52
+ // MethodSignature (interface / type)
32
53
  if (typescript_1.default.isMethodSignature(decl)) {
33
54
  const parent = decl.parent;
34
- if (typescript_1.default.isInterfaceDeclaration(parent) || typescript_1.default.isTypeLiteralNode(parent)) {
55
+ if (typescript_1.default.isInterfaceDeclaration(parent) ||
56
+ typescript_1.default.isTypeLiteralNode(parent)) {
35
57
  const name = decl.name.getText();
36
58
  const type = checker.getTypeAtLocation(parent);
37
59
  const props = type.getProperties();
@@ -44,7 +66,7 @@ function resolveFromSymbol(symbol, checker, visited = new Set(), depth = 0) {
44
66
  }
45
67
  }
46
68
  }
47
- // SAFE fallback
69
+ // fallback recursion
48
70
  const s = checker.getSymbolAtLocation(decl);
49
71
  if (s && s !== symbol) {
50
72
  const resolved = resolveFromSymbol(s, checker, visited, depth + 1);
@@ -55,6 +77,28 @@ function resolveFromSymbol(symbol, checker, visited = new Set(), depth = 0) {
55
77
  return null;
56
78
  }
57
79
  function resolveFunctionFromCall(expr, checker) {
80
+ // tracker.track
81
+ if (typescript_1.default.isPropertyAccessExpression(expr)) {
82
+ let symbol = checker.getSymbolAtLocation(expr.name);
83
+ if (symbol && (symbol.flags & typescript_1.default.SymbolFlags.Alias)) {
84
+ symbol = checker.getAliasedSymbol(symbol);
85
+ }
86
+ if (symbol) {
87
+ const resolved = resolveFromSymbol(symbol, checker);
88
+ if (resolved)
89
+ return resolved;
90
+ }
91
+ }
92
+ // tracker["track"]
93
+ if (typescript_1.default.isElementAccessExpression(expr)) {
94
+ const symbol = checker.getSymbolAtLocation(expr.argumentExpression);
95
+ if (symbol) {
96
+ const resolved = resolveFromSymbol(symbol, checker);
97
+ if (resolved)
98
+ return resolved;
99
+ }
100
+ }
101
+ // normal call signatures
58
102
  const type = checker.getTypeAtLocation(expr);
59
103
  const signatures = type.getCallSignatures();
60
104
  for (const sig of signatures) {
@@ -64,7 +108,6 @@ function resolveFunctionFromCall(expr, checker) {
64
108
  if (isFunctionLike(decl)) {
65
109
  return decl;
66
110
  }
67
- // interface method
68
111
  if (typescript_1.default.isMethodSignature(decl)) {
69
112
  const symbol = checker.getSymbolAtLocation(decl.name);
70
113
  if (symbol) {
@@ -74,5 +117,10 @@ function resolveFunctionFromCall(expr, checker) {
74
117
  }
75
118
  }
76
119
  }
120
+ // fallback
121
+ const symbol = checker.getSymbolAtLocation(expr);
122
+ if (symbol) {
123
+ return resolveFromSymbol(symbol, checker);
124
+ }
77
125
  return null;
78
126
  }
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.EventraEngine = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_1 = __importDefault(require("fs"));
4
9
  const languageService_1 = require("./languageService");
5
10
  const scanner_1 = require("./scanner");
6
11
  const graph_1 = require("./graph");
@@ -16,31 +21,40 @@ class EventraEngine {
16
21
  const { baseUrl, paths } = this.ts.getModuleResolutionConfig();
17
22
  this.graph = new graph_1.DependencyGraph(baseUrl, paths);
18
23
  }
24
+ normalize(file) {
25
+ return path_1.default.resolve(file).replace(/\\/g, "/");
26
+ }
27
+ empty() {
28
+ return {
29
+ events: new Set(),
30
+ detectedFunctionWrappers: new Set(),
31
+ detectedComponentWrappers: new Map(),
32
+ };
33
+ }
34
+ // PRELOAD
19
35
  preloadFile(file, content) {
36
+ file = this.normalize(file);
20
37
  this.ts.updateFile(file, content);
38
+ const source = this.ts.getSourceFile(file);
39
+ if (source) {
40
+ this.graph.update(file, source);
41
+ }
21
42
  }
22
43
  // SCAN FILE
23
44
  scanFile(file, content, config) {
45
+ file = this.normalize(file);
24
46
  const h = (0, hash_1.hash)(content);
25
- // skip unchanged
26
47
  if (this.fileHash.get(file) === h) {
27
- return (this.fileResults.get(file) ?? {
28
- events: new Set(),
29
- detectedFunctionWrappers: new Set(),
30
- detectedComponentWrappers: new Map(),
31
- });
48
+ return this.fileResults.get(file) ?? this.empty();
32
49
  }
33
50
  this.fileHash.set(file, h);
34
51
  this.ts.updateFile(file, content);
35
52
  const source = this.ts.getSourceFile(file);
36
53
  const checker = this.ts.getChecker();
37
54
  if (!source || !checker) {
38
- return {
39
- events: new Set(),
40
- detectedFunctionWrappers: new Set(),
41
- detectedComponentWrappers: new Map(),
42
- };
55
+ return this.empty();
43
56
  }
57
+ // обновляем graph
44
58
  this.graph.update(file, source);
45
59
  const res = (0, scanner_1.scanSource)(source, checker, config);
46
60
  this.fileResults.set(file, res);
@@ -48,26 +62,35 @@ class EventraEngine {
48
62
  }
49
63
  // UPDATE FILE (incremental)
50
64
  updateFile(file, content, config) {
65
+ file = this.normalize(file);
51
66
  const res = this.scanFile(file, content, config);
52
67
  const dependents = this.graph.getAllDependentsDeep(file);
53
68
  for (const dep of dependents) {
54
- if ((0, boundary_1.isExternalFile)(dep))
55
- continue;
56
- const depContent = this.ts.getFileContent(dep);
57
- if (!depContent)
69
+ const abs = this.normalize(dep);
70
+ if ((0, boundary_1.isExternalFile)(abs))
58
71
  continue;
72
+ let depContent = this.ts.getFileContent(abs);
73
+ if (!depContent) {
74
+ try {
75
+ depContent = fs_1.default.readFileSync(abs, "utf-8");
76
+ }
77
+ catch {
78
+ continue;
79
+ }
80
+ }
59
81
  const h = (0, hash_1.hash)(depContent);
60
- if (this.fileHash.get(dep) === h)
82
+ if (this.fileHash.get(abs) === h) {
61
83
  continue;
62
- this.fileHash.set(dep, h);
63
- this.ts.updateFile(dep, depContent);
64
- const source = this.ts.getSourceFile(dep);
84
+ }
85
+ this.fileHash.set(abs, h);
86
+ this.ts.updateFile(abs, depContent);
87
+ const source = this.ts.getSourceFile(abs);
65
88
  const checker = this.ts.getChecker();
66
89
  if (!source || !checker)
67
90
  continue;
68
- this.graph.update(dep, source);
91
+ this.graph.update(abs, source);
69
92
  const r = (0, scanner_1.scanSource)(source, checker, config);
70
- this.fileResults.set(dep, r);
93
+ this.fileResults.set(abs, r);
71
94
  }
72
95
  return res;
73
96
  }
@@ -81,33 +104,42 @@ class EventraEngine {
81
104
  }
82
105
  // REMOVE FILE
83
106
  removeFile(file, config) {
107
+ file = this.normalize(file);
108
+ const dependents = this.graph.getAllDependentsDeep(file);
84
109
  this.ts.removeFile(file);
85
110
  this.fileResults.delete(file);
86
111
  this.fileHash.delete(file);
87
112
  this.graph.remove(file);
88
- const dependents = this.graph.getAllDependentsDeep(file);
89
113
  for (const dep of dependents) {
90
- if ((0, boundary_1.isExternalFile)(dep))
91
- continue;
92
- const content = this.ts.getFileContent(dep);
93
- if (!content)
114
+ const abs = this.normalize(dep);
115
+ if ((0, boundary_1.isExternalFile)(abs))
94
116
  continue;
117
+ let content = this.ts.getFileContent(abs);
118
+ if (!content) {
119
+ try {
120
+ content = fs_1.default.readFileSync(abs, "utf-8");
121
+ }
122
+ catch {
123
+ continue;
124
+ }
125
+ }
95
126
  const h = (0, hash_1.hash)(content);
96
- if (this.fileHash.get(dep) === h)
127
+ if (this.fileHash.get(abs) === h)
97
128
  continue;
98
- this.fileHash.set(dep, h);
99
- this.ts.updateFile(dep, content);
100
- const source = this.ts.getSourceFile(dep);
129
+ this.fileHash.set(abs, h);
130
+ this.ts.updateFile(abs, content);
131
+ const source = this.ts.getSourceFile(abs);
101
132
  const checker = this.ts.getChecker();
102
133
  if (!source || !checker)
103
134
  continue;
135
+ this.graph.update(abs, source);
104
136
  const r = (0, scanner_1.scanSource)(source, checker, config ?? {
105
137
  events: [],
106
138
  wrappers: [],
107
139
  functionWrappers: [],
108
140
  sync: { include: [], exclude: [] },
109
141
  });
110
- this.fileResults.set(dep, r);
142
+ this.fileResults.set(abs, r);
111
143
  }
112
144
  }
113
145
  }
@@ -5,21 +5,33 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.resolveExportedSymbol = resolveExportedSymbol;
7
7
  const typescript_1 = __importDefault(require("typescript"));
8
+ function isRealDeclaration(node) {
9
+ return (typescript_1.default.isFunctionDeclaration(node) ||
10
+ typescript_1.default.isVariableDeclaration(node) ||
11
+ typescript_1.default.isClassDeclaration(node));
12
+ }
8
13
  function resolveExportedSymbol(symbol, checker, visited = new Set()) {
9
14
  if (visited.has(symbol))
10
15
  return null;
11
16
  visited.add(symbol);
17
+ // unwrap alias
12
18
  if (symbol.flags & typescript_1.default.SymbolFlags.Alias) {
13
19
  const aliased = checker.getAliasedSymbol(symbol);
14
20
  return resolveExportedSymbol(aliased, checker, visited);
15
21
  }
16
- if (symbol.getDeclarations()?.length) {
22
+ // export symbol
23
+ const exportSymbol = checker.getExportSymbolOfSymbol(symbol);
24
+ if (exportSymbol && exportSymbol !== symbol) {
25
+ return resolveExportedSymbol(exportSymbol, checker, visited);
26
+ }
27
+ const decls = symbol.getDeclarations() ?? [];
28
+ if (decls.some(isRealDeclaration)) {
17
29
  return symbol;
18
30
  }
19
- const declarations = symbol.getDeclarations() ?? [];
20
- for (const decl of declarations) {
31
+ // exports (re-export)
32
+ for (const decl of decls) {
21
33
  const source = decl.getSourceFile();
22
- const moduleSymbol = checker.getSymbolAtLocation(source);
34
+ const moduleSymbol = source.symbol;
23
35
  if (!moduleSymbol)
24
36
  continue;
25
37
  const exports = checker.getExportsOfModule(moduleSymbol);
@@ -10,19 +10,81 @@ 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
+ }
13
18
  }
14
19
  });
15
20
  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
32
+ if (typescript_1.default.isIdentifier(arg)) {
33
+ const idx = paramIndex.get(arg.text);
34
+ if (idx !== undefined) {
35
+ result = idx;
36
+ return true;
37
+ }
38
+ }
39
+ // string literal
40
+ if (typescript_1.default.isStringLiteral(arg)) {
41
+ result = 0;
42
+ return true;
43
+ }
44
+ // template `${name}`
45
+ if (typescript_1.default.isTemplateExpression(arg)) {
46
+ for (const span of arg.templateSpans) {
47
+ if (typescript_1.default.isIdentifier(span.expression)) {
48
+ const idx = paramIndex.get(span.expression.text);
49
+ if (idx !== undefined) {
50
+ result = idx;
51
+ return true;
52
+ }
53
+ }
54
+ }
55
+ result = 0;
56
+ return true;
57
+ }
58
+ // object { event: name }
59
+ if (typescript_1.default.isObjectLiteralExpression(arg)) {
60
+ for (const prop of arg.properties) {
61
+ if (!typescript_1.default.isPropertyAssignment(prop))
62
+ continue;
63
+ const name = prop.name.getText();
64
+ if (["event", "name", "type"].includes(name)) {
65
+ return checkArg(prop.initializer);
66
+ }
67
+ }
68
+ }
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
+ return false;
77
+ }
16
78
  function visit(node) {
79
+ if (result !== null)
80
+ return;
17
81
  if (typescript_1.default.isCallExpression(node)) {
18
82
  let isTrackCall = false;
19
83
  if (typescript_1.default.isPropertyAccessExpression(node.expression)) {
20
- const method = node.expression.name.text;
21
- if (method === "track") {
84
+ if (node.expression.name.text === "track") {
22
85
  isTrackCall = true;
23
86
  }
24
87
  }
25
- // fallback
26
88
  if (typescript_1.default.isIdentifier(node.expression)) {
27
89
  if (node.expression.text === "track") {
28
90
  isTrackCall = true;
@@ -30,17 +92,8 @@ function findTrackParamIndex(fn) {
30
92
  }
31
93
  if (isTrackCall) {
32
94
  for (const arg of node.arguments) {
33
- if (typescript_1.default.isIdentifier(arg)) {
34
- const idx = paramIndex.get(arg.text);
35
- if (idx !== undefined) {
36
- result = idx;
37
- return;
38
- }
39
- }
40
- if (typescript_1.default.isStringLiteral(arg)) {
41
- result = 0;
95
+ if (checkArg(arg))
42
96
  return;
43
- }
44
97
  }
45
98
  }
46
99
  }
@@ -18,13 +18,16 @@ class DependencyGraph {
18
18
  this.paths = paths;
19
19
  }
20
20
  normalize(file) {
21
- return path_1.default.resolve(file);
21
+ return path_1.default.resolve(file).replace(/\\/g, "/");
22
22
  }
23
+ // MODULE RESOLVE
23
24
  resolveModule(module, from) {
25
+ // relative import
24
26
  if (module.startsWith(".")) {
25
27
  const abs = path_1.default.resolve(path_1.default.dirname(from), module);
26
28
  return this.resolveFile(abs);
27
29
  }
30
+ // tsconfig paths
28
31
  for (const key in this.paths) {
29
32
  const pattern = key.replace(/\*/g, "(.*)");
30
33
  const regex = new RegExp("^" + pattern + "$");
@@ -43,9 +46,19 @@ class DependencyGraph {
43
46
  return resolved;
44
47
  }
45
48
  }
49
+ // node resolution (safe)
50
+ try {
51
+ const resolved = require.resolve(module, {
52
+ paths: [path_1.default.dirname(from)],
53
+ });
54
+ return this.normalize(resolved);
55
+ }
56
+ catch { }
57
+ // fallback
46
58
  const abs = path_1.default.resolve(this.baseUrl, module);
47
59
  return this.resolveFile(abs);
48
60
  }
61
+ // FILE RESOLVE
49
62
  resolveFile(base) {
50
63
  if (this.fileCache.has(base)) {
51
64
  return this.fileCache.get(base);
@@ -56,6 +69,12 @@ class DependencyGraph {
56
69
  base + ".tsx",
57
70
  base + ".js",
58
71
  base + ".jsx",
72
+ base + ".mjs",
73
+ base + ".cjs",
74
+ base + ".d.ts",
75
+ base + ".vue",
76
+ base + ".svelte",
77
+ base + ".astro",
59
78
  path_1.default.join(base, "index.ts"),
60
79
  path_1.default.join(base, "index.tsx"),
61
80
  path_1.default.join(base, "index.js"),
@@ -70,12 +89,22 @@ class DependencyGraph {
70
89
  this.fileCache.set(base, null);
71
90
  return null;
72
91
  }
92
+ // UPDATE GRAPH
73
93
  update(file, source) {
74
94
  const normalizedFile = this.normalize(file);
95
+ for (const deps of this.reverse.values()) {
96
+ deps.delete(normalizedFile);
97
+ }
75
98
  this.exports.set(normalizedFile, new Set());
76
99
  for (const stmt of source.statements) {
100
+ // IMPORT
77
101
  if (typescript_1.default.isImportDeclaration(stmt)) {
78
- const module = stmt.moduleSpecifier.getText().replace(/['"]/g, "");
102
+ // ignore import type
103
+ if (stmt.importClause?.importKind === "type")
104
+ continue;
105
+ const module = stmt.moduleSpecifier
106
+ .getText()
107
+ .replace(/['"]/g, "");
79
108
  const resolved = this.resolveModule(module, normalizedFile);
80
109
  if (!resolved)
81
110
  continue;
@@ -84,8 +113,13 @@ class DependencyGraph {
84
113
  }
85
114
  this.reverse.get(resolved).add(normalizedFile);
86
115
  }
87
- if (typescript_1.default.isExportDeclaration(stmt) && stmt.moduleSpecifier) {
88
- const module = stmt.moduleSpecifier.getText().replace(/['"]/g, "");
116
+ // EXPORT (re-export)
117
+ if (typescript_1.default.isExportDeclaration(stmt)) {
118
+ if (!stmt.moduleSpecifier)
119
+ continue;
120
+ const module = stmt.moduleSpecifier
121
+ .getText()
122
+ .replace(/['"]/g, "");
89
123
  const resolved = this.resolveModule(module, normalizedFile);
90
124
  if (!resolved)
91
125
  continue;
@@ -97,6 +131,7 @@ class DependencyGraph {
97
131
  }
98
132
  }
99
133
  }
134
+ // DEPENDENTS
100
135
  getAllDependentsDeep(file) {
101
136
  const start = this.normalize(file);
102
137
  const visited = new Set();
@@ -116,6 +151,7 @@ class DependencyGraph {
116
151
  walk(start);
117
152
  return [...result];
118
153
  }
154
+ // REMOVE
119
155
  remove(file) {
120
156
  const normalized = this.normalize(file);
121
157
  this.reverse.delete(normalized);