project-librarian 0.4.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.
@@ -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
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,211 @@
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.indexJavaScriptLike = indexJavaScriptLike;
37
+ const path = __importStar(require("node:path"));
38
+ const ts = __importStar(require("typescript"));
39
+ const shared_1 = require("./shared");
40
+ const httpMethods = new Set(["all", "delete", "get", "patch", "post", "put"]);
41
+ function scriptKindForPath(relativePath) {
42
+ const extension = path.extname(relativePath).toLowerCase();
43
+ if (extension === ".tsx")
44
+ return ts.ScriptKind.TSX;
45
+ if (extension === ".jsx")
46
+ return ts.ScriptKind.JSX;
47
+ if ([".ts", ".mts", ".cts"].includes(extension))
48
+ return ts.ScriptKind.TS;
49
+ return ts.ScriptKind.JS;
50
+ }
51
+ function tsLine(sourceFile, node) {
52
+ return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
53
+ }
54
+ function nodeName(node, sourceFile) {
55
+ if (ts.isIdentifier(node))
56
+ return node.text;
57
+ if (ts.isStringLiteral(node) || ts.isNumericLiteral(node))
58
+ return node.text;
59
+ if (ts.isPrivateIdentifier(node))
60
+ return node.text;
61
+ return (0, shared_1.oneLine)(node.getText(sourceFile));
62
+ }
63
+ function propertyNameText(name, sourceFile) {
64
+ if (!name)
65
+ return "";
66
+ return nodeName(name, sourceFile);
67
+ }
68
+ function callTarget(expression, sourceFile) {
69
+ if (ts.isIdentifier(expression))
70
+ return expression.text;
71
+ if (ts.isPropertyAccessExpression(expression))
72
+ return (0, shared_1.oneLine)(expression.getText(sourceFile));
73
+ if (ts.isElementAccessExpression(expression))
74
+ return (0, shared_1.oneLine)(expression.getText(sourceFile));
75
+ return (0, shared_1.oneLine)(expression.getText(sourceFile));
76
+ }
77
+ function importBindingText(importClause, sourceFile) {
78
+ if (!importClause)
79
+ return "";
80
+ const names = [];
81
+ if (importClause.name)
82
+ names.push(importClause.name.text);
83
+ const namedBindings = importClause.namedBindings;
84
+ if (namedBindings && ts.isNamespaceImport(namedBindings))
85
+ names.push(`* as ${namedBindings.name.text}`);
86
+ if (namedBindings && ts.isNamedImports(namedBindings)) {
87
+ for (const element of namedBindings.elements)
88
+ names.push(element.name.text);
89
+ }
90
+ return names.join(", ") || (0, shared_1.oneLine)(importClause.getText(sourceFile));
91
+ }
92
+ function stringArg(node) {
93
+ if (!node)
94
+ return "";
95
+ return ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node) ? node.text : "";
96
+ }
97
+ function handlerArg(node, sourceFile) {
98
+ if (!node)
99
+ return "";
100
+ return callTarget(node, sourceFile);
101
+ }
102
+ function routeFromCall(node, sourceFile) {
103
+ if (!ts.isPropertyAccessExpression(node.expression))
104
+ return null;
105
+ const method = node.expression.name.text.toLowerCase();
106
+ if (!httpMethods.has(method))
107
+ return null;
108
+ const receiver = node.expression.expression;
109
+ if (!ts.isIdentifier(receiver) || !["app", "router", "server"].includes(receiver.text))
110
+ return null;
111
+ const route = stringArg(node.arguments[0]);
112
+ if (!route)
113
+ return null;
114
+ return {
115
+ handler: handlerArg(node.arguments[1], sourceFile),
116
+ method: method.toUpperCase(),
117
+ route,
118
+ };
119
+ }
120
+ function routeFromDecorator(node, sourceFile) {
121
+ const decorators = ts.canHaveDecorators(node) ? ts.getDecorators(node) ?? [] : [];
122
+ const routes = [];
123
+ for (const decorator of decorators) {
124
+ const expression = decorator.expression;
125
+ if (!ts.isCallExpression(expression))
126
+ continue;
127
+ const callee = expression.expression;
128
+ if (!ts.isIdentifier(callee))
129
+ continue;
130
+ const method = callee.text.toLowerCase();
131
+ if (!httpMethods.has(method))
132
+ continue;
133
+ routes.push({ method: method.toUpperCase(), route: stringArg(expression.arguments[0]) || "/" });
134
+ }
135
+ return routes;
136
+ }
137
+ function signatureFor(node, sourceFile) {
138
+ return (0, shared_1.oneLine)(node.getText(sourceFile));
139
+ }
140
+ function indexJavaScriptLike(file, statements) {
141
+ const sourceFile = ts.createSourceFile(file.path, file.text, ts.ScriptTarget.Latest, true, scriptKindForPath(file.path));
142
+ function visit(node, context) {
143
+ let nextContext = context;
144
+ if (ts.isFunctionDeclaration(node)) {
145
+ const name = node.name?.text ?? "";
146
+ (0, shared_1.insertSymbol)(statements, name, "function", file, tsLine(sourceFile, node), signatureFor(node, sourceFile));
147
+ if (name)
148
+ nextContext = name;
149
+ }
150
+ else if (ts.isClassDeclaration(node)) {
151
+ const name = node.name?.text ?? "";
152
+ (0, shared_1.insertSymbol)(statements, name, "class", file, tsLine(sourceFile, node), signatureFor(node, sourceFile));
153
+ if (name)
154
+ nextContext = name;
155
+ }
156
+ else if (ts.isInterfaceDeclaration(node)) {
157
+ (0, shared_1.insertSymbol)(statements, node.name.text, "interface", file, tsLine(sourceFile, node), signatureFor(node, sourceFile));
158
+ }
159
+ else if (ts.isTypeAliasDeclaration(node)) {
160
+ (0, shared_1.insertSymbol)(statements, node.name.text, "type", file, tsLine(sourceFile, node), signatureFor(node, sourceFile));
161
+ }
162
+ else if (ts.isEnumDeclaration(node)) {
163
+ (0, shared_1.insertSymbol)(statements, node.name.text, "enum", file, tsLine(sourceFile, node), signatureFor(node, sourceFile));
164
+ }
165
+ else if (ts.isMethodDeclaration(node)) {
166
+ const name = propertyNameText(node.name, sourceFile);
167
+ (0, shared_1.insertSymbol)(statements, name, "method", file, tsLine(sourceFile, node), signatureFor(node, sourceFile));
168
+ for (const route of routeFromDecorator(node, sourceFile)) {
169
+ statements.insertRoute.run(route.method, route.route, file.path, tsLine(sourceFile, node), name);
170
+ (0, shared_1.insertEdge)(statements, "route_to_handler", "route", `${route.method} ${route.route}`, "symbol", name, file, tsLine(sourceFile, node), signatureFor(node, sourceFile));
171
+ }
172
+ if (name)
173
+ nextContext = name;
174
+ }
175
+ else if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
176
+ const symbolKind = node.initializer && (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer)) ? "function" : "variable";
177
+ (0, shared_1.insertSymbol)(statements, node.name.text, symbolKind, file, tsLine(sourceFile, node), signatureFor(node, sourceFile));
178
+ if (symbolKind === "function")
179
+ nextContext = node.name.text;
180
+ }
181
+ else if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
182
+ const imported = importBindingText(node.importClause, sourceFile);
183
+ statements.insertImport.run(file.path, node.moduleSpecifier.text, imported, tsLine(sourceFile, node), signatureFor(node, sourceFile));
184
+ (0, shared_1.insertEdge)(statements, "import", "file", file.path, "module", node.moduleSpecifier.text, file, tsLine(sourceFile, node), signatureFor(node, sourceFile));
185
+ }
186
+ else if (ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {
187
+ const exported = node.exportClause ? (0, shared_1.oneLine)(node.exportClause.getText(sourceFile)) : "";
188
+ statements.insertImport.run(file.path, node.moduleSpecifier.text, exported, tsLine(sourceFile, node), signatureFor(node, sourceFile));
189
+ (0, shared_1.insertEdge)(statements, "export", "file", file.path, "module", node.moduleSpecifier.text, file, tsLine(sourceFile, node), signatureFor(node, sourceFile));
190
+ }
191
+ else if (ts.isCallExpression(node)) {
192
+ const route = routeFromCall(node, sourceFile);
193
+ if (route) {
194
+ statements.insertRoute.run(route.method, route.route, file.path, tsLine(sourceFile, node), route.handler);
195
+ (0, shared_1.insertEdge)(statements, "route_to_handler", "route", `${route.method} ${route.route}`, "symbol", route.handler, file, tsLine(sourceFile, node), signatureFor(node, sourceFile));
196
+ }
197
+ if (ts.isIdentifier(node.expression) && node.expression.text === "require") {
198
+ const moduleName = stringArg(node.arguments[0]);
199
+ if (moduleName) {
200
+ statements.insertImport.run(file.path, moduleName, "", tsLine(sourceFile, node), signatureFor(node, sourceFile));
201
+ (0, shared_1.insertEdge)(statements, "import", "file", file.path, "module", moduleName, file, tsLine(sourceFile, node), signatureFor(node, sourceFile));
202
+ }
203
+ }
204
+ else {
205
+ (0, shared_1.insertEdge)(statements, "call", context ? "symbol" : "file", context || file.path, "symbol", callTarget(node.expression, sourceFile), file, tsLine(sourceFile, node), signatureFor(node, sourceFile));
206
+ }
207
+ }
208
+ ts.forEachChild(node, (child) => visit(child, nextContext));
209
+ }
210
+ visit(sourceFile, "");
211
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.planIndexUpdate = planIndexUpdate;
4
+ function planIndexUpdate(currentFiles, indexedHashes) {
5
+ const currentByPath = new Map(currentFiles.map((file) => [file.path, file]));
6
+ const deletedPaths = Array.from(indexedHashes.keys()).filter((filePath) => !currentByPath.has(filePath));
7
+ const reindexedFiles = currentFiles.filter((file) => indexedHashes.get(file.path) !== file.hash);
8
+ return {
9
+ addedFiles: reindexedFiles.filter((file) => !indexedHashes.has(file.path)),
10
+ changedFiles: reindexedFiles.filter((file) => indexedHashes.has(file.path)),
11
+ currentByPath,
12
+ deletedPaths,
13
+ reindexedFiles,
14
+ unchangedFiles: currentFiles.length - reindexedFiles.length,
15
+ };
16
+ }