@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,49 +4,49 @@
|
|
|
4
4
|
* Get detailed signature information for a function, method, class, or type.
|
|
5
5
|
* Includes parameters, return types, generics, and documentation.
|
|
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 = `Get detailed signature information for a function, method, class, interface, or type.
|
|
14
14
|
Returns parameters with types, return type, generics, and extracted documentation (JSDoc/TSDoc).
|
|
15
15
|
Useful for understanding API contracts without reading full source code.`;
|
|
16
16
|
// Tool input schema
|
|
17
17
|
const TOOL_INPUT_SCHEMA = {
|
|
18
|
-
type:
|
|
18
|
+
type: "object",
|
|
19
19
|
properties: {
|
|
20
20
|
path: {
|
|
21
|
-
type:
|
|
22
|
-
description:
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "File containing the symbol",
|
|
23
23
|
},
|
|
24
24
|
name: {
|
|
25
|
-
type:
|
|
26
|
-
description:
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "Symbol name to get signature for",
|
|
27
27
|
},
|
|
28
28
|
line: {
|
|
29
|
-
type:
|
|
30
|
-
description:
|
|
29
|
+
type: "number",
|
|
30
|
+
description: "Line number for disambiguation (optional)",
|
|
31
31
|
},
|
|
32
32
|
includeDoc: {
|
|
33
|
-
type:
|
|
34
|
-
description:
|
|
33
|
+
type: "boolean",
|
|
34
|
+
description: "Include full documentation (default: true)",
|
|
35
35
|
default: true,
|
|
36
36
|
},
|
|
37
37
|
expandTypes: {
|
|
38
|
-
type:
|
|
39
|
-
description:
|
|
38
|
+
type: "boolean",
|
|
39
|
+
description: "Expand type aliases (default: false)",
|
|
40
40
|
default: false,
|
|
41
41
|
},
|
|
42
42
|
},
|
|
43
|
-
required: [
|
|
43
|
+
required: ["path", "name"],
|
|
44
44
|
};
|
|
45
45
|
/**
|
|
46
46
|
* getSignature tool
|
|
47
47
|
*/
|
|
48
48
|
export const getSignatureTool = defineTool({
|
|
49
|
-
name:
|
|
49
|
+
name: "get_signature",
|
|
50
50
|
description: TOOL_DESCRIPTION,
|
|
51
51
|
inputSchema: TOOL_INPUT_SCHEMA,
|
|
52
52
|
execute: executeGetSignature,
|
|
@@ -55,7 +55,7 @@ export const getSignatureTool = defineTool({
|
|
|
55
55
|
* Execute the getSignature tool
|
|
56
56
|
*/
|
|
57
57
|
async function executeGetSignature(input) {
|
|
58
|
-
const { path: inputPath, name, line, includeDoc = true, expandTypes = false } = input;
|
|
58
|
+
const { path: inputPath, name, line, includeDoc = true, expandTypes = false, } = input;
|
|
59
59
|
try {
|
|
60
60
|
const resolvedPath = path.resolve(inputPath);
|
|
61
61
|
// Check if file exists
|
|
@@ -70,8 +70,8 @@ async function executeGetSignature(input) {
|
|
|
70
70
|
if (!detection.language || !isLanguageSupported(detection.language)) {
|
|
71
71
|
return createErrorResult(`Unsupported language for file: ${resolvedPath}`);
|
|
72
72
|
}
|
|
73
|
-
const content = await fs.readFile(resolvedPath,
|
|
74
|
-
const sourceFile = ts.createSourceFile(resolvedPath, content, ts.ScriptTarget.Latest, true, resolvedPath.endsWith(
|
|
73
|
+
const content = await fs.readFile(resolvedPath, "utf-8");
|
|
74
|
+
const sourceFile = ts.createSourceFile(resolvedPath, content, ts.ScriptTarget.Latest, true, resolvedPath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
|
|
75
75
|
// Find the symbol
|
|
76
76
|
const result = findSymbolSignature(sourceFile, name, line, includeDoc, expandTypes);
|
|
77
77
|
if (!result) {
|
|
@@ -108,48 +108,49 @@ function findSymbolSignature(sourceFile, symbolName, targetLine, includeDoc, _ex
|
|
|
108
108
|
// Function declarations
|
|
109
109
|
if (ts.isFunctionDeclaration(node) && node.name?.text === symbolName) {
|
|
110
110
|
found.node = node;
|
|
111
|
-
found.kind =
|
|
111
|
+
found.kind = "function";
|
|
112
112
|
}
|
|
113
113
|
// Variable declarations (arrow functions, const functions)
|
|
114
114
|
else if (ts.isVariableDeclaration(node) &&
|
|
115
115
|
ts.isIdentifier(node.name) &&
|
|
116
116
|
node.name.text === symbolName) {
|
|
117
117
|
if (node.initializer &&
|
|
118
|
-
(ts.isArrowFunction(node.initializer) ||
|
|
118
|
+
(ts.isArrowFunction(node.initializer) ||
|
|
119
|
+
ts.isFunctionExpression(node.initializer))) {
|
|
119
120
|
found.node = node;
|
|
120
|
-
found.kind =
|
|
121
|
+
found.kind = "function";
|
|
121
122
|
}
|
|
122
123
|
else {
|
|
123
124
|
found.node = node;
|
|
124
|
-
found.kind =
|
|
125
|
+
found.kind = "variable";
|
|
125
126
|
}
|
|
126
127
|
}
|
|
127
128
|
// Class declarations
|
|
128
129
|
else if (ts.isClassDeclaration(node) && node.name?.text === symbolName) {
|
|
129
130
|
found.node = node;
|
|
130
|
-
found.kind =
|
|
131
|
+
found.kind = "class";
|
|
131
132
|
}
|
|
132
133
|
// Interface declarations
|
|
133
134
|
else if (ts.isInterfaceDeclaration(node) && node.name.text === symbolName) {
|
|
134
135
|
found.node = node;
|
|
135
|
-
found.kind =
|
|
136
|
+
found.kind = "interface";
|
|
136
137
|
}
|
|
137
138
|
// Type alias declarations
|
|
138
139
|
else if (ts.isTypeAliasDeclaration(node) && node.name.text === symbolName) {
|
|
139
140
|
found.node = node;
|
|
140
|
-
found.kind =
|
|
141
|
+
found.kind = "type";
|
|
141
142
|
}
|
|
142
143
|
// Enum declarations
|
|
143
144
|
else if (ts.isEnumDeclaration(node) && node.name.text === symbolName) {
|
|
144
145
|
found.node = node;
|
|
145
|
-
found.kind =
|
|
146
|
+
found.kind = "enum";
|
|
146
147
|
}
|
|
147
148
|
// Method declarations (inside classes)
|
|
148
149
|
else if (ts.isMethodDeclaration(node) &&
|
|
149
150
|
ts.isIdentifier(node.name) &&
|
|
150
151
|
node.name.text === symbolName) {
|
|
151
152
|
found.node = node;
|
|
152
|
-
found.kind =
|
|
153
|
+
found.kind = "method";
|
|
153
154
|
}
|
|
154
155
|
ts.forEachChild(node, visit);
|
|
155
156
|
};
|
|
@@ -166,21 +167,23 @@ function extractSignature(node, kind, sourceFile, includeDoc) {
|
|
|
166
167
|
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
167
168
|
const exported = isExported(node);
|
|
168
169
|
const name = getNodeName(node);
|
|
169
|
-
const documentation = includeDoc
|
|
170
|
+
const documentation = includeDoc
|
|
171
|
+
? extractDocumentation(node, sourceFile)
|
|
172
|
+
: undefined;
|
|
170
173
|
switch (kind) {
|
|
171
|
-
case
|
|
174
|
+
case "function":
|
|
172
175
|
return extractFunctionSignature(node, sourceFile, name, line + 1, exported, documentation);
|
|
173
|
-
case
|
|
176
|
+
case "method":
|
|
174
177
|
return extractMethodSignature(node, sourceFile, name, line + 1, exported, documentation);
|
|
175
|
-
case
|
|
178
|
+
case "class":
|
|
176
179
|
return extractClassSignature(node, sourceFile, name, line + 1, exported, documentation);
|
|
177
|
-
case
|
|
180
|
+
case "interface":
|
|
178
181
|
return extractInterfaceSignature(node, sourceFile, name, line + 1, exported, documentation);
|
|
179
|
-
case
|
|
182
|
+
case "type":
|
|
180
183
|
return extractTypeSignature(node, sourceFile, name, line + 1, exported, documentation);
|
|
181
|
-
case
|
|
184
|
+
case "enum":
|
|
182
185
|
return extractEnumSignature(node, sourceFile, name, line + 1, exported, documentation);
|
|
183
|
-
case
|
|
186
|
+
case "variable":
|
|
184
187
|
return extractVariableSignature(node, sourceFile, name, line + 1, exported, documentation);
|
|
185
188
|
default:
|
|
186
189
|
return {
|
|
@@ -208,7 +211,7 @@ function extractFunctionSignature(node, sourceFile, name, line, exported, docume
|
|
|
208
211
|
else {
|
|
209
212
|
return {
|
|
210
213
|
name,
|
|
211
|
-
kind:
|
|
214
|
+
kind: "function",
|
|
212
215
|
line,
|
|
213
216
|
signature: node.getText(sourceFile),
|
|
214
217
|
formattedSignature: node.getText(sourceFile),
|
|
@@ -219,17 +222,20 @@ function extractFunctionSignature(node, sourceFile, name, line, exported, docume
|
|
|
219
222
|
const parameters = extractParameters(funcNode.parameters, sourceFile, documentation);
|
|
220
223
|
const returnType = extractReturnType(funcNode, sourceFile);
|
|
221
224
|
const generics = extractGenerics(funcNode.typeParameters, sourceFile);
|
|
222
|
-
const isAsync = funcNode.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ??
|
|
225
|
+
const isAsync = funcNode.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ??
|
|
226
|
+
false;
|
|
223
227
|
// Build signature string
|
|
224
|
-
const asyncPrefix = isAsync ?
|
|
225
|
-
const genericsStr = generics.length > 0
|
|
226
|
-
|
|
227
|
-
|
|
228
|
+
const asyncPrefix = isAsync ? "async " : "";
|
|
229
|
+
const genericsStr = generics.length > 0
|
|
230
|
+
? `<${generics.map((g) => formatGeneric(g)).join(", ")}>`
|
|
231
|
+
: "";
|
|
232
|
+
const paramsStr = parameters.map((p) => formatParameter(p)).join(", ");
|
|
233
|
+
const returnStr = returnType ? `: ${returnType.type}` : "";
|
|
228
234
|
const signature = `${asyncPrefix}function ${name}${genericsStr}(${paramsStr})${returnStr}`;
|
|
229
235
|
const formattedSignature = formatMultilineSignature(asyncPrefix, name, genericsStr, parameters, returnType);
|
|
230
236
|
return {
|
|
231
237
|
name,
|
|
232
|
-
kind:
|
|
238
|
+
kind: "function",
|
|
233
239
|
line,
|
|
234
240
|
signature,
|
|
235
241
|
formattedSignature,
|
|
@@ -248,17 +254,20 @@ function extractMethodSignature(node, sourceFile, name, line, exported, document
|
|
|
248
254
|
const returnType = extractReturnType(node, sourceFile);
|
|
249
255
|
const generics = extractGenerics(node.typeParameters, sourceFile);
|
|
250
256
|
const isAsync = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
|
|
251
|
-
const isStatic = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ??
|
|
252
|
-
|
|
253
|
-
const
|
|
254
|
-
const
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
+
const isStatic = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ??
|
|
258
|
+
false;
|
|
259
|
+
const asyncPrefix = isAsync ? "async " : "";
|
|
260
|
+
const staticPrefix = isStatic ? "static " : "";
|
|
261
|
+
const genericsStr = generics.length > 0
|
|
262
|
+
? `<${generics.map((g) => formatGeneric(g)).join(", ")}>`
|
|
263
|
+
: "";
|
|
264
|
+
const paramsStr = parameters.map((p) => formatParameter(p)).join(", ");
|
|
265
|
+
const returnStr = returnType ? `: ${returnType.type}` : "";
|
|
257
266
|
const signature = `${staticPrefix}${asyncPrefix}${name}${genericsStr}(${paramsStr})${returnStr}`;
|
|
258
267
|
const formattedSignature = signature;
|
|
259
268
|
return {
|
|
260
269
|
name,
|
|
261
|
-
kind:
|
|
270
|
+
kind: "method",
|
|
262
271
|
line,
|
|
263
272
|
signature,
|
|
264
273
|
formattedSignature,
|
|
@@ -280,29 +289,32 @@ function extractClassSignature(node, sourceFile, name, line, exported, documenta
|
|
|
280
289
|
let constructorSignature;
|
|
281
290
|
if (constructor) {
|
|
282
291
|
const params = extractParameters(constructor.parameters, sourceFile, undefined);
|
|
283
|
-
constructorSignature = `constructor(${params.map((p) => formatParameter(p)).join(
|
|
292
|
+
constructorSignature = `constructor(${params.map((p) => formatParameter(p)).join(", ")})`;
|
|
284
293
|
}
|
|
285
294
|
// Build extends/implements
|
|
286
|
-
let heritage =
|
|
295
|
+
let heritage = "";
|
|
287
296
|
if (node.heritageClauses) {
|
|
288
297
|
for (const clause of node.heritageClauses) {
|
|
289
298
|
const tokenKind = clause.token;
|
|
290
299
|
if (tokenKind === ts.SyntaxKind.ExtendsKeyword) {
|
|
291
|
-
heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(
|
|
300
|
+
heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(", ")}`;
|
|
292
301
|
}
|
|
293
302
|
else if (tokenKind === ts.SyntaxKind.ImplementsKeyword) {
|
|
294
|
-
heritage += ` implements ${clause.types.map((t) => t.getText(sourceFile)).join(
|
|
303
|
+
heritage += ` implements ${clause.types.map((t) => t.getText(sourceFile)).join(", ")}`;
|
|
295
304
|
}
|
|
296
305
|
}
|
|
297
306
|
}
|
|
298
|
-
const isAbstract = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AbstractKeyword) ??
|
|
299
|
-
|
|
300
|
-
const
|
|
307
|
+
const isAbstract = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AbstractKeyword) ??
|
|
308
|
+
false;
|
|
309
|
+
const abstractPrefix = isAbstract ? "abstract " : "";
|
|
310
|
+
const genericsStr = generics.length > 0
|
|
311
|
+
? `<${generics.map((g) => formatGeneric(g)).join(", ")}>`
|
|
312
|
+
: "";
|
|
301
313
|
const signature = `${abstractPrefix}class ${name}${genericsStr}${heritage}`;
|
|
302
314
|
const formattedSignature = signature;
|
|
303
315
|
return {
|
|
304
316
|
name,
|
|
305
|
-
kind:
|
|
317
|
+
kind: "class",
|
|
306
318
|
line,
|
|
307
319
|
signature,
|
|
308
320
|
formattedSignature,
|
|
@@ -320,18 +332,20 @@ function extractInterfaceSignature(node, sourceFile, name, line, exported, docum
|
|
|
320
332
|
const generics = extractGenerics(node.typeParameters, sourceFile);
|
|
321
333
|
const members = extractInterfaceMembers(node, sourceFile);
|
|
322
334
|
// Build extends
|
|
323
|
-
let heritage =
|
|
335
|
+
let heritage = "";
|
|
324
336
|
if (node.heritageClauses) {
|
|
325
337
|
for (const clause of node.heritageClauses) {
|
|
326
|
-
heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(
|
|
338
|
+
heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(", ")}`;
|
|
327
339
|
}
|
|
328
340
|
}
|
|
329
|
-
const genericsStr = generics.length > 0
|
|
341
|
+
const genericsStr = generics.length > 0
|
|
342
|
+
? `<${generics.map((g) => formatGeneric(g)).join(", ")}>`
|
|
343
|
+
: "";
|
|
330
344
|
const signature = `interface ${name}${genericsStr}${heritage}`;
|
|
331
345
|
const formattedSignature = signature;
|
|
332
346
|
return {
|
|
333
347
|
name,
|
|
334
|
-
kind:
|
|
348
|
+
kind: "interface",
|
|
335
349
|
line,
|
|
336
350
|
signature,
|
|
337
351
|
formattedSignature,
|
|
@@ -347,15 +361,17 @@ function extractInterfaceSignature(node, sourceFile, name, line, exported, docum
|
|
|
347
361
|
function extractTypeSignature(node, sourceFile, name, line, exported, documentation) {
|
|
348
362
|
const generics = extractGenerics(node.typeParameters, sourceFile);
|
|
349
363
|
const typeText = node.type.getText(sourceFile);
|
|
350
|
-
const genericsStr = generics.length > 0
|
|
364
|
+
const genericsStr = generics.length > 0
|
|
365
|
+
? `<${generics.map((g) => formatGeneric(g)).join(", ")}>`
|
|
366
|
+
: "";
|
|
351
367
|
const signature = `type ${name}${genericsStr} = ${typeText}`;
|
|
352
368
|
// Format multi-line for complex types
|
|
353
369
|
const formattedSignature = typeText.length > 60
|
|
354
|
-
? `type ${name}${genericsStr} = \n ${typeText.replace(/\n/g,
|
|
370
|
+
? `type ${name}${genericsStr} = \n ${typeText.replace(/\n/g, "\n ")}`
|
|
355
371
|
: signature;
|
|
356
372
|
return {
|
|
357
373
|
name,
|
|
358
|
-
kind:
|
|
374
|
+
kind: "type",
|
|
359
375
|
line,
|
|
360
376
|
signature,
|
|
361
377
|
formattedSignature,
|
|
@@ -370,7 +386,7 @@ function extractTypeSignature(node, sourceFile, name, line, exported, documentat
|
|
|
370
386
|
function extractEnumSignature(node, sourceFile, name, line, exported, documentation) {
|
|
371
387
|
const members = node.members.map((member) => ({
|
|
372
388
|
name: member.name.getText(sourceFile),
|
|
373
|
-
kind:
|
|
389
|
+
kind: "property",
|
|
374
390
|
signature: member.initializer
|
|
375
391
|
? `${member.name.getText(sourceFile)} = ${member.initializer.getText(sourceFile)}`
|
|
376
392
|
: member.name.getText(sourceFile),
|
|
@@ -378,11 +394,11 @@ function extractEnumSignature(node, sourceFile, name, line, exported, documentat
|
|
|
378
394
|
readonly: true,
|
|
379
395
|
}));
|
|
380
396
|
const isConst = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ConstKeyword) ?? false;
|
|
381
|
-
const constPrefix = isConst ?
|
|
397
|
+
const constPrefix = isConst ? "const " : "";
|
|
382
398
|
const signature = `${constPrefix}enum ${name}`;
|
|
383
399
|
return {
|
|
384
400
|
name,
|
|
385
|
-
kind:
|
|
401
|
+
kind: "enum",
|
|
386
402
|
line,
|
|
387
403
|
signature,
|
|
388
404
|
formattedSignature: signature,
|
|
@@ -399,25 +415,29 @@ function extractVariableSignature(node, sourceFile, name, line, exported, docume
|
|
|
399
415
|
const typeText = typeNode ? typeNode.getText(sourceFile) : undefined;
|
|
400
416
|
// Determine const/let/var
|
|
401
417
|
const parent = node.parent;
|
|
402
|
-
let declKind =
|
|
418
|
+
let declKind = "const";
|
|
403
419
|
if (ts.isVariableDeclarationList(parent)) {
|
|
404
420
|
if (parent.flags & ts.NodeFlags.Let)
|
|
405
|
-
declKind =
|
|
421
|
+
declKind = "let";
|
|
406
422
|
else if (parent.flags & ts.NodeFlags.Const)
|
|
407
|
-
declKind =
|
|
423
|
+
declKind = "const";
|
|
408
424
|
else
|
|
409
|
-
declKind =
|
|
425
|
+
declKind = "var";
|
|
410
426
|
}
|
|
411
|
-
const signature = typeText
|
|
427
|
+
const signature = typeText
|
|
428
|
+
? `${declKind} ${name}: ${typeText}`
|
|
429
|
+
: `${declKind} ${name}`;
|
|
412
430
|
return {
|
|
413
431
|
name,
|
|
414
|
-
kind:
|
|
432
|
+
kind: "variable",
|
|
415
433
|
line,
|
|
416
434
|
signature,
|
|
417
435
|
formattedSignature: signature,
|
|
418
436
|
exported,
|
|
419
437
|
documentation,
|
|
420
|
-
returnType: typeText
|
|
438
|
+
returnType: typeText
|
|
439
|
+
? { type: typeText, isPromise: false, nullable: false }
|
|
440
|
+
: undefined,
|
|
421
441
|
};
|
|
422
442
|
}
|
|
423
443
|
/**
|
|
@@ -426,10 +446,12 @@ function extractVariableSignature(node, sourceFile, name, line, exported, docume
|
|
|
426
446
|
function extractParameters(params, sourceFile, documentation) {
|
|
427
447
|
return params.map((param) => {
|
|
428
448
|
const paramName = param.name.getText(sourceFile);
|
|
429
|
-
const type = param.type ? param.type.getText(sourceFile) :
|
|
449
|
+
const type = param.type ? param.type.getText(sourceFile) : "any";
|
|
430
450
|
const optional = param.questionToken !== undefined || param.initializer !== undefined;
|
|
431
451
|
const rest = param.dotDotDotToken !== undefined;
|
|
432
|
-
const defaultValue = param.initializer
|
|
452
|
+
const defaultValue = param.initializer
|
|
453
|
+
? param.initializer.getText(sourceFile)
|
|
454
|
+
: undefined;
|
|
433
455
|
const description = documentation?.params?.[paramName];
|
|
434
456
|
return {
|
|
435
457
|
name: paramName,
|
|
@@ -448,8 +470,8 @@ function extractReturnType(node, sourceFile) {
|
|
|
448
470
|
if (!node.type)
|
|
449
471
|
return undefined;
|
|
450
472
|
const typeText = node.type.getText(sourceFile);
|
|
451
|
-
const isPromise = typeText.startsWith(
|
|
452
|
-
const nullable = typeText.includes(
|
|
473
|
+
const isPromise = typeText.startsWith("Promise<") || typeText.startsWith("Promise ");
|
|
474
|
+
const nullable = typeText.includes("| null") || typeText.includes("| undefined");
|
|
453
475
|
return {
|
|
454
476
|
type: typeText,
|
|
455
477
|
isPromise,
|
|
@@ -464,7 +486,9 @@ function extractGenerics(typeParams, sourceFile) {
|
|
|
464
486
|
return [];
|
|
465
487
|
return typeParams.map((param) => ({
|
|
466
488
|
name: param.name.getText(sourceFile),
|
|
467
|
-
constraint: param.constraint
|
|
489
|
+
constraint: param.constraint
|
|
490
|
+
? param.constraint.getText(sourceFile)
|
|
491
|
+
: undefined,
|
|
468
492
|
default: param.default ? param.default.getText(sourceFile) : undefined,
|
|
469
493
|
}));
|
|
470
494
|
}
|
|
@@ -479,14 +503,16 @@ function extractClassMembers(node, sourceFile) {
|
|
|
479
503
|
// Handle property declarations
|
|
480
504
|
if (ts.isPropertyDeclaration(member)) {
|
|
481
505
|
const memberName = member.name.getText(sourceFile);
|
|
482
|
-
const mods = ts.canHaveModifiers(member)
|
|
506
|
+
const mods = ts.canHaveModifiers(member)
|
|
507
|
+
? ts.getModifiers(member)
|
|
508
|
+
: undefined;
|
|
483
509
|
const isStatic = mods?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ?? false;
|
|
484
510
|
const isReadonly = mods?.some((m) => m.kind === ts.SyntaxKind.ReadonlyKeyword) ?? false;
|
|
485
511
|
const visibility = getVisibility(member);
|
|
486
|
-
const type = member.type ? member.type.getText(sourceFile) :
|
|
512
|
+
const type = member.type ? member.type.getText(sourceFile) : "any";
|
|
487
513
|
members.push({
|
|
488
514
|
name: memberName,
|
|
489
|
-
kind:
|
|
515
|
+
kind: "property",
|
|
490
516
|
signature: `${memberName}: ${type}`,
|
|
491
517
|
optional: member.questionToken !== undefined,
|
|
492
518
|
readonly: isReadonly,
|
|
@@ -497,14 +523,20 @@ function extractClassMembers(node, sourceFile) {
|
|
|
497
523
|
// Handle method declarations
|
|
498
524
|
else if (ts.isMethodDeclaration(member)) {
|
|
499
525
|
const memberName = member.name.getText(sourceFile);
|
|
500
|
-
const mods = ts.canHaveModifiers(member)
|
|
526
|
+
const mods = ts.canHaveModifiers(member)
|
|
527
|
+
? ts.getModifiers(member)
|
|
528
|
+
: undefined;
|
|
501
529
|
const isStatic = mods?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ?? false;
|
|
502
530
|
const visibility = getVisibility(member);
|
|
503
|
-
const params = member.parameters
|
|
504
|
-
|
|
531
|
+
const params = member.parameters
|
|
532
|
+
.map((p) => p.getText(sourceFile))
|
|
533
|
+
.join(", ");
|
|
534
|
+
const returnType = member.type
|
|
535
|
+
? `: ${member.type.getText(sourceFile)}`
|
|
536
|
+
: "";
|
|
505
537
|
members.push({
|
|
506
538
|
name: memberName,
|
|
507
|
-
kind:
|
|
539
|
+
kind: "method",
|
|
508
540
|
signature: `${memberName}(${params})${returnType}`,
|
|
509
541
|
optional: member.questionToken !== undefined,
|
|
510
542
|
readonly: false,
|
|
@@ -515,13 +547,17 @@ function extractClassMembers(node, sourceFile) {
|
|
|
515
547
|
// Handle getter accessors
|
|
516
548
|
else if (ts.isGetAccessor(member)) {
|
|
517
549
|
const memberName = member.name.getText(sourceFile);
|
|
518
|
-
const mods = ts.canHaveModifiers(member)
|
|
550
|
+
const mods = ts.canHaveModifiers(member)
|
|
551
|
+
? ts.getModifiers(member)
|
|
552
|
+
: undefined;
|
|
519
553
|
const isStatic = mods?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ?? false;
|
|
520
554
|
const visibility = getVisibility(member);
|
|
521
|
-
const returnType = member.type
|
|
555
|
+
const returnType = member.type
|
|
556
|
+
? `: ${member.type.getText(sourceFile)}`
|
|
557
|
+
: "";
|
|
522
558
|
members.push({
|
|
523
559
|
name: memberName,
|
|
524
|
-
kind:
|
|
560
|
+
kind: "getter",
|
|
525
561
|
signature: `get ${memberName}()${returnType}`,
|
|
526
562
|
optional: false,
|
|
527
563
|
readonly: true,
|
|
@@ -532,14 +568,16 @@ function extractClassMembers(node, sourceFile) {
|
|
|
532
568
|
// Handle setter accessors
|
|
533
569
|
else if (ts.isSetAccessor(member)) {
|
|
534
570
|
const memberName = member.name.getText(sourceFile);
|
|
535
|
-
const mods = ts.canHaveModifiers(member)
|
|
571
|
+
const mods = ts.canHaveModifiers(member)
|
|
572
|
+
? ts.getModifiers(member)
|
|
573
|
+
: undefined;
|
|
536
574
|
const isStatic = mods?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ?? false;
|
|
537
575
|
const visibility = getVisibility(member);
|
|
538
576
|
const param = member.parameters[0];
|
|
539
577
|
const paramStr = param.getText(sourceFile);
|
|
540
578
|
members.push({
|
|
541
579
|
name: memberName,
|
|
542
|
-
kind:
|
|
580
|
+
kind: "setter",
|
|
543
581
|
signature: `set ${memberName}(${paramStr})`,
|
|
544
582
|
optional: false,
|
|
545
583
|
readonly: false,
|
|
@@ -558,11 +596,11 @@ function extractInterfaceMembers(node, sourceFile) {
|
|
|
558
596
|
for (const member of node.members) {
|
|
559
597
|
if (ts.isPropertySignature(member)) {
|
|
560
598
|
const memberName = member.name.getText(sourceFile);
|
|
561
|
-
const type = member.type ? member.type.getText(sourceFile) :
|
|
599
|
+
const type = member.type ? member.type.getText(sourceFile) : "any";
|
|
562
600
|
const isReadonly = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.ReadonlyKeyword) ?? false;
|
|
563
601
|
members.push({
|
|
564
602
|
name: memberName,
|
|
565
|
-
kind:
|
|
603
|
+
kind: "property",
|
|
566
604
|
signature: `${memberName}: ${type}`,
|
|
567
605
|
optional: member.questionToken !== undefined,
|
|
568
606
|
readonly: isReadonly,
|
|
@@ -570,11 +608,15 @@ function extractInterfaceMembers(node, sourceFile) {
|
|
|
570
608
|
}
|
|
571
609
|
else if (ts.isMethodSignature(member)) {
|
|
572
610
|
const memberName = member.name.getText(sourceFile);
|
|
573
|
-
const params = member.parameters
|
|
574
|
-
|
|
611
|
+
const params = member.parameters
|
|
612
|
+
.map((p) => p.getText(sourceFile))
|
|
613
|
+
.join(", ");
|
|
614
|
+
const returnType = member.type
|
|
615
|
+
? `: ${member.type.getText(sourceFile)}`
|
|
616
|
+
: "";
|
|
575
617
|
members.push({
|
|
576
618
|
name: memberName,
|
|
577
|
-
kind:
|
|
619
|
+
kind: "method",
|
|
578
620
|
signature: `${memberName}(${params})${returnType}`,
|
|
579
621
|
optional: member.questionToken !== undefined,
|
|
580
622
|
readonly: false,
|
|
@@ -592,16 +634,16 @@ function extractDocumentation(node, sourceFile) {
|
|
|
592
634
|
if (!jsDocComments?.length && !jsDocTags.length)
|
|
593
635
|
return undefined;
|
|
594
636
|
const doc = {
|
|
595
|
-
summary:
|
|
637
|
+
summary: "",
|
|
596
638
|
};
|
|
597
639
|
// Get comment text
|
|
598
640
|
if (jsDocComments?.length) {
|
|
599
641
|
const firstDoc = jsDocComments[0];
|
|
600
|
-
if (typeof firstDoc.comment ===
|
|
601
|
-
const lines = firstDoc.comment.split(
|
|
642
|
+
if (typeof firstDoc.comment === "string") {
|
|
643
|
+
const lines = firstDoc.comment.split("\n");
|
|
602
644
|
doc.summary = lines[0].trim();
|
|
603
645
|
if (lines.length > 1) {
|
|
604
|
-
doc.description = lines.slice(1).join(
|
|
646
|
+
doc.description = lines.slice(1).join("\n").trim();
|
|
605
647
|
}
|
|
606
648
|
}
|
|
607
649
|
}
|
|
@@ -612,27 +654,27 @@ function extractDocumentation(node, sourceFile) {
|
|
|
612
654
|
const see = [];
|
|
613
655
|
for (const tag of jsDocTags) {
|
|
614
656
|
const tagName = tag.tagName.text;
|
|
615
|
-
const tagComment = typeof tag.comment ===
|
|
616
|
-
if (tagName ===
|
|
657
|
+
const tagComment = typeof tag.comment === "string" ? tag.comment : "";
|
|
658
|
+
if (tagName === "param" && ts.isJSDocParameterTag(tag)) {
|
|
617
659
|
const paramName = tag.name.getText(sourceFile);
|
|
618
660
|
params[paramName] = tagComment;
|
|
619
661
|
}
|
|
620
|
-
else if (tagName ===
|
|
662
|
+
else if (tagName === "returns" || tagName === "return") {
|
|
621
663
|
doc.returns = tagComment;
|
|
622
664
|
}
|
|
623
|
-
else if (tagName ===
|
|
665
|
+
else if (tagName === "throws" || tagName === "exception") {
|
|
624
666
|
throws.push(tagComment);
|
|
625
667
|
}
|
|
626
|
-
else if (tagName ===
|
|
668
|
+
else if (tagName === "example") {
|
|
627
669
|
examples.push(tagComment);
|
|
628
670
|
}
|
|
629
|
-
else if (tagName ===
|
|
671
|
+
else if (tagName === "see") {
|
|
630
672
|
see.push(tagComment);
|
|
631
673
|
}
|
|
632
674
|
else if (ts.isJSDocDeprecatedTag(tag)) {
|
|
633
|
-
doc.deprecatedMessage = tagComment ||
|
|
675
|
+
doc.deprecatedMessage = tagComment || "This API is deprecated";
|
|
634
676
|
}
|
|
635
|
-
else if (tagName ===
|
|
677
|
+
else if (tagName === "since") {
|
|
636
678
|
doc.since = tagComment;
|
|
637
679
|
}
|
|
638
680
|
}
|
|
@@ -667,7 +709,7 @@ function getNodeName(node) {
|
|
|
667
709
|
return node.name.text;
|
|
668
710
|
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name))
|
|
669
711
|
return node.name.text;
|
|
670
|
-
return
|
|
712
|
+
return "<anonymous>";
|
|
671
713
|
}
|
|
672
714
|
/**
|
|
673
715
|
* Check if node is exported
|
|
@@ -680,27 +722,27 @@ function isExported(node) {
|
|
|
680
722
|
const varStatement = varDeclList.parent;
|
|
681
723
|
if (ts.canHaveModifiers(varStatement)) {
|
|
682
724
|
const modifiers = ts.getModifiers(varStatement);
|
|
683
|
-
return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
725
|
+
return (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false);
|
|
684
726
|
}
|
|
685
727
|
return false;
|
|
686
728
|
}
|
|
687
729
|
if (!ts.canHaveModifiers(node))
|
|
688
730
|
return false;
|
|
689
731
|
const modifiers = ts.getModifiers(node);
|
|
690
|
-
return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
732
|
+
return (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false);
|
|
691
733
|
}
|
|
692
734
|
/**
|
|
693
735
|
* Get visibility modifier
|
|
694
736
|
*/
|
|
695
737
|
function getVisibility(node) {
|
|
696
738
|
if (!ts.canHaveModifiers(node))
|
|
697
|
-
return
|
|
739
|
+
return "public";
|
|
698
740
|
const modifiers = ts.getModifiers(node);
|
|
699
741
|
if (modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword))
|
|
700
|
-
return
|
|
742
|
+
return "private";
|
|
701
743
|
if (modifiers?.some((m) => m.kind === ts.SyntaxKind.ProtectedKeyword))
|
|
702
|
-
return
|
|
703
|
-
return
|
|
744
|
+
return "protected";
|
|
745
|
+
return "public";
|
|
704
746
|
}
|
|
705
747
|
/**
|
|
706
748
|
* Format a generic parameter
|
|
@@ -719,7 +761,7 @@ function formatGeneric(g) {
|
|
|
719
761
|
function formatParameter(p) {
|
|
720
762
|
let result = p.rest ? `...${p.name}` : p.name;
|
|
721
763
|
if (p.optional && !p.defaultValue)
|
|
722
|
-
result +=
|
|
764
|
+
result += "?";
|
|
723
765
|
result += `: ${p.type}`;
|
|
724
766
|
if (p.defaultValue)
|
|
725
767
|
result += ` = ${p.defaultValue}`;
|
|
@@ -730,13 +772,15 @@ function formatParameter(p) {
|
|
|
730
772
|
*/
|
|
731
773
|
function formatMultilineSignature(asyncPrefix, name, genericsStr, parameters, returnType) {
|
|
732
774
|
if (parameters.length <= 2) {
|
|
733
|
-
const paramsStr = parameters.map((p) => formatParameter(p)).join(
|
|
734
|
-
const returnStr = returnType ? `: ${returnType.type}` :
|
|
775
|
+
const paramsStr = parameters.map((p) => formatParameter(p)).join(", ");
|
|
776
|
+
const returnStr = returnType ? `: ${returnType.type}` : "";
|
|
735
777
|
return `${asyncPrefix}function ${name}${genericsStr}(${paramsStr})${returnStr}`;
|
|
736
778
|
}
|
|
737
779
|
// Multi-line for many parameters
|
|
738
|
-
const paramsLines = parameters
|
|
739
|
-
|
|
780
|
+
const paramsLines = parameters
|
|
781
|
+
.map((p) => ` ${formatParameter(p)}`)
|
|
782
|
+
.join(",\n");
|
|
783
|
+
const returnStr = returnType ? `: ${returnType.type}` : "";
|
|
740
784
|
return `${asyncPrefix}function ${name}${genericsStr}(\n${paramsLines}\n)${returnStr}`;
|
|
741
785
|
}
|
|
742
786
|
/**
|
|
@@ -744,7 +788,7 @@ function formatMultilineSignature(asyncPrefix, name, genericsStr, parameters, re
|
|
|
744
788
|
*/
|
|
745
789
|
export function createGetSignatureTool(options) {
|
|
746
790
|
return defineTool({
|
|
747
|
-
name: options?.name ??
|
|
791
|
+
name: options?.name ?? "get_signature",
|
|
748
792
|
description: options?.description ?? TOOL_DESCRIPTION,
|
|
749
793
|
inputSchema: TOOL_INPUT_SCHEMA,
|
|
750
794
|
execute: async (input) => {
|