Skip to content

Commit 53b2c52

Browse files
feat: richer symbol metadata — signatures, JSDoc, type members, call graph (#19)
* feat: richer symbol metadata — generics, return types, enum members Signatures now include generic type parameters (`<T extends Base>`), return type annotations (`: Promise<void>`), and class/interface heritage (`extends`, `implements`). Enum members are extracted into a new `members TEXT` column as JSON. Benchmarked on a 1,653-file React/TS codebase: 973 functions gain return types, 873 symbols gain generics, 291 enum member values captured across 50 enums. Index time +7% (negligible), DB size unchanged. * feat: JSDoc extraction and type_members table Add doc_comment column to symbols (3,084 documented symbols on benchmark repo) and new type_members table for interface/type-alias properties (12,052 members extracted). Agents can now query type shapes and symbol documentation without reading files. SCHEMA_VERSION bumped to 2. * feat: extract const literal values into symbols.value Captures string, number, boolean, null, negative numbers, `as const`, and simple template literals. 615 values extracted on benchmark repo. * feat: symbol nesting via parent_name + class member extraction Adds parent_name column to symbols for scope tracking. A visitor stack assigns parent context to nested functions/consts (10,202 nested symbols on benchmark). Class methods, properties, and getters/setters are now extracted as individual symbols with parent_name pointing to the class. * feat: call graph extraction — function-scoped, deduped per file New `calls` table tracks which functions call which. Edges are deduped per file and limited to function-scoped calls (module-level excluded). Benchmark (merchant-dashboard-v2): 13,804 edges, 2,700 callers, 5,310 callees. Index time unchanged, DB +5MB (23→28MB). * chore: add changeset for richer symbol metadata * fix: call graph improvements — qualified scope, this.method(), multi-declarator scope fix - Add caller_scope column to calls table (dot-joined scope path, e.g. UserService.run) so same-named methods across classes are no longer conflated. Dedup key now uses full scope path. - Handle this.foo() calls in CallExpression (emitted as this.methodName). - Fix multi-declarator scope corruption: VariableDeclaration:exit now iterates in reverse so const a = () => {}, b = () => {} correctly pops both scopes. - Document new class-member kind values (method, property, getter, setter) in architecture.md. - Sync template SKILL.md with authoring skill query examples. * perf: reduce allocations and redundant I/O in parser and index engine - Cache scopeStack.join(".") via scopePush/scopePop helpers - Hoist hot-path regex literals (RE_COMPONENT, RE_HOOK) to module scope - Replace findJsDoc gap regex with charCodeAt loop (no .slice()) - Cache getProjectRoot() in getChangedFiles, insertParsedResults, indexFiles - Eliminate redundant getAllFileHashes call in incremental path - Batch DELETE for deleted files (single IN() vs N separate DELETEs) - Hoist fileURLToPath and getProjectRoot() in worker-pool spawn loop - Increase BATCH_SIZE 100→500 for fewer INSERT round-trips - Zero-alloc isPathExcluded via charCodeAt segment scan - Update docs: schema version 1→2, batch size references * docs: fix stale schema comment, add caller_scope index, expand parser checklist - Update SCHEMA_VERSION comment to reflect current bump-on-change policy - Add idx_calls_scope covering index for caller_scope queries - Expand parser extraction checklist in architecture.md with JSDoc, const values, type members, call graph, and symbol nesting
1 parent 630c0b4 commit 53b2c52

16 files changed

Lines changed: 1272 additions & 61 deletions

File tree

.agents/rules/codemap.mdc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ If the question looks like any of these → use the index:
5656
| "How many files/symbols/components are there?" | any table with `COUNT(*)` |
5757
| "What are the CSS classes in X?" | `css_classes` |
5858
| "What keyframe animations exist?" | `css_keyframes` |
59+
| "What fields does interface/type X have?" | `type_members` |
60+
| "Is symbol X deprecated?" / "What does X do?" | `symbols` (`doc_comment`) |
61+
| "Who calls X?" / "What does X call?" | `calls` |
5962

6063
## When Grep / Read IS appropriate
6164

@@ -93,6 +96,15 @@ bun src/index.ts query --json "<SQL>"
9396
| CSS design tokens | `SELECT name, value, scope FROM css_variables WHERE name LIKE '--%...'` |
9497
| CSS module classes | `SELECT name, file_path FROM css_classes WHERE is_module = 1` |
9598
| CSS keyframes | `SELECT name, file_path FROM css_keyframes` |
99+
| Type/interface shape | `SELECT name, type, is_optional, is_readonly FROM type_members WHERE symbol_name = '...'` |
100+
| Deprecated symbols | `SELECT name, kind, file_path, doc_comment FROM symbols WHERE doc_comment LIKE '%@deprecated%'` |
101+
| Symbol docs | `SELECT name, signature, doc_comment FROM symbols WHERE name = '...' AND doc_comment IS NOT NULL` |
102+
| Const values | `SELECT name, value, file_path FROM symbols WHERE kind = 'const' AND value IS NOT NULL AND name LIKE '%...'` |
103+
| Class members | `SELECT name, kind, signature FROM symbols WHERE parent_name = '...'` |
104+
| Top-level only | `SELECT name, kind, signature FROM symbols WHERE parent_name IS NULL AND file_path LIKE '%...'` |
105+
| Who calls X? | `SELECT DISTINCT caller_name, file_path FROM calls WHERE callee_name = '...'` |
106+
| What does X call? | `SELECT DISTINCT callee_name FROM calls WHERE caller_name = '...'` |
107+
| Call hotspots | `SELECT callee_name, COUNT(*) as fan_in FROM calls GROUP BY callee_name ORDER BY fan_in DESC LIMIT 10` |
96108

97109
**Use `DISTINCT`** on dependency and import queries — a file importing multiple specifiers from the same module produces duplicate rows.
98110

.agents/skills/codemap/SKILL.md

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,35 @@ LIMIT 10
8585
| kind | TEXT | `function`, `class`, `type`, `interface`, `enum`, `const` |
8686
| line_start | INTEGER | Start line (1-based) |
8787
| line_end | INTEGER | End line (1-based) |
88-
| signature | TEXT | e.g. `createHandler()`, `type UserProps` |
88+
| signature | TEXT | Reconstructed signature with generics and return types |
8989
| is_exported | INTEGER | 1 if exported |
9090
| is_default_export | INTEGER | 1 if default export |
91+
| members | TEXT | JSON enum members (NULL for non-enums) |
92+
| doc_comment | TEXT | Leading JSDoc text (cleaned), NULL when absent |
93+
| value | TEXT | Literal value for consts (`"ok"`, `42`, `true`, `null`) |
94+
| parent_name | TEXT | Enclosing symbol name (class/function), NULL = top-level |
95+
96+
### `calls` — Function-scoped call edges (deduped per file)
97+
98+
| Column | Type | Description |
99+
| ------------ | ---------- | ----------------------------------------------- |
100+
| id | INTEGER PK | Auto-increment ID |
101+
| file_path | TEXT FK | References `files(path)` |
102+
| caller_name | TEXT | Calling function/method name |
103+
| caller_scope | TEXT | Dot-joined scope path (e.g. `MyClass.run`) |
104+
| callee_name | TEXT | Called function, `obj.method`, or `this.method` |
105+
106+
### `type_members` — Properties of interfaces and object-literal type aliases
107+
108+
| Column | Type | Description |
109+
| ----------- | ---------- | -------------------------------------------------- |
110+
| id | INTEGER PK | Auto-increment ID |
111+
| file_path | TEXT FK | References `files(path)` |
112+
| symbol_name | TEXT | Parent interface / type alias name |
113+
| name | TEXT | Property or method name |
114+
| type | TEXT | Type annotation (e.g. `string`, `(key) => number`) |
115+
| is_optional | INTEGER | 1 if `?` modifier |
116+
| is_readonly | INTEGER | 1 if `readonly` modifier |
91117

92118
### `imports` — Import statements
93119

@@ -190,6 +216,46 @@ FROM symbols WHERE name LIKE '%Config%' ORDER BY name;
190216
SELECT name, kind, signature
191217
FROM symbols WHERE file_path LIKE '%settings-provider%' AND is_exported = 1;
192218

219+
-- Enum values (what are the valid members of an enum?)
220+
SELECT name, members FROM symbols
221+
WHERE kind = 'enum' AND name = 'TransactionStatus';
222+
223+
-- Interface / type shape (what fields does a type have?)
224+
SELECT name, type, is_optional, is_readonly FROM type_members
225+
WHERE symbol_name = 'UserSession';
226+
227+
-- Deprecated symbols (find @deprecated via JSDoc)
228+
SELECT name, kind, file_path, doc_comment FROM symbols
229+
WHERE doc_comment LIKE '%@deprecated%';
230+
231+
-- Symbol documentation
232+
SELECT name, signature, doc_comment FROM symbols
233+
WHERE name = 'formatCurrency' AND doc_comment IS NOT NULL;
234+
235+
-- Const values (config flags, magic strings)
236+
SELECT name, value, file_path FROM symbols
237+
WHERE kind = 'const' AND value IS NOT NULL AND name LIKE '%URL%';
238+
239+
-- Class methods (what does class X expose?)
240+
SELECT name, kind, signature FROM symbols
241+
WHERE parent_name = 'UserService' ORDER BY name;
242+
243+
-- Top-level symbols only (skip nested helpers)
244+
SELECT name, kind, signature FROM symbols
245+
WHERE parent_name IS NULL AND file_path LIKE '%utils%';
246+
247+
-- Who calls function X? (fan-in)
248+
SELECT DISTINCT caller_name, file_path FROM calls
249+
WHERE callee_name = 'fetchUser';
250+
251+
-- What does function X call? (fan-out)
252+
SELECT DISTINCT callee_name FROM calls
253+
WHERE caller_name = 'processUser';
254+
255+
-- Most-called functions (hotspots)
256+
SELECT callee_name, COUNT(*) as fan_in FROM calls
257+
GROUP BY callee_name ORDER BY fan_in DESC LIMIT 10;
258+
193259
-- File overview (imports + exports)
194260
SELECT 'import' as dir, source as name, specifiers as detail
195261
FROM imports WHERE file_path LIKE '%OrderRow%'
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
"@stainless-code/codemap": minor
3+
---
4+
5+
Richer symbol metadata: generics, return types, JSDoc, type members, const values, symbol nesting, call graph
6+
7+
- Signatures now include generic type parameters, return type annotations, and heritage clauses (extends/implements)
8+
- New `doc_comment` column on symbols extracts leading JSDoc comments
9+
- New `type_members` table indexes properties and methods of interfaces and object-literal types
10+
- New `value` column on symbols captures const literal values (strings, numbers, booleans, null)
11+
- New `parent_name` column on symbols tracks scope nesting; class methods/properties/getters extracted as individual symbols
12+
- New `calls` table tracks function-scoped call edges with `caller_scope` for qualified disambiguation (deduped per file)
13+
- Enum members extracted into `members` column as JSON
14+
- Performance: cached scope strings, hoisted hot-path regex, batch deletes, reduced redundant I/O, BATCH_SIZE 100→500
15+
- SCHEMA_VERSION bumped to 2

0 commit comments

Comments
 (0)