@mgamil/mapx 0.2.4

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.
Files changed (203) hide show
  1. package/LICENSE +194 -0
  2. package/README.md +488 -0
  3. package/VERSION +1 -0
  4. package/dist/agents/generator.d.ts +74 -0
  5. package/dist/agents/generator.js +375 -0
  6. package/dist/agents/templates.d.ts +29 -0
  7. package/dist/agents/templates.js +459 -0
  8. package/dist/cli.d.ts +16 -0
  9. package/dist/cli.js +1835 -0
  10. package/dist/core/cluster-engine.d.ts +32 -0
  11. package/dist/core/cluster-engine.js +314 -0
  12. package/dist/core/config.d.ts +29 -0
  13. package/dist/core/config.js +178 -0
  14. package/dist/core/context-builder.d.ts +61 -0
  15. package/dist/core/context-builder.js +252 -0
  16. package/dist/core/flow-tracer.d.ts +63 -0
  17. package/dist/core/flow-tracer.js +366 -0
  18. package/dist/core/git-tracker.d.ts +20 -0
  19. package/dist/core/git-tracker.js +159 -0
  20. package/dist/core/graph.d.ts +42 -0
  21. package/dist/core/graph.js +186 -0
  22. package/dist/core/metrics.d.ts +24 -0
  23. package/dist/core/metrics.js +87 -0
  24. package/dist/core/scanner.d.ts +53 -0
  25. package/dist/core/scanner.js +949 -0
  26. package/dist/core/store-bun.d.ts +13 -0
  27. package/dist/core/store-bun.js +34 -0
  28. package/dist/core/store-interface.d.ts +15 -0
  29. package/dist/core/store-interface.js +7 -0
  30. package/dist/core/store-node.d.ts +13 -0
  31. package/dist/core/store-node.js +35 -0
  32. package/dist/core/store.d.ts +132 -0
  33. package/dist/core/store.js +614 -0
  34. package/dist/core/workspace-manager.d.ts +9 -0
  35. package/dist/core/workspace-manager.js +64 -0
  36. package/dist/exporters/dot-exporter.d.ts +16 -0
  37. package/dist/exporters/dot-exporter.js +179 -0
  38. package/dist/exporters/graph-exporter.d.ts +14 -0
  39. package/dist/exporters/graph-exporter.js +85 -0
  40. package/dist/exporters/index.d.ts +9 -0
  41. package/dist/exporters/index.js +12 -0
  42. package/dist/exporters/llm-exporter.d.ts +18 -0
  43. package/dist/exporters/llm-exporter.js +224 -0
  44. package/dist/exporters/svg-exporter.d.ts +19 -0
  45. package/dist/exporters/svg-exporter.js +319 -0
  46. package/dist/exporters/toon-exporter.d.ts +16 -0
  47. package/dist/exporters/toon-exporter.js +246 -0
  48. package/dist/frameworks/detectors/aspnet.d.ts +11 -0
  49. package/dist/frameworks/detectors/aspnet.js +52 -0
  50. package/dist/frameworks/detectors/django.d.ts +14 -0
  51. package/dist/frameworks/detectors/django.js +135 -0
  52. package/dist/frameworks/detectors/drupal.d.ts +13 -0
  53. package/dist/frameworks/detectors/drupal.js +94 -0
  54. package/dist/frameworks/detectors/express.d.ts +12 -0
  55. package/dist/frameworks/detectors/express.js +234 -0
  56. package/dist/frameworks/detectors/fastapi.d.ts +12 -0
  57. package/dist/frameworks/detectors/fastapi.js +203 -0
  58. package/dist/frameworks/detectors/flask.d.ts +12 -0
  59. package/dist/frameworks/detectors/flask.js +244 -0
  60. package/dist/frameworks/detectors/go.d.ts +11 -0
  61. package/dist/frameworks/detectors/go.js +75 -0
  62. package/dist/frameworks/detectors/laravel.d.ts +11 -0
  63. package/dist/frameworks/detectors/laravel.js +462 -0
  64. package/dist/frameworks/detectors/nestjs.d.ts +12 -0
  65. package/dist/frameworks/detectors/nestjs.js +155 -0
  66. package/dist/frameworks/detectors/nextjs.d.ts +11 -0
  67. package/dist/frameworks/detectors/nextjs.js +118 -0
  68. package/dist/frameworks/detectors/rails.d.ts +12 -0
  69. package/dist/frameworks/detectors/rails.js +76 -0
  70. package/dist/frameworks/detectors/react-router.d.ts +11 -0
  71. package/dist/frameworks/detectors/react-router.js +115 -0
  72. package/dist/frameworks/detectors/rust.d.ts +11 -0
  73. package/dist/frameworks/detectors/rust.js +59 -0
  74. package/dist/frameworks/detectors/spring.d.ts +11 -0
  75. package/dist/frameworks/detectors/spring.js +56 -0
  76. package/dist/frameworks/detectors/sveltekit.d.ts +11 -0
  77. package/dist/frameworks/detectors/sveltekit.js +154 -0
  78. package/dist/frameworks/detectors/symfony.d.ts +13 -0
  79. package/dist/frameworks/detectors/symfony.js +175 -0
  80. package/dist/frameworks/detectors/tanstack-router.d.ts +12 -0
  81. package/dist/frameworks/detectors/tanstack-router.js +80 -0
  82. package/dist/frameworks/detectors/vapor.d.ts +11 -0
  83. package/dist/frameworks/detectors/vapor.js +52 -0
  84. package/dist/frameworks/detectors/vue-router.d.ts +12 -0
  85. package/dist/frameworks/detectors/vue-router.js +237 -0
  86. package/dist/frameworks/detectors/wordpress.d.ts +13 -0
  87. package/dist/frameworks/detectors/wordpress.js +141 -0
  88. package/dist/frameworks/detectors/yii.d.ts +11 -0
  89. package/dist/frameworks/detectors/yii.js +131 -0
  90. package/dist/frameworks/framework-registry.d.ts +13 -0
  91. package/dist/frameworks/framework-registry.js +77 -0
  92. package/dist/frameworks/route-registry.d.ts +26 -0
  93. package/dist/frameworks/route-registry.js +102 -0
  94. package/dist/index.d.ts +19 -0
  95. package/dist/index.js +30 -0
  96. package/dist/languages/index.d.ts +2 -0
  97. package/dist/languages/index.js +7 -0
  98. package/dist/languages/installer.d.ts +13 -0
  99. package/dist/languages/installer.js +103 -0
  100. package/dist/languages/registry.d.ts +19 -0
  101. package/dist/languages/registry.js +427 -0
  102. package/dist/main.d.ts +2 -0
  103. package/dist/main.js +20 -0
  104. package/dist/mcp.d.ts +11 -0
  105. package/dist/mcp.js +1699 -0
  106. package/dist/parsers/common-methods.d.ts +3 -0
  107. package/dist/parsers/common-methods.js +33 -0
  108. package/dist/parsers/fallback-parser.d.ts +10 -0
  109. package/dist/parsers/fallback-parser.js +18 -0
  110. package/dist/parsers/generic-wasm-parser.d.ts +23 -0
  111. package/dist/parsers/generic-wasm-parser.js +168 -0
  112. package/dist/parsers/ignored-symbols.d.ts +26 -0
  113. package/dist/parsers/ignored-symbols.js +77 -0
  114. package/dist/parsers/index.d.ts +9 -0
  115. package/dist/parsers/index.js +13 -0
  116. package/dist/parsers/languages/javascript.d.ts +11 -0
  117. package/dist/parsers/languages/javascript.js +28 -0
  118. package/dist/parsers/languages/php.d.ts +15 -0
  119. package/dist/parsers/languages/php.js +648 -0
  120. package/dist/parsers/languages/typescript.d.ts +10 -0
  121. package/dist/parsers/languages/typescript.js +9 -0
  122. package/dist/parsers/languages/vue.d.ts +13 -0
  123. package/dist/parsers/languages/vue.js +63 -0
  124. package/dist/parsers/parse-worker.d.ts +2 -0
  125. package/dist/parsers/parse-worker.js +185 -0
  126. package/dist/parsers/parser-interface.d.ts +9 -0
  127. package/dist/parsers/parser-interface.js +0 -0
  128. package/dist/parsers/parser-registry.d.ts +8 -0
  129. package/dist/parsers/parser-registry.js +52 -0
  130. package/dist/parsers/wasm-parser.d.ts +16 -0
  131. package/dist/parsers/wasm-parser.js +110 -0
  132. package/dist/types.d.ts +172 -0
  133. package/dist/types.js +0 -0
  134. package/dist/ui/index.html +270 -0
  135. package/dist/ui/main.js +581 -0
  136. package/dist/ui/main.js.map +7 -0
  137. package/dist/ui/styles.css +573 -0
  138. package/dist/ui-events.d.ts +36 -0
  139. package/dist/ui-events.js +61 -0
  140. package/dist/ui-server.d.ts +12 -0
  141. package/dist/ui-server.js +504 -0
  142. package/package.json +179 -0
  143. package/queries/bash/references.scm +22 -0
  144. package/queries/bash/symbols.scm +15 -0
  145. package/queries/c/references.scm +14 -0
  146. package/queries/c/symbols.scm +30 -0
  147. package/queries/c-sharp/references.scm +26 -0
  148. package/queries/c-sharp/symbols.scm +57 -0
  149. package/queries/cpp/references.scm +21 -0
  150. package/queries/cpp/symbols.scm +44 -0
  151. package/queries/dart/references.scm +33 -0
  152. package/queries/dart/symbols.scm +38 -0
  153. package/queries/elixir/references.scm +45 -0
  154. package/queries/elixir/symbols.scm +41 -0
  155. package/queries/go/references.scm +22 -0
  156. package/queries/go/symbols.scm +53 -0
  157. package/queries/java/references.scm +32 -0
  158. package/queries/java/symbols.scm +41 -0
  159. package/queries/javascript/references.scm +14 -0
  160. package/queries/javascript/symbols.scm +23 -0
  161. package/queries/kotlin/references.scm +31 -0
  162. package/queries/kotlin/symbols.scm +24 -0
  163. package/queries/lua/references.scm +19 -0
  164. package/queries/lua/symbols.scm +29 -0
  165. package/queries/pascal/references.scm +29 -0
  166. package/queries/pascal/symbols.scm +45 -0
  167. package/queries/php/references.scm +109 -0
  168. package/queries/php/symbols.scm +33 -0
  169. package/queries/python/references.scm +50 -0
  170. package/queries/python/symbols.scm +21 -0
  171. package/queries/ruby/references.scm +48 -0
  172. package/queries/ruby/symbols.scm +24 -0
  173. package/queries/rust/references.scm +31 -0
  174. package/queries/rust/symbols.scm +35 -0
  175. package/queries/scala/references.scm +30 -0
  176. package/queries/scala/symbols.scm +35 -0
  177. package/queries/svelte/references.scm +20 -0
  178. package/queries/svelte/symbols.scm +30 -0
  179. package/queries/swift/references.scm +22 -0
  180. package/queries/swift/symbols.scm +37 -0
  181. package/queries/typescript/references.scm +25 -0
  182. package/queries/typescript/symbols.scm +35 -0
  183. package/queries/vue/references.scm +20 -0
  184. package/queries/vue/symbols.scm +28 -0
  185. package/queries/zig/references.scm +20 -0
  186. package/queries/zig/symbols.scm +22 -0
  187. package/wasm/tree-sitter-c.wasm +0 -0
  188. package/wasm/tree-sitter-c_sharp.wasm +0 -0
  189. package/wasm/tree-sitter-cpp.wasm +0 -0
  190. package/wasm/tree-sitter-dart.wasm +0 -0
  191. package/wasm/tree-sitter-go.wasm +0 -0
  192. package/wasm/tree-sitter-java.wasm +0 -0
  193. package/wasm/tree-sitter-javascript.wasm +0 -0
  194. package/wasm/tree-sitter-kotlin.wasm +0 -0
  195. package/wasm/tree-sitter-php.wasm +0 -0
  196. package/wasm/tree-sitter-python.wasm +0 -0
  197. package/wasm/tree-sitter-ruby.wasm +0 -0
  198. package/wasm/tree-sitter-rust.wasm +0 -0
  199. package/wasm/tree-sitter-scala.wasm +0 -0
  200. package/wasm/tree-sitter-swift.wasm +0 -0
  201. package/wasm/tree-sitter-tsx.wasm +0 -0
  202. package/wasm/tree-sitter-typescript.wasm +0 -0
  203. package/wasm/tree-sitter-vue.wasm +0 -0
