@kurtel/cli 0.1.14 → 0.1.15
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/dist/memory/ast.js +216 -1
- package/dist/memory/indexer.js +1 -1
- package/package.json +1 -1
package/dist/memory/ast.js
CHANGED
|
@@ -17,6 +17,10 @@ function grammarFor(ext) {
|
|
|
17
17
|
case ".mjs":
|
|
18
18
|
case ".cjs": return "javascript"; // jsx couvert par la grammaire JS
|
|
19
19
|
case ".py": return "python";
|
|
20
|
+
case ".java": return "java";
|
|
21
|
+
case ".go": return "go";
|
|
22
|
+
case ".rs": return "rust";
|
|
23
|
+
case ".cs": return "c_sharp";
|
|
20
24
|
default: return null;
|
|
21
25
|
}
|
|
22
26
|
}
|
|
@@ -324,6 +328,196 @@ function extractPy(rel, src, root) {
|
|
|
324
328
|
}
|
|
325
329
|
return facts;
|
|
326
330
|
}
|
|
331
|
+
// ── Java ─────────────────────────────────────────────────────────────────────
|
|
332
|
+
const JAVA_DEF_KINDS = new Set(["method_declaration", "constructor_declaration"]);
|
|
333
|
+
const SPRING_MAPPINGS = {
|
|
334
|
+
GetMapping: "GET", PostMapping: "POST", PutMapping: "PUT",
|
|
335
|
+
DeleteMapping: "DELETE", PatchMapping: "PATCH", RequestMapping: "*",
|
|
336
|
+
};
|
|
337
|
+
function extractJava(rel, src, root) {
|
|
338
|
+
const facts = emptyFacts(rel, src);
|
|
339
|
+
for (const imp of root.descendantsOfType("import_declaration")) {
|
|
340
|
+
const id = imp.descendantsOfType("scoped_identifier")[0] ?? imp.namedChildren[0];
|
|
341
|
+
if (id) {
|
|
342
|
+
const full = id.text;
|
|
343
|
+
const cls = full.split(".").pop();
|
|
344
|
+
facts.importSpecs.push(full);
|
|
345
|
+
if (cls && /^[A-Z]/.test(cls))
|
|
346
|
+
facts.namedImports[cls] = full;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
for (const m of root.descendantsOfType(["method_declaration", "constructor_declaration"])) {
|
|
350
|
+
const name = m.childForFieldName("name");
|
|
351
|
+
if (name) {
|
|
352
|
+
facts.defs.push({ name: name.text, line: line(m) });
|
|
353
|
+
facts.exports.push(name.text);
|
|
354
|
+
}
|
|
355
|
+
for (const ann of m.descendantsOfType(["annotation", "marker_annotation"])) {
|
|
356
|
+
const an = ann.childForFieldName("name")?.text;
|
|
357
|
+
if (an && SPRING_MAPPINGS[an]) {
|
|
358
|
+
const arg = ann.descendantsOfType("string_literal")[0];
|
|
359
|
+
facts.routes.push({ method: SPRING_MAPPINGS[an], path: arg ? stripQuotes(arg.text) : "", file: rel, line: line(ann), framework: "spring" });
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
for (const c of root.descendantsOfType(["class_declaration", "interface_declaration", "enum_declaration"])) {
|
|
364
|
+
const name = c.childForFieldName("name");
|
|
365
|
+
if (name)
|
|
366
|
+
facts.exports.push(name.text);
|
|
367
|
+
}
|
|
368
|
+
for (const call of root.descendantsOfType("method_invocation")) {
|
|
369
|
+
const name = call.childForFieldName("name");
|
|
370
|
+
const obj = call.childForFieldName("object");
|
|
371
|
+
const owner = enclosingDefLine(call, JAVA_DEF_KINDS, (n) => n.childForFieldName("name"));
|
|
372
|
+
if (obj && /^[A-Z]/.test(obj.text))
|
|
373
|
+
facts.rawCalls.push({ name: obj.text + ".", line: line(call), owner });
|
|
374
|
+
if (name)
|
|
375
|
+
facts.rawCalls.push({ name: name.text, line: line(call), owner });
|
|
376
|
+
}
|
|
377
|
+
return facts;
|
|
378
|
+
}
|
|
379
|
+
// ── Go ───────────────────────────────────────────────────────────────────────
|
|
380
|
+
const GO_DEF_KINDS = new Set(["function_declaration", "method_declaration"]);
|
|
381
|
+
function extractGo(rel, src, root) {
|
|
382
|
+
const facts = emptyFacts(rel, src);
|
|
383
|
+
for (const spec of root.descendantsOfType("import_spec")) {
|
|
384
|
+
const path = spec.childForFieldName("path");
|
|
385
|
+
if (path) {
|
|
386
|
+
const p = stripQuotes(path.text);
|
|
387
|
+
facts.importSpecs.push(p);
|
|
388
|
+
const pkg = p.split("/").pop();
|
|
389
|
+
if (pkg)
|
|
390
|
+
facts.namedImports[pkg] = p;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
for (const fn of root.descendantsOfType(["function_declaration", "method_declaration"])) {
|
|
394
|
+
const name = fn.childForFieldName("name");
|
|
395
|
+
if (name) {
|
|
396
|
+
facts.defs.push({ name: name.text, line: line(fn) });
|
|
397
|
+
if (/^[A-Z]/.test(name.text))
|
|
398
|
+
facts.exports.push(name.text);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
for (const ts of root.descendantsOfType("type_spec")) {
|
|
402
|
+
const name = ts.childForFieldName("name");
|
|
403
|
+
if (name && /^[A-Z]/.test(name.text))
|
|
404
|
+
facts.exports.push(name.text);
|
|
405
|
+
}
|
|
406
|
+
for (const call of root.descendantsOfType("call_expression")) {
|
|
407
|
+
const fn = call.childForFieldName("function");
|
|
408
|
+
const owner = enclosingDefLine(call, GO_DEF_KINDS, (n) => n.childForFieldName("name"));
|
|
409
|
+
if (!fn)
|
|
410
|
+
continue;
|
|
411
|
+
if (fn.type === "identifier") {
|
|
412
|
+
facts.rawCalls.push({ name: fn.text, line: line(call), owner });
|
|
413
|
+
}
|
|
414
|
+
else if (fn.type === "selector_expression") {
|
|
415
|
+
const operand = fn.childForFieldName("operand");
|
|
416
|
+
if (operand?.type === "identifier")
|
|
417
|
+
facts.rawCalls.push({ name: operand.text + ".", line: line(call), owner });
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return facts;
|
|
421
|
+
}
|
|
422
|
+
// ── Rust ─────────────────────────────────────────────────────────────────────
|
|
423
|
+
const RUST_DEF_KINDS = new Set(["function_item"]);
|
|
424
|
+
function extractRust(rel, src, root) {
|
|
425
|
+
const facts = emptyFacts(rel, src);
|
|
426
|
+
for (const use of root.descendantsOfType("use_declaration")) {
|
|
427
|
+
const full = use.text.replace(/^use\s+/, "").replace(/;$/, "").trim();
|
|
428
|
+
const parts = full.split("::");
|
|
429
|
+
if (parts.length >= 2) {
|
|
430
|
+
const name = parts[parts.length - 1].replace(/[{}\s].*$/, "");
|
|
431
|
+
const path = parts.slice(0, -1).join("/").replace(/^crate\//, "src/").replace(/^crate$/, "src");
|
|
432
|
+
facts.importSpecs.push(path);
|
|
433
|
+
if (/^[a-z_]\w*$/i.test(name))
|
|
434
|
+
facts.namedImports[name] = path;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
for (const fn of root.descendantsOfType("function_item")) {
|
|
438
|
+
const name = fn.childForFieldName("name");
|
|
439
|
+
if (name) {
|
|
440
|
+
facts.defs.push({ name: name.text, line: line(fn) });
|
|
441
|
+
if (fn.children.some((c) => c.type === "visibility_modifier"))
|
|
442
|
+
facts.exports.push(name.text);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
for (const s of root.descendantsOfType(["struct_item", "enum_item", "trait_item"])) {
|
|
446
|
+
const name = s.childForFieldName("name");
|
|
447
|
+
if (name)
|
|
448
|
+
facts.exports.push(name.text);
|
|
449
|
+
}
|
|
450
|
+
for (const call of root.descendantsOfType("call_expression")) {
|
|
451
|
+
const fn = call.childForFieldName("function");
|
|
452
|
+
const owner = enclosingDefLine(call, RUST_DEF_KINDS, (n) => n.childForFieldName("name"));
|
|
453
|
+
if (!fn)
|
|
454
|
+
continue;
|
|
455
|
+
if (fn.type === "identifier") {
|
|
456
|
+
facts.rawCalls.push({ name: fn.text, line: line(call), owner });
|
|
457
|
+
}
|
|
458
|
+
else if (fn.type === "scoped_identifier") {
|
|
459
|
+
const name = fn.descendantsOfType("identifier").pop();
|
|
460
|
+
if (name)
|
|
461
|
+
facts.rawCalls.push({ name: name.text, line: line(call), owner });
|
|
462
|
+
}
|
|
463
|
+
else if (fn.type === "field_expression") {
|
|
464
|
+
const field = fn.childForFieldName("field");
|
|
465
|
+
if (field)
|
|
466
|
+
facts.rawCalls.push({ name: field.text, line: line(call), owner });
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return facts;
|
|
470
|
+
}
|
|
471
|
+
// ── C# ───────────────────────────────────────────────────────────────────────
|
|
472
|
+
const CS_DEF_KINDS = new Set(["method_declaration", "constructor_declaration"]);
|
|
473
|
+
const CS_HTTP_ATTRS = {
|
|
474
|
+
HttpGet: "GET", HttpPost: "POST", HttpPut: "PUT", HttpDelete: "DELETE", HttpPatch: "PATCH", Route: "*",
|
|
475
|
+
};
|
|
476
|
+
function extractCSharp(rel, src, root) {
|
|
477
|
+
const facts = emptyFacts(rel, src);
|
|
478
|
+
for (const u of root.descendantsOfType("using_directive")) {
|
|
479
|
+
const name = u.descendantsOfType("qualified_name")[0] ?? u.descendantsOfType("identifier")[0];
|
|
480
|
+
if (name)
|
|
481
|
+
facts.importSpecs.push(name.text);
|
|
482
|
+
}
|
|
483
|
+
for (const m of root.descendantsOfType(["method_declaration", "constructor_declaration"])) {
|
|
484
|
+
const name = m.childForFieldName("name");
|
|
485
|
+
if (name) {
|
|
486
|
+
facts.defs.push({ name: name.text, line: line(m) });
|
|
487
|
+
facts.exports.push(name.text);
|
|
488
|
+
}
|
|
489
|
+
for (const attr of m.descendantsOfType("attribute")) {
|
|
490
|
+
const an = attr.childForFieldName("name")?.text;
|
|
491
|
+
if (an && CS_HTTP_ATTRS[an]) {
|
|
492
|
+
const arg = attr.descendantsOfType("string_literal")[0];
|
|
493
|
+
facts.routes.push({ method: CS_HTTP_ATTRS[an], path: arg ? stripQuotes(arg.text) : "", file: rel, line: line(attr), framework: "aspnet" });
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
for (const c of root.descendantsOfType(["class_declaration", "interface_declaration", "record_declaration"])) {
|
|
498
|
+
const name = c.childForFieldName("name");
|
|
499
|
+
if (name)
|
|
500
|
+
facts.exports.push(name.text);
|
|
501
|
+
}
|
|
502
|
+
for (const call of root.descendantsOfType("invocation_expression")) {
|
|
503
|
+
const fn = call.childForFieldName("function");
|
|
504
|
+
const owner = enclosingDefLine(call, CS_DEF_KINDS, (n) => n.childForFieldName("name"));
|
|
505
|
+
if (!fn)
|
|
506
|
+
continue;
|
|
507
|
+
if (fn.type === "identifier") {
|
|
508
|
+
facts.rawCalls.push({ name: fn.text, line: line(call), owner });
|
|
509
|
+
}
|
|
510
|
+
else if (fn.type === "member_access_expression") {
|
|
511
|
+
const obj = fn.childForFieldName("expression");
|
|
512
|
+
const name = fn.childForFieldName("name");
|
|
513
|
+
if (obj?.type === "identifier" && /^[A-Z]/.test(obj.text))
|
|
514
|
+
facts.rawCalls.push({ name: obj.text + ".", line: line(call), owner });
|
|
515
|
+
if (name)
|
|
516
|
+
facts.rawCalls.push({ name: name.text, line: line(call), owner });
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return facts;
|
|
520
|
+
}
|
|
327
521
|
// ── Point d'entrée ───────────────────────────────────────────────────────────
|
|
328
522
|
const MAX_DEFS = 40;
|
|
329
523
|
const MAX_CALLS = 1000;
|
|
@@ -336,7 +530,28 @@ export async function extractFileAst(rel, src, ext) {
|
|
|
336
530
|
try {
|
|
337
531
|
ctx.parser.setLanguage(ctx.lang);
|
|
338
532
|
tree = ctx.parser.parse(src);
|
|
339
|
-
const
|
|
533
|
+
const root = tree.rootNode;
|
|
534
|
+
let facts;
|
|
535
|
+
switch (ext) {
|
|
536
|
+
case ".py":
|
|
537
|
+
facts = extractPy(rel, src, root);
|
|
538
|
+
break;
|
|
539
|
+
case ".java":
|
|
540
|
+
facts = extractJava(rel, src, root);
|
|
541
|
+
break;
|
|
542
|
+
case ".go":
|
|
543
|
+
facts = extractGo(rel, src, root);
|
|
544
|
+
break;
|
|
545
|
+
case ".rs":
|
|
546
|
+
facts = extractRust(rel, src, root);
|
|
547
|
+
break;
|
|
548
|
+
case ".cs":
|
|
549
|
+
facts = extractCSharp(rel, src, root);
|
|
550
|
+
break;
|
|
551
|
+
default:
|
|
552
|
+
facts = extractJs(rel, src, root);
|
|
553
|
+
break; // ts/tsx/js/jsx
|
|
554
|
+
}
|
|
340
555
|
// Bornes + dédupe defs (première occurrence par nom), tri par ligne — comme la voie regex.
|
|
341
556
|
const seen = new Set();
|
|
342
557
|
facts.defs = facts.defs
|
package/dist/memory/indexer.js
CHANGED
|
@@ -8,7 +8,7 @@ import { extractFileAst, nextRouteFor } from "./ast.js";
|
|
|
8
8
|
// output). Heuristiques regex pragmatiques pour TS/JS/Python ; le point
|
|
9
9
|
// d'extension propre pour passer à tree-sitter plus tard est extractFile().
|
|
10
10
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
11
|
-
const CODE_EXT = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py"]);
|
|
11
|
+
const CODE_EXT = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".java", ".go", ".rs", ".cs"]);
|
|
12
12
|
const IGNORE_DIRS = new Set([
|
|
13
13
|
"node_modules", ".git", "dist", "build", "out", ".next", ".nuxt", "coverage",
|
|
14
14
|
"vendor", "__pycache__", ".venv", "venv", ".kurtel", ".claude", ".idea", ".vscode",
|