Skip to content

Commit 5dc0177

Browse files
committed
feat(map): include signatures in export display
- Add signature field to ExportInfo type - Extract signatures from indexed document metadata - Display signatures in formatted output (truncated to 60 chars) - Fall back to name if no signature available Provides richer context for AI assistants to understand APIs.
1 parent 8173922 commit 5dc0177

File tree

3 files changed

+73
-2
lines changed

3 files changed

+73
-2
lines changed

packages/core/src/map/__tests__/map.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ describe('Codebase Map', () => {
6969
path: 'packages/cli/src/cli.ts',
7070
type: 'function',
7171
name: 'main',
72+
signature: 'function main(args: string[]): Promise<void>',
7273
startLine: 5,
7374
endLine: 50,
7475
language: 'typescript',
@@ -167,6 +168,30 @@ describe('Codebase Map', () => {
167168
expect(nodeWithExports?.exports?.[0].name).toBeDefined();
168169
});
169170

171+
it('should include signatures in exports when available', async () => {
172+
const indexer = createMockIndexer();
173+
const map = await generateCodebaseMap(indexer, { depth: 5, includeExports: true });
174+
175+
// Find any node with an export that has a signature
176+
const findExportWithSignature = (
177+
node: typeof map.root
178+
): { name: string; signature?: string } | null => {
179+
if (node.exports) {
180+
const withSig = node.exports.find((e) => e.signature);
181+
if (withSig) return withSig;
182+
}
183+
for (const child of node.children) {
184+
const found = findExportWithSignature(child);
185+
if (found) return found;
186+
}
187+
return null;
188+
};
189+
190+
const exportWithSig = findExportWithSignature(map.root);
191+
expect(exportWithSig).not.toBeNull();
192+
expect(exportWithSig?.signature).toBe('function main(args: string[]): Promise<void>');
193+
});
194+
170195
it('should not include exports when includeExports is false', async () => {
171196
const indexer = createMockIndexer();
172197
const map = await generateCodebaseMap(indexer, { depth: 5, includeExports: false });
@@ -259,6 +284,41 @@ describe('Codebase Map', () => {
259284
expect(output).toContain('exports:');
260285
});
261286

287+
it('should show signatures in exports when available', async () => {
288+
const indexer = createMockIndexer();
289+
const map = await generateCodebaseMap(indexer, { depth: 5, includeExports: true });
290+
const output = formatCodebaseMap(map, { includeExports: true });
291+
292+
// The main function has a signature, should appear in output
293+
expect(output).toContain('function main(args: string[]): Promise<void>');
294+
});
295+
296+
it('should truncate long signatures', async () => {
297+
const longSigResults: SearchResult[] = [
298+
{
299+
id: 'src/index.ts:longFunction:1',
300+
score: 0.9,
301+
metadata: {
302+
path: 'src/index.ts',
303+
type: 'function',
304+
name: 'longFunction',
305+
signature:
306+
'function longFunction(param1: string, param2: number, param3: boolean, param4: object): Promise<ComplexReturnType>',
307+
exported: true,
308+
},
309+
},
310+
];
311+
312+
const indexer = createMockIndexer(longSigResults);
313+
const map = await generateCodebaseMap(indexer, { depth: 5, includeExports: true });
314+
const output = formatCodebaseMap(map, { includeExports: true });
315+
316+
// Should be truncated with ...
317+
expect(output).toContain('...');
318+
// Should not contain the full signature
319+
expect(output).not.toContain('ComplexReturnType');
320+
});
321+
262322
it('should show component counts', async () => {
263323
const indexer = createMockIndexer();
264324
const map = await generateCodebaseMap(indexer);

packages/core/src/map/index.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ function extractExports(docs: SearchResult[], maxExports: number): ExportInfo[]
161161
name: doc.metadata.name as string,
162162
type: (doc.metadata.type as string) || 'unknown',
163163
file: (doc.metadata.path as string) || (doc.metadata.file as string) || '',
164+
signature: doc.metadata.signature as string | undefined,
164165
});
165166

166167
if (exports.length >= maxExports) break;
@@ -266,8 +267,16 @@ function formatNode(
266267
// Add exports if present
267268
if (opts.includeExports && node.exports && node.exports.length > 0) {
268269
const exportPrefix = prefix + (isLast ? ' ' : '│ ');
269-
const exportNames = node.exports.map((e) => e.name).join(', ');
270-
lines.push(`${exportPrefix}└── exports: ${exportNames}`);
270+
const exportItems = node.exports.map((e) => {
271+
// Use signature if available, otherwise just name
272+
if (e.signature) {
273+
// Truncate long signatures
274+
const sig = e.signature.length > 60 ? `${e.signature.slice(0, 57)}...` : e.signature;
275+
return sig;
276+
}
277+
return e.name;
278+
});
279+
lines.push(`${exportPrefix}└── exports: ${exportItems.join(', ')}`);
271280
}
272281

273282
// Format children

packages/core/src/map/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export interface ExportInfo {
3131
type: string;
3232
/** File where it's defined */
3333
file: string;
34+
/** Function/method signature (if available) */
35+
signature?: string;
3436
}
3537

3638
/**

0 commit comments

Comments
 (0)