@maxgfr/codeindex 2.7.0
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 +115 -0
- package/docs/MIGRATION.md +100 -0
- package/package.json +89 -0
- package/scripts/cli.mjs +10 -0
- package/scripts/engine.d.mts +618 -0
- package/scripts/engine.mjs +10655 -0
- package/scripts/grammars/bash.wasm +0 -0
- package/scripts/grammars/c.wasm +0 -0
- package/scripts/grammars/c_sharp.wasm +0 -0
- package/scripts/grammars/cpp.wasm +0 -0
- package/scripts/grammars/go.wasm +0 -0
- package/scripts/grammars/java.wasm +0 -0
- package/scripts/grammars/javascript.wasm +0 -0
- package/scripts/grammars/lua.wasm +0 -0
- package/scripts/grammars/php.wasm +0 -0
- package/scripts/grammars/python.wasm +0 -0
- package/scripts/grammars/ruby.wasm +0 -0
- package/scripts/grammars/rust.wasm +0 -0
- package/scripts/grammars/scala.wasm +0 -0
- package/scripts/grammars/tsx.wasm +0 -0
- package/scripts/grammars/typescript.wasm +0 -0
- package/scripts/grammars/web-tree-sitter.wasm +0 -0
- package/src/ast/extract.ts +713 -0
- package/src/ast/loader.ts +104 -0
- package/src/bm25.ts +156 -0
- package/src/callers.ts +0 -0
- package/src/calls.ts +131 -0
- package/src/categorize.ts +80 -0
- package/src/centrality.ts +148 -0
- package/src/classify.ts +53 -0
- package/src/cli-entry.ts +16 -0
- package/src/community.ts +345 -0
- package/src/complexity.ts +69 -0
- package/src/coupling.ts +0 -0
- package/src/deadcode.ts +46 -0
- package/src/edit.ts +93 -0
- package/src/engine-cli.ts +278 -0
- package/src/engine.ts +148 -0
- package/src/extract/code.ts +376 -0
- package/src/extract/markdown.ts +135 -0
- package/src/git.ts +205 -0
- package/src/glob.ts +56 -0
- package/src/graph.ts +0 -0
- package/src/grep.ts +115 -0
- package/src/hash.ts +13 -0
- package/src/ignore.ts +134 -0
- package/src/lang/c.ts +26 -0
- package/src/lang/common.ts +68 -0
- package/src/lang/csharp.ts +22 -0
- package/src/lang/elixir.ts +18 -0
- package/src/lang/go.ts +22 -0
- package/src/lang/java.ts +19 -0
- package/src/lang/js-ts.ts +112 -0
- package/src/lang/kotlin.ts +20 -0
- package/src/lang/lua.ts +18 -0
- package/src/lang/php.ts +24 -0
- package/src/lang/python.ts +22 -0
- package/src/lang/registry.ts +54 -0
- package/src/lang/ruby.ts +17 -0
- package/src/lang/rust.ts +22 -0
- package/src/lang/scala.ts +19 -0
- package/src/lang/shell.ts +17 -0
- package/src/lang/swift.ts +23 -0
- package/src/mcp.ts +512 -0
- package/src/memory.ts +75 -0
- package/src/modules.ts +128 -0
- package/src/pipeline.ts +59 -0
- package/src/query.ts +118 -0
- package/src/render/graph-json.ts +16 -0
- package/src/render/symbols-json.ts +79 -0
- package/src/repomap.ts +52 -0
- package/src/resolve.ts +950 -0
- package/src/rules.ts +249 -0
- package/src/scan.ts +172 -0
- package/src/sort.ts +12 -0
- package/src/surprise.ts +58 -0
- package/src/tests-map.ts +105 -0
- package/src/types.ts +201 -0
- package/src/util.ts +169 -0
- package/src/viz.ts +44 -0
- package/src/walk.ts +216 -0
- package/src/workspaces.ts +748 -0
package/src/lang/go.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CodeSymbol } from "../types.js";
|
|
2
|
+
import { scan, type Rule } from "./common.js";
|
|
3
|
+
|
|
4
|
+
// Go. Exported identifiers start with an uppercase letter — that drives the
|
|
5
|
+
// `exported` flag. Methods carry a receiver: `func (r T) Name(...)`.
|
|
6
|
+
const upper = (name: string) => /^[A-Z]/.test(name);
|
|
7
|
+
|
|
8
|
+
const RULES: Rule[] = [
|
|
9
|
+
{ re: /^func\s+\([^)]*\)\s+(?<name>[\w]+)\s*\(/, kind: "method", exported: (m) => upper(m.groups!.name!) },
|
|
10
|
+
{ re: /^func\s+(?<name>[\w]+)\s*\(/, kind: "function", exported: (m) => upper(m.groups!.name!) },
|
|
11
|
+
{ re: /^type\s+(?<name>[\w]+)\s+struct\b/, kind: "struct", exported: (m) => upper(m.groups!.name!) },
|
|
12
|
+
{ re: /^type\s+(?<name>[\w]+)\s+interface\b/, kind: "interface", exported: (m) => upper(m.groups!.name!) },
|
|
13
|
+
{ re: /^type\s+(?<name>[\w]+)\s+/, kind: "type", exported: (m) => upper(m.groups!.name!) },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
export const go = {
|
|
17
|
+
lang: "go",
|
|
18
|
+
exts: [".go"],
|
|
19
|
+
extract(rel: string, content: string): CodeSymbol[] {
|
|
20
|
+
return scan(rel, content, "go", RULES);
|
|
21
|
+
},
|
|
22
|
+
};
|
package/src/lang/java.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CodeSymbol } from "../types.js";
|
|
2
|
+
import { scan, type Rule } from "./common.js";
|
|
3
|
+
|
|
4
|
+
// Java. Types and methods, with `public` driving the exported flag. The method
|
|
5
|
+
// rule is conservative: a visibility modifier, a return type, then `name(`.
|
|
6
|
+
const RULES: Rule[] = [
|
|
7
|
+
{ re: /^\s*(?:public|protected|private)?\s*(?:abstract\s+|final\s+)?class\s+(?<name>[\w]+)/, kind: "class", exported: (_m, l) => /\bpublic\b/.test(l) },
|
|
8
|
+
{ re: /^\s*(?:public|protected|private)?\s*interface\s+(?<name>[\w]+)/, kind: "interface", exported: (_m, l) => /\bpublic\b/.test(l) },
|
|
9
|
+
{ re: /^\s*(?:public|protected|private)?\s*enum\s+(?<name>[\w]+)/, kind: "enum", exported: (_m, l) => /\bpublic\b/.test(l) },
|
|
10
|
+
{ re: /^\s*(?:public|protected|private)\s+(?:static\s+|final\s+|abstract\s+|synchronized\s+)*[\w<>\[\],.?\s]+\s+(?<name>[\w]+)\s*\(/, kind: "method", exported: (_m, l) => /\bpublic\b/.test(l) },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
export const java = {
|
|
14
|
+
lang: "java",
|
|
15
|
+
exts: [".java"],
|
|
16
|
+
extract(rel: string, content: string): CodeSymbol[] {
|
|
17
|
+
return scan(rel, content, "java", RULES);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { CodeSymbol } from "../types.js";
|
|
2
|
+
import { scan, type Rule } from "./common.js";
|
|
3
|
+
|
|
4
|
+
// JavaScript / TypeScript. Heuristic, line-based: catches top-level
|
|
5
|
+
// declarations and their `export` status, which is what drives ranking and
|
|
6
|
+
// "where is X defined" navigation.
|
|
7
|
+
const RULES: Rule[] = [
|
|
8
|
+
{ re: /^\s*export\s+(?:async\s+)?function\s+(?<name>[\w$]+)/, kind: "function", exported: true },
|
|
9
|
+
{ re: /^\s*export\s+default\s+(?:async\s+)?function\s+(?<name>[\w$]+)/, kind: "function", exported: true },
|
|
10
|
+
{ re: /^\s*export\s+default\s+(?:abstract\s+)?class\s+(?<name>[\w$]+)/, kind: "class", exported: true },
|
|
11
|
+
{ re: /^\s*(?:async\s+)?function\s+(?<name>[\w$]+)/, kind: "function", exported: false },
|
|
12
|
+
{ re: /^\s*export\s+(?:abstract\s+)?class\s+(?<name>[\w$]+)/, kind: "class", exported: true },
|
|
13
|
+
{ re: /^\s*(?:abstract\s+)?class\s+(?<name>[\w$]+)/, kind: "class", exported: false },
|
|
14
|
+
{ re: /^\s*export\s+interface\s+(?<name>[\w$]+)/, kind: "interface", exported: true },
|
|
15
|
+
{ re: /^\s*interface\s+(?<name>[\w$]+)/, kind: "interface", exported: false },
|
|
16
|
+
{ re: /^\s*export\s+type\s+(?<name>[\w$]+)/, kind: "type", exported: true },
|
|
17
|
+
{ re: /^\s*type\s+(?<name>[\w$]+)\s*[=<]/, kind: "type", exported: false },
|
|
18
|
+
{ re: /^\s*export\s+enum\s+(?<name>[\w$]+)/, kind: "enum", exported: true },
|
|
19
|
+
{ re: /^\s*export\s+const\s+enum\s+(?<name>[\w$]+)/, kind: "enum", exported: true },
|
|
20
|
+
// exported const/let bound to an arrow fn or value
|
|
21
|
+
{ re: /^\s*export\s+(?:const|let|var)\s+(?<name>[\w$]+)\s*[:=]/, kind: "const", exported: true },
|
|
22
|
+
// CommonJS named exports: `exports.foo = …`, `module.exports.foo = …`
|
|
23
|
+
{ re: /^\s*exports\.(?<name>[\w$]+)\s*=/, kind: "const", exported: true },
|
|
24
|
+
{ re: /^\s*module\.exports\.(?<name>[\w$]+)\s*=/, kind: "const", exported: true },
|
|
25
|
+
// top-level const arrow function (not exported)
|
|
26
|
+
{ re: /^\s*(?:const|let)\s+(?<name>[\w$]+)\s*=\s*(?:async\s*)?\([^)]*\)\s*(?::[^=]+)?=>/, kind: "const", exported: false },
|
|
27
|
+
// `export default Foo;` — a class/const declared above and exported by reference.
|
|
28
|
+
{ re: /^\s*export\s+default\s+(?<name>[A-Za-z_$][\w$]*)\s*;?\s*$/, kind: "default", exported: true },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
// An anonymous default export (`export default function () {}`, `export default
|
|
32
|
+
// class extends Base {}`, `export default () => …`, `export default {…}`) has no
|
|
33
|
+
// name to capture — it gets named after the file stem (ultradoc parity), so the
|
|
34
|
+
// module's default export is still a real, referencable symbol.
|
|
35
|
+
const ANON_DEFAULT_RE = /^\s*export\s+default\s+(?:async\s+)?(?:function|class)?\s*(?:\(|\{|extends\b)/;
|
|
36
|
+
const NAMED_DEFAULT_RE = /^\s*export\s+default\s+(?:async\s+)?(?:function|class)\s+(?!extends\b)[\w$]+/;
|
|
37
|
+
|
|
38
|
+
function stemOf(rel: string): string {
|
|
39
|
+
return (rel.split("/").pop() ?? "").replace(/\.[^.]+$/, "");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Post-pass flipping local declarations to exported when an export LIST names
|
|
43
|
+
// them — forms the one-symbol-per-line rules above cannot see (mirrors
|
|
44
|
+
// ultradoc's applyExportLists):
|
|
45
|
+
// - `export { a, b as c }` marks locals `a`/`b` (the alias `c` itself is emitted
|
|
46
|
+
// as a `reexport` symbol by extract/code.ts's extractReexports, both tiers);
|
|
47
|
+
// `export { … } from "x"` is a pure re-export and names no locals.
|
|
48
|
+
// - `module.exports = { foo, bar: baz }` marks the shorthand names, keys and
|
|
49
|
+
// identifier values (key = the exported surface, value = the local decl).
|
|
50
|
+
// - `export default Foo;` marks the ORIGINAL `Foo` declaration (the line rule
|
|
51
|
+
// above keeps emitting the `default` reference symbol for byte-compat).
|
|
52
|
+
const EXPORT_LIST_RE = /export\s*\{([^}]*)\}\s*(from\b)?/g;
|
|
53
|
+
const CJS_OBJECT_RE = /module\.exports\s*=\s*\{([^}]*)\}/g;
|
|
54
|
+
const DEFAULT_ID_RE = /(^|\n)\s*export\s+default\s+([A-Za-z_$][\w$]*)\s*;?\s*(?=\n|$)/g;
|
|
55
|
+
|
|
56
|
+
function applyExportLists(content: string, symbols: CodeSymbol[]): void {
|
|
57
|
+
const markExported = (name: string | undefined): void => {
|
|
58
|
+
if (!name || name === "default") return;
|
|
59
|
+
for (const s of symbols) if (s.name === name) s.exported = true;
|
|
60
|
+
};
|
|
61
|
+
const handleList = (inner: string, cjs: boolean): void => {
|
|
62
|
+
for (const raw of inner.split(",")) {
|
|
63
|
+
const part = raw.trim().replace(/^type\s+/, "");
|
|
64
|
+
if (!part) continue;
|
|
65
|
+
const asMatch = /^([\w$]+)\s+as\s+([\w$]+)$/.exec(part);
|
|
66
|
+
if (asMatch) {
|
|
67
|
+
if (asMatch[2] !== "default") markExported(asMatch[1]);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (cjs) {
|
|
71
|
+
const kv = /^([\w$]+)\s*:\s*([\w$]+)$/.exec(part);
|
|
72
|
+
if (kv) {
|
|
73
|
+
markExported(kv[1]);
|
|
74
|
+
markExported(kv[2]);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
markExported(/^([\w$]+)/.exec(part)?.[1]);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
let m: RegExpExecArray | null;
|
|
82
|
+
EXPORT_LIST_RE.lastIndex = 0;
|
|
83
|
+
while ((m = EXPORT_LIST_RE.exec(content))) {
|
|
84
|
+
if (!m[2]) handleList(m[1] ?? "", false);
|
|
85
|
+
}
|
|
86
|
+
CJS_OBJECT_RE.lastIndex = 0;
|
|
87
|
+
while ((m = CJS_OBJECT_RE.exec(content))) handleList(m[1] ?? "", true);
|
|
88
|
+
DEFAULT_ID_RE.lastIndex = 0;
|
|
89
|
+
while ((m = DEFAULT_ID_RE.exec(content))) markExported(m[2]);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export const jsTs = {
|
|
93
|
+
lang: "javascript/typescript",
|
|
94
|
+
exts: [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"],
|
|
95
|
+
extract(rel: string, content: string): CodeSymbol[] {
|
|
96
|
+
const lang = rel.match(/\.(ts|tsx|mts|cts)$/) ? "typescript" : "javascript";
|
|
97
|
+
const symbols = scan(rel, content, lang, RULES);
|
|
98
|
+
const lines = content.split(/\r?\n/);
|
|
99
|
+
for (let i = 0; i < lines.length; i++) {
|
|
100
|
+
const line = lines[i]!;
|
|
101
|
+
if (ANON_DEFAULT_RE.test(line) && !NAMED_DEFAULT_RE.test(line)) {
|
|
102
|
+
symbols.push({
|
|
103
|
+
name: stemOf(rel), kind: "default", file: rel, line: i + 1,
|
|
104
|
+
signature: line.trim().slice(0, 200), exported: true, lang,
|
|
105
|
+
});
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
applyExportLists(content, symbols);
|
|
110
|
+
return symbols;
|
|
111
|
+
},
|
|
112
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CodeSymbol } from "../types.js";
|
|
2
|
+
import { scan, type Rule } from "./common.js";
|
|
3
|
+
|
|
4
|
+
// Kotlin. `private`/`internal` are not exported; the default (public) is.
|
|
5
|
+
const vis = (_m: RegExpExecArray, l: string) => !/\b(private|internal)\b/.test(l);
|
|
6
|
+
|
|
7
|
+
const RULES: Rule[] = [
|
|
8
|
+
{ re: /^\s*(?:public\s+|internal\s+|private\s+|abstract\s+|sealed\s+|open\s+|final\s+|data\s+)*class\s+(?<name>\w+)/, kind: "class", exported: vis },
|
|
9
|
+
{ re: /^\s*(?:public\s+|internal\s+|private\s+|fun\s+)?interface\s+(?<name>\w+)/, kind: "interface", exported: vis },
|
|
10
|
+
{ re: /^\s*(?:public\s+|internal\s+|private\s+|companion\s+)?object\s+(?<name>\w+)/, kind: "object", exported: vis },
|
|
11
|
+
{ re: /^\s*(?:public\s+|internal\s+|private\s+|protected\s+|override\s+|open\s+|abstract\s+|suspend\s+|inline\s+|operator\s+)*fun\s+(?:<[^>]*>\s+)?(?<name>\w+)\s*\(/, kind: "function", exported: vis },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
export const kotlin = {
|
|
15
|
+
lang: "kotlin",
|
|
16
|
+
exts: [".kt", ".kts"],
|
|
17
|
+
extract(rel: string, content: string): CodeSymbol[] {
|
|
18
|
+
return scan(rel, content, "kotlin", RULES);
|
|
19
|
+
},
|
|
20
|
+
};
|
package/src/lang/lua.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CodeSymbol } from "../types.js";
|
|
2
|
+
import { scan, type Rule } from "./common.js";
|
|
3
|
+
|
|
4
|
+
// Lua. `function name(…)`, `local function name(…)`, `Table.method(…)` /
|
|
5
|
+
// `Table:method(…)`, and `name = function(…)`.
|
|
6
|
+
const RULES: Rule[] = [
|
|
7
|
+
{ re: /^\s*local\s+function\s+(?<name>[\w.:]+)\s*\(/, kind: "function", exported: false },
|
|
8
|
+
{ re: /^\s*function\s+(?<name>[\w.:]+)\s*\(/, kind: "function", exported: true },
|
|
9
|
+
{ re: /^\s*(?:local\s+)?(?<name>[\w.]+)\s*=\s*function\s*\(/, kind: "function", exported: true },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
export const lua = {
|
|
13
|
+
lang: "lua",
|
|
14
|
+
exts: [".lua"],
|
|
15
|
+
extract(rel: string, content: string): CodeSymbol[] {
|
|
16
|
+
return scan(rel, content, "lua", RULES);
|
|
17
|
+
},
|
|
18
|
+
};
|
package/src/lang/php.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CodeSymbol } from "../types.js";
|
|
2
|
+
import { scan, type Rule } from "./common.js";
|
|
3
|
+
|
|
4
|
+
// PHP. Classes/interfaces/traits/enums and functions/methods. Methods marked
|
|
5
|
+
// `private`/`protected` are treated as non-exported.
|
|
6
|
+
const RULES: Rule[] = [
|
|
7
|
+
{ re: /^\s*(?:abstract\s+|final\s+)*class\s+(?<name>\w+)/, kind: "class", exported: true },
|
|
8
|
+
{ re: /^\s*interface\s+(?<name>\w+)/, kind: "interface", exported: true },
|
|
9
|
+
{ re: /^\s*trait\s+(?<name>\w+)/, kind: "trait", exported: true },
|
|
10
|
+
{ re: /^\s*enum\s+(?<name>\w+)/, kind: "enum", exported: true },
|
|
11
|
+
{
|
|
12
|
+
re: /^\s*(?:public\s+|protected\s+|private\s+|static\s+|abstract\s+|final\s+)*function\s+(?<name>\w+)\s*\(/,
|
|
13
|
+
kind: "function",
|
|
14
|
+
exported: (_m, l) => !/\b(private|protected)\b/.test(l),
|
|
15
|
+
},
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
export const php = {
|
|
19
|
+
lang: "php",
|
|
20
|
+
exts: [".php"],
|
|
21
|
+
extract(rel: string, content: string): CodeSymbol[] {
|
|
22
|
+
return scan(rel, content, "php", RULES);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CodeSymbol } from "../types.js";
|
|
2
|
+
import { scan, type Rule } from "./common.js";
|
|
3
|
+
|
|
4
|
+
// Python. A name not prefixed with "_" is treated as part of the public
|
|
5
|
+
// surface (the usual convention). Indented `def` → method; column-0 `def` →
|
|
6
|
+
// module function.
|
|
7
|
+
const pub = (name: string) => !name.startsWith("_") || name.startsWith("__");
|
|
8
|
+
|
|
9
|
+
const RULES: Rule[] = [
|
|
10
|
+
{ re: /^(?:async\s+)?def\s+(?<name>[\w]+)\s*\(/, kind: "function", exported: (m) => pub(m.groups!.name!) },
|
|
11
|
+
{ re: /^\s+(?:async\s+)?def\s+(?<name>[\w]+)\s*\(/, kind: "method", exported: (m) => pub(m.groups!.name!) },
|
|
12
|
+
{ re: /^class\s+(?<name>[\w]+)/, kind: "class", exported: (m) => pub(m.groups!.name!) },
|
|
13
|
+
{ re: /^\s+class\s+(?<name>[\w]+)/, kind: "class", exported: (m) => pub(m.groups!.name!) },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
export const python = {
|
|
17
|
+
lang: "python",
|
|
18
|
+
exts: [".py", ".pyi"],
|
|
19
|
+
extract(rel: string, content: string): CodeSymbol[] {
|
|
20
|
+
return scan(rel, content, "python", RULES);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { CodeSymbol } from "../types.js";
|
|
2
|
+
import { extToLang } from "./common.js";
|
|
3
|
+
import { jsTs } from "./js-ts.js";
|
|
4
|
+
import { python } from "./python.js";
|
|
5
|
+
import { go } from "./go.js";
|
|
6
|
+
import { ruby } from "./ruby.js";
|
|
7
|
+
import { java } from "./java.js";
|
|
8
|
+
import { rust } from "./rust.js";
|
|
9
|
+
import { csharp } from "./csharp.js";
|
|
10
|
+
import { php } from "./php.js";
|
|
11
|
+
import { swift } from "./swift.js";
|
|
12
|
+
import { kotlin } from "./kotlin.js";
|
|
13
|
+
import { c } from "./c.js";
|
|
14
|
+
import { lua } from "./lua.js";
|
|
15
|
+
import { shell } from "./shell.js";
|
|
16
|
+
import { elixir } from "./elixir.js";
|
|
17
|
+
import { scala } from "./scala.js";
|
|
18
|
+
|
|
19
|
+
export interface Extractor {
|
|
20
|
+
lang: string;
|
|
21
|
+
exts: string[];
|
|
22
|
+
extract(rel: string, content: string): CodeSymbol[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Registry of symbol extractors keyed by file extension. Adding a language is a
|
|
26
|
+
// matter of writing one `lang/<x>.ts` and registering it here — the same
|
|
27
|
+
// registry pattern reconstruct uses for its framework adapters.
|
|
28
|
+
const EXTRACTORS: Extractor[] = [
|
|
29
|
+
jsTs, python, go, ruby, java, rust,
|
|
30
|
+
csharp, php, swift, kotlin, c, lua, shell, elixir, scala,
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const BY_EXT = new Map<string, Extractor>();
|
|
34
|
+
for (const e of EXTRACTORS) for (const ext of e.exts) BY_EXT.set(ext, e);
|
|
35
|
+
|
|
36
|
+
// Extract declared symbols from one file. Returns [] for languages without a
|
|
37
|
+
// dedicated extractor (their content is still fully searchable via ripgrep).
|
|
38
|
+
export function extractSymbols(rel: string, ext: string, content: string): CodeSymbol[] {
|
|
39
|
+
const extractor = BY_EXT.get(ext);
|
|
40
|
+
if (!extractor) return [];
|
|
41
|
+
try {
|
|
42
|
+
return extractor.extract(rel, content);
|
|
43
|
+
} catch {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Human-readable language label for an extension (used for the language
|
|
49
|
+
// histogram), falling back to the broad table for non-extracted languages.
|
|
50
|
+
export function languageOf(ext: string): string {
|
|
51
|
+
return BY_EXT.get(ext)?.lang ?? extToLang(ext);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { extToLang };
|
package/src/lang/ruby.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CodeSymbol } from "../types.js";
|
|
2
|
+
import { scan, type Rule } from "./common.js";
|
|
3
|
+
|
|
4
|
+
// Ruby. `def` (instance/class methods), `class`, and `module` declarations.
|
|
5
|
+
const RULES: Rule[] = [
|
|
6
|
+
{ re: /^\s*def\s+(?:self\.)?(?<name>[\w?!=]+)/, kind: "method", exported: true },
|
|
7
|
+
{ re: /^\s*class\s+(?<name>[\w:]+)/, kind: "class", exported: true },
|
|
8
|
+
{ re: /^\s*module\s+(?<name>[\w:]+)/, kind: "module", exported: true },
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
export const ruby = {
|
|
12
|
+
lang: "ruby",
|
|
13
|
+
exts: [".rb", ".rake"],
|
|
14
|
+
extract(rel: string, content: string): CodeSymbol[] {
|
|
15
|
+
return scan(rel, content, "ruby", RULES);
|
|
16
|
+
},
|
|
17
|
+
};
|
package/src/lang/rust.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CodeSymbol } from "../types.js";
|
|
2
|
+
import { scan, type Rule } from "./common.js";
|
|
3
|
+
|
|
4
|
+
// Rust. `pub` marks the public surface. Covers fn / struct / enum / trait /
|
|
5
|
+
// type declarations.
|
|
6
|
+
const isPub = (_m: RegExpExecArray, l: string) => /^\s*pub\b/.test(l);
|
|
7
|
+
|
|
8
|
+
const RULES: Rule[] = [
|
|
9
|
+
{ re: /^\s*(?:pub(?:\([^)]*\))?\s+)?(?:async\s+)?(?:unsafe\s+)?fn\s+(?<name>[\w]+)/, kind: "function", exported: isPub },
|
|
10
|
+
{ re: /^\s*(?:pub(?:\([^)]*\))?\s+)?struct\s+(?<name>[\w]+)/, kind: "struct", exported: isPub },
|
|
11
|
+
{ re: /^\s*(?:pub(?:\([^)]*\))?\s+)?enum\s+(?<name>[\w]+)/, kind: "enum", exported: isPub },
|
|
12
|
+
{ re: /^\s*(?:pub(?:\([^)]*\))?\s+)?trait\s+(?<name>[\w]+)/, kind: "trait", exported: isPub },
|
|
13
|
+
{ re: /^\s*(?:pub(?:\([^)]*\))?\s+)?type\s+(?<name>[\w]+)/, kind: "type", exported: isPub },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
export const rust = {
|
|
17
|
+
lang: "rust",
|
|
18
|
+
exts: [".rs"],
|
|
19
|
+
extract(rel: string, content: string): CodeSymbol[] {
|
|
20
|
+
return scan(rel, content, "rust", RULES);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CodeSymbol } from "../types.js";
|
|
2
|
+
import { scan, type Rule } from "./common.js";
|
|
3
|
+
|
|
4
|
+
// Scala. class/trait/object (incl. `case class`) and `def`. `private`/
|
|
5
|
+
// `protected` defs are not exported.
|
|
6
|
+
const RULES: Rule[] = [
|
|
7
|
+
{ re: /^\s*(?:final\s+|sealed\s+|abstract\s+|implicit\s+)*(?:case\s+)?class\s+(?<name>\w+)/, kind: "class", exported: true },
|
|
8
|
+
{ re: /^\s*(?:sealed\s+)?trait\s+(?<name>\w+)/, kind: "trait", exported: true },
|
|
9
|
+
{ re: /^\s*(?:case\s+)?object\s+(?<name>\w+)/, kind: "object", exported: true },
|
|
10
|
+
{ re: /^\s*(?:override\s+|final\s+|private\s+|protected\s+|implicit\s+)*def\s+(?<name>\w+)/, kind: "def", exported: (_m, l) => !/\b(private|protected)\b/.test(l) },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
export const scala = {
|
|
14
|
+
lang: "scala",
|
|
15
|
+
exts: [".scala", ".sc"],
|
|
16
|
+
extract(rel: string, content: string): CodeSymbol[] {
|
|
17
|
+
return scan(rel, content, "scala", RULES);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CodeSymbol } from "../types.js";
|
|
2
|
+
import { scan, type Rule } from "./common.js";
|
|
3
|
+
|
|
4
|
+
// Shell (bash/zsh/sh). Both function syntaxes: `function name { … }` and
|
|
5
|
+
// `name() { … }`.
|
|
6
|
+
const RULES: Rule[] = [
|
|
7
|
+
{ re: /^\s*function\s+(?<name>[\w:-]+)\s*(?:\(\))?\s*\{?/, kind: "function", exported: true },
|
|
8
|
+
{ re: /^\s*(?<name>[A-Za-z_][\w:-]*)\s*\(\)\s*\{?/, kind: "function", exported: true },
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
export const shell = {
|
|
12
|
+
lang: "shell",
|
|
13
|
+
exts: [".sh", ".bash", ".zsh", ".ksh"],
|
|
14
|
+
extract(rel: string, content: string): CodeSymbol[] {
|
|
15
|
+
return scan(rel, content, "shell", RULES);
|
|
16
|
+
},
|
|
17
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CodeSymbol } from "../types.js";
|
|
2
|
+
import { scan, type Rule } from "./common.js";
|
|
3
|
+
|
|
4
|
+
// Swift. Types and funcs. `private`/`fileprivate` are not exported; everything
|
|
5
|
+
// else (internal/public/open, the default) is treated as public surface.
|
|
6
|
+
const vis = (_m: RegExpExecArray, l: string) => !/\b(private|fileprivate)\b/.test(l);
|
|
7
|
+
const MODS = "(?:public\\s+|open\\s+|internal\\s+|private\\s+|fileprivate\\s+)?(?:final\\s+)?";
|
|
8
|
+
|
|
9
|
+
const RULES: Rule[] = [
|
|
10
|
+
{ re: new RegExp(`^\\s*${MODS}class\\s+(?<name>\\w+)`), kind: "class", exported: vis },
|
|
11
|
+
{ re: new RegExp(`^\\s*${MODS}struct\\s+(?<name>\\w+)`), kind: "struct", exported: vis },
|
|
12
|
+
{ re: new RegExp(`^\\s*${MODS}enum\\s+(?<name>\\w+)`), kind: "enum", exported: vis },
|
|
13
|
+
{ re: new RegExp(`^\\s*${MODS}protocol\\s+(?<name>\\w+)`), kind: "protocol", exported: vis },
|
|
14
|
+
{ re: /^\s*(?:public\s+|open\s+|internal\s+|private\s+|fileprivate\s+)?(?:static\s+|class\s+|final\s+|override\s+|mutating\s+|@\w+\s+)*func\s+(?<name>\w+)/, kind: "function", exported: vis },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export const swift = {
|
|
18
|
+
lang: "swift",
|
|
19
|
+
exts: [".swift"],
|
|
20
|
+
extract(rel: string, content: string): CodeSymbol[] {
|
|
21
|
+
return scan(rel, content, "swift", RULES);
|
|
22
|
+
},
|
|
23
|
+
};
|