@mneme-ai/core 0.8.3
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.md +31 -0
- package/dist/correlate/index.d.ts +44 -0
- package/dist/correlate/index.d.ts.map +1 -0
- package/dist/correlate/index.js +21 -0
- package/dist/correlate/index.js.map +1 -0
- package/dist/enrich/index.d.ts +35 -0
- package/dist/enrich/index.d.ts.map +1 -0
- package/dist/enrich/index.js +69 -0
- package/dist/enrich/index.js.map +1 -0
- package/dist/entities/cosine-clones.d.ts +6 -0
- package/dist/entities/cosine-clones.d.ts.map +1 -0
- package/dist/entities/cosine-clones.js +142 -0
- package/dist/entities/cosine-clones.js.map +1 -0
- package/dist/entities/cosine-clones.test.d.ts +2 -0
- package/dist/entities/cosine-clones.test.d.ts.map +1 -0
- package/dist/entities/cosine-clones.test.js +109 -0
- package/dist/entities/cosine-clones.test.js.map +1 -0
- package/dist/entities/index.d.ts +74 -0
- package/dist/entities/index.d.ts.map +1 -0
- package/dist/entities/index.js +24 -0
- package/dist/entities/index.js.map +1 -0
- package/dist/entities/python-parser.d.ts +16 -0
- package/dist/entities/python-parser.d.ts.map +1 -0
- package/dist/entities/python-parser.js +248 -0
- package/dist/entities/python-parser.js.map +1 -0
- package/dist/entities/typescript-parser.d.ts +18 -0
- package/dist/entities/typescript-parser.d.ts.map +1 -0
- package/dist/entities/typescript-parser.js +220 -0
- package/dist/entities/typescript-parser.js.map +1 -0
- package/dist/entities/typescript-parser.test.d.ts +2 -0
- package/dist/entities/typescript-parser.test.d.ts.map +1 -0
- package/dist/entities/typescript-parser.test.js +103 -0
- package/dist/entities/typescript-parser.test.js.map +1 -0
- package/dist/git/blame.d.ts +9 -0
- package/dist/git/blame.d.ts.map +1 -0
- package/dist/git/blame.js +56 -0
- package/dist/git/blame.js.map +1 -0
- package/dist/git/exec.d.ts +13 -0
- package/dist/git/exec.d.ts.map +1 -0
- package/dist/git/exec.js +40 -0
- package/dist/git/exec.js.map +1 -0
- package/dist/git/github.d.ts +62 -0
- package/dist/git/github.d.ts.map +1 -0
- package/dist/git/github.js +115 -0
- package/dist/git/github.js.map +1 -0
- package/dist/git/github.test.d.ts +2 -0
- package/dist/git/github.test.d.ts.map +1 -0
- package/dist/git/github.test.js +86 -0
- package/dist/git/github.test.js.map +1 -0
- package/dist/git/gitlab.d.ts +66 -0
- package/dist/git/gitlab.d.ts.map +1 -0
- package/dist/git/gitlab.js +121 -0
- package/dist/git/gitlab.js.map +1 -0
- package/dist/git/gitlab.test.d.ts +2 -0
- package/dist/git/gitlab.test.d.ts.map +1 -0
- package/dist/git/gitlab.test.js +122 -0
- package/dist/git/gitlab.test.js.map +1 -0
- package/dist/git/index.d.ts +7 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +7 -0
- package/dist/git/index.js.map +1 -0
- package/dist/git/log.d.ts +11 -0
- package/dist/git/log.d.ts.map +1 -0
- package/dist/git/log.js +107 -0
- package/dist/git/log.js.map +1 -0
- package/dist/git/log.test.d.ts +2 -0
- package/dist/git/log.test.d.ts.map +1 -0
- package/dist/git/log.test.js +88 -0
- package/dist/git/log.test.js.map +1 -0
- package/dist/git/repo.d.ts +12 -0
- package/dist/git/repo.d.ts.map +1 -0
- package/dist/git/repo.js +50 -0
- package/dist/git/repo.js.map +1 -0
- package/dist/git/repo.test.d.ts +2 -0
- package/dist/git/repo.test.d.ts.map +1 -0
- package/dist/git/repo.test.js +35 -0
- package/dist/git/repo.test.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer/index.d.ts +2 -0
- package/dist/indexer/index.d.ts.map +1 -0
- package/dist/indexer/index.js +2 -0
- package/dist/indexer/index.js.map +1 -0
- package/dist/indexer/indexer.d.ts +22 -0
- package/dist/indexer/indexer.d.ts.map +1 -0
- package/dist/indexer/indexer.js +107 -0
- package/dist/indexer/indexer.js.map +1 -0
- package/dist/indexer/indexer.test.d.ts +2 -0
- package/dist/indexer/indexer.test.d.ts.map +1 -0
- package/dist/indexer/indexer.test.js +80 -0
- package/dist/indexer/indexer.test.js.map +1 -0
- package/dist/retrieve/index.d.ts +3 -0
- package/dist/retrieve/index.d.ts.map +1 -0
- package/dist/retrieve/index.js +3 -0
- package/dist/retrieve/index.js.map +1 -0
- package/dist/retrieve/rerank.d.ts +44 -0
- package/dist/retrieve/rerank.d.ts.map +1 -0
- package/dist/retrieve/rerank.js +68 -0
- package/dist/retrieve/rerank.js.map +1 -0
- package/dist/retrieve/rerank.test.d.ts +2 -0
- package/dist/retrieve/rerank.test.d.ts.map +1 -0
- package/dist/retrieve/rerank.test.js +52 -0
- package/dist/retrieve/rerank.test.js.map +1 -0
- package/dist/retrieve/search.d.ts +31 -0
- package/dist/retrieve/search.d.ts.map +1 -0
- package/dist/retrieve/search.js +170 -0
- package/dist/retrieve/search.js.map +1 -0
- package/dist/retrieve/search.test.d.ts +2 -0
- package/dist/retrieve/search.test.d.ts.map +1 -0
- package/dist/retrieve/search.test.js +105 -0
- package/dist/retrieve/search.test.js.map +1 -0
- package/dist/store/index.d.ts +3 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +3 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/schema.d.ts +11 -0
- package/dist/store/schema.d.ts.map +1 -0
- package/dist/store/schema.js +129 -0
- package/dist/store/schema.js.map +1 -0
- package/dist/store/sqlite.d.ts +51 -0
- package/dist/store/sqlite.d.ts.map +1 -0
- package/dist/store/sqlite.js +262 -0
- package/dist/store/sqlite.js.map +1 -0
- package/dist/store/sqlite.test.d.ts +2 -0
- package/dist/store/sqlite.test.d.ts.map +1 -0
- package/dist/store/sqlite.test.js +128 -0
- package/dist/store/sqlite.test.js.map +1 -0
- package/dist/types.d.ts +115 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/util/index.d.ts +15 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +65 -0
- package/dist/util/index.js.map +1 -0
- package/dist/util/index.test.d.ts +2 -0
- package/dist/util/index.test.d.ts.map +1 -0
- package/dist/util/index.test.js +37 -0
- package/dist/util/index.test.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Python entity parser.
|
|
3
|
+
*
|
|
4
|
+
* Strategy: spawn Python's own `ast` module via `python3 -c <script>` and read
|
|
5
|
+
* JSON back. Python ships everywhere a developer's machine runs Python code, so
|
|
6
|
+
* we lean on the runtime that's already there. This works for:
|
|
7
|
+
*
|
|
8
|
+
* • Code from 10 years ago (Python 3.6+)
|
|
9
|
+
* • Code written yesterday by a human
|
|
10
|
+
* • Code generated by an AI assistant (most LLMs emit syntactically valid Python)
|
|
11
|
+
*
|
|
12
|
+
* If Python is not on PATH, the parser raises a clean error rather than guessing
|
|
13
|
+
* with regex. The TypeScript parser remains the default for TS/JS; this one
|
|
14
|
+
* activates per-file based on extension.
|
|
15
|
+
*
|
|
16
|
+
* Why not tree-sitter? Three reasons:
|
|
17
|
+
* 1. tree-sitter native binaries are platform-fragile on Windows.
|
|
18
|
+
* 2. The WASM build (`web-tree-sitter`) requires shipping a grammar `.wasm`
|
|
19
|
+
* file and is fiddly to install.
|
|
20
|
+
* 3. Python's `ast` is the same AST CPython itself uses to compile your code.
|
|
21
|
+
* It cannot be more accurate.
|
|
22
|
+
*/
|
|
23
|
+
import { createHash } from "node:crypto";
|
|
24
|
+
import { spawn } from "node:child_process";
|
|
25
|
+
import { readFile } from "node:fs/promises";
|
|
26
|
+
import { join, extname } from "node:path";
|
|
27
|
+
import { execGit } from "../git/exec.js";
|
|
28
|
+
const PY_EXTENSIONS = new Set([".py", ".pyi"]);
|
|
29
|
+
/**
|
|
30
|
+
* Embedded Python script. Reads source from stdin, emits a JSON list of
|
|
31
|
+
* entities to stdout. Stays under 2k chars so cli args / stdin don't strain.
|
|
32
|
+
*/
|
|
33
|
+
const PY_SCRIPT = String.raw `import sys, json, ast
|
|
34
|
+
src = sys.stdin.read()
|
|
35
|
+
try:
|
|
36
|
+
tree = ast.parse(src)
|
|
37
|
+
except SyntaxError as e:
|
|
38
|
+
json.dump({"error": f"SyntaxError at line {e.lineno}: {e.msg}"}, sys.stdout)
|
|
39
|
+
sys.exit(0)
|
|
40
|
+
|
|
41
|
+
def sig(node):
|
|
42
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
43
|
+
args = [a.arg for a in node.args.args]
|
|
44
|
+
ret = ""
|
|
45
|
+
if node.returns is not None:
|
|
46
|
+
try:
|
|
47
|
+
ret = " -> " + ast.unparse(node.returns)
|
|
48
|
+
except Exception:
|
|
49
|
+
pass
|
|
50
|
+
prefix = "async def " if isinstance(node, ast.AsyncFunctionDef) else "def "
|
|
51
|
+
return f"{prefix}{node.name}({', '.join(args)}){ret}"
|
|
52
|
+
if isinstance(node, ast.ClassDef):
|
|
53
|
+
bases = []
|
|
54
|
+
for b in node.bases:
|
|
55
|
+
try:
|
|
56
|
+
bases.append(ast.unparse(b))
|
|
57
|
+
except Exception:
|
|
58
|
+
bases.append("?")
|
|
59
|
+
suffix = f"({', '.join(bases)})" if bases else ""
|
|
60
|
+
return f"class {node.name}{suffix}"
|
|
61
|
+
return ""
|
|
62
|
+
|
|
63
|
+
out = []
|
|
64
|
+
def is_module_level(parent):
|
|
65
|
+
return isinstance(parent, ast.Module)
|
|
66
|
+
|
|
67
|
+
# Walk: top-level defs + class methods + module-level Assign that look like exports.
|
|
68
|
+
for node in tree.body:
|
|
69
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
70
|
+
out.append({
|
|
71
|
+
"kind": "function",
|
|
72
|
+
"name": node.name,
|
|
73
|
+
"startLine": node.lineno,
|
|
74
|
+
"endLine": getattr(node, "end_lineno", node.lineno) or node.lineno,
|
|
75
|
+
"signature": sig(node),
|
|
76
|
+
})
|
|
77
|
+
elif isinstance(node, ast.ClassDef):
|
|
78
|
+
out.append({
|
|
79
|
+
"kind": "class",
|
|
80
|
+
"name": node.name,
|
|
81
|
+
"startLine": node.lineno,
|
|
82
|
+
"endLine": getattr(node, "end_lineno", node.lineno) or node.lineno,
|
|
83
|
+
"signature": sig(node),
|
|
84
|
+
})
|
|
85
|
+
for sub in node.body:
|
|
86
|
+
if isinstance(sub, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
87
|
+
out.append({
|
|
88
|
+
"kind": "function",
|
|
89
|
+
"name": f"{node.name}.{sub.name}",
|
|
90
|
+
"startLine": sub.lineno,
|
|
91
|
+
"endLine": getattr(sub, "end_lineno", sub.lineno) or sub.lineno,
|
|
92
|
+
"signature": sig(sub),
|
|
93
|
+
})
|
|
94
|
+
elif isinstance(node, ast.Assign):
|
|
95
|
+
for t in node.targets:
|
|
96
|
+
if isinstance(t, ast.Name) and not t.id.startswith("_"):
|
|
97
|
+
out.append({
|
|
98
|
+
"kind": "variable",
|
|
99
|
+
"name": t.id,
|
|
100
|
+
"startLine": node.lineno,
|
|
101
|
+
"endLine": getattr(node, "end_lineno", node.lineno) or node.lineno,
|
|
102
|
+
"signature": "",
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
json.dump(out, sys.stdout)
|
|
106
|
+
`;
|
|
107
|
+
export class PythonParser {
|
|
108
|
+
name = "python-ast";
|
|
109
|
+
languages = ["python"];
|
|
110
|
+
pythonCmd = null;
|
|
111
|
+
/** Detect which Python binary works on this machine. */
|
|
112
|
+
async preload() {
|
|
113
|
+
if (this.pythonCmd)
|
|
114
|
+
return;
|
|
115
|
+
for (const cmd of ["python3", "python"]) {
|
|
116
|
+
const ok = await this.probe(cmd);
|
|
117
|
+
if (ok) {
|
|
118
|
+
this.pythonCmd = cmd;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
throw new Error("Python parser requires `python3` (or `python`) on PATH. Install Python 3.8+ to enable Python entity parsing.");
|
|
123
|
+
}
|
|
124
|
+
async *parseRepo(opts) {
|
|
125
|
+
await this.preload();
|
|
126
|
+
const files = await listPyFiles(opts.cwd, opts.paths);
|
|
127
|
+
let i = 0;
|
|
128
|
+
for (const relPath of files) {
|
|
129
|
+
i++;
|
|
130
|
+
let source;
|
|
131
|
+
try {
|
|
132
|
+
source = await readFile(join(opts.cwd, relPath), "utf8");
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
opts.onProgress?.(i);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const entities = await this.parseSource(relPath, source);
|
|
140
|
+
for (const e of entities)
|
|
141
|
+
yield e;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// best-effort — keep going on bad files
|
|
145
|
+
}
|
|
146
|
+
opts.onProgress?.(i);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
parseFile(_filePath, _source) {
|
|
150
|
+
// Synchronous parse not supported (subprocess-based). Use parseRepo.
|
|
151
|
+
throw new Error("PythonParser.parseFile is not synchronous — call parseSourceAsync() or use parseRepo().");
|
|
152
|
+
}
|
|
153
|
+
async parseSourceAsync(filePath, source) {
|
|
154
|
+
await this.preload();
|
|
155
|
+
return this.parseSource(filePath, source);
|
|
156
|
+
}
|
|
157
|
+
async parseSource(filePath, source) {
|
|
158
|
+
const raw = await this.runPython(source);
|
|
159
|
+
if (!raw)
|
|
160
|
+
return [];
|
|
161
|
+
let parsed;
|
|
162
|
+
try {
|
|
163
|
+
parsed = JSON.parse(raw);
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
168
|
+
if (parsed && typeof parsed === "object" && parsed.error) {
|
|
169
|
+
// Syntax error in the file — emit nothing. This is normal for partial files.
|
|
170
|
+
return [];
|
|
171
|
+
}
|
|
172
|
+
if (!Array.isArray(parsed))
|
|
173
|
+
return [];
|
|
174
|
+
const out = [];
|
|
175
|
+
for (const item of parsed) {
|
|
176
|
+
const kind = String(item.kind);
|
|
177
|
+
const name = String(item.name);
|
|
178
|
+
const startLine = Number(item.startLine);
|
|
179
|
+
const endLine = Number(item.endLine);
|
|
180
|
+
const signature = item.signature ? String(item.signature) : undefined;
|
|
181
|
+
if (!["function", "class", "variable"].includes(kind) || !name || !startLine)
|
|
182
|
+
continue;
|
|
183
|
+
out.push({
|
|
184
|
+
id: stableId(filePath, kind, name, startLine),
|
|
185
|
+
kind: kind,
|
|
186
|
+
name,
|
|
187
|
+
filePath,
|
|
188
|
+
startLine,
|
|
189
|
+
endLine,
|
|
190
|
+
signature,
|
|
191
|
+
language: "python",
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
return out;
|
|
195
|
+
}
|
|
196
|
+
runPython(source) {
|
|
197
|
+
return new Promise((resolve) => {
|
|
198
|
+
if (!this.pythonCmd)
|
|
199
|
+
return resolve("");
|
|
200
|
+
const child = spawn(this.pythonCmd, ["-c", PY_SCRIPT], { windowsHide: true });
|
|
201
|
+
const chunks = [];
|
|
202
|
+
child.stdout.on("data", (b) => chunks.push(b));
|
|
203
|
+
child.stderr.on("data", () => {
|
|
204
|
+
/* swallow — bad files happen, syntax errors come back as JSON */
|
|
205
|
+
});
|
|
206
|
+
child.on("error", () => resolve(""));
|
|
207
|
+
child.on("close", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
208
|
+
child.stdin.end(source, "utf8");
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
probe(cmd) {
|
|
212
|
+
return new Promise((resolve) => {
|
|
213
|
+
const child = spawn(cmd, ["-c", "import sys; print(sys.version_info[0])"], {
|
|
214
|
+
windowsHide: true,
|
|
215
|
+
});
|
|
216
|
+
let out = "";
|
|
217
|
+
child.stdout.on("data", (b) => (out += b.toString()));
|
|
218
|
+
child.on("error", () => resolve(false));
|
|
219
|
+
child.on("close", (code) => {
|
|
220
|
+
resolve(code === 0 && out.trim().startsWith("3"));
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
async function listPyFiles(cwd, paths) {
|
|
226
|
+
const r = await execGit(["ls-files"], { cwd });
|
|
227
|
+
if (r.code !== 0)
|
|
228
|
+
return [];
|
|
229
|
+
const tracked = r.stdout
|
|
230
|
+
.split("\n")
|
|
231
|
+
.map((l) => l.trim())
|
|
232
|
+
.filter(Boolean)
|
|
233
|
+
.filter((p) => PY_EXTENSIONS.has(extname(p).toLowerCase()))
|
|
234
|
+
.filter((p) => !/(^|\/)tests?\//.test(p))
|
|
235
|
+
.filter((p) => !/_test\.py$|\/test_/.test(p))
|
|
236
|
+
.filter((p) => !/(^|\/)(\.venv|venv|__pycache__|dist|build)\//.test(p));
|
|
237
|
+
if (!paths || paths.length === 0)
|
|
238
|
+
return tracked;
|
|
239
|
+
return tracked.filter((p) => paths.some((needle) => p === needle || p.startsWith(needle + "/")));
|
|
240
|
+
}
|
|
241
|
+
function stableId(filePath, kind, name, line) {
|
|
242
|
+
const h = createHash("sha1")
|
|
243
|
+
.update(`${filePath}|${kind}|${name}|${line}`)
|
|
244
|
+
.digest("hex")
|
|
245
|
+
.slice(0, 12);
|
|
246
|
+
return `e_${h}`;
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=python-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"python-parser.js","sourceRoot":"","sources":["../../src/entities/python-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Entity } from "../types.js";
|
|
2
|
+
import type { EntityParser, ParseOptions } from "./index.js";
|
|
3
|
+
export declare class TypeScriptParser implements EntityParser {
|
|
4
|
+
readonly name = "typescript-compiler-api";
|
|
5
|
+
readonly languages: string[];
|
|
6
|
+
private ts;
|
|
7
|
+
parseRepo(opts: ParseOptions): AsyncIterable<Entity>;
|
|
8
|
+
parseFile(filePath: string, source: string): Iterable<Entity>;
|
|
9
|
+
/** Eager-load typescript so subsequent sync parseFile() calls work. */
|
|
10
|
+
preload(): Promise<void>;
|
|
11
|
+
private loadTs;
|
|
12
|
+
private parseSourceFileImpl;
|
|
13
|
+
private emitFromStatement;
|
|
14
|
+
private makeEntity;
|
|
15
|
+
}
|
|
16
|
+
/** For tests: build entity-embedding text from name + signature + signature-extracted body. */
|
|
17
|
+
export declare function entityEmbeddingText(e: Entity, body?: string): string;
|
|
18
|
+
//# sourceMappingURL=typescript-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typescript-parser.d.ts","sourceRoot":"","sources":["../../src/entities/typescript-parser.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK7D,qBAAa,gBAAiB,YAAW,YAAY;IACnD,QAAQ,CAAC,IAAI,6BAA6B;IAC1C,QAAQ,CAAC,SAAS,WAA8C;IAGhE,OAAO,CAAC,EAAE,CAA4C;IAE/C,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,CAAC,MAAM,CAAC;IAsB3D,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAW7D,uEAAuE;IACjE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAIhB,MAAM;IAYpB,OAAO,CAAE,mBAAmB;IAmB5B,OAAO,CAAE,iBAAiB;IAiD1B,OAAO,CAAC,UAAU;CAwBnB;AAsFD,+FAA+F;AAC/F,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAKpE"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript / JavaScript entity parser.
|
|
3
|
+
*
|
|
4
|
+
* Uses the TypeScript compiler API (zero new runtime deps — `typescript` is
|
|
5
|
+
* a soft peer dep). Parses .ts / .tsx / .js / .jsx files into Entity records:
|
|
6
|
+
*
|
|
7
|
+
* function declarations, class declarations, interface declarations,
|
|
8
|
+
* type aliases, exported variable bindings, exported re-exports.
|
|
9
|
+
*
|
|
10
|
+
* Skips: nested closures, IIFEs, anonymous arrow functions assigned to non-
|
|
11
|
+
* exported variables. The goal is "things a human would consider a unit",
|
|
12
|
+
* not every AST node.
|
|
13
|
+
*/
|
|
14
|
+
import { createHash } from "node:crypto";
|
|
15
|
+
import { readFile } from "node:fs/promises";
|
|
16
|
+
import { join, extname } from "node:path";
|
|
17
|
+
import { execGit } from "../git/exec.js";
|
|
18
|
+
const TS_EXTENSIONS = new Set([".ts", ".tsx", ".mts", ".cts"]);
|
|
19
|
+
const JS_EXTENSIONS = new Set([".js", ".jsx", ".mjs", ".cjs"]);
|
|
20
|
+
export class TypeScriptParser {
|
|
21
|
+
name = "typescript-compiler-api";
|
|
22
|
+
languages = ["typescript", "tsx", "javascript", "jsx"];
|
|
23
|
+
// Lazy-loaded to keep `typescript` an optional peer dep.
|
|
24
|
+
ts = null;
|
|
25
|
+
async *parseRepo(opts) {
|
|
26
|
+
const ts = await this.loadTs();
|
|
27
|
+
const files = await listTsJsFiles(opts.cwd, opts.paths);
|
|
28
|
+
let processed = 0;
|
|
29
|
+
for (const relPath of files) {
|
|
30
|
+
const abs = join(opts.cwd, relPath);
|
|
31
|
+
let source;
|
|
32
|
+
try {
|
|
33
|
+
source = await readFile(abs, "utf8");
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
processed++;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const language = languageForPath(relPath);
|
|
40
|
+
for (const e of this.parseSourceFileImpl(relPath, source, language, ts)) {
|
|
41
|
+
yield e;
|
|
42
|
+
}
|
|
43
|
+
processed++;
|
|
44
|
+
opts.onProgress?.(processed);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
parseFile(filePath, source) {
|
|
48
|
+
if (!this.ts) {
|
|
49
|
+
throw new Error("TypeScriptParser.parseFile() requires parseRepo to be called first " +
|
|
50
|
+
"(or call await parser['loadTs']() once). The peer dep `typescript` is loaded lazily.");
|
|
51
|
+
}
|
|
52
|
+
const language = languageForPath(filePath);
|
|
53
|
+
return this.parseSourceFileImpl(filePath, source, language, this.ts);
|
|
54
|
+
}
|
|
55
|
+
/** Eager-load typescript so subsequent sync parseFile() calls work. */
|
|
56
|
+
async preload() {
|
|
57
|
+
await this.loadTs();
|
|
58
|
+
}
|
|
59
|
+
async loadTs() {
|
|
60
|
+
if (this.ts)
|
|
61
|
+
return this.ts;
|
|
62
|
+
try {
|
|
63
|
+
this.ts = await import("typescript");
|
|
64
|
+
return this.ts;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
throw new Error("TypeScriptParser requires the `typescript` package. Install it with: npm install --save-dev typescript");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
*parseSourceFileImpl(filePath, source, language, ts) {
|
|
71
|
+
const sf = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest,
|
|
72
|
+
/* setParentNodes */ true, filePath.endsWith(".tsx") || filePath.endsWith(".jsx") ? ts.ScriptKind.TSX : undefined);
|
|
73
|
+
for (const node of sf.statements) {
|
|
74
|
+
yield* this.emitFromStatement(node, sf, filePath, language, ts);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
*emitFromStatement(node, sf, filePath, language, ts) {
|
|
78
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
79
|
+
yield this.makeEntity("function", node.name.text, node, sf, filePath, language, ts);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (ts.isClassDeclaration(node) && node.name) {
|
|
83
|
+
yield this.makeEntity("class", node.name.text, node, sf, filePath, language, ts);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (ts.isInterfaceDeclaration(node)) {
|
|
87
|
+
yield this.makeEntity("type", node.name.text, node, sf, filePath, language, ts);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (ts.isTypeAliasDeclaration(node)) {
|
|
91
|
+
yield this.makeEntity("type", node.name.text, node, sf, filePath, language, ts);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (ts.isVariableStatement(node)) {
|
|
95
|
+
// Only emit exported variables — anonymous internal bindings would create noise.
|
|
96
|
+
if (!hasModifier(node, ts.SyntaxKind.ExportKeyword, ts))
|
|
97
|
+
return;
|
|
98
|
+
for (const decl of node.declarationList.declarations) {
|
|
99
|
+
if (ts.isIdentifier(decl.name)) {
|
|
100
|
+
// If the initializer is an arrow function or function expression, classify as function.
|
|
101
|
+
const kind = decl.initializer &&
|
|
102
|
+
(ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))
|
|
103
|
+
? "function"
|
|
104
|
+
: "variable";
|
|
105
|
+
yield this.makeEntity(kind, decl.name.text, node, sf, filePath, language, ts);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (ts.isModuleDeclaration(node) && node.name && ts.isIdentifier(node.name)) {
|
|
111
|
+
yield this.makeEntity("module", node.name.text, node, sf, filePath, language, ts);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (ts.isEnumDeclaration(node)) {
|
|
115
|
+
yield this.makeEntity("type", node.name.text, node, sf, filePath, language, ts);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
makeEntity(kind, name, node, sf, filePath, language, ts) {
|
|
120
|
+
const start = sf.getLineAndCharacterOfPosition(node.getStart(sf, /*includeJsDoc*/ false));
|
|
121
|
+
const end = sf.getLineAndCharacterOfPosition(node.getEnd());
|
|
122
|
+
const signature = extractSignature(node, sf, ts);
|
|
123
|
+
const id = stableId(filePath, kind, name, start.line);
|
|
124
|
+
return {
|
|
125
|
+
id,
|
|
126
|
+
kind,
|
|
127
|
+
name,
|
|
128
|
+
filePath,
|
|
129
|
+
startLine: start.line + 1,
|
|
130
|
+
endLine: end.line + 1,
|
|
131
|
+
signature,
|
|
132
|
+
language,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/** Use git ls-files when available — automatic .gitignore respect. Fall back to filesystem walk. */
|
|
137
|
+
async function listTsJsFiles(cwd, paths) {
|
|
138
|
+
const r = await execGit(["ls-files"], { cwd });
|
|
139
|
+
if (r.code !== 0) {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
const all = r.stdout
|
|
143
|
+
.split("\n")
|
|
144
|
+
.map((l) => l.trim())
|
|
145
|
+
.filter(Boolean);
|
|
146
|
+
const tracked = all.filter((p) => {
|
|
147
|
+
const ext = extname(p).toLowerCase();
|
|
148
|
+
if (!TS_EXTENSIONS.has(ext) && !JS_EXTENSIONS.has(ext))
|
|
149
|
+
return false;
|
|
150
|
+
// Skip type declaration files — they expose types but no implementation.
|
|
151
|
+
if (p.endsWith(".d.ts"))
|
|
152
|
+
return false;
|
|
153
|
+
// Skip tests by default — they tend to dominate clone clusters with assertion plumbing.
|
|
154
|
+
if (/(^|\/)tests?\//.test(p))
|
|
155
|
+
return false;
|
|
156
|
+
if (/\.(test|spec)\./.test(p))
|
|
157
|
+
return false;
|
|
158
|
+
return true;
|
|
159
|
+
});
|
|
160
|
+
if (!paths || paths.length === 0)
|
|
161
|
+
return tracked;
|
|
162
|
+
return tracked.filter((p) => paths.some((needle) => p === needle || p.startsWith(needle + "/")));
|
|
163
|
+
}
|
|
164
|
+
function languageForPath(p) {
|
|
165
|
+
const ext = extname(p).toLowerCase();
|
|
166
|
+
if (ext === ".ts" || ext === ".mts" || ext === ".cts")
|
|
167
|
+
return "typescript";
|
|
168
|
+
if (ext === ".tsx")
|
|
169
|
+
return "tsx";
|
|
170
|
+
if (ext === ".jsx")
|
|
171
|
+
return "jsx";
|
|
172
|
+
return "javascript";
|
|
173
|
+
}
|
|
174
|
+
function hasModifier(node, kind, ts) {
|
|
175
|
+
// `node.modifiers` is preferred but on some node kinds we still need ts.canHaveModifiers.
|
|
176
|
+
const mods = ts.canHaveModifiers?.(node)
|
|
177
|
+
? ts.getModifiers(node)
|
|
178
|
+
: node.modifiers;
|
|
179
|
+
return Array.isArray(mods) && mods.some((m) => m.kind === kind);
|
|
180
|
+
}
|
|
181
|
+
function extractSignature(node, sf, ts) {
|
|
182
|
+
// For functions/methods grab everything up to the opening brace.
|
|
183
|
+
if (ts.isFunctionDeclaration(node) ||
|
|
184
|
+
ts.isMethodDeclaration(node) ||
|
|
185
|
+
ts.isFunctionExpression(node) ||
|
|
186
|
+
ts.isArrowFunction(node)) {
|
|
187
|
+
const text = node.getText(sf);
|
|
188
|
+
const braceIdx = text.indexOf("{");
|
|
189
|
+
return braceIdx >= 0 ? text.slice(0, braceIdx).trim() : text.trim().slice(0, 200);
|
|
190
|
+
}
|
|
191
|
+
if (ts.isClassDeclaration(node) && node.name) {
|
|
192
|
+
const text = node.getText(sf);
|
|
193
|
+
const braceIdx = text.indexOf("{");
|
|
194
|
+
return braceIdx >= 0 ? text.slice(0, braceIdx).trim() : text.trim().slice(0, 200);
|
|
195
|
+
}
|
|
196
|
+
if (ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)) {
|
|
197
|
+
return node.getText(sf).slice(0, 200).trim();
|
|
198
|
+
}
|
|
199
|
+
if (ts.isVariableStatement(node)) {
|
|
200
|
+
return node.getText(sf).slice(0, 160).trim();
|
|
201
|
+
}
|
|
202
|
+
return node.getText(sf).slice(0, 120).trim();
|
|
203
|
+
}
|
|
204
|
+
function stableId(filePath, kind, name, line) {
|
|
205
|
+
const h = createHash("sha1")
|
|
206
|
+
.update(`${filePath}|${kind}|${name}|${line}`)
|
|
207
|
+
.digest("hex")
|
|
208
|
+
.slice(0, 12);
|
|
209
|
+
return `e_${h}`;
|
|
210
|
+
}
|
|
211
|
+
/** For tests: build entity-embedding text from name + signature + signature-extracted body. */
|
|
212
|
+
export function entityEmbeddingText(e, body) {
|
|
213
|
+
const parts = [`${e.kind} ${e.name}`];
|
|
214
|
+
if (e.signature)
|
|
215
|
+
parts.push(e.signature);
|
|
216
|
+
if (body)
|
|
217
|
+
parts.push(body.slice(0, 600));
|
|
218
|
+
return parts.join("\n");
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=typescript-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typescript-parser.js","sourceRoot":"","sources":["../../src/entities/typescript-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typescript-parser.test.d.ts","sourceRoot":"","sources":["../../src/entities/typescript-parser.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll } from "vitest";
|
|
2
|
+
import { TypeScriptParser } from "./typescript-parser.js";
|
|
3
|
+
let parser;
|
|
4
|
+
beforeAll(async () => {
|
|
5
|
+
parser = new TypeScriptParser();
|
|
6
|
+
await parser.preload();
|
|
7
|
+
});
|
|
8
|
+
function parse(filePath, source) {
|
|
9
|
+
return Array.from(parser.parseFile(filePath, source));
|
|
10
|
+
}
|
|
11
|
+
describe("TypeScriptParser", () => {
|
|
12
|
+
it("extracts function declarations", () => {
|
|
13
|
+
const out = parse("x.ts", `
|
|
14
|
+
export function charge(amount: number): number {
|
|
15
|
+
return amount;
|
|
16
|
+
}
|
|
17
|
+
`);
|
|
18
|
+
expect(out).toHaveLength(1);
|
|
19
|
+
expect(out[0].kind).toBe("function");
|
|
20
|
+
expect(out[0].name).toBe("charge");
|
|
21
|
+
expect(out[0].signature).toContain("charge(amount: number): number");
|
|
22
|
+
});
|
|
23
|
+
it("extracts class declarations", () => {
|
|
24
|
+
const out = parse("x.ts", `
|
|
25
|
+
export class OrderQueue {
|
|
26
|
+
enqueue(x: any) {}
|
|
27
|
+
}
|
|
28
|
+
`);
|
|
29
|
+
const cls = out.find((e) => e.kind === "class");
|
|
30
|
+
expect(cls).toBeDefined();
|
|
31
|
+
expect(cls.name).toBe("OrderQueue");
|
|
32
|
+
});
|
|
33
|
+
it("extracts interfaces and type aliases as 'type'", () => {
|
|
34
|
+
const out = parse("x.ts", `
|
|
35
|
+
export interface User { id: string; }
|
|
36
|
+
export type Email = string;
|
|
37
|
+
`);
|
|
38
|
+
const kinds = out.filter((e) => e.kind === "type").map((e) => e.name);
|
|
39
|
+
expect(kinds).toContain("User");
|
|
40
|
+
expect(kinds).toContain("Email");
|
|
41
|
+
});
|
|
42
|
+
it("treats exported arrow functions as 'function' kind", () => {
|
|
43
|
+
const out = parse("x.ts", `export const handler = (x: number) => x + 1;`);
|
|
44
|
+
expect(out).toHaveLength(1);
|
|
45
|
+
expect(out[0].kind).toBe("function");
|
|
46
|
+
expect(out[0].name).toBe("handler");
|
|
47
|
+
});
|
|
48
|
+
it("treats exported plain values as 'variable' kind", () => {
|
|
49
|
+
const out = parse("x.ts", `export const VERSION = "0.2.0";`);
|
|
50
|
+
expect(out[0].kind).toBe("variable");
|
|
51
|
+
expect(out[0].name).toBe("VERSION");
|
|
52
|
+
});
|
|
53
|
+
it("does not emit non-exported variables", () => {
|
|
54
|
+
const out = parse("x.ts", `
|
|
55
|
+
const internal = 42;
|
|
56
|
+
export const exposed = 1;
|
|
57
|
+
`);
|
|
58
|
+
const names = out.map((e) => e.name);
|
|
59
|
+
expect(names).not.toContain("internal");
|
|
60
|
+
expect(names).toContain("exposed");
|
|
61
|
+
});
|
|
62
|
+
it("captures startLine and endLine accurately", () => {
|
|
63
|
+
const src = [
|
|
64
|
+
"// line 1",
|
|
65
|
+
"// line 2",
|
|
66
|
+
"export function foo() {",
|
|
67
|
+
" return 1;",
|
|
68
|
+
"}",
|
|
69
|
+
].join("\n");
|
|
70
|
+
const [foo] = parse("x.ts", src);
|
|
71
|
+
expect(foo.startLine).toBe(3);
|
|
72
|
+
expect(foo.endLine).toBe(5);
|
|
73
|
+
});
|
|
74
|
+
it("produces stable, file-specific ids", () => {
|
|
75
|
+
const a = parse("a.ts", "export function f() {}");
|
|
76
|
+
const b = parse("b.ts", "export function f() {}");
|
|
77
|
+
expect(a[0].id).not.toBe(b[0].id);
|
|
78
|
+
const a2 = parse("a.ts", "export function f() {}");
|
|
79
|
+
expect(a[0].id).toBe(a2[0].id);
|
|
80
|
+
});
|
|
81
|
+
it("handles TSX files", () => {
|
|
82
|
+
const out = parse("Component.tsx", `export function Button(props: { label: string }) {
|
|
83
|
+
return <button>{props.label}</button>;
|
|
84
|
+
}`);
|
|
85
|
+
expect(out).toHaveLength(1);
|
|
86
|
+
expect(out[0].language).toBe("tsx");
|
|
87
|
+
});
|
|
88
|
+
it("handles JS files", () => {
|
|
89
|
+
const out = parse("a.js", `export function add(a, b) { return a + b; }`);
|
|
90
|
+
expect(out[0].language).toBe("javascript");
|
|
91
|
+
});
|
|
92
|
+
it("extracts multiple top-level statements", () => {
|
|
93
|
+
const out = parse("x.ts", `
|
|
94
|
+
export function a() {}
|
|
95
|
+
export class B {}
|
|
96
|
+
export interface C {}
|
|
97
|
+
export const d = 1;
|
|
98
|
+
export const e = () => 2;
|
|
99
|
+
`);
|
|
100
|
+
expect(out.map((e) => e.name).sort()).toEqual(["B", "C", "a", "d", "e"]);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
//# sourceMappingURL=typescript-parser.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typescript-parser.test.js","sourceRoot":"","sources":["../../src/entities/typescript-parser.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface BlameLine {
|
|
2
|
+
commitHash: string;
|
|
3
|
+
authorName: string;
|
|
4
|
+
authorTime: number;
|
|
5
|
+
lineNumber: number;
|
|
6
|
+
content: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function blame(cwd: string, filePath: string, startLine?: number, endLine?: number): Promise<BlameLine[]>;
|
|
9
|
+
//# sourceMappingURL=blame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blame.d.ts","sourceRoot":"","sources":["../../src/git/blame.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,KAAK,CACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,SAAS,EAAE,CAAC,CAQtB"}
|