@compilr-dev/agents-coding-ts 0.1.2 → 0.1.4
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/index.d.ts +8 -5
- package/dist/index.js +14 -4
- package/dist/parser/index.d.ts +2 -2
- package/dist/parser/index.js +1 -1
- package/dist/parser/typescript-parser.d.ts +2 -2
- package/dist/parser/typescript-parser.js +77 -54
- package/dist/skills/code-health.js +18 -5
- package/dist/skills/code-structure.js +15 -5
- package/dist/skills/dependency-audit.js +16 -5
- package/dist/skills/index.d.ts +7 -7
- package/dist/skills/index.js +11 -11
- package/dist/skills/refactor-impact.js +16 -5
- package/dist/skills/type-analysis.js +16 -5
- package/dist/tools/find-dead-code.d.ts +2 -2
- package/dist/tools/find-dead-code.js +82 -58
- package/dist/tools/find-duplicates.d.ts +2 -2
- package/dist/tools/find-duplicates.js +41 -38
- package/dist/tools/find-implementations.d.ts +2 -2
- package/dist/tools/find-implementations.js +44 -36
- package/dist/tools/find-patterns.d.ts +2 -2
- package/dist/tools/find-patterns.js +154 -148
- package/dist/tools/find-references.d.ts +2 -2
- package/dist/tools/find-references.js +76 -72
- package/dist/tools/find-symbol.d.ts +2 -2
- package/dist/tools/find-symbol.js +106 -96
- package/dist/tools/get-call-graph.d.ts +2 -2
- package/dist/tools/get-call-graph.js +52 -47
- package/dist/tools/get-complexity.d.ts +2 -2
- package/dist/tools/get-complexity.js +94 -46
- package/dist/tools/get-dependency-graph.d.ts +2 -2
- package/dist/tools/get-dependency-graph.js +66 -52
- package/dist/tools/get-documentation.d.ts +2 -2
- package/dist/tools/get-documentation.js +154 -122
- package/dist/tools/get-exports.d.ts +2 -2
- package/dist/tools/get-exports.js +73 -61
- package/dist/tools/get-file-structure.d.ts +2 -2
- package/dist/tools/get-file-structure.js +16 -16
- package/dist/tools/get-imports.d.ts +2 -2
- package/dist/tools/get-imports.js +46 -46
- package/dist/tools/get-signature.d.ts +2 -2
- package/dist/tools/get-signature.js +168 -124
- package/dist/tools/get-type-hierarchy.d.ts +2 -2
- package/dist/tools/get-type-hierarchy.js +53 -44
- package/dist/tools/index.d.ts +18 -16
- package/dist/tools/index.js +17 -15
- package/dist/tools/read-symbol.d.ts +62 -0
- package/dist/tools/read-symbol.js +464 -0
- package/dist/tools/types.d.ts +27 -27
- package/package.json +3 -3
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* Extract JSDoc/TSDoc documentation from source files.
|
|
5
5
|
* Provides documentation coverage metrics and identifies undocumented exports.
|
|
6
6
|
*/
|
|
7
|
-
import * as fs from
|
|
8
|
-
import * as path from
|
|
9
|
-
import * as ts from
|
|
10
|
-
import { defineTool, createSuccessResult, createErrorResult } from
|
|
11
|
-
import { detectLanguage, isLanguageSupported } from
|
|
7
|
+
import * as fs from "node:fs/promises";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import * as ts from "typescript";
|
|
10
|
+
import { defineTool, createSuccessResult, createErrorResult, } from "@compilr-dev/agents";
|
|
11
|
+
import { detectLanguage, isLanguageSupported, } from "../parser/typescript-parser.js";
|
|
12
12
|
// Tool description
|
|
13
13
|
const TOOL_DESCRIPTION = `Extract JSDoc/TSDoc documentation from source files.
|
|
14
14
|
Returns documented symbols with their signatures and documentation content.
|
|
@@ -16,52 +16,52 @@ Calculates documentation coverage metrics and identifies undocumented exports.
|
|
|
16
16
|
Useful for generating API documentation and measuring doc coverage.`;
|
|
17
17
|
// Tool input schema
|
|
18
18
|
const TOOL_INPUT_SCHEMA = {
|
|
19
|
-
type:
|
|
19
|
+
type: "object",
|
|
20
20
|
properties: {
|
|
21
21
|
path: {
|
|
22
|
-
type:
|
|
23
|
-
description:
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "File or directory to analyze",
|
|
24
24
|
},
|
|
25
25
|
recursive: {
|
|
26
|
-
type:
|
|
27
|
-
description:
|
|
26
|
+
type: "boolean",
|
|
27
|
+
description: "Recursive analysis for directories (default: false)",
|
|
28
28
|
default: false,
|
|
29
29
|
},
|
|
30
30
|
kinds: {
|
|
31
|
-
type:
|
|
32
|
-
items: { type:
|
|
33
|
-
description:
|
|
31
|
+
type: "array",
|
|
32
|
+
items: { type: "string" },
|
|
33
|
+
description: "Filter by symbol kinds: function, class, interface, type, enum, variable, method, property",
|
|
34
34
|
},
|
|
35
35
|
exportedOnly: {
|
|
36
|
-
type:
|
|
37
|
-
description:
|
|
36
|
+
type: "boolean",
|
|
37
|
+
description: "Only include exported symbols (default: false)",
|
|
38
38
|
default: false,
|
|
39
39
|
},
|
|
40
40
|
documentedOnly: {
|
|
41
|
-
type:
|
|
42
|
-
description:
|
|
41
|
+
type: "boolean",
|
|
42
|
+
description: "Only include symbols with documentation (default: true)",
|
|
43
43
|
default: true,
|
|
44
44
|
},
|
|
45
45
|
maxFiles: {
|
|
46
|
-
type:
|
|
47
|
-
description:
|
|
46
|
+
type: "number",
|
|
47
|
+
description: "Maximum files to analyze (default: 50)",
|
|
48
48
|
default: 50,
|
|
49
49
|
},
|
|
50
50
|
includePrivate: {
|
|
51
|
-
type:
|
|
52
|
-
description:
|
|
51
|
+
type: "boolean",
|
|
52
|
+
description: "Include private class members (default: false)",
|
|
53
53
|
default: false,
|
|
54
54
|
},
|
|
55
55
|
},
|
|
56
|
-
required: [
|
|
56
|
+
required: ["path"],
|
|
57
57
|
};
|
|
58
58
|
// Default exclusions
|
|
59
|
-
const DEFAULT_EXCLUDE = [
|
|
59
|
+
const DEFAULT_EXCLUDE = ["node_modules", "dist", "build", ".git", "coverage"];
|
|
60
60
|
/**
|
|
61
61
|
* getDocumentation tool
|
|
62
62
|
*/
|
|
63
63
|
export const getDocumentationTool = defineTool({
|
|
64
|
-
name:
|
|
64
|
+
name: "get_documentation",
|
|
65
65
|
description: TOOL_DESCRIPTION,
|
|
66
66
|
inputSchema: TOOL_INPUT_SCHEMA,
|
|
67
67
|
execute: executeGetDocumentation,
|
|
@@ -120,7 +120,9 @@ async function executeGetDocumentation(input) {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
|
-
const coveragePercent = totalSymbols > 0
|
|
123
|
+
const coveragePercent = totalSymbols > 0
|
|
124
|
+
? Math.round((documentedSymbols / totalSymbols) * 100)
|
|
125
|
+
: 100;
|
|
124
126
|
const result = {
|
|
125
127
|
path: resolvedPath,
|
|
126
128
|
files: fileResults,
|
|
@@ -170,7 +172,8 @@ async function collectFiles(dirPath, files, maxDepth, maxFiles, currentDepth = 0
|
|
|
170
172
|
}
|
|
171
173
|
else if (entry.isFile()) {
|
|
172
174
|
// Only include TypeScript/JavaScript files
|
|
173
|
-
if (/\.(ts|tsx|js|jsx)$/.test(entry.name) &&
|
|
175
|
+
if (/\.(ts|tsx|js|jsx)$/.test(entry.name) &&
|
|
176
|
+
!entry.name.endsWith(".d.ts")) {
|
|
174
177
|
files.push(fullPath);
|
|
175
178
|
}
|
|
176
179
|
}
|
|
@@ -185,12 +188,12 @@ async function collectFiles(dirPath, files, maxDepth, maxFiles, currentDepth = 0
|
|
|
185
188
|
*/
|
|
186
189
|
async function analyzeFile(filePath, options) {
|
|
187
190
|
try {
|
|
188
|
-
const content = await fs.readFile(filePath,
|
|
191
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
189
192
|
const detection = detectLanguage(filePath);
|
|
190
193
|
if (!detection.language || !isLanguageSupported(detection.language)) {
|
|
191
194
|
return null;
|
|
192
195
|
}
|
|
193
|
-
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, filePath.endsWith(
|
|
196
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
|
|
194
197
|
// Extract file-level documentation
|
|
195
198
|
const fileDoc = extractFileDocumentation(sourceFile);
|
|
196
199
|
// Extract symbol documentation
|
|
@@ -212,7 +215,9 @@ async function analyzeFile(filePath, options) {
|
|
|
212
215
|
const totalSymbols = allSymbols.length;
|
|
213
216
|
const documentedCount = allSymbols.filter((s) => hasDocumentation(s.documentation)).length;
|
|
214
217
|
const undocumentedCount = totalSymbols - documentedCount;
|
|
215
|
-
const coveragePercent = totalSymbols > 0
|
|
218
|
+
const coveragePercent = totalSymbols > 0
|
|
219
|
+
? Math.round((documentedCount / totalSymbols) * 100)
|
|
220
|
+
: 100;
|
|
216
221
|
return {
|
|
217
222
|
path: filePath,
|
|
218
223
|
fileDoc: fileDoc && hasDocumentation(fileDoc) ? fileDoc : undefined,
|
|
@@ -239,25 +244,27 @@ function extractFileDocumentation(sourceFile) {
|
|
|
239
244
|
if (!match)
|
|
240
245
|
return undefined;
|
|
241
246
|
const commentText = match[1];
|
|
242
|
-
const lines = commentText
|
|
247
|
+
const lines = commentText
|
|
248
|
+
.split("\n")
|
|
249
|
+
.map((l) => l.replace(/^\s*\*\s?/, "").trim());
|
|
243
250
|
// Filter out @module and similar file-level tags, and empty lines
|
|
244
251
|
const descLines = [];
|
|
245
252
|
let isFileLevel = false;
|
|
246
253
|
for (const line of lines) {
|
|
247
|
-
if (line.startsWith(
|
|
248
|
-
line.startsWith(
|
|
249
|
-
line.startsWith(
|
|
254
|
+
if (line.startsWith("@module") ||
|
|
255
|
+
line.startsWith("@fileoverview") ||
|
|
256
|
+
line.startsWith("@file")) {
|
|
250
257
|
isFileLevel = true;
|
|
251
258
|
}
|
|
252
|
-
else if (!line.startsWith(
|
|
259
|
+
else if (!line.startsWith("@") && line.length > 0) {
|
|
253
260
|
descLines.push(line);
|
|
254
261
|
}
|
|
255
262
|
}
|
|
256
263
|
// Only return if this looks like a file-level comment
|
|
257
264
|
if (!isFileLevel && descLines.length === 0)
|
|
258
265
|
return undefined;
|
|
259
|
-
const summary = descLines[0] ||
|
|
260
|
-
const description = descLines.length > 1 ? descLines.slice(1).join(
|
|
266
|
+
const summary = descLines[0] || "";
|
|
267
|
+
const description = descLines.length > 1 ? descLines.slice(1).join("\n").trim() : undefined;
|
|
261
268
|
return {
|
|
262
269
|
summary,
|
|
263
270
|
description,
|
|
@@ -269,56 +276,58 @@ function extractFileDocumentation(sourceFile) {
|
|
|
269
276
|
function extractSymbols(node, sourceFile, symbols, options, _containerName) {
|
|
270
277
|
// Function declarations
|
|
271
278
|
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
272
|
-
symbols.push(extractSymbolInfo(node, sourceFile,
|
|
279
|
+
symbols.push(extractSymbolInfo(node, sourceFile, "function", node.name.text));
|
|
273
280
|
}
|
|
274
281
|
// Variable declarations (arrow functions, const values)
|
|
275
282
|
else if (ts.isVariableStatement(node)) {
|
|
276
283
|
for (const decl of node.declarationList.declarations) {
|
|
277
284
|
if (ts.isIdentifier(decl.name)) {
|
|
278
285
|
const kind = decl.initializer &&
|
|
279
|
-
(ts.isArrowFunction(decl.initializer) ||
|
|
280
|
-
|
|
281
|
-
|
|
286
|
+
(ts.isArrowFunction(decl.initializer) ||
|
|
287
|
+
ts.isFunctionExpression(decl.initializer))
|
|
288
|
+
? "function"
|
|
289
|
+
: "variable";
|
|
282
290
|
symbols.push(extractSymbolInfo(node, sourceFile, kind, decl.name.text));
|
|
283
291
|
}
|
|
284
292
|
}
|
|
285
293
|
}
|
|
286
294
|
// Class declarations
|
|
287
295
|
else if (ts.isClassDeclaration(node) && node.name) {
|
|
288
|
-
symbols.push(extractSymbolInfo(node, sourceFile,
|
|
296
|
+
symbols.push(extractSymbolInfo(node, sourceFile, "class", node.name.text));
|
|
289
297
|
// Extract class members
|
|
290
298
|
for (const member of node.members) {
|
|
291
299
|
// Skip private members if not included
|
|
292
300
|
if (!options.includePrivate && isPrivateMember(member))
|
|
293
301
|
continue;
|
|
294
302
|
if (ts.isMethodDeclaration(member) && ts.isIdentifier(member.name)) {
|
|
295
|
-
symbols.push(extractSymbolInfo(member, sourceFile,
|
|
303
|
+
symbols.push(extractSymbolInfo(member, sourceFile, "method", member.name.text, node.name.text));
|
|
296
304
|
}
|
|
297
|
-
else if (ts.isPropertyDeclaration(member) &&
|
|
298
|
-
|
|
305
|
+
else if (ts.isPropertyDeclaration(member) &&
|
|
306
|
+
ts.isIdentifier(member.name)) {
|
|
307
|
+
symbols.push(extractSymbolInfo(member, sourceFile, "property", member.name.text, node.name.text));
|
|
299
308
|
}
|
|
300
309
|
}
|
|
301
310
|
}
|
|
302
311
|
// Interface declarations
|
|
303
312
|
else if (ts.isInterfaceDeclaration(node)) {
|
|
304
|
-
symbols.push(extractSymbolInfo(node, sourceFile,
|
|
313
|
+
symbols.push(extractSymbolInfo(node, sourceFile, "interface", node.name.text));
|
|
305
314
|
// Extract interface members
|
|
306
315
|
for (const member of node.members) {
|
|
307
316
|
if (ts.isPropertySignature(member) && ts.isIdentifier(member.name)) {
|
|
308
|
-
symbols.push(extractSymbolInfo(member, sourceFile,
|
|
317
|
+
symbols.push(extractSymbolInfo(member, sourceFile, "property", member.name.text, node.name.text));
|
|
309
318
|
}
|
|
310
319
|
else if (ts.isMethodSignature(member) && ts.isIdentifier(member.name)) {
|
|
311
|
-
symbols.push(extractSymbolInfo(member, sourceFile,
|
|
320
|
+
symbols.push(extractSymbolInfo(member, sourceFile, "method", member.name.text, node.name.text));
|
|
312
321
|
}
|
|
313
322
|
}
|
|
314
323
|
}
|
|
315
324
|
// Type alias declarations
|
|
316
325
|
else if (ts.isTypeAliasDeclaration(node)) {
|
|
317
|
-
symbols.push(extractSymbolInfo(node, sourceFile,
|
|
326
|
+
symbols.push(extractSymbolInfo(node, sourceFile, "type", node.name.text));
|
|
318
327
|
}
|
|
319
328
|
// Enum declarations
|
|
320
329
|
else if (ts.isEnumDeclaration(node)) {
|
|
321
|
-
symbols.push(extractSymbolInfo(node, sourceFile,
|
|
330
|
+
symbols.push(extractSymbolInfo(node, sourceFile, "enum", node.name.text));
|
|
322
331
|
}
|
|
323
332
|
// Continue traversing (but skip into class/interface bodies as they're handled above)
|
|
324
333
|
if (!ts.isClassDeclaration(node) && !ts.isInterfaceDeclaration(node)) {
|
|
@@ -334,7 +343,7 @@ function isPrivateMember(node) {
|
|
|
334
343
|
if (!ts.canHaveModifiers(node))
|
|
335
344
|
return false;
|
|
336
345
|
const modifiers = ts.getModifiers(node);
|
|
337
|
-
return modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword) ?? false;
|
|
346
|
+
return (modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword) ?? false);
|
|
338
347
|
}
|
|
339
348
|
/**
|
|
340
349
|
* Extract symbol information
|
|
@@ -364,7 +373,7 @@ function isExported(node) {
|
|
|
364
373
|
const varStatement = varDeclList.parent;
|
|
365
374
|
if (ts.canHaveModifiers(varStatement)) {
|
|
366
375
|
const modifiers = ts.getModifiers(varStatement);
|
|
367
|
-
return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
376
|
+
return (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false);
|
|
368
377
|
}
|
|
369
378
|
return false;
|
|
370
379
|
}
|
|
@@ -382,131 +391,154 @@ function isExported(node) {
|
|
|
382
391
|
if (!ts.canHaveModifiers(node))
|
|
383
392
|
return false;
|
|
384
393
|
const modifiers = ts.getModifiers(node);
|
|
385
|
-
return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
394
|
+
return (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false);
|
|
386
395
|
}
|
|
387
396
|
/**
|
|
388
397
|
* Extract signature from node
|
|
389
398
|
*/
|
|
390
399
|
function extractSignature(node, sourceFile, kind) {
|
|
391
400
|
switch (kind) {
|
|
392
|
-
case
|
|
401
|
+
case "function": {
|
|
393
402
|
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
394
|
-
const params = node.parameters
|
|
395
|
-
|
|
403
|
+
const params = node.parameters
|
|
404
|
+
.map((p) => p.getText(sourceFile))
|
|
405
|
+
.join(", ");
|
|
406
|
+
const returnType = node.type
|
|
407
|
+
? `: ${node.type.getText(sourceFile)}`
|
|
408
|
+
: "";
|
|
396
409
|
const generics = node.typeParameters
|
|
397
|
-
? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(
|
|
398
|
-
:
|
|
410
|
+
? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(", ")}>`
|
|
411
|
+
: "";
|
|
399
412
|
return `function ${node.name.text}${generics}(${params})${returnType}`;
|
|
400
413
|
}
|
|
401
414
|
if (ts.isVariableStatement(node)) {
|
|
402
415
|
const decl = node.declarationList.declarations[0];
|
|
403
416
|
if (ts.isIdentifier(decl.name)) {
|
|
404
417
|
if (decl.initializer &&
|
|
405
|
-
(ts.isArrowFunction(decl.initializer) ||
|
|
418
|
+
(ts.isArrowFunction(decl.initializer) ||
|
|
419
|
+
ts.isFunctionExpression(decl.initializer))) {
|
|
406
420
|
const func = decl.initializer;
|
|
407
|
-
const params = func.parameters
|
|
408
|
-
|
|
421
|
+
const params = func.parameters
|
|
422
|
+
.map((p) => p.getText(sourceFile))
|
|
423
|
+
.join(", ");
|
|
424
|
+
const returnType = func.type
|
|
425
|
+
? `: ${func.type.getText(sourceFile)}`
|
|
426
|
+
: "";
|
|
409
427
|
return `const ${decl.name.text} = (${params})${returnType} => ...`;
|
|
410
428
|
}
|
|
411
429
|
}
|
|
412
430
|
}
|
|
413
|
-
return node.getText(sourceFile).split(
|
|
431
|
+
return node.getText(sourceFile).split("\n")[0];
|
|
414
432
|
}
|
|
415
|
-
case
|
|
433
|
+
case "class": {
|
|
416
434
|
if (ts.isClassDeclaration(node) && node.name) {
|
|
417
435
|
const generics = node.typeParameters
|
|
418
|
-
? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(
|
|
419
|
-
:
|
|
420
|
-
let heritage =
|
|
436
|
+
? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(", ")}>`
|
|
437
|
+
: "";
|
|
438
|
+
let heritage = "";
|
|
421
439
|
if (node.heritageClauses) {
|
|
422
440
|
for (const clause of node.heritageClauses) {
|
|
423
441
|
const tokenKind = clause.token;
|
|
424
442
|
if (tokenKind === ts.SyntaxKind.ExtendsKeyword) {
|
|
425
|
-
heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(
|
|
443
|
+
heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(", ")}`;
|
|
426
444
|
}
|
|
427
445
|
else if (tokenKind === ts.SyntaxKind.ImplementsKeyword) {
|
|
428
|
-
heritage += ` implements ${clause.types.map((t) => t.getText(sourceFile)).join(
|
|
446
|
+
heritage += ` implements ${clause.types.map((t) => t.getText(sourceFile)).join(", ")}`;
|
|
429
447
|
}
|
|
430
448
|
}
|
|
431
449
|
}
|
|
432
450
|
return `class ${node.name.text}${generics}${heritage}`;
|
|
433
451
|
}
|
|
434
|
-
return node.getText(sourceFile).split(
|
|
452
|
+
return node.getText(sourceFile).split("\n")[0];
|
|
435
453
|
}
|
|
436
|
-
case
|
|
454
|
+
case "interface": {
|
|
437
455
|
if (ts.isInterfaceDeclaration(node)) {
|
|
438
456
|
const generics = node.typeParameters
|
|
439
|
-
? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(
|
|
440
|
-
:
|
|
441
|
-
let heritage =
|
|
457
|
+
? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(", ")}>`
|
|
458
|
+
: "";
|
|
459
|
+
let heritage = "";
|
|
442
460
|
if (node.heritageClauses) {
|
|
443
461
|
for (const clause of node.heritageClauses) {
|
|
444
|
-
heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(
|
|
462
|
+
heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(", ")}`;
|
|
445
463
|
}
|
|
446
464
|
}
|
|
447
465
|
return `interface ${node.name.text}${generics}${heritage}`;
|
|
448
466
|
}
|
|
449
|
-
return node.getText(sourceFile).split(
|
|
467
|
+
return node.getText(sourceFile).split("\n")[0];
|
|
450
468
|
}
|
|
451
|
-
case
|
|
469
|
+
case "type": {
|
|
452
470
|
if (ts.isTypeAliasDeclaration(node)) {
|
|
453
471
|
const generics = node.typeParameters
|
|
454
|
-
? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(
|
|
455
|
-
:
|
|
472
|
+
? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(", ")}>`
|
|
473
|
+
: "";
|
|
456
474
|
const typeText = node.type.getText(sourceFile);
|
|
457
475
|
// Truncate long types
|
|
458
476
|
const maxLen = 80;
|
|
459
|
-
const truncatedType = typeText.length > maxLen
|
|
477
|
+
const truncatedType = typeText.length > maxLen
|
|
478
|
+
? typeText.slice(0, maxLen) + "..."
|
|
479
|
+
: typeText;
|
|
460
480
|
return `type ${node.name.text}${generics} = ${truncatedType}`;
|
|
461
481
|
}
|
|
462
|
-
return node.getText(sourceFile).split(
|
|
482
|
+
return node.getText(sourceFile).split("\n")[0];
|
|
463
483
|
}
|
|
464
|
-
case
|
|
484
|
+
case "enum": {
|
|
465
485
|
if (ts.isEnumDeclaration(node)) {
|
|
466
|
-
const members = node.members
|
|
467
|
-
|
|
468
|
-
|
|
486
|
+
const members = node.members
|
|
487
|
+
.map((m) => m.name.getText(sourceFile))
|
|
488
|
+
.slice(0, 5);
|
|
489
|
+
const suffix = node.members.length > 5 ? ", ..." : "";
|
|
490
|
+
return `enum ${node.name.text} { ${members.join(", ")}${suffix} }`;
|
|
469
491
|
}
|
|
470
|
-
return node.getText(sourceFile).split(
|
|
492
|
+
return node.getText(sourceFile).split("\n")[0];
|
|
471
493
|
}
|
|
472
|
-
case
|
|
494
|
+
case "variable": {
|
|
473
495
|
if (ts.isVariableStatement(node)) {
|
|
474
496
|
const decl = node.declarationList.declarations[0];
|
|
475
497
|
if (ts.isIdentifier(decl.name)) {
|
|
476
|
-
const typeText = decl.type
|
|
498
|
+
const typeText = decl.type
|
|
499
|
+
? `: ${decl.type.getText(sourceFile)}`
|
|
500
|
+
: "";
|
|
477
501
|
return `const ${decl.name.text}${typeText}`;
|
|
478
502
|
}
|
|
479
503
|
}
|
|
480
|
-
return node.getText(sourceFile).split(
|
|
504
|
+
return node.getText(sourceFile).split("\n")[0];
|
|
481
505
|
}
|
|
482
|
-
case
|
|
506
|
+
case "method": {
|
|
483
507
|
if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
484
|
-
const params = node.parameters
|
|
485
|
-
|
|
508
|
+
const params = node.parameters
|
|
509
|
+
.map((p) => p.getText(sourceFile))
|
|
510
|
+
.join(", ");
|
|
511
|
+
const returnType = node.type
|
|
512
|
+
? `: ${node.type.getText(sourceFile)}`
|
|
513
|
+
: "";
|
|
486
514
|
return `${node.name.text}(${params})${returnType}`;
|
|
487
515
|
}
|
|
488
516
|
if (ts.isMethodSignature(node) && ts.isIdentifier(node.name)) {
|
|
489
|
-
const params = node.parameters
|
|
490
|
-
|
|
517
|
+
const params = node.parameters
|
|
518
|
+
.map((p) => p.getText(sourceFile))
|
|
519
|
+
.join(", ");
|
|
520
|
+
const returnType = node.type
|
|
521
|
+
? `: ${node.type.getText(sourceFile)}`
|
|
522
|
+
: "";
|
|
491
523
|
return `${node.name.text}(${params})${returnType}`;
|
|
492
524
|
}
|
|
493
|
-
return node.getText(sourceFile).split(
|
|
525
|
+
return node.getText(sourceFile).split("\n")[0];
|
|
494
526
|
}
|
|
495
|
-
case
|
|
527
|
+
case "property": {
|
|
496
528
|
if (ts.isPropertyDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
497
|
-
const typeText = node.type ? `: ${node.type.getText(sourceFile)}` :
|
|
498
|
-
const optional = node.questionToken ?
|
|
529
|
+
const typeText = node.type ? `: ${node.type.getText(sourceFile)}` : "";
|
|
530
|
+
const optional = node.questionToken ? "?" : "";
|
|
499
531
|
return `${node.name.text}${optional}${typeText}`;
|
|
500
532
|
}
|
|
501
533
|
if (ts.isPropertySignature(node) && ts.isIdentifier(node.name)) {
|
|
502
|
-
const typeText = node.type ? `: ${node.type.getText(sourceFile)}` :
|
|
503
|
-
const optional = node.questionToken ?
|
|
534
|
+
const typeText = node.type ? `: ${node.type.getText(sourceFile)}` : "";
|
|
535
|
+
const optional = node.questionToken ? "?" : "";
|
|
504
536
|
return `${node.name.text}${optional}${typeText}`;
|
|
505
537
|
}
|
|
506
|
-
return node.getText(sourceFile).split(
|
|
538
|
+
return node.getText(sourceFile).split("\n")[0];
|
|
507
539
|
}
|
|
508
540
|
default:
|
|
509
|
-
return node.getText(sourceFile).split(
|
|
541
|
+
return node.getText(sourceFile).split("\n")[0];
|
|
510
542
|
}
|
|
511
543
|
}
|
|
512
544
|
/**
|
|
@@ -516,29 +548,29 @@ function extractDocumentation(node, sourceFile) {
|
|
|
516
548
|
const jsDocTags = ts.getJSDocTags(node);
|
|
517
549
|
const jsDocComments = node.jsDoc;
|
|
518
550
|
const doc = {
|
|
519
|
-
summary:
|
|
551
|
+
summary: "",
|
|
520
552
|
};
|
|
521
553
|
// Get comment text
|
|
522
554
|
if (jsDocComments?.length) {
|
|
523
555
|
const firstDoc = jsDocComments[0];
|
|
524
|
-
if (typeof firstDoc.comment ===
|
|
525
|
-
const lines = firstDoc.comment.split(
|
|
556
|
+
if (typeof firstDoc.comment === "string") {
|
|
557
|
+
const lines = firstDoc.comment.split("\n");
|
|
526
558
|
doc.summary = lines[0].trim();
|
|
527
559
|
if (lines.length > 1) {
|
|
528
|
-
doc.description = lines.slice(1).join(
|
|
560
|
+
doc.description = lines.slice(1).join("\n").trim();
|
|
529
561
|
}
|
|
530
562
|
}
|
|
531
|
-
else if (firstDoc.comment && typeof firstDoc.comment !==
|
|
563
|
+
else if (firstDoc.comment && typeof firstDoc.comment !== "string") {
|
|
532
564
|
// JSDocComment can be an array of JSDocText | JSDocLink
|
|
533
565
|
const commentParts = firstDoc.comment;
|
|
534
566
|
const text = commentParts
|
|
535
|
-
.map((c) => (c.kind === ts.SyntaxKind.JSDocText ? c.text :
|
|
536
|
-
.join(
|
|
567
|
+
.map((c) => (c.kind === ts.SyntaxKind.JSDocText ? c.text : ""))
|
|
568
|
+
.join("")
|
|
537
569
|
.trim();
|
|
538
|
-
const lines = text.split(
|
|
570
|
+
const lines = text.split("\n");
|
|
539
571
|
doc.summary = lines[0].trim();
|
|
540
572
|
if (lines.length > 1) {
|
|
541
|
-
doc.description = lines.slice(1).join(
|
|
573
|
+
doc.description = lines.slice(1).join("\n").trim();
|
|
542
574
|
}
|
|
543
575
|
}
|
|
544
576
|
}
|
|
@@ -549,37 +581,37 @@ function extractDocumentation(node, sourceFile) {
|
|
|
549
581
|
const see = [];
|
|
550
582
|
for (const tag of jsDocTags) {
|
|
551
583
|
const tagName = tag.tagName.text;
|
|
552
|
-
let tagComment =
|
|
553
|
-
if (typeof tag.comment ===
|
|
584
|
+
let tagComment = "";
|
|
585
|
+
if (typeof tag.comment === "string") {
|
|
554
586
|
tagComment = tag.comment;
|
|
555
587
|
}
|
|
556
|
-
else if (tag.comment && typeof tag.comment !==
|
|
588
|
+
else if (tag.comment && typeof tag.comment !== "string") {
|
|
557
589
|
const commentParts = tag.comment;
|
|
558
590
|
tagComment = commentParts
|
|
559
|
-
.map((c) => (c.kind === ts.SyntaxKind.JSDocText ? c.text :
|
|
560
|
-
.join(
|
|
591
|
+
.map((c) => (c.kind === ts.SyntaxKind.JSDocText ? c.text : ""))
|
|
592
|
+
.join("")
|
|
561
593
|
.trim();
|
|
562
594
|
}
|
|
563
|
-
if (tagName ===
|
|
595
|
+
if (tagName === "param" && ts.isJSDocParameterTag(tag)) {
|
|
564
596
|
const paramName = tag.name.getText(sourceFile);
|
|
565
597
|
params[paramName] = tagComment;
|
|
566
598
|
}
|
|
567
|
-
else if (tagName ===
|
|
599
|
+
else if (tagName === "returns" || tagName === "return") {
|
|
568
600
|
doc.returns = tagComment;
|
|
569
601
|
}
|
|
570
|
-
else if (tagName ===
|
|
602
|
+
else if (tagName === "throws" || tagName === "exception") {
|
|
571
603
|
throws.push(tagComment);
|
|
572
604
|
}
|
|
573
|
-
else if (tagName ===
|
|
605
|
+
else if (tagName === "example") {
|
|
574
606
|
examples.push(tagComment);
|
|
575
607
|
}
|
|
576
|
-
else if (tagName ===
|
|
608
|
+
else if (tagName === "see") {
|
|
577
609
|
see.push(tagComment);
|
|
578
610
|
}
|
|
579
611
|
else if (ts.isJSDocDeprecatedTag(tag)) {
|
|
580
|
-
doc.deprecatedMessage = tagComment ||
|
|
612
|
+
doc.deprecatedMessage = tagComment || "This API is deprecated";
|
|
581
613
|
}
|
|
582
|
-
else if (tagName ===
|
|
614
|
+
else if (tagName === "since") {
|
|
583
615
|
doc.since = tagComment;
|
|
584
616
|
}
|
|
585
617
|
}
|
|
@@ -598,7 +630,7 @@ function extractDocumentation(node, sourceFile) {
|
|
|
598
630
|
*/
|
|
599
631
|
export function createGetDocumentationTool(options) {
|
|
600
632
|
return defineTool({
|
|
601
|
-
name: options?.name ??
|
|
633
|
+
name: options?.name ?? "get_documentation",
|
|
602
634
|
description: options?.description ?? TOOL_DESCRIPTION,
|
|
603
635
|
inputSchema: TOOL_INPUT_SCHEMA,
|
|
604
636
|
execute: async (input) => {
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Get all exports from a module.
|
|
5
5
|
* Uses TypeScript Compiler API for accurate AST analysis.
|
|
6
6
|
*/
|
|
7
|
-
import type { Tool } from
|
|
8
|
-
import type { GetExportsInput } from
|
|
7
|
+
import type { Tool } from "@compilr-dev/agents";
|
|
8
|
+
import type { GetExportsInput } from "./types.js";
|
|
9
9
|
/**
|
|
10
10
|
* getExports tool - Get all exports from a module
|
|
11
11
|
*/
|