project-librarian 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +42 -11
- package/README.md +39 -9
- package/SKILL.md +1 -0
- package/dist/args.js +20 -3
- package/dist/code-index/evidence.js +79 -0
- package/dist/code-index/extractors/config.js +58 -0
- package/dist/code-index/extractors/light-languages.js +52 -0
- package/dist/code-index/extractors/registry.js +137 -0
- package/dist/code-index/extractors/shared.js +36 -0
- package/dist/code-index/extractors/tree-sitter.js +319 -0
- package/dist/code-index/extractors/types.js +2 -0
- package/dist/code-index/extractors/typescript.js +211 -0
- package/dist/code-index/incremental.js +16 -0
- package/dist/code-index/index-health.js +164 -0
- package/dist/code-index/modes.js +303 -0
- package/dist/code-index/ownership.js +183 -0
- package/dist/code-index/reports.js +322 -0
- package/dist/code-index/schema.js +196 -0
- package/dist/code-index/search.js +153 -0
- package/dist/code-index-file-policy.js +21 -27
- package/dist/code-index.js +224 -1657
- package/dist/init-project-wiki.js +65 -37
- package/dist/mcp-server.js +325 -11
- package/dist/migration.js +10 -6
- package/dist/modes.js +139 -54
- package/dist/path-ignore-policy.js +30 -0
- package/dist/retrieval-eval.js +68 -0
- package/dist/wiki-concepts.js +49 -0
- package/dist/wiki-corpus.js +25 -0
- package/dist/wiki-diagnostics.js +19 -0
- package/dist/wiki-files.js +107 -1
- package/dist/wiki-graph.js +26 -2
- package/dist/wiki-visualizer.js +558 -0
- package/package.json +11 -4
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.indexPythonLight = indexPythonLight;
|
|
4
|
+
exports.indexGoLight = indexGoLight;
|
|
5
|
+
const shared_1 = require("./shared");
|
|
6
|
+
function indexPythonLight(file, statements) {
|
|
7
|
+
const symbolPatterns = [
|
|
8
|
+
[/^\s*def\s+([A-Za-z_]\w*)\s*\(([^)]*)\)/gm, "function", (match) => `def ${match[1] ?? ""}(${match[2] ?? ""})`],
|
|
9
|
+
[/^\s*class\s+([A-Za-z_]\w*)/gm, "class", (match) => `class ${match[1] ?? ""}`],
|
|
10
|
+
];
|
|
11
|
+
for (const [regex, kind, signature] of symbolPatterns) {
|
|
12
|
+
(0, shared_1.insertMatches)(file, regex, (match, line) => (0, shared_1.insertSymbol)(statements, match[1] ?? "", kind, file, line, signature(match)));
|
|
13
|
+
}
|
|
14
|
+
const importPatterns = [
|
|
15
|
+
[/^\s*from\s+([A-Za-z0-9_.$]+)\s+import\s+(.+)$/gm, (match) => [match[1] ?? "", match[2] ?? ""]],
|
|
16
|
+
[/^\s*import\s+([A-Za-z0-9_.$, \t]+)$/gm, (match) => [match[1] ?? "", ""]],
|
|
17
|
+
];
|
|
18
|
+
for (const [regex, fields] of importPatterns) {
|
|
19
|
+
(0, shared_1.insertMatches)(file, regex, (match, line) => {
|
|
20
|
+
const [toRef, imported] = fields(match);
|
|
21
|
+
statements.insertImport.run(file.path, toRef, imported.trim(), line, match[0].trim());
|
|
22
|
+
(0, shared_1.insertEdge)(statements, "import", "file", file.path, "module", toRef, file, line, match[0].trim());
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function indexGoLight(file, statements) {
|
|
27
|
+
const symbolPatterns = [
|
|
28
|
+
[/^\s*func\s*\(\s*[^)]*\)\s*([A-Za-z_]\w*)\s*\(([^)]*)\)/gm, "method", (match) => match[1] ?? "", (match) => `func (...) ${match[1] ?? ""}(${match[2] ?? ""})`],
|
|
29
|
+
[/^\s*func\s+([A-Za-z_]\w*)\s*\(([^)]*)\)/gm, "function", (match) => match[1] ?? "", (match) => `func ${match[1] ?? ""}(${match[2] ?? ""})`],
|
|
30
|
+
[/^\s*type\s+([A-Za-z_]\w*)\s+(struct|interface)?/gm, "type", (match) => match[1] ?? "", (match) => `type ${match[1] ?? ""} ${match[2] ?? ""}`.trim()],
|
|
31
|
+
[/^\s*const\s+([A-Za-z_]\w*)\b/gm, "constant", (match) => match[1] ?? "", (match) => `const ${match[1] ?? ""}`],
|
|
32
|
+
[/^\s*var\s+([A-Za-z_]\w*)\b/gm, "variable", (match) => match[1] ?? "", (match) => `var ${match[1] ?? ""}`],
|
|
33
|
+
];
|
|
34
|
+
for (const [regex, kind, name, signature] of symbolPatterns) {
|
|
35
|
+
(0, shared_1.insertMatches)(file, regex, (match, line) => (0, shared_1.insertSymbol)(statements, name(match), kind, file, line, signature(match)));
|
|
36
|
+
}
|
|
37
|
+
(0, shared_1.insertMatches)(file, /^\s*import\s+(?:(?:([A-Za-z_]\w*|[_.])\s+)?\"([^\"]+)\"|`([^`]+)`)/gm, (match, line) => {
|
|
38
|
+
const imported = match[1] ?? "";
|
|
39
|
+
const toRef = match[2] ?? match[3] ?? "";
|
|
40
|
+
(0, shared_1.insertGoImport)(file, statements, toRef, imported, line, match[0].trim());
|
|
41
|
+
});
|
|
42
|
+
(0, shared_1.insertMatches)(file, /^\s*import\s*\(([\s\S]*?)^\s*\)/gm, (blockMatch) => {
|
|
43
|
+
const block = blockMatch[1] ?? "";
|
|
44
|
+
const blockStart = blockMatch.index ?? 0;
|
|
45
|
+
for (const lineMatch of block.matchAll(/^\s*(?:([A-Za-z_]\w*|[_.])\s+)?\"([^\"]+)\"/gm)) {
|
|
46
|
+
const imported = lineMatch[1] ?? "";
|
|
47
|
+
const toRef = lineMatch[2] ?? "";
|
|
48
|
+
const line = (0, shared_1.lineNumber)(file.text, blockStart + (lineMatch.index ?? 0));
|
|
49
|
+
(0, shared_1.insertGoImport)(file, statements, toRef, imported, line, lineMatch[0].trim());
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.extractionProfile = extractionProfile;
|
|
37
|
+
exports.createExtractionBackendRegistry = createExtractionBackendRegistry;
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
39
|
+
const config_1 = require("./config");
|
|
40
|
+
const light_languages_1 = require("./light-languages");
|
|
41
|
+
const tree_sitter_1 = require("./tree-sitter");
|
|
42
|
+
const typescript_1 = require("./typescript");
|
|
43
|
+
function treeSitterProfile(relativePath) {
|
|
44
|
+
const extension = path.extname(relativePath).toLowerCase();
|
|
45
|
+
if ([".ts", ".mts", ".cts"].includes(extension))
|
|
46
|
+
return "tree-sitter-typescript";
|
|
47
|
+
if (extension === ".tsx")
|
|
48
|
+
return "tree-sitter-tsx";
|
|
49
|
+
if ([".js", ".mjs", ".cjs", ".jsx"].includes(extension))
|
|
50
|
+
return "tree-sitter-javascript";
|
|
51
|
+
if (extension === ".py")
|
|
52
|
+
return "tree-sitter-python";
|
|
53
|
+
if (extension === ".go")
|
|
54
|
+
return "tree-sitter-go";
|
|
55
|
+
if ([".c", ".h"].includes(extension))
|
|
56
|
+
return "tree-sitter-c";
|
|
57
|
+
if ([".cc", ".cpp", ".cxx", ".hpp", ".hh", ".hxx"].includes(extension))
|
|
58
|
+
return "tree-sitter-cpp";
|
|
59
|
+
if (extension === ".cs")
|
|
60
|
+
return "tree-sitter-csharp";
|
|
61
|
+
if (extension === ".java")
|
|
62
|
+
return "tree-sitter-java";
|
|
63
|
+
if ([".kt", ".kts"].includes(extension))
|
|
64
|
+
return "tree-sitter-kotlin";
|
|
65
|
+
if (extension === ".php")
|
|
66
|
+
return "tree-sitter-php";
|
|
67
|
+
if (extension === ".rs")
|
|
68
|
+
return "tree-sitter-rust";
|
|
69
|
+
if (extension === ".swift")
|
|
70
|
+
return "tree-sitter-swift";
|
|
71
|
+
return "inventory-only";
|
|
72
|
+
}
|
|
73
|
+
function extractionProfile(relativePath, language, parserMode) {
|
|
74
|
+
if (language === "config")
|
|
75
|
+
return "config";
|
|
76
|
+
if (parserMode === "tree-sitter")
|
|
77
|
+
return treeSitterProfile(relativePath);
|
|
78
|
+
if (isJavaScriptLikeProfileInput(language))
|
|
79
|
+
return "typescript-ast";
|
|
80
|
+
if (language === "python")
|
|
81
|
+
return "python-light";
|
|
82
|
+
if (language === "go")
|
|
83
|
+
return "go-light";
|
|
84
|
+
return "inventory-only";
|
|
85
|
+
}
|
|
86
|
+
function isJavaScriptLikeProfileInput(language) {
|
|
87
|
+
return language === "javascript" || language === "typescript";
|
|
88
|
+
}
|
|
89
|
+
function createExtractionBackendRegistry(fail) {
|
|
90
|
+
const extractionBackends = [
|
|
91
|
+
{
|
|
92
|
+
id: "typescript-compiler",
|
|
93
|
+
index: typescript_1.indexJavaScriptLike,
|
|
94
|
+
label: "TypeScript compiler API",
|
|
95
|
+
profile: "typescript-ast",
|
|
96
|
+
strength: "structural",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: "regex-light",
|
|
100
|
+
index: light_languages_1.indexPythonLight,
|
|
101
|
+
label: "Python lightweight regex",
|
|
102
|
+
profile: "python-light",
|
|
103
|
+
strength: "light",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: "regex-light",
|
|
107
|
+
index: light_languages_1.indexGoLight,
|
|
108
|
+
label: "Go lightweight regex",
|
|
109
|
+
profile: "go-light",
|
|
110
|
+
strength: "light",
|
|
111
|
+
},
|
|
112
|
+
...(0, tree_sitter_1.treeSitterBackends)(fail),
|
|
113
|
+
{
|
|
114
|
+
id: "config-key-value",
|
|
115
|
+
index: (file, statements) => (0, config_1.indexConfigs)(file, statements.insertConfig),
|
|
116
|
+
label: "Configuration key/value extractor",
|
|
117
|
+
profile: "config",
|
|
118
|
+
strength: "config",
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: "inventory-only",
|
|
122
|
+
index: () => undefined,
|
|
123
|
+
label: "Inventory-only file listing",
|
|
124
|
+
profile: "inventory-only",
|
|
125
|
+
strength: "inventory",
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
const extractionBackendsByProfile = new Map(extractionBackends.map((backend) => [backend.profile, backend]));
|
|
129
|
+
return {
|
|
130
|
+
backendForProfile(profile) {
|
|
131
|
+
const backend = extractionBackendsByProfile.get(profile);
|
|
132
|
+
if (!backend)
|
|
133
|
+
fail(`missing extraction backend for profile: ${profile}`);
|
|
134
|
+
return backend;
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.oneLine = oneLine;
|
|
4
|
+
exports.lineNumber = lineNumber;
|
|
5
|
+
exports.insertSymbol = insertSymbol;
|
|
6
|
+
exports.insertEdge = insertEdge;
|
|
7
|
+
exports.insertMatches = insertMatches;
|
|
8
|
+
exports.insertGoImport = insertGoImport;
|
|
9
|
+
function oneLine(text) {
|
|
10
|
+
return text.replace(/\s+/g, " ").trim().slice(0, 240);
|
|
11
|
+
}
|
|
12
|
+
function lineNumber(text, index) {
|
|
13
|
+
return text.slice(0, index).split(/\r?\n/).length;
|
|
14
|
+
}
|
|
15
|
+
function insertSymbol(statements, name, kind, file, line, signature) {
|
|
16
|
+
if (!name)
|
|
17
|
+
return;
|
|
18
|
+
statements.insertSymbol.run(name, kind, file.path, line, signature);
|
|
19
|
+
statements.insertSymbolFts.run(name, kind, file.path, signature);
|
|
20
|
+
}
|
|
21
|
+
function insertEdge(statements, kind, sourceKind, source, targetKind, target, file, line, evidence) {
|
|
22
|
+
if (!target)
|
|
23
|
+
return;
|
|
24
|
+
statements.insertEdge.run(kind, sourceKind, source, targetKind, target, file.path, line, evidence);
|
|
25
|
+
}
|
|
26
|
+
function insertMatches(file, regex, insert) {
|
|
27
|
+
for (const match of file.text.matchAll(regex)) {
|
|
28
|
+
insert(match, lineNumber(file.text, match.index ?? 0));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function insertGoImport(file, statements, toRef, imported, line, raw) {
|
|
32
|
+
if (!toRef)
|
|
33
|
+
return;
|
|
34
|
+
statements.insertImport.run(file.path, toRef, imported, line, raw);
|
|
35
|
+
insertEdge(statements, "import", "file", file.path, "module", toRef, file, line, raw);
|
|
36
|
+
}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.treeSitterBackends = treeSitterBackends;
|
|
4
|
+
const shared_1 = require("./shared");
|
|
5
|
+
const treeSitterGrammarPackages = {
|
|
6
|
+
"tree-sitter-c": "@sengac/tree-sitter-c",
|
|
7
|
+
"tree-sitter-cpp": "@sengac/tree-sitter-cpp",
|
|
8
|
+
"tree-sitter-csharp": "@sengac/tree-sitter-c-sharp",
|
|
9
|
+
"tree-sitter-go": "@sengac/tree-sitter-go",
|
|
10
|
+
"tree-sitter-java": "@sengac/tree-sitter-java",
|
|
11
|
+
"tree-sitter-javascript": "@sengac/tree-sitter-javascript",
|
|
12
|
+
"tree-sitter-kotlin": "@sengac/tree-sitter-kotlin",
|
|
13
|
+
"tree-sitter-php": "@sengac/tree-sitter-php",
|
|
14
|
+
"tree-sitter-python": "@sengac/tree-sitter-python",
|
|
15
|
+
"tree-sitter-rust": "@sengac/tree-sitter-rust",
|
|
16
|
+
"tree-sitter-swift": "@sengac/tree-sitter-swift",
|
|
17
|
+
};
|
|
18
|
+
function createTreeSitterParserResolver(fail) {
|
|
19
|
+
const treeSitterParsers = new Map();
|
|
20
|
+
function requireTreeSitterPackage(packageName) {
|
|
21
|
+
try {
|
|
22
|
+
return require(packageName);
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
26
|
+
fail(`--code-parser tree-sitter requires optional package ${packageName}; install project optional dependencies with npm install. Error: ${message}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function treeSitterGrammarForProfile(profile) {
|
|
30
|
+
if (profile === "tree-sitter-typescript" || profile === "tree-sitter-tsx") {
|
|
31
|
+
const grammars = requireTreeSitterPackage("@sengac/tree-sitter-typescript");
|
|
32
|
+
const grammar = profile === "tree-sitter-tsx" ? grammars.tsx : grammars.typescript;
|
|
33
|
+
if (!grammar)
|
|
34
|
+
fail(`tree-sitter-typescript did not expose the expected ${profile === "tree-sitter-tsx" ? "tsx" : "typescript"} grammar`);
|
|
35
|
+
return grammar;
|
|
36
|
+
}
|
|
37
|
+
const packageName = treeSitterGrammarPackages[profile];
|
|
38
|
+
if (packageName) {
|
|
39
|
+
const grammarModule = requireTreeSitterPackage(packageName);
|
|
40
|
+
const grammar = profile === "tree-sitter-php"
|
|
41
|
+
? grammarModule.php ?? grammarModule.php_only
|
|
42
|
+
: grammarModule;
|
|
43
|
+
if (!grammar)
|
|
44
|
+
fail(`${packageName} did not expose a Tree-sitter grammar for ${profile}`);
|
|
45
|
+
return grammar;
|
|
46
|
+
}
|
|
47
|
+
fail(`missing Tree-sitter grammar for profile: ${profile}`);
|
|
48
|
+
}
|
|
49
|
+
return (profile) => {
|
|
50
|
+
const cached = treeSitterParsers.get(profile);
|
|
51
|
+
if (cached)
|
|
52
|
+
return cached;
|
|
53
|
+
const Parser = requireTreeSitterPackage("@sengac/tree-sitter");
|
|
54
|
+
const parser = new Parser();
|
|
55
|
+
parser.setLanguage(treeSitterGrammarForProfile(profile));
|
|
56
|
+
treeSitterParsers.set(profile, parser);
|
|
57
|
+
return parser;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function treeSitterLine(node) {
|
|
61
|
+
return node.startPosition.row + 1;
|
|
62
|
+
}
|
|
63
|
+
function treeSitterFieldText(node, fieldName) {
|
|
64
|
+
return node.childForFieldName(fieldName)?.text ?? "";
|
|
65
|
+
}
|
|
66
|
+
function treeSitterSignature(node) {
|
|
67
|
+
return (0, shared_1.oneLine)(node.text);
|
|
68
|
+
}
|
|
69
|
+
function unquoteLiteral(text) {
|
|
70
|
+
const trimmed = text.trim();
|
|
71
|
+
if (trimmed.length >= 2) {
|
|
72
|
+
const first = trimmed[0];
|
|
73
|
+
const last = trimmed[trimmed.length - 1];
|
|
74
|
+
if ((first === "\"" && last === "\"") || (first === "'" && last === "'") || (first === "`" && last === "`"))
|
|
75
|
+
return trimmed.slice(1, -1);
|
|
76
|
+
}
|
|
77
|
+
return trimmed;
|
|
78
|
+
}
|
|
79
|
+
function forEachNamedTreeSitterNode(node, visit) {
|
|
80
|
+
visit(node);
|
|
81
|
+
for (let index = 0; index < node.namedChildCount; index += 1) {
|
|
82
|
+
const child = node.namedChild(index);
|
|
83
|
+
if (child)
|
|
84
|
+
forEachNamedTreeSitterNode(child, visit);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function firstNamedChildOfType(node, type) {
|
|
88
|
+
for (let index = 0; index < node.namedChildCount; index += 1) {
|
|
89
|
+
const child = node.namedChild(index);
|
|
90
|
+
if (child?.type === type)
|
|
91
|
+
return child;
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
function treeSitterModuleSpecifier(node) {
|
|
96
|
+
const source = treeSitterFieldText(node, "source");
|
|
97
|
+
if (source)
|
|
98
|
+
return unquoteLiteral(source);
|
|
99
|
+
const raw = node.text;
|
|
100
|
+
return raw.match(/\bfrom\s*["'`]([^"'`]+)["'`]/)?.[1]
|
|
101
|
+
?? raw.match(/^\s*import\s*["'`]([^"'`]+)["'`]/)?.[1]
|
|
102
|
+
?? raw.match(/\brequire\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/)?.[1]
|
|
103
|
+
?? "";
|
|
104
|
+
}
|
|
105
|
+
function indexTreeSitterJavaScriptLike(file, statements, parserForProfile) {
|
|
106
|
+
const tree = parserForProfile(file.profile).parse(file.text);
|
|
107
|
+
function visit(node, context) {
|
|
108
|
+
let nextContext = context;
|
|
109
|
+
if (node.type === "function_declaration") {
|
|
110
|
+
const name = treeSitterFieldText(node, "name");
|
|
111
|
+
(0, shared_1.insertSymbol)(statements, name, "function", file, treeSitterLine(node), treeSitterSignature(node));
|
|
112
|
+
if (name)
|
|
113
|
+
nextContext = name;
|
|
114
|
+
}
|
|
115
|
+
else if (node.type === "class_declaration") {
|
|
116
|
+
const name = treeSitterFieldText(node, "name");
|
|
117
|
+
(0, shared_1.insertSymbol)(statements, name, "class", file, treeSitterLine(node), treeSitterSignature(node));
|
|
118
|
+
if (name)
|
|
119
|
+
nextContext = name;
|
|
120
|
+
}
|
|
121
|
+
else if (node.type === "method_definition" || node.type === "method_signature") {
|
|
122
|
+
const name = treeSitterFieldText(node, "name");
|
|
123
|
+
(0, shared_1.insertSymbol)(statements, name, "method", file, treeSitterLine(node), treeSitterSignature(node));
|
|
124
|
+
if (name)
|
|
125
|
+
nextContext = name;
|
|
126
|
+
}
|
|
127
|
+
else if (node.type === "interface_declaration") {
|
|
128
|
+
(0, shared_1.insertSymbol)(statements, treeSitterFieldText(node, "name"), "interface", file, treeSitterLine(node), treeSitterSignature(node));
|
|
129
|
+
}
|
|
130
|
+
else if (node.type === "type_alias_declaration") {
|
|
131
|
+
(0, shared_1.insertSymbol)(statements, treeSitterFieldText(node, "name"), "type", file, treeSitterLine(node), treeSitterSignature(node));
|
|
132
|
+
}
|
|
133
|
+
else if (node.type === "enum_declaration") {
|
|
134
|
+
(0, shared_1.insertSymbol)(statements, treeSitterFieldText(node, "name"), "enum", file, treeSitterLine(node), treeSitterSignature(node));
|
|
135
|
+
}
|
|
136
|
+
else if (node.type === "variable_declarator") {
|
|
137
|
+
const name = treeSitterFieldText(node, "name");
|
|
138
|
+
const valueType = node.childForFieldName("value")?.type ?? "";
|
|
139
|
+
const symbolKind = ["arrow_function", "function", "function_expression"].includes(valueType) ? "function" : "variable";
|
|
140
|
+
(0, shared_1.insertSymbol)(statements, name, symbolKind, file, treeSitterLine(node), treeSitterSignature(node));
|
|
141
|
+
if (symbolKind === "function" && name)
|
|
142
|
+
nextContext = name;
|
|
143
|
+
}
|
|
144
|
+
else if (node.type === "import_statement" || node.type === "export_statement") {
|
|
145
|
+
const toRef = treeSitterModuleSpecifier(node);
|
|
146
|
+
if (toRef) {
|
|
147
|
+
const imported = node.text.match(/^\s*import\s+(.+?)\s+from\s*["'`]/)?.[1] ?? node.text.match(/^\s*export\s+(.+?)\s+from\s*["'`]/)?.[1] ?? "";
|
|
148
|
+
statements.insertImport.run(file.path, toRef, (0, shared_1.oneLine)(imported), treeSitterLine(node), treeSitterSignature(node));
|
|
149
|
+
(0, shared_1.insertEdge)(statements, node.type === "export_statement" ? "export" : "import", "file", file.path, "module", toRef, file, treeSitterLine(node), treeSitterSignature(node));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else if (node.type === "call_expression") {
|
|
153
|
+
const raw = node.text;
|
|
154
|
+
const routeMatch = raw.match(/^(?:app|router|server)\.(get|post|put|patch|delete|all)\s*\(\s*["'`]([^"'`]+)["'`]\s*,\s*([^,)]+)/);
|
|
155
|
+
if (routeMatch) {
|
|
156
|
+
const method = (routeMatch[1] ?? "").toUpperCase();
|
|
157
|
+
const route = routeMatch[2] ?? "";
|
|
158
|
+
const handler = (0, shared_1.oneLine)(routeMatch[3] ?? "");
|
|
159
|
+
statements.insertRoute.run(method, route, file.path, treeSitterLine(node), handler);
|
|
160
|
+
(0, shared_1.insertEdge)(statements, "route_to_handler", "route", `${method} ${route}`, "symbol", handler, file, treeSitterLine(node), treeSitterSignature(node));
|
|
161
|
+
}
|
|
162
|
+
const requireRef = treeSitterModuleSpecifier(node);
|
|
163
|
+
if (requireRef) {
|
|
164
|
+
statements.insertImport.run(file.path, requireRef, "", treeSitterLine(node), treeSitterSignature(node));
|
|
165
|
+
(0, shared_1.insertEdge)(statements, "import", "file", file.path, "module", requireRef, file, treeSitterLine(node), treeSitterSignature(node));
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
const target = treeSitterFieldText(node, "function");
|
|
169
|
+
(0, shared_1.insertEdge)(statements, "call", context ? "symbol" : "file", context || file.path, "symbol", target, file, treeSitterLine(node), treeSitterSignature(node));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
for (let index = 0; index < node.namedChildCount; index += 1) {
|
|
173
|
+
const child = node.namedChild(index);
|
|
174
|
+
if (child)
|
|
175
|
+
visit(child, nextContext);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
visit(tree.rootNode, "");
|
|
179
|
+
}
|
|
180
|
+
function indexTreeSitterPython(file, statements, parserForProfile) {
|
|
181
|
+
const tree = parserForProfile(file.profile).parse(file.text);
|
|
182
|
+
forEachNamedTreeSitterNode(tree.rootNode, (node) => {
|
|
183
|
+
if (node.type === "function_definition") {
|
|
184
|
+
const name = treeSitterFieldText(node, "name");
|
|
185
|
+
(0, shared_1.insertSymbol)(statements, name, "function", file, treeSitterLine(node), treeSitterSignature(node));
|
|
186
|
+
}
|
|
187
|
+
else if (node.type === "class_definition") {
|
|
188
|
+
const name = treeSitterFieldText(node, "name");
|
|
189
|
+
(0, shared_1.insertSymbol)(statements, name, "class", file, treeSitterLine(node), treeSitterSignature(node));
|
|
190
|
+
}
|
|
191
|
+
else if (node.type === "import_statement" || node.type === "import_from_statement") {
|
|
192
|
+
const raw = node.text.trim();
|
|
193
|
+
const fromMatch = raw.match(/^from\s+([A-Za-z0-9_.$]+)\s+import\s+(.+)$/);
|
|
194
|
+
const importMatch = raw.match(/^import\s+(.+)$/);
|
|
195
|
+
const toRef = fromMatch?.[1] ?? importMatch?.[1] ?? "";
|
|
196
|
+
const imported = fromMatch?.[2] ?? "";
|
|
197
|
+
if (toRef) {
|
|
198
|
+
statements.insertImport.run(file.path, toRef, imported.trim(), treeSitterLine(node), raw);
|
|
199
|
+
(0, shared_1.insertEdge)(statements, "import", "file", file.path, "module", toRef, file, treeSitterLine(node), raw);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
function indexTreeSitterGo(file, statements, parserForProfile) {
|
|
205
|
+
const tree = parserForProfile(file.profile).parse(file.text);
|
|
206
|
+
forEachNamedTreeSitterNode(tree.rootNode, (node) => {
|
|
207
|
+
if (node.type === "function_declaration") {
|
|
208
|
+
const name = treeSitterFieldText(node, "name");
|
|
209
|
+
(0, shared_1.insertSymbol)(statements, name, "function", file, treeSitterLine(node), treeSitterSignature(node));
|
|
210
|
+
}
|
|
211
|
+
else if (node.type === "method_declaration") {
|
|
212
|
+
const name = treeSitterFieldText(node, "name");
|
|
213
|
+
(0, shared_1.insertSymbol)(statements, name, "method", file, treeSitterLine(node), treeSitterSignature(node));
|
|
214
|
+
}
|
|
215
|
+
else if (node.type === "type_declaration") {
|
|
216
|
+
const spec = firstNamedChildOfType(node, "type_spec");
|
|
217
|
+
const name = spec ? treeSitterFieldText(spec, "name") : "";
|
|
218
|
+
(0, shared_1.insertSymbol)(statements, name, "type", file, treeSitterLine(node), treeSitterSignature(node));
|
|
219
|
+
}
|
|
220
|
+
else if (node.type === "const_declaration" || node.type === "var_declaration") {
|
|
221
|
+
const spec = firstNamedChildOfType(node, node.type === "const_declaration" ? "const_spec" : "var_spec");
|
|
222
|
+
const name = spec ? treeSitterFieldText(spec, "name") : "";
|
|
223
|
+
(0, shared_1.insertSymbol)(statements, name, node.type === "const_declaration" ? "constant" : "variable", file, treeSitterLine(node), treeSitterSignature(node));
|
|
224
|
+
}
|
|
225
|
+
else if (node.type === "import_spec") {
|
|
226
|
+
const toRef = unquoteLiteral(treeSitterFieldText(node, "path") || (node.text.match(/"([^"]+)"/)?.[1] ?? ""));
|
|
227
|
+
const imported = treeSitterFieldText(node, "name");
|
|
228
|
+
(0, shared_1.insertGoImport)(file, statements, toRef, imported, treeSitterLine(node), treeSitterSignature(node));
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
function treeSitterGenericLanguage(file, fail) {
|
|
233
|
+
const normalized = file.profile.replace(/^tree-sitter-/, "");
|
|
234
|
+
if (["c", "cpp", "csharp", "java", "kotlin", "php", "rust", "swift"].includes(normalized))
|
|
235
|
+
return normalized;
|
|
236
|
+
fail(`unsupported generic Tree-sitter profile: ${file.profile}`);
|
|
237
|
+
}
|
|
238
|
+
function symbolNameFromPatterns(text, patterns) {
|
|
239
|
+
for (const pattern of patterns) {
|
|
240
|
+
const match = text.match(pattern);
|
|
241
|
+
if (match?.[1])
|
|
242
|
+
return match[1];
|
|
243
|
+
}
|
|
244
|
+
return "";
|
|
245
|
+
}
|
|
246
|
+
function treeSitterGenericSymbol(node, language) {
|
|
247
|
+
const raw = node.text;
|
|
248
|
+
const fieldName = treeSitterFieldText(node, "name");
|
|
249
|
+
const patterns = {
|
|
250
|
+
c: [[["function_definition"], "function", [/\b([A-Za-z_]\w*)\s*\([^;{}]*\)\s*\{/]], [["struct_specifier"], "struct", [/\bstruct\s+([A-Za-z_]\w*)/]], [["enum_specifier"], "enum", [/\benum\s+([A-Za-z_]\w*)/]]],
|
|
251
|
+
cpp: [[["function_definition"], "function", [/\b([A-Za-z_]\w*)\s*\([^;{}]*\)\s*(?:const\s*)?\{/]], [["class_specifier"], "class", [/\bclass\s+([A-Za-z_]\w*)/, /\bstruct\s+([A-Za-z_]\w*)/]], [["namespace_definition"], "namespace", [/\bnamespace\s+([A-Za-z_]\w*)/]], [["enum_specifier"], "enum", [/\benum(?:\s+class)?\s+([A-Za-z_]\w*)/]]],
|
|
252
|
+
csharp: [[["method_declaration", "constructor_declaration"], "method", [/\b([A-Za-z_]\w*)\s*\(/]], [["class_declaration"], "class", [/\bclass\s+([A-Za-z_]\w*)/]], [["interface_declaration"], "interface", [/\binterface\s+([A-Za-z_]\w*)/]], [["struct_declaration"], "struct", [/\bstruct\s+([A-Za-z_]\w*)/]], [["enum_declaration"], "enum", [/\benum\s+([A-Za-z_]\w*)/]]],
|
|
253
|
+
java: [[["method_declaration", "constructor_declaration"], "method", [/\b([A-Za-z_]\w*)\s*\(/]], [["class_declaration"], "class", [/\bclass\s+([A-Za-z_]\w*)/]], [["interface_declaration"], "interface", [/\binterface\s+([A-Za-z_]\w*)/]], [["enum_declaration"], "enum", [/\benum\s+([A-Za-z_]\w*)/]]],
|
|
254
|
+
kotlin: [[["function_declaration"], "function", [/\bfun\s+([A-Za-z_]\w*)/]], [["class_declaration"], "class", [/\bclass\s+([A-Za-z_]\w*)/, /\binterface\s+([A-Za-z_]\w*)/]], [["object_declaration"], "object", [/\bobject\s+([A-Za-z_]\w*)/]]],
|
|
255
|
+
php: [[["function_definition"], "function", [/\bfunction\s+([A-Za-z_]\w*)/]], [["method_declaration"], "method", [/\bfunction\s+([A-Za-z_]\w*)/]], [["class_declaration"], "class", [/\bclass\s+([A-Za-z_]\w*)/]], [["interface_declaration"], "interface", [/\binterface\s+([A-Za-z_]\w*)/]], [["trait_declaration"], "trait", [/\btrait\s+([A-Za-z_]\w*)/]]],
|
|
256
|
+
rust: [[["function_item"], "function", [/\bfn\s+([A-Za-z_]\w*)/]], [["struct_item"], "struct", [/\bstruct\s+([A-Za-z_]\w*)/]], [["enum_item"], "enum", [/\benum\s+([A-Za-z_]\w*)/]], [["trait_item"], "trait", [/\btrait\s+([A-Za-z_]\w*)/]], [["impl_item"], "impl", [/\bimpl(?:\s*<[^>]+>)?\s+([A-Za-z_]\w*)/]]],
|
|
257
|
+
swift: [[["function_declaration"], "function", [/\bfunc\s+([A-Za-z_]\w*)/]], [["class_declaration"], "class", [/\bclass\s+([A-Za-z_]\w*)/]], [["struct_declaration"], "struct", [/\bstruct\s+([A-Za-z_]\w*)/]], [["protocol_declaration"], "protocol", [/\bprotocol\s+([A-Za-z_]\w*)/]], [["enum_declaration"], "enum", [/\benum\s+([A-Za-z_]\w*)/]]],
|
|
258
|
+
};
|
|
259
|
+
for (const [types, kind, regexes] of patterns[language] ?? []) {
|
|
260
|
+
if (!types.includes(node.type))
|
|
261
|
+
continue;
|
|
262
|
+
const name = fieldName || symbolNameFromPatterns(raw, regexes);
|
|
263
|
+
return name ? { kind, name } : null;
|
|
264
|
+
}
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
function treeSitterGenericImport(node, language) {
|
|
268
|
+
const raw = node.text.trim();
|
|
269
|
+
const importTypes = {
|
|
270
|
+
c: ["preproc_include"],
|
|
271
|
+
cpp: ["preproc_include", "using_declaration", "namespace_alias_definition"],
|
|
272
|
+
csharp: ["using_directive"],
|
|
273
|
+
java: ["import_declaration"],
|
|
274
|
+
kotlin: ["import_header"],
|
|
275
|
+
php: ["namespace_use_declaration"],
|
|
276
|
+
rust: ["use_declaration"],
|
|
277
|
+
swift: ["import_declaration"],
|
|
278
|
+
};
|
|
279
|
+
if (!(importTypes[language] ?? []).includes(node.type))
|
|
280
|
+
return null;
|
|
281
|
+
const toRef = raw.match(/#include\s*[<"]([^>"]+)[>"]/)?.[1]
|
|
282
|
+
?? raw.match(/\bimport\s+([A-Za-z0-9_.*.$\\/-]+)/)?.[1]
|
|
283
|
+
?? raw.match(/\busing\s+([A-Za-z0-9_.*.$\\/-]+)/)?.[1]
|
|
284
|
+
?? raw.match(/\buse\s+([A-Za-z0-9_:{}*,\s]+);?/)?.[1]?.replace(/\s+/g, " ").trim()
|
|
285
|
+
?? "";
|
|
286
|
+
return toRef ? { imported: "", kind: language === "rust" ? "use" : "import", toRef } : null;
|
|
287
|
+
}
|
|
288
|
+
function indexTreeSitterGeneric(file, statements, parserForProfile, fail) {
|
|
289
|
+
const language = treeSitterGenericLanguage(file, fail);
|
|
290
|
+
const tree = parserForProfile(file.profile).parse(file.text);
|
|
291
|
+
forEachNamedTreeSitterNode(tree.rootNode, (node) => {
|
|
292
|
+
const symbol = treeSitterGenericSymbol(node, language);
|
|
293
|
+
if (symbol)
|
|
294
|
+
(0, shared_1.insertSymbol)(statements, symbol.name, symbol.kind, file, treeSitterLine(node), treeSitterSignature(node));
|
|
295
|
+
const imported = treeSitterGenericImport(node, language);
|
|
296
|
+
if (imported) {
|
|
297
|
+
statements.insertImport.run(file.path, imported.toRef, imported.imported, treeSitterLine(node), treeSitterSignature(node));
|
|
298
|
+
(0, shared_1.insertEdge)(statements, imported.kind, "file", file.path, "module", imported.toRef, file, treeSitterLine(node), treeSitterSignature(node));
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
function treeSitterBackends(fail) {
|
|
303
|
+
const parserForProfile = createTreeSitterParserResolver(fail);
|
|
304
|
+
return [
|
|
305
|
+
{ id: "tree-sitter-javascript", index: (file, statements) => indexTreeSitterJavaScriptLike(file, statements, parserForProfile), label: "Tree-sitter JavaScript grammar", profile: "tree-sitter-javascript", strength: "structural" },
|
|
306
|
+
{ id: "tree-sitter-typescript", index: (file, statements) => indexTreeSitterJavaScriptLike(file, statements, parserForProfile), label: "Tree-sitter TypeScript grammar", profile: "tree-sitter-typescript", strength: "structural" },
|
|
307
|
+
{ id: "tree-sitter-typescript", index: (file, statements) => indexTreeSitterJavaScriptLike(file, statements, parserForProfile), label: "Tree-sitter TSX grammar", profile: "tree-sitter-tsx", strength: "structural" },
|
|
308
|
+
{ id: "tree-sitter-python", index: (file, statements) => indexTreeSitterPython(file, statements, parserForProfile), label: "Tree-sitter Python grammar", profile: "tree-sitter-python", strength: "structural" },
|
|
309
|
+
{ id: "tree-sitter-go", index: (file, statements) => indexTreeSitterGo(file, statements, parserForProfile), label: "Tree-sitter Go grammar", profile: "tree-sitter-go", strength: "structural" },
|
|
310
|
+
{ id: "tree-sitter-c", index: (file, statements) => indexTreeSitterGeneric(file, statements, parserForProfile, fail), label: "Tree-sitter C grammar", profile: "tree-sitter-c", strength: "structural" },
|
|
311
|
+
{ id: "tree-sitter-cpp", index: (file, statements) => indexTreeSitterGeneric(file, statements, parserForProfile, fail), label: "Tree-sitter C++ grammar", profile: "tree-sitter-cpp", strength: "structural" },
|
|
312
|
+
{ id: "tree-sitter-csharp", index: (file, statements) => indexTreeSitterGeneric(file, statements, parserForProfile, fail), label: "Tree-sitter C# grammar", profile: "tree-sitter-csharp", strength: "structural" },
|
|
313
|
+
{ id: "tree-sitter-java", index: (file, statements) => indexTreeSitterGeneric(file, statements, parserForProfile, fail), label: "Tree-sitter Java grammar", profile: "tree-sitter-java", strength: "structural" },
|
|
314
|
+
{ id: "tree-sitter-kotlin", index: (file, statements) => indexTreeSitterGeneric(file, statements, parserForProfile, fail), label: "Tree-sitter Kotlin grammar", profile: "tree-sitter-kotlin", strength: "structural" },
|
|
315
|
+
{ id: "tree-sitter-php", index: (file, statements) => indexTreeSitterGeneric(file, statements, parserForProfile, fail), label: "Tree-sitter PHP grammar", profile: "tree-sitter-php", strength: "structural" },
|
|
316
|
+
{ id: "tree-sitter-rust", index: (file, statements) => indexTreeSitterGeneric(file, statements, parserForProfile, fail), label: "Tree-sitter Rust grammar", profile: "tree-sitter-rust", strength: "structural" },
|
|
317
|
+
{ id: "tree-sitter-swift", index: (file, statements) => indexTreeSitterGeneric(file, statements, parserForProfile, fail), label: "Tree-sitter Swift grammar", profile: "tree-sitter-swift", strength: "structural" },
|
|
318
|
+
];
|
|
319
|
+
}
|