@@ -0,0 +1,159 @@
1
+ import { execSync } from "node:child_process";
2
+ import { resolve, join } from "node:path";
3
+ function getGitBlobHashes(repoRoot) {
4
+ const hashes = /* @__PURE__ */ new Map();
5
+ try {
6
+ const output = execSync("git ls-tree -r HEAD", {
7
+ cwd: repoRoot,
8
+ encoding: "utf-8",
9
+ maxBuffer: 50 * 1024 * 1024
10
+ });
11
+ for (const line of output.split("\n")) {
12
+ if (!line) continue;
13
+ const tab = line.indexOf(" ");
14
+ if (tab === -1) continue;
15
+ const parts = line.slice(0, tab).split(" ");
16
+ if (parts.length < 3) continue;
17
+ const hash = parts[2];
18
+ const filePath = line.slice(tab + 1);
19
+ if (hash && filePath) hashes.set(filePath, hash);
20
+ }
21
+ } catch {
22
+ }
23
+ return hashes;
24
+ }
25
+ function getChangedFiles(repoRoot, since) {
26
+ const changes = [];
27
+ try {
28
+ let command;
29
+ if (since) {
30
+ command = `git diff --name-status ${since}`;
31
+ } else {
32
+ command = "git diff --name-status HEAD";
33
+ }
34
+ const output = execSync(command, {
35
+ cwd: repoRoot,
36
+ encoding: "utf-8",
37
+ maxBuffer: 50 * 1024 * 1024
38
+ });
39
+ for (const line of output.trim().split("\n").filter(Boolean)) {
40
+ const parts = line.split(" ");
41
+ const status = parts[0].charAt(0);
42
+ const filePath = parts[parts.length - 1];
43
+ const statusMap = {
44
+ "A": "added",
45
+ "M": "modified",
46
+ "D": "removed",
47
+ "R": "renamed",
48
+ "C": "modified"
49
+ };
50
+ changes.push({ path: filePath, status: statusMap[status] || "modified" });
51
+ }
52
+ } catch {
53
+ }
54
+ try {
55
+ const stagedOutput = execSync("git diff --name-status --cached", {
56
+ cwd: repoRoot,
57
+ encoding: "utf-8"
58
+ }).trim();
59
+ for (const line of stagedOutput.split("\n").filter(Boolean)) {
60
+ const parts = line.split(" ");
61
+ const status = parts[0].charAt(0);
62
+ const filePath = parts[parts.length - 1];
63
+ if (!changes.find((c) => c.path === filePath)) {
64
+ const statusMap = {
65
+ "A": "added",
66
+ "M": "modified",
67
+ "D": "removed",
68
+ "R": "renamed"
69
+ };
70
+ changes.push({ path: filePath, status: statusMap[status] || "modified" });
71
+ }
72
+ }
73
+ } catch {
74
+ }
75
+ return changes;
76
+ }
77
+ function getCurrentCommitSha(repoRoot) {
78
+ try {
79
+ return execSync("git rev-parse HEAD", { cwd: repoRoot, encoding: "utf-8" }).trim();
80
+ } catch {
81
+ return null;
82
+ }
83
+ }
84
+ function getPreviousCommitSha(repoRoot) {
85
+ try {
86
+ return execSync("git rev-parse HEAD~1", { cwd: repoRoot, encoding: "utf-8" }).trim();
87
+ } catch {
88
+ return null;
89
+ }
90
+ }
91
+ function isGitRepo(dir) {
92
+ try {
93
+ execSync("git rev-parse --git-dir", { cwd: dir, stdio: "pipe" });
94
+ return true;
95
+ } catch {
96
+ return false;
97
+ }
98
+ }
99
+ function getRepoName(repoRoot) {
100
+ try {
101
+ const remote = execSync("git remote get-url origin", { cwd: repoRoot, encoding: "utf-8" }).trim();
102
+ const basename = remote.split("/").pop() || "unknown";
103
+ return basename.replace(/\.git$/, "");
104
+ } catch {
105
+ return resolve(repoRoot).split("/").pop() || "unknown";
106
+ }
107
+ }
108
+ import { existsSync, readFileSync } from "node:fs";
109
+ function discoverSubmodules(repoRoot) {
110
+ const gitmodulesPath = join(repoRoot, ".gitmodules");
111
+ if (!existsSync(gitmodulesPath)) return [];
112
+ const submodules = [];
113
+ try {
114
+ const content = readFileSync(gitmodulesPath, "utf-8");
115
+ let currentSubmodule = null;
116
+ for (const line of content.split("\n")) {
117
+ const trimmed = line.trim();
118
+ if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith(";")) continue;
119
+ const sectionMatch = trimmed.match(/^\[submodule\s+"([^"]+)"\]$/i);
120
+ if (sectionMatch) {
121
+ if (currentSubmodule && currentSubmodule.name && currentSubmodule.path && currentSubmodule.url) {
122
+ submodules.push(currentSubmodule);
123
+ }
124
+ currentSubmodule = {
125
+ name: sectionMatch[1],
126
+ isInitialized: false
127
+ };
128
+ continue;
129
+ }
130
+ if (currentSubmodule && trimmed.includes("=")) {
131
+ const eq = trimmed.indexOf("=");
132
+ const key = trimmed.slice(0, eq).trim().toLowerCase();
133
+ const val = trimmed.slice(eq + 1).trim();
134
+ if (key === "path") {
135
+ currentSubmodule.path = val;
136
+ const subPath = join(repoRoot, val);
137
+ const gitFile = join(subPath, ".git");
138
+ currentSubmodule.isInitialized = existsSync(gitFile);
139
+ } else if (key === "url") {
140
+ currentSubmodule.url = val;
141
+ }
142
+ }
143
+ }
144
+ if (currentSubmodule && currentSubmodule.name && currentSubmodule.path && currentSubmodule.url) {
145
+ submodules.push(currentSubmodule);
146
+ }
147
+ } catch {
148
+ }
149
+ return submodules;
150
+ }
151
+ export {
152
+ discoverSubmodules,
153
+ getChangedFiles,
154
+ getCurrentCommitSha,
155
+ getGitBlobHashes,
156
+ getPreviousCommitSha,
157
+ getRepoName,
158
+ isGitRepo
159
+ };
@@ -0,0 +1,42 @@
1
+ import { SymbolKind, GraphEdge } from '../types.js';
2
+
3
+ declare class MapxGraph {
4
+ private graph;
5
+ private repo;
6
+ constructor(repo: string);
7
+ addFileNode(filePath: string, language: string, sizeBytes: number, lines: number): void;
8
+ addSymbolNode(symbolId: string, filePath: string, name: string, kind: SymbolKind, startLine: number, endLine: number, scope: string | null): void;
9
+ addDependencyEdge(edge: GraphEdge): void;
10
+ computePageRank(): Map<string, number>;
11
+ getRankedFiles(): Array<{
12
+ path: string;
13
+ pagerank: number;
14
+ language: string;
15
+ }>;
16
+ getRankedSymbols(): Array<{
17
+ name: string;
18
+ kind: SymbolKind;
19
+ filePath: string;
20
+ startLine: number;
21
+ pagerank: number;
22
+ scope: string | null;
23
+ }>;
24
+ getDependencies(filePath: string): Array<{
25
+ target: string;
26
+ type: string;
27
+ }>;
28
+ getReverseDependencies(filePath: string): Array<{
29
+ source: string;
30
+ type: string;
31
+ }>;
32
+ getFileCount(): number;
33
+ getSymbolCount(): number;
34
+ getEdgeCount(): number;
35
+ dropFrameworkEdgesForRepo(repoName: string): void;
36
+ toJSON(): object;
37
+ static fromJSON(data: object, repo: string): MapxGraph;
38
+ private fileNodeId;
39
+ private symbolNodeId;
40
+ }
41
+
42
+ export { MapxGraph };
@@ -0,0 +1,186 @@
1
+ import Graph from "graphology";
2
+ import pagerank from "graphology-metrics/centrality/pagerank.js";
3
+ class MapxGraph {
4
+ graph;
5
+ repo;
6
+ constructor(repo) {
7
+ this.repo = repo;
8
+ this.graph = new Graph({ type: "directed", multi: true });
9
+ }
10
+ addFileNode(filePath, language, sizeBytes, lines) {
11
+ const nodeId = this.fileNodeId(filePath);
12
+ if (!this.graph.hasNode(nodeId)) {
13
+ this.graph.addNode(nodeId, { type: "file", path: filePath, language, sizeBytes, lines });
14
+ } else {
15
+ this.graph.mergeNodeAttributes(nodeId, { language, sizeBytes, lines });
16
+ }
17
+ }
18
+ addSymbolNode(symbolId, filePath, name, kind, startLine, endLine, scope) {
19
+ const nodeId = this.symbolNodeId(filePath, symbolId);
20
+ if (!this.graph.hasNode(nodeId)) {
21
+ this.graph.addNode(nodeId, { type: "symbol", name, kind, filePath, startLine, endLine, scope });
22
+ } else {
23
+ this.graph.mergeNodeAttributes(nodeId, { kind, startLine, endLine, scope });
24
+ }
25
+ const fileNodeId = this.fileNodeId(filePath);
26
+ if (this.graph.hasNode(fileNodeId) && !this.graph.hasEdge(fileNodeId, nodeId)) {
27
+ this.graph.addDirectedEdge(fileNodeId, nodeId, { type: "contains" });
28
+ }
29
+ if (scope) {
30
+ const parentNodeId = this.symbolNodeId(filePath, scope);
31
+ if (this.graph.hasNode(parentNodeId) && parentNodeId !== nodeId && !this.graph.hasEdge(parentNodeId, nodeId)) {
32
+ this.graph.addDirectedEdge(parentNodeId, nodeId, { type: "contains" });
33
+ }
34
+ }
35
+ }
36
+ addDependencyEdge(edge) {
37
+ const sourceId = this.fileNodeId(edge.sourceFile);
38
+ const targetId = this.fileNodeId(edge.targetFile);
39
+ if (this.graph.hasNode(sourceId) && this.graph.hasNode(targetId)) {
40
+ const edgeKey = `${sourceId}->${targetId}:${edge.edgeType}:${edge.sourceSymbol || ""}`;
41
+ if (!this.graph.hasEdge(edgeKey)) {
42
+ try {
43
+ this.graph.addDirectedEdgeWithKey(edgeKey, sourceId, targetId, {
44
+ type: edge.edgeType,
45
+ sourceSymbol: edge.sourceSymbol,
46
+ targetSymbol: edge.targetSymbol,
47
+ weight: edge.weight,
48
+ verifiability: edge.verifiability || "verified",
49
+ metadata: edge.metadata || {},
50
+ repo: edge.repo,
51
+ targetRepo: edge.targetRepo
52
+ });
53
+ } catch {
54
+ }
55
+ }
56
+ }
57
+ }
58
+ computePageRank() {
59
+ try {
60
+ const scores = pagerank(this.graph, { alpha: 0.85 });
61
+ for (const [node, score] of Object.entries(scores)) {
62
+ if (this.graph.hasNode(node)) {
63
+ this.graph.mergeNodeAttributes(node, { pagerank: score });
64
+ }
65
+ }
66
+ return new Map(Object.entries(scores));
67
+ } catch {
68
+ return /* @__PURE__ */ new Map();
69
+ }
70
+ }
71
+ getRankedFiles() {
72
+ const scores = this.computePageRank();
73
+ const files = [];
74
+ for (const [nodeId, score] of scores) {
75
+ const attrs = this.graph.getNodeAttributes(nodeId);
76
+ if (attrs.type === "file") {
77
+ files.push({ path: attrs.path, pagerank: score, language: attrs.language });
78
+ }
79
+ }
80
+ files.sort((a, b) => b.pagerank - a.pagerank);
81
+ return files;
82
+ }
83
+ getRankedSymbols() {
84
+ const fileRank = this.computePageRank();
85
+ const symbols = [];
86
+ for (const node of this.graph.nodes()) {
87
+ const attrs = this.graph.getNodeAttributes(node);
88
+ if (attrs.type === "symbol") {
89
+ const parentFileRank = fileRank.get(this.fileNodeId(attrs.filePath)) || 0;
90
+ const inDegree = this.graph.inDegree(node);
91
+ const symbolRank = parentFileRank * (1 + inDegree * 0.1);
92
+ symbols.push({
93
+ name: attrs.name,
94
+ kind: attrs.kind,
95
+ filePath: attrs.filePath,
96
+ startLine: attrs.startLine,
97
+ pagerank: symbolRank,
98
+ scope: attrs.scope
99
+ });
100
+ }
101
+ }
102
+ symbols.sort((a, b) => b.pagerank - a.pagerank);
103
+ return symbols;
104
+ }
105
+ getDependencies(filePath) {
106
+ const nodeId = this.fileNodeId(filePath);
107
+ if (!this.graph.hasNode(nodeId)) return [];
108
+ const deps = [];
109
+ for (const edge of this.graph.outEdges(nodeId)) {
110
+ const attrs = this.graph.getEdgeAttributes(edge);
111
+ if (attrs.type !== "contains") {
112
+ const target = this.graph.getNodeAttributes(this.graph.target(edge));
113
+ if (target.type === "file") {
114
+ deps.push({ target: target.path, type: attrs.type });
115
+ }
116
+ }
117
+ }
118
+ return deps;
119
+ }
120
+ getReverseDependencies(filePath) {
121
+ const nodeId = this.fileNodeId(filePath);
122
+ if (!this.graph.hasNode(nodeId)) return [];
123
+ const rdeps = [];
124
+ for (const edge of this.graph.inEdges(nodeId)) {
125
+ const attrs = this.graph.getEdgeAttributes(edge);
126
+ if (attrs.type !== "contains") {
127
+ const source = this.graph.getNodeAttributes(this.graph.source(edge));
128
+ if (source.type === "file") {
129
+ rdeps.push({ source: source.path, type: attrs.type });
130
+ }
131
+ }
132
+ }
133
+ return rdeps;
134
+ }
135
+ getFileCount() {
136
+ let count = 0;
137
+ for (const node of this.graph.nodes()) {
138
+ if (this.graph.getNodeAttribute(node, "type") === "file") count++;
139
+ }
140
+ return count;
141
+ }
142
+ getSymbolCount() {
143
+ let count = 0;
144
+ for (const node of this.graph.nodes()) {
145
+ if (this.graph.getNodeAttribute(node, "type") === "symbol") count++;
146
+ }
147
+ return count;
148
+ }
149
+ getEdgeCount() {
150
+ let count = 0;
151
+ for (const edge of this.graph.edges()) {
152
+ const attrs = this.graph.getEdgeAttributes(edge);
153
+ if (attrs.type !== "contains") count++;
154
+ }
155
+ return count;
156
+ }
157
+ dropFrameworkEdgesForRepo(repoName) {
158
+ const toDrop = [];
159
+ for (const edge of this.graph.edges()) {
160
+ const attrs = this.graph.getEdgeAttributes(edge);
161
+ if (attrs.repo === repoName && ["route", "middleware", "hook", "graphql_resolver", "message_handler", "websocket_handler"].includes(attrs.type)) {
162
+ toDrop.push(edge);
163
+ }
164
+ }
165
+ for (const edge of toDrop) {
166
+ this.graph.dropEdge(edge);
167
+ }
168
+ }
169
+ toJSON() {
170
+ return this.graph.toJSON();
171
+ }
172
+ static fromJSON(data, repo) {
173
+ const cg = new MapxGraph(repo);
174
+ cg.graph.import(data);
175
+ return cg;
176
+ }
177
+ fileNodeId(filePath) {
178
+ return `file://${filePath}`;
179
+ }
180
+ symbolNodeId(filePath, symbolName) {
181
+ return `symbol://${filePath}::${symbolName}`;
182
+ }
183
+ }
184
+ export {
185
+ MapxGraph
186
+ };
@@ -0,0 +1,24 @@
1
+ import { Store } from './store.js';
2
+ import './store-interface.js';
3
+ import './graph.js';
4
+ import '../types.js';
5
+
6
+ interface FileMetrics {
7
+ path: string;
8
+ language: string;
9
+ afferent: number;
10
+ efferent: number;
11
+ instability: number;
12
+ }
13
+ declare function calculateMetrics(store: Store, options?: {
14
+ repo?: string;
15
+ language?: string;
16
+ verifiedOnly?: boolean;
17
+ }): FileMetrics[];
18
+ interface GraphMetrics {
19
+ density: number;
20
+ transitivity: number;
21
+ }
22
+ declare function calculateGraphMetrics(store: Store, repo?: string): GraphMetrics;
23
+
24
+ export { type FileMetrics, type GraphMetrics, calculateGraphMetrics, calculateMetrics };
@@ -0,0 +1,87 @@
1
+ function calculateMetrics(store, options = {}) {
2
+ const files = store.getAllFiles(options.repo);
3
+ const edges = store.getAllEdges(options.repo);
4
+ const afferentMap = /* @__PURE__ */ new Map();
5
+ const efferentMap = /* @__PURE__ */ new Map();
6
+ for (const f of files) {
7
+ afferentMap.set(f.path, /* @__PURE__ */ new Set());
8
+ efferentMap.set(f.path, /* @__PURE__ */ new Set());
9
+ }
10
+ for (const e of edges) {
11
+ if (options.verifiedOnly && e.verifiability === "inferred") {
12
+ continue;
13
+ }
14
+ const src = e.source_file;
15
+ const tgt = e.target_file;
16
+ if (src === tgt) continue;
17
+ if (afferentMap.has(tgt)) {
18
+ afferentMap.get(tgt).add(src);
19
+ }
20
+ if (efferentMap.has(src)) {
21
+ efferentMap.get(src).add(tgt);
22
+ }
23
+ }
24
+ const results = [];
25
+ for (const f of files) {
26
+ const path = f.path;
27
+ const lang = f.language;
28
+ if (options.language && lang.toLowerCase() !== options.language.toLowerCase()) {
29
+ continue;
30
+ }
31
+ const ca = afferentMap.get(path)?.size || 0;
32
+ const ce = efferentMap.get(path)?.size || 0;
33
+ const sum = ca + ce;
34
+ const instability = sum > 0 ? ce / sum : 0;
35
+ results.push({
36
+ path,
37
+ language: lang,
38
+ afferent: ca,
39
+ efferent: ce,
40
+ instability
41
+ });
42
+ }
43
+ return results.sort((a, b) => b.instability - a.instability || b.afferent - a.afferent || a.path.localeCompare(b.path));
44
+ }
45
+ function calculateGraphMetrics(store, repo) {
46
+ const files = store.getAllFiles(repo);
47
+ const edges = store.getAllEdges(repo);
48
+ const fileCount = files.length;
49
+ const edgeCount = edges.length;
50
+ const density = fileCount > 1 ? edgeCount / (fileCount * (fileCount - 1)) : 0;
51
+ const adj = /* @__PURE__ */ new Map();
52
+ for (const f of files) {
53
+ adj.set(f.path, /* @__PURE__ */ new Set());
54
+ }
55
+ for (const e of edges) {
56
+ const src = e.source_file;
57
+ const tgt = e.target_file;
58
+ if (!src || !tgt || src === tgt) continue;
59
+ if (!adj.has(src)) adj.set(src, /* @__PURE__ */ new Set());
60
+ if (!adj.has(tgt)) adj.set(tgt, /* @__PURE__ */ new Set());
61
+ adj.get(src).add(tgt);
62
+ adj.get(tgt).add(src);
63
+ }
64
+ let totalTriplets = 0;
65
+ let closedTriplets = 0;
66
+ for (const neighbors of adj.values()) {
67
+ const k = neighbors.size;
68
+ if (k < 2) continue;
69
+ totalTriplets += k * (k - 1) / 2;
70
+ const neighborArr = Array.from(neighbors);
71
+ for (let i = 0; i < neighborArr.length; i++) {
72
+ for (let j = i + 1; j < neighborArr.length; j++) {
73
+ const u = neighborArr[i];
74
+ const w = neighborArr[j];
75
+ if (adj.get(u)?.has(w)) {
76
+ closedTriplets++;
77
+ }
78
+ }
79
+ }
80
+ }
81
+ const transitivity = totalTriplets > 0 ? closedTriplets / totalTriplets : 0;
82
+ return { density, transitivity };
83
+ }
84
+ export {
85
+ calculateGraphMetrics,
86
+ calculateMetrics
87
+ };
@@ -0,0 +1,53 @@
1
+ import { Store } from './store.js';
2
+ import { MapxGraph } from './graph.js';
3
+ import { Config } from './config.js';
4
+ import { ProgressCallback, ScanResult } from '../types.js';
5
+ import './store-interface.js';
6
+ import '../languages/registry.js';
7
+
8
+ declare function buildMatcher(excludes: string[], includes: string[]): (rel: string) => boolean;
9
+ declare class Scanner {
10
+ private store;
11
+ private config;
12
+ private graph;
13
+ private onProgress?;
14
+ private concurrency;
15
+ private aborted;
16
+ private cliExcludes;
17
+ private cliIncludes;
18
+ private workspaceFileMap;
19
+ constructor(store: Store, config: Config, graph: MapxGraph, onProgress?: ProgressCallback, options?: {
20
+ excludes?: string[];
21
+ includes?: string[];
22
+ });
23
+ abort(): void;
24
+ private loadResumeState;
25
+ private saveResumeState;
26
+ private clearResumeState;
27
+ private getLockPath;
28
+ private acquireScanLock;
29
+ private releaseScanLock;
30
+ scanFull(repoNames?: string[], options?: {
31
+ force?: boolean;
32
+ }): Promise<ScanResult>;
33
+ private _scanFullForRepo;
34
+ scanIncremental(repoNames?: string[]): Promise<ScanResult>;
35
+ private _scanIncrementalForRepo;
36
+ private discoverFiles;
37
+ private detectDeletedFiles;
38
+ private parseFilesParallel;
39
+ private parseWithWorkers;
40
+ private parseOnMainThread;
41
+ private writeParseResult;
42
+ private writeParseResultWithMap;
43
+ private resolveReferences;
44
+ private resolveReferencesWithMap;
45
+ private resolveRequirePath;
46
+ private resolveImportPath;
47
+ private resolveSymbolToFile;
48
+ private shouldExcludeDir;
49
+ private getFileInfo;
50
+ private scanFrameworkRoutesAndHooks;
51
+ }
52
+
53
+ export { Scanner, buildMatcher };