@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.
- package/LICENSE +194 -0
- package/README.md +488 -0
- package/VERSION +1 -0
- package/dist/agents/generator.d.ts +74 -0
- package/dist/agents/generator.js +375 -0
- package/dist/agents/templates.d.ts +29 -0
- package/dist/agents/templates.js +459 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.js +1835 -0
- package/dist/core/cluster-engine.d.ts +32 -0
- package/dist/core/cluster-engine.js +314 -0
- package/dist/core/config.d.ts +29 -0
- package/dist/core/config.js +178 -0
- package/dist/core/context-builder.d.ts +61 -0
- package/dist/core/context-builder.js +252 -0
- package/dist/core/flow-tracer.d.ts +63 -0
- package/dist/core/flow-tracer.js +366 -0
- package/dist/core/git-tracker.d.ts +20 -0
- package/dist/core/git-tracker.js +159 -0
- package/dist/core/graph.d.ts +42 -0
- package/dist/core/graph.js +186 -0
- package/dist/core/metrics.d.ts +24 -0
- package/dist/core/metrics.js +87 -0
- package/dist/core/scanner.d.ts +53 -0
- package/dist/core/scanner.js +949 -0
- package/dist/core/store-bun.d.ts +13 -0
- package/dist/core/store-bun.js +34 -0
- package/dist/core/store-interface.d.ts +15 -0
- package/dist/core/store-interface.js +7 -0
- package/dist/core/store-node.d.ts +13 -0
- package/dist/core/store-node.js +35 -0
- package/dist/core/store.d.ts +132 -0
- package/dist/core/store.js +614 -0
- package/dist/core/workspace-manager.d.ts +9 -0
- package/dist/core/workspace-manager.js +64 -0
- package/dist/exporters/dot-exporter.d.ts +16 -0
- package/dist/exporters/dot-exporter.js +179 -0
- package/dist/exporters/graph-exporter.d.ts +14 -0
- package/dist/exporters/graph-exporter.js +85 -0
- package/dist/exporters/index.d.ts +9 -0
- package/dist/exporters/index.js +12 -0
- package/dist/exporters/llm-exporter.d.ts +18 -0
- package/dist/exporters/llm-exporter.js +224 -0
- package/dist/exporters/svg-exporter.d.ts +19 -0
- package/dist/exporters/svg-exporter.js +319 -0
- package/dist/exporters/toon-exporter.d.ts +16 -0
- package/dist/exporters/toon-exporter.js +246 -0
- package/dist/frameworks/detectors/aspnet.d.ts +11 -0
- package/dist/frameworks/detectors/aspnet.js +52 -0
- package/dist/frameworks/detectors/django.d.ts +14 -0
- package/dist/frameworks/detectors/django.js +135 -0
- package/dist/frameworks/detectors/drupal.d.ts +13 -0
- package/dist/frameworks/detectors/drupal.js +94 -0
- package/dist/frameworks/detectors/express.d.ts +12 -0
- package/dist/frameworks/detectors/express.js +234 -0
- package/dist/frameworks/detectors/fastapi.d.ts +12 -0
- package/dist/frameworks/detectors/fastapi.js +203 -0
- package/dist/frameworks/detectors/flask.d.ts +12 -0
- package/dist/frameworks/detectors/flask.js +244 -0
- package/dist/frameworks/detectors/go.d.ts +11 -0
- package/dist/frameworks/detectors/go.js +75 -0
- package/dist/frameworks/detectors/laravel.d.ts +11 -0
- package/dist/frameworks/detectors/laravel.js +462 -0
- package/dist/frameworks/detectors/nestjs.d.ts +12 -0
- package/dist/frameworks/detectors/nestjs.js +155 -0
- package/dist/frameworks/detectors/nextjs.d.ts +11 -0
- package/dist/frameworks/detectors/nextjs.js +118 -0
- package/dist/frameworks/detectors/rails.d.ts +12 -0
- package/dist/frameworks/detectors/rails.js +76 -0
- package/dist/frameworks/detectors/react-router.d.ts +11 -0
- package/dist/frameworks/detectors/react-router.js +115 -0
- package/dist/frameworks/detectors/rust.d.ts +11 -0
- package/dist/frameworks/detectors/rust.js +59 -0
- package/dist/frameworks/detectors/spring.d.ts +11 -0
- package/dist/frameworks/detectors/spring.js +56 -0
- package/dist/frameworks/detectors/sveltekit.d.ts +11 -0
- package/dist/frameworks/detectors/sveltekit.js +154 -0
- package/dist/frameworks/detectors/symfony.d.ts +13 -0
- package/dist/frameworks/detectors/symfony.js +175 -0
- package/dist/frameworks/detectors/tanstack-router.d.ts +12 -0
- package/dist/frameworks/detectors/tanstack-router.js +80 -0
- package/dist/frameworks/detectors/vapor.d.ts +11 -0
- package/dist/frameworks/detectors/vapor.js +52 -0
- package/dist/frameworks/detectors/vue-router.d.ts +12 -0
- package/dist/frameworks/detectors/vue-router.js +237 -0
- package/dist/frameworks/detectors/wordpress.d.ts +13 -0
- package/dist/frameworks/detectors/wordpress.js +141 -0
- package/dist/frameworks/detectors/yii.d.ts +11 -0
- package/dist/frameworks/detectors/yii.js +131 -0
- package/dist/frameworks/framework-registry.d.ts +13 -0
- package/dist/frameworks/framework-registry.js +77 -0
- package/dist/frameworks/route-registry.d.ts +26 -0
- package/dist/frameworks/route-registry.js +102 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +30 -0
- package/dist/languages/index.d.ts +2 -0
- package/dist/languages/index.js +7 -0
- package/dist/languages/installer.d.ts +13 -0
- package/dist/languages/installer.js +103 -0
- package/dist/languages/registry.d.ts +19 -0
- package/dist/languages/registry.js +427 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +20 -0
- package/dist/mcp.d.ts +11 -0
- package/dist/mcp.js +1699 -0
- package/dist/parsers/common-methods.d.ts +3 -0
- package/dist/parsers/common-methods.js +33 -0
- package/dist/parsers/fallback-parser.d.ts +10 -0
- package/dist/parsers/fallback-parser.js +18 -0
- package/dist/parsers/generic-wasm-parser.d.ts +23 -0
- package/dist/parsers/generic-wasm-parser.js +168 -0
- package/dist/parsers/ignored-symbols.d.ts +26 -0
- package/dist/parsers/ignored-symbols.js +77 -0
- package/dist/parsers/index.d.ts +9 -0
- package/dist/parsers/index.js +13 -0
- package/dist/parsers/languages/javascript.d.ts +11 -0
- package/dist/parsers/languages/javascript.js +28 -0
- package/dist/parsers/languages/php.d.ts +15 -0
- package/dist/parsers/languages/php.js +648 -0
- package/dist/parsers/languages/typescript.d.ts +10 -0
- package/dist/parsers/languages/typescript.js +9 -0
- package/dist/parsers/languages/vue.d.ts +13 -0
- package/dist/parsers/languages/vue.js +63 -0
- package/dist/parsers/parse-worker.d.ts +2 -0
- package/dist/parsers/parse-worker.js +185 -0
- package/dist/parsers/parser-interface.d.ts +9 -0
- package/dist/parsers/parser-interface.js +0 -0
- package/dist/parsers/parser-registry.d.ts +8 -0
- package/dist/parsers/parser-registry.js +52 -0
- package/dist/parsers/wasm-parser.d.ts +16 -0
- package/dist/parsers/wasm-parser.js +110 -0
- package/dist/types.d.ts +172 -0
- package/dist/types.js +0 -0
- package/dist/ui/index.html +270 -0
- package/dist/ui/main.js +581 -0
- package/dist/ui/main.js.map +7 -0
- package/dist/ui/styles.css +573 -0
- package/dist/ui-events.d.ts +36 -0
- package/dist/ui-events.js +61 -0
- package/dist/ui-server.d.ts +12 -0
- package/dist/ui-server.js +504 -0
- package/package.json +179 -0
- package/queries/bash/references.scm +22 -0
- package/queries/bash/symbols.scm +15 -0
- package/queries/c/references.scm +14 -0
- package/queries/c/symbols.scm +30 -0
- package/queries/c-sharp/references.scm +26 -0
- package/queries/c-sharp/symbols.scm +57 -0
- package/queries/cpp/references.scm +21 -0
- package/queries/cpp/symbols.scm +44 -0
- package/queries/dart/references.scm +33 -0
- package/queries/dart/symbols.scm +38 -0
- package/queries/elixir/references.scm +45 -0
- package/queries/elixir/symbols.scm +41 -0
- package/queries/go/references.scm +22 -0
- package/queries/go/symbols.scm +53 -0
- package/queries/java/references.scm +32 -0
- package/queries/java/symbols.scm +41 -0
- package/queries/javascript/references.scm +14 -0
- package/queries/javascript/symbols.scm +23 -0
- package/queries/kotlin/references.scm +31 -0
- package/queries/kotlin/symbols.scm +24 -0
- package/queries/lua/references.scm +19 -0
- package/queries/lua/symbols.scm +29 -0
- package/queries/pascal/references.scm +29 -0
- package/queries/pascal/symbols.scm +45 -0
- package/queries/php/references.scm +109 -0
- package/queries/php/symbols.scm +33 -0
- package/queries/python/references.scm +50 -0
- package/queries/python/symbols.scm +21 -0
- package/queries/ruby/references.scm +48 -0
- package/queries/ruby/symbols.scm +24 -0
- package/queries/rust/references.scm +31 -0
- package/queries/rust/symbols.scm +35 -0
- package/queries/scala/references.scm +30 -0
- package/queries/scala/symbols.scm +35 -0
- package/queries/svelte/references.scm +20 -0
- package/queries/svelte/symbols.scm +30 -0
- package/queries/swift/references.scm +22 -0
- package/queries/swift/symbols.scm +37 -0
- package/queries/typescript/references.scm +25 -0
- package/queries/typescript/symbols.scm +35 -0
- package/queries/vue/references.scm +20 -0
- package/queries/vue/symbols.scm +28 -0
- package/queries/zig/references.scm +20 -0
- package/queries/zig/symbols.scm +22 -0
- package/wasm/tree-sitter-c.wasm +0 -0
- package/wasm/tree-sitter-c_sharp.wasm +0 -0
- package/wasm/tree-sitter-cpp.wasm +0 -0
- package/wasm/tree-sitter-dart.wasm +0 -0
- package/wasm/tree-sitter-go.wasm +0 -0
- package/wasm/tree-sitter-java.wasm +0 -0
- package/wasm/tree-sitter-javascript.wasm +0 -0
- package/wasm/tree-sitter-kotlin.wasm +0 -0
- package/wasm/tree-sitter-php.wasm +0 -0
- package/wasm/tree-sitter-python.wasm +0 -0
- package/wasm/tree-sitter-ruby.wasm +0 -0
- package/wasm/tree-sitter-rust.wasm +0 -0
- package/wasm/tree-sitter-scala.wasm +0 -0
- package/wasm/tree-sitter-swift.wasm +0 -0
- package/wasm/tree-sitter-tsx.wasm +0 -0
- package/wasm/tree-sitter-typescript.wasm +0 -0
- package/wasm/tree-sitter-vue.wasm +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { TypeScriptParser } from "./typescript.js";
|
|
2
|
+
import { getBuiltinLanguages } from "../../languages/registry.js";
|
|
3
|
+
class VueParser {
|
|
4
|
+
languageName = "vue";
|
|
5
|
+
supportedExtensions = [".vue"];
|
|
6
|
+
tsParser;
|
|
7
|
+
constructor(langDef) {
|
|
8
|
+
const builtin = getBuiltinLanguages();
|
|
9
|
+
this.tsParser = new TypeScriptParser(builtin.typescript);
|
|
10
|
+
}
|
|
11
|
+
async parse(filePath, source, options) {
|
|
12
|
+
const symbols = [];
|
|
13
|
+
const references = [];
|
|
14
|
+
const errors = [];
|
|
15
|
+
const scriptRegex = /<script\b([^>]*)>([\s\S]*?)<\/script>/gi;
|
|
16
|
+
let match;
|
|
17
|
+
while ((match = scriptRegex.exec(source)) !== null) {
|
|
18
|
+
const code = match[2];
|
|
19
|
+
const matchIndex = match.index;
|
|
20
|
+
const openingTagMatch = source.slice(matchIndex).match(/<script\b[^>]*>/i);
|
|
21
|
+
const openingTagLength = openingTagMatch ? openingTagMatch[0].length : 0;
|
|
22
|
+
const beforeCode = source.slice(0, matchIndex + openingTagLength);
|
|
23
|
+
const startLine = beforeCode.split("\n").length;
|
|
24
|
+
try {
|
|
25
|
+
const res = await this.tsParser.parse(filePath, code, options);
|
|
26
|
+
if (res.symbols) {
|
|
27
|
+
for (const sym of res.symbols) {
|
|
28
|
+
symbols.push({
|
|
29
|
+
...sym,
|
|
30
|
+
startLine: sym.startLine + startLine - 1,
|
|
31
|
+
endLine: sym.endLine + startLine - 1
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (res.references) {
|
|
36
|
+
for (const ref of res.references) {
|
|
37
|
+
references.push({
|
|
38
|
+
...ref,
|
|
39
|
+
startLine: ref.startLine + startLine - 1
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (res.errors) {
|
|
44
|
+
for (const err of res.errors) {
|
|
45
|
+
errors.push({
|
|
46
|
+
...err,
|
|
47
|
+
line: err.line ? err.line + startLine - 1 : startLine
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} catch (err) {
|
|
52
|
+
errors.push({
|
|
53
|
+
message: `Failed to parse Vue script block starting at line ${startLine}: ${err.message}`,
|
|
54
|
+
line: startLine
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return { symbols, references, errors };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export {
|
|
62
|
+
VueParser
|
|
63
|
+
};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { parentPort, workerData } from "node:worker_threads";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { resolve, dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
const REF_TYPE_MAP = {
|
|
7
|
+
import: "import",
|
|
8
|
+
require: "require",
|
|
9
|
+
extends: "extends",
|
|
10
|
+
implements: "implements",
|
|
11
|
+
call: "call",
|
|
12
|
+
instantiation: "instantiation"
|
|
13
|
+
};
|
|
14
|
+
let parserReady = false;
|
|
15
|
+
let Parser;
|
|
16
|
+
let Language;
|
|
17
|
+
let Query;
|
|
18
|
+
let loadedLanguages = /* @__PURE__ */ new Map();
|
|
19
|
+
let langDefs;
|
|
20
|
+
let assetRoot;
|
|
21
|
+
let nameByNodeId;
|
|
22
|
+
function findAssetRoot() {
|
|
23
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
24
|
+
if (existsSync(thisFile)) {
|
|
25
|
+
return resolve(dirname(thisFile), "..", "..");
|
|
26
|
+
}
|
|
27
|
+
const binDir = dirname(process.execPath);
|
|
28
|
+
const candidates = [
|
|
29
|
+
binDir,
|
|
30
|
+
resolve(binDir, "..", "share", "mapx"),
|
|
31
|
+
join(process.env["HOME"] ?? "", ".local", "share", "mapx")
|
|
32
|
+
];
|
|
33
|
+
for (const dir of candidates) {
|
|
34
|
+
if (existsSync(join(dir, "wasm"))) return dir;
|
|
35
|
+
}
|
|
36
|
+
return binDir;
|
|
37
|
+
}
|
|
38
|
+
async function initParser() {
|
|
39
|
+
if (parserReady) return;
|
|
40
|
+
assetRoot = findAssetRoot();
|
|
41
|
+
const mod = await import("web-tree-sitter");
|
|
42
|
+
Parser = mod.Parser;
|
|
43
|
+
Language = mod.Language;
|
|
44
|
+
Query = mod.Query;
|
|
45
|
+
await Parser.init();
|
|
46
|
+
parserReady = true;
|
|
47
|
+
}
|
|
48
|
+
async function parseFile(job) {
|
|
49
|
+
const empty = { id: job.id, symbols: [], references: [], errors: [] };
|
|
50
|
+
let source;
|
|
51
|
+
try {
|
|
52
|
+
source = await readFile(job.absolutePath, "utf-8");
|
|
53
|
+
} catch {
|
|
54
|
+
return { ...empty, errors: [{ message: `Failed to read ${job.filePath}` }] };
|
|
55
|
+
}
|
|
56
|
+
const ext = job.filePath.substring(job.filePath.lastIndexOf("."));
|
|
57
|
+
let langKey = "";
|
|
58
|
+
for (const [key, def] of langDefs) {
|
|
59
|
+
if (def.extensions.includes(ext)) {
|
|
60
|
+
langKey = key;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (!langKey) return empty;
|
|
65
|
+
let langCtx = loadedLanguages.get(langKey);
|
|
66
|
+
if (!langCtx) {
|
|
67
|
+
try {
|
|
68
|
+
const def = langDefs.get(langKey);
|
|
69
|
+
const wasmPath = resolve(assetRoot, def.grammarWasm);
|
|
70
|
+
const wasmBuffer = await readFile(wasmPath);
|
|
71
|
+
const language = await Language.load(wasmBuffer);
|
|
72
|
+
const symbolsQuery = await readFile(resolve(assetRoot, def.queries.symbols), "utf-8");
|
|
73
|
+
const referencesQuery = await readFile(resolve(assetRoot, def.queries.references), "utf-8");
|
|
74
|
+
const parser = new Parser();
|
|
75
|
+
parser.setLanguage(language);
|
|
76
|
+
const compiledSymQuery = new Query(language, symbolsQuery);
|
|
77
|
+
const compiledRefQuery = new Query(language, referencesQuery);
|
|
78
|
+
langCtx = { language, symbolsQuery, referencesQuery, parser, compiledSymQuery, compiledRefQuery };
|
|
79
|
+
loadedLanguages.set(langKey, langCtx);
|
|
80
|
+
} catch {
|
|
81
|
+
return { ...empty, errors: [{ message: `Failed to load language for ${job.filePath}` }] };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const tree = langCtx.parser.parse(source);
|
|
86
|
+
if (!tree) {
|
|
87
|
+
return { ...empty, errors: [{ message: `Parser returned null for ${job.filePath}` }] };
|
|
88
|
+
}
|
|
89
|
+
const symbols = [];
|
|
90
|
+
const references = [];
|
|
91
|
+
nameByNodeId = /* @__PURE__ */ new Map();
|
|
92
|
+
try {
|
|
93
|
+
const symQuery = langCtx.compiledSymQuery;
|
|
94
|
+
const allSymCaptures = symQuery.captures(tree.rootNode);
|
|
95
|
+
const kindNodeIds = /* @__PURE__ */ new Set();
|
|
96
|
+
for (const capture of allSymCaptures) {
|
|
97
|
+
if (capture.name.startsWith("symbol.kind_")) {
|
|
98
|
+
kindNodeIds.add(capture.node.id);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
for (const capture of allSymCaptures) {
|
|
102
|
+
if (capture.name === "symbol.name") {
|
|
103
|
+
let node = capture.node.parent;
|
|
104
|
+
while (node) {
|
|
105
|
+
if (kindNodeIds.has(node.id)) {
|
|
106
|
+
nameByNodeId.set(node.id, capture.node.text);
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
node = node.parent;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (const capture of allSymCaptures) {
|
|
114
|
+
if (capture.name.startsWith("symbol.kind_")) {
|
|
115
|
+
const kind = capture.name.replace("symbol.kind_", "");
|
|
116
|
+
const name = nameByNodeId.get(capture.node.id) || capture.node.text;
|
|
117
|
+
symbols.push({
|
|
118
|
+
name,
|
|
119
|
+
kind,
|
|
120
|
+
scope: null,
|
|
121
|
+
signature: name,
|
|
122
|
+
startLine: capture.node.startPosition.row + 1,
|
|
123
|
+
endLine: capture.node.endPosition.row + 1,
|
|
124
|
+
metadata: {}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const refQuery = langCtx.compiledRefQuery;
|
|
132
|
+
for (const capture of refQuery.captures(tree.rootNode)) {
|
|
133
|
+
const startLine = capture.node.startPosition.row + 1;
|
|
134
|
+
if (capture.name.startsWith("ref.target_")) {
|
|
135
|
+
const rawType = capture.name.replace("ref.target_", "");
|
|
136
|
+
const refType = REF_TYPE_MAP[rawType] || "call";
|
|
137
|
+
let targetName = capture.node.text;
|
|
138
|
+
if (rawType === "import") {
|
|
139
|
+
targetName = targetName.replace(/^['"]|['"]$/g, "");
|
|
140
|
+
}
|
|
141
|
+
references.push({
|
|
142
|
+
sourceSymbol: null,
|
|
143
|
+
targetName,
|
|
144
|
+
referenceType: refType,
|
|
145
|
+
startLine
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
} catch {
|
|
150
|
+
}
|
|
151
|
+
return { id: job.id, symbols, references, errors: [] };
|
|
152
|
+
} catch {
|
|
153
|
+
return { ...empty, errors: [{ message: `Failed to parse ${job.filePath}` }] };
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async function initLanguages() {
|
|
157
|
+
for (const [key, def] of langDefs) {
|
|
158
|
+
try {
|
|
159
|
+
const wasmPath = resolve(assetRoot, def.grammarWasm);
|
|
160
|
+
const wasmBuffer = await readFile(wasmPath);
|
|
161
|
+
const language = await Language.load(wasmBuffer);
|
|
162
|
+
const symbolsQuery = await readFile(resolve(assetRoot, def.queries.symbols), "utf-8");
|
|
163
|
+
const referencesQuery = await readFile(resolve(assetRoot, def.queries.references), "utf-8");
|
|
164
|
+
const parser = new Parser();
|
|
165
|
+
parser.setLanguage(language);
|
|
166
|
+
const compiledSymQuery = new Query(language, symbolsQuery);
|
|
167
|
+
const compiledRefQuery = new Query(language, referencesQuery);
|
|
168
|
+
loadedLanguages.set(key, { language, symbolsQuery, referencesQuery, parser, compiledSymQuery, compiledRefQuery });
|
|
169
|
+
} catch {
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async function main() {
|
|
174
|
+
langDefs = new Map(Object.entries(workerData.languages));
|
|
175
|
+
await initParser();
|
|
176
|
+
await initLanguages();
|
|
177
|
+
parentPort.on("message", async (job) => {
|
|
178
|
+
const result = await parseFile(job);
|
|
179
|
+
parentPort.postMessage(result);
|
|
180
|
+
});
|
|
181
|
+
parentPort.postMessage({ type: "ready" });
|
|
182
|
+
}
|
|
183
|
+
main().catch((err) => {
|
|
184
|
+
parentPort.postMessage({ type: "error", error: err.message });
|
|
185
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ParseResult } from '../types.js';
|
|
2
|
+
|
|
3
|
+
interface LanguageParser {
|
|
4
|
+
readonly languageName: string;
|
|
5
|
+
readonly supportedExtensions: string[];
|
|
6
|
+
parse(filePath: string, source: string, options?: any): Promise<ParseResult>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type { LanguageParser };
|
|
File without changes
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { LanguageParser } from './parser-interface.js';
|
|
2
|
+
import { LanguageDefinition } from '../languages/registry.js';
|
|
3
|
+
import '../types.js';
|
|
4
|
+
|
|
5
|
+
declare function getParserForFile(filePath: string, userLanguages?: Record<string, LanguageDefinition>): LanguageParser;
|
|
6
|
+
declare function clearParserCache(): void;
|
|
7
|
+
|
|
8
|
+
export { clearParserCache, getParserForFile };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { getLanguageForFile } from "../languages/registry.js";
|
|
2
|
+
import { PhpParser } from "./languages/php.js";
|
|
3
|
+
import { JavaScriptParser } from "./languages/javascript.js";
|
|
4
|
+
import { TypeScriptParser } from "./languages/typescript.js";
|
|
5
|
+
import { VueParser } from "./languages/vue.js";
|
|
6
|
+
import { FallbackParser } from "./fallback-parser.js";
|
|
7
|
+
import { GenericWasmParser } from "./generic-wasm-parser.js";
|
|
8
|
+
import { isLanguageInstalled } from "../languages/installer.js";
|
|
9
|
+
const parserCache = /* @__PURE__ */ new Map();
|
|
10
|
+
const fallbackParser = new FallbackParser();
|
|
11
|
+
function getParserForFile(filePath, userLanguages) {
|
|
12
|
+
const langDef = getLanguageForFile(filePath, userLanguages);
|
|
13
|
+
if (!langDef) return fallbackParser;
|
|
14
|
+
if (langDef.tier === "installable" && !isLanguageInstalled(langDef.name)) {
|
|
15
|
+
return fallbackParser;
|
|
16
|
+
}
|
|
17
|
+
const cached = parserCache.get(langDef.name);
|
|
18
|
+
if (cached) return cached;
|
|
19
|
+
const parser = createParser(langDef);
|
|
20
|
+
parserCache.set(langDef.name, parser);
|
|
21
|
+
return parser;
|
|
22
|
+
}
|
|
23
|
+
function createParser(langDef) {
|
|
24
|
+
switch (langDef.name) {
|
|
25
|
+
case "php":
|
|
26
|
+
return new PhpParser(langDef);
|
|
27
|
+
case "javascript":
|
|
28
|
+
return new JavaScriptParser(langDef);
|
|
29
|
+
case "typescript":
|
|
30
|
+
return new TypeScriptParser(langDef);
|
|
31
|
+
case "vue":
|
|
32
|
+
return new VueParser(langDef);
|
|
33
|
+
case "python":
|
|
34
|
+
case "go":
|
|
35
|
+
case "rust":
|
|
36
|
+
case "java":
|
|
37
|
+
case "c-sharp":
|
|
38
|
+
return new GenericWasmParser(langDef);
|
|
39
|
+
default:
|
|
40
|
+
if (langDef.tier === "bundled" || langDef.tier === "installable" || langDef.tier === "user") {
|
|
41
|
+
return new GenericWasmParser(langDef);
|
|
42
|
+
}
|
|
43
|
+
return fallbackParser;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function clearParserCache() {
|
|
47
|
+
parserCache.clear();
|
|
48
|
+
}
|
|
49
|
+
export {
|
|
50
|
+
clearParserCache,
|
|
51
|
+
getParserForFile
|
|
52
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { QueryCapture, Language } from 'web-tree-sitter';
|
|
2
|
+
import { LanguageDefinition } from '../languages/registry.js';
|
|
3
|
+
import '../types.js';
|
|
4
|
+
|
|
5
|
+
declare const PROJECT_ROOT: string;
|
|
6
|
+
declare function loadLanguage(langDef: LanguageDefinition): Promise<Language>;
|
|
7
|
+
interface ParsedCaptures {
|
|
8
|
+
symbols: Map<string, QueryCapture[]>;
|
|
9
|
+
references: Map<string, QueryCapture[]>;
|
|
10
|
+
nameByNodeId: Map<number, string>;
|
|
11
|
+
scopeByNodeId: Map<number, string>;
|
|
12
|
+
}
|
|
13
|
+
declare function parseWithQueries(source: string, language: Language, symbolsQuery: string, referencesQuery: string): Promise<ParsedCaptures>;
|
|
14
|
+
declare function loadQueryFile(queryPath: string): Promise<string>;
|
|
15
|
+
|
|
16
|
+
export { PROJECT_ROOT, type ParsedCaptures, loadLanguage, loadQueryFile, parseWithQueries };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Parser, Language, Query } from "web-tree-sitter";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { resolve, dirname, join, isAbsolute } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
const __thisFile = fileURLToPath(import.meta.url);
|
|
7
|
+
function findAssetRoot() {
|
|
8
|
+
if (existsSync(__thisFile)) {
|
|
9
|
+
return resolve(dirname(__thisFile), "..", "..");
|
|
10
|
+
}
|
|
11
|
+
const binDir = dirname(process.execPath);
|
|
12
|
+
const candidates = [
|
|
13
|
+
binDir,
|
|
14
|
+
// assets next to binary
|
|
15
|
+
resolve(binDir, "..", "share", "mapx"),
|
|
16
|
+
// XDG system: /usr/local/share/mapx
|
|
17
|
+
join(process.env["HOME"] ?? "", ".local", "share", "mapx")
|
|
18
|
+
// XDG user
|
|
19
|
+
];
|
|
20
|
+
for (const dir of candidates) {
|
|
21
|
+
if (existsSync(join(dir, "wasm"))) return dir;
|
|
22
|
+
}
|
|
23
|
+
return binDir;
|
|
24
|
+
}
|
|
25
|
+
const PROJECT_ROOT = findAssetRoot();
|
|
26
|
+
let initPromise = null;
|
|
27
|
+
function ensureInit() {
|
|
28
|
+
if (!initPromise) {
|
|
29
|
+
initPromise = Parser.init();
|
|
30
|
+
}
|
|
31
|
+
return initPromise;
|
|
32
|
+
}
|
|
33
|
+
async function loadLanguage(langDef) {
|
|
34
|
+
await ensureInit();
|
|
35
|
+
const wasmPath = isAbsolute(langDef.grammarWasm) ? langDef.grammarWasm : resolve(PROJECT_ROOT, langDef.grammarWasm);
|
|
36
|
+
const wasmBuffer = await readFile(wasmPath);
|
|
37
|
+
const language = await Language.load(wasmBuffer);
|
|
38
|
+
return language;
|
|
39
|
+
}
|
|
40
|
+
async function parseWithQueries(source, language, symbolsQuery, referencesQuery) {
|
|
41
|
+
await ensureInit();
|
|
42
|
+
const parser = new Parser();
|
|
43
|
+
parser.setLanguage(language);
|
|
44
|
+
const tree = parser.parse(source);
|
|
45
|
+
if (!tree) {
|
|
46
|
+
return { symbols: /* @__PURE__ */ new Map(), references: /* @__PURE__ */ new Map(), nameByNodeId: /* @__PURE__ */ new Map(), scopeByNodeId: /* @__PURE__ */ new Map() };
|
|
47
|
+
}
|
|
48
|
+
const symbolCaptures = /* @__PURE__ */ new Map();
|
|
49
|
+
const refCaptures = /* @__PURE__ */ new Map();
|
|
50
|
+
const nameByNodeId = /* @__PURE__ */ new Map();
|
|
51
|
+
const scopeByNodeId = /* @__PURE__ */ new Map();
|
|
52
|
+
try {
|
|
53
|
+
const symQuery = new Query(language, symbolsQuery);
|
|
54
|
+
const symMatches = symQuery.captures(tree.rootNode);
|
|
55
|
+
const kindNodeIds = /* @__PURE__ */ new Set();
|
|
56
|
+
for (const capture of symMatches) {
|
|
57
|
+
const existing = symbolCaptures.get(capture.name) || [];
|
|
58
|
+
existing.push(capture);
|
|
59
|
+
symbolCaptures.set(capture.name, existing);
|
|
60
|
+
if (capture.name.startsWith("symbol.kind_")) {
|
|
61
|
+
kindNodeIds.add(capture.node.id);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
for (const capture of symMatches) {
|
|
65
|
+
if (capture.name === "symbol.name") {
|
|
66
|
+
let node = capture.node.parent;
|
|
67
|
+
while (node) {
|
|
68
|
+
if (kindNodeIds.has(node.id)) {
|
|
69
|
+
nameByNodeId.set(node.id, capture.node.text);
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
node = node.parent;
|
|
73
|
+
}
|
|
74
|
+
} else if (capture.name === "symbol.scope") {
|
|
75
|
+
let node = capture.node.parent;
|
|
76
|
+
while (node) {
|
|
77
|
+
if (kindNodeIds.has(node.id)) {
|
|
78
|
+
scopeByNodeId.set(node.id, capture.node.text);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
node = node.parent;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} catch (e) {
|
|
86
|
+
if (!e.message?.includes("no query")) throw e;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const refQuery = new Query(language, referencesQuery);
|
|
90
|
+
const refMatches = refQuery.captures(tree.rootNode);
|
|
91
|
+
for (const capture of refMatches) {
|
|
92
|
+
const existing = refCaptures.get(capture.name) || [];
|
|
93
|
+
existing.push(capture);
|
|
94
|
+
refCaptures.set(capture.name, existing);
|
|
95
|
+
}
|
|
96
|
+
} catch (e) {
|
|
97
|
+
if (!e.message?.includes("no query")) throw e;
|
|
98
|
+
}
|
|
99
|
+
return { symbols: symbolCaptures, references: refCaptures, nameByNodeId, scopeByNodeId };
|
|
100
|
+
}
|
|
101
|
+
async function loadQueryFile(queryPath) {
|
|
102
|
+
const fullPath = isAbsolute(queryPath) ? queryPath : resolve(PROJECT_ROOT, queryPath);
|
|
103
|
+
return readFile(fullPath, "utf-8");
|
|
104
|
+
}
|
|
105
|
+
export {
|
|
106
|
+
PROJECT_ROOT,
|
|
107
|
+
loadLanguage,
|
|
108
|
+
loadQueryFile,
|
|
109
|
+
parseWithQueries
|
|
110
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
interface CodeFile {
|
|
2
|
+
path: string;
|
|
3
|
+
repo: string;
|
|
4
|
+
language: string;
|
|
5
|
+
gitBlobHash: string | null;
|
|
6
|
+
lastScanned: string | null;
|
|
7
|
+
sizeBytes: number;
|
|
8
|
+
lines: number;
|
|
9
|
+
metadata?: Record<string, any>;
|
|
10
|
+
}
|
|
11
|
+
interface ExtractedSymbol {
|
|
12
|
+
name: string;
|
|
13
|
+
kind: SymbolKind;
|
|
14
|
+
scope: string | null;
|
|
15
|
+
signature: string;
|
|
16
|
+
startLine: number;
|
|
17
|
+
endLine: number;
|
|
18
|
+
metadata: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
type SymbolKind = 'class' | 'method' | 'function' | 'interface' | 'trait' | 'constant' | 'enum' | 'property' | 'namespace' | 'struct' | 'module' | 'field';
|
|
21
|
+
interface ExtractedReference {
|
|
22
|
+
sourceSymbol: string | null;
|
|
23
|
+
targetName: string;
|
|
24
|
+
referenceType: ReferenceType;
|
|
25
|
+
startLine: number;
|
|
26
|
+
verifiability?: 'verified' | 'inferred';
|
|
27
|
+
metadata?: Record<string, any>;
|
|
28
|
+
}
|
|
29
|
+
type ReferenceType = 'import' | 'require' | 'extends' | 'implements' | 'call' | 'instantiation' | 'return_type' | 'param_type' | 'relation' | 'route' | 'middleware' | 'binding' | 'dispatch' | 'notify' | 'hook' | 'graphql_resolver' | 'message_handler' | 'websocket_handler';
|
|
30
|
+
interface ParseResult {
|
|
31
|
+
symbols: ExtractedSymbol[];
|
|
32
|
+
references: ExtractedReference[];
|
|
33
|
+
errors: ParseError[];
|
|
34
|
+
fileMetadata?: Record<string, any>;
|
|
35
|
+
}
|
|
36
|
+
interface ParseError {
|
|
37
|
+
message: string;
|
|
38
|
+
line?: number;
|
|
39
|
+
}
|
|
40
|
+
interface GraphEdge {
|
|
41
|
+
id?: number;
|
|
42
|
+
sourceFile: string;
|
|
43
|
+
targetFile: string;
|
|
44
|
+
sourceSymbol: string | null;
|
|
45
|
+
targetSymbol: string | null;
|
|
46
|
+
edgeType: ReferenceType;
|
|
47
|
+
repo: string;
|
|
48
|
+
weight: number;
|
|
49
|
+
verifiability?: 'verified' | 'inferred';
|
|
50
|
+
metadata?: Record<string, any>;
|
|
51
|
+
targetRepo?: string | null;
|
|
52
|
+
}
|
|
53
|
+
type ScanPhase = 'discover' | 'index' | 'parse' | 'resolve' | 'detect' | 'cluster';
|
|
54
|
+
interface ScanProgress {
|
|
55
|
+
phase: ScanPhase;
|
|
56
|
+
current: number;
|
|
57
|
+
total: number;
|
|
58
|
+
file?: string;
|
|
59
|
+
}
|
|
60
|
+
type ProgressCallback = (progress: ScanProgress) => void;
|
|
61
|
+
interface ScanResult {
|
|
62
|
+
filesScanned: number;
|
|
63
|
+
symbolsFound: number;
|
|
64
|
+
edgesFound: number;
|
|
65
|
+
durationMs: number;
|
|
66
|
+
languageBreakdown: Record<string, number>;
|
|
67
|
+
interrupted?: boolean;
|
|
68
|
+
totalFiles?: number;
|
|
69
|
+
}
|
|
70
|
+
interface Snapshot {
|
|
71
|
+
commitSha: string;
|
|
72
|
+
parentSha: string | null;
|
|
73
|
+
timestamp: string;
|
|
74
|
+
filesAdded: string[];
|
|
75
|
+
filesModified: string[];
|
|
76
|
+
filesRemoved: string[];
|
|
77
|
+
symbolsDelta: {
|
|
78
|
+
added: number;
|
|
79
|
+
removed: number;
|
|
80
|
+
changed: number;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
interface ExportOptions {
|
|
84
|
+
format: 'llm' | 'json' | 'dot' | 'svg' | 'toon';
|
|
85
|
+
tokenBudget: number;
|
|
86
|
+
repo?: string;
|
|
87
|
+
files?: string[];
|
|
88
|
+
delimiter?: 'comma' | 'tab' | 'pipe';
|
|
89
|
+
keyFolding?: boolean;
|
|
90
|
+
}
|
|
91
|
+
interface RepoConfig {
|
|
92
|
+
name: string;
|
|
93
|
+
path: string;
|
|
94
|
+
framework?: string;
|
|
95
|
+
languages?: Record<string, UserLanguageDefinition>;
|
|
96
|
+
}
|
|
97
|
+
interface UserLanguageDefinition {
|
|
98
|
+
extensions: string[];
|
|
99
|
+
grammarWasm: string;
|
|
100
|
+
queries: {
|
|
101
|
+
symbols?: string;
|
|
102
|
+
references?: string;
|
|
103
|
+
};
|
|
104
|
+
nodeMappings: Partial<Record<SymbolKind, string>>;
|
|
105
|
+
}
|
|
106
|
+
interface MapxConfig {
|
|
107
|
+
version: string;
|
|
108
|
+
repos: RepoConfig[];
|
|
109
|
+
languages: Record<string, UserLanguageDefinition>;
|
|
110
|
+
settings: {
|
|
111
|
+
maxTokenBudget: number;
|
|
112
|
+
excludePatterns: string[];
|
|
113
|
+
includePatterns: string[];
|
|
114
|
+
php?: {
|
|
115
|
+
facadeMap?: Record<string, string>;
|
|
116
|
+
};
|
|
117
|
+
[key: string]: any;
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
interface SubmoduleInfo {
|
|
121
|
+
name: string;
|
|
122
|
+
path: string;
|
|
123
|
+
url: string;
|
|
124
|
+
isInitialized: boolean;
|
|
125
|
+
}
|
|
126
|
+
interface WorkspaceInfo {
|
|
127
|
+
path: string;
|
|
128
|
+
repos: RepoConfig[];
|
|
129
|
+
}
|
|
130
|
+
interface RepoSummary {
|
|
131
|
+
name: string;
|
|
132
|
+
path: string;
|
|
133
|
+
type: 'primary' | 'submodule' | 'peer';
|
|
134
|
+
fileCount: number;
|
|
135
|
+
symbolCount: number;
|
|
136
|
+
edgeCount: number;
|
|
137
|
+
crossRepoEdgeCount: number;
|
|
138
|
+
lastScanned: string | null;
|
|
139
|
+
headSha: string | null;
|
|
140
|
+
}
|
|
141
|
+
interface ScanContext {
|
|
142
|
+
workspaceRoot: string;
|
|
143
|
+
repoName: string;
|
|
144
|
+
resolveSymbolToFile: (symbolName: string) => string | null;
|
|
145
|
+
}
|
|
146
|
+
interface RouteBinding {
|
|
147
|
+
framework: string;
|
|
148
|
+
method: string;
|
|
149
|
+
path: string;
|
|
150
|
+
handlerFile: string;
|
|
151
|
+
handlerSymbol?: string;
|
|
152
|
+
middlewares?: string[];
|
|
153
|
+
metadata?: Record<string, any>;
|
|
154
|
+
}
|
|
155
|
+
interface HookBinding {
|
|
156
|
+
framework: string;
|
|
157
|
+
hookName: string;
|
|
158
|
+
hookType: string;
|
|
159
|
+
handlerFile: string;
|
|
160
|
+
handlerSymbol?: string;
|
|
161
|
+
metadata?: Record<string, any>;
|
|
162
|
+
}
|
|
163
|
+
interface FrameworkDetector {
|
|
164
|
+
readonly name: string;
|
|
165
|
+
readonly language: string;
|
|
166
|
+
readonly filePattern: RegExp;
|
|
167
|
+
detect(projectRoot: string, files: string[]): Promise<boolean>;
|
|
168
|
+
extractRoutes(filePath: string, content: string, ctx: ScanContext): Promise<RouteBinding[]>;
|
|
169
|
+
extractHooks?(filePath: string, content: string, ctx: ScanContext): Promise<HookBinding[]>;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export type { CodeFile, ExportOptions, ExtractedReference, ExtractedSymbol, FrameworkDetector, GraphEdge, HookBinding, MapxConfig, ParseError, ParseResult, ProgressCallback, ReferenceType, RepoConfig, RepoSummary, RouteBinding, ScanContext, ScanPhase, ScanProgress, ScanResult, Snapshot, SubmoduleInfo, SymbolKind, UserLanguageDefinition, WorkspaceInfo };
|
package/dist/types.js
ADDED
|
File without changes
|