index_symbols
Build an in-memory symbol index for cross-file lookups to enable symbol-aware code analysis and workspace exploration.
Instructions
Build in-memory symbol index for cross-file lookups.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| root | Yes | Root directory to index | |
| languages | No | Languages to index | |
| symbolTypes | No | Symbol types to include |
Implementation Reference
- src/tools/symbols.ts:369-465 (handler)The `indexSymbols` method within the `SymbolIndexer` class performs the indexing logic by scanning the source directory for files, parsing them based on language-specific regex patterns, and caching the results for efficiency.
indexSymbols( root: string, options: { languages?: string[]; symbolTypes?: string[]; } = {} ): IndexSymbolsResult { const startTime = performance.now(); const resolvedRoot = this.config.resolveWorkspacePath(root); if (!this.config.isPathAllowed(resolvedRoot)) { throw new Error(`Access denied: Path '${root}' is not in the allowlist`); } const languages = options.languages || ['typescript', 'javascript', 'python']; // Build language extensions set for filtering const langExtensions = new Set<string>(); for (const lang of languages) { const exts = this.languageExtensions[lang]; if (exts) { exts.forEach((ext) => langExtensions.add(ext)); } } // Check cache - but we still need to filter by language const cacheKey = resolvedRoot; const cached = this.cache.get(cacheKey); if (cached && Date.now() - cached.timestamp < this.cacheTTL) { // Filter cached results by language and symbol types let symbols = cached.symbols; // Filter by language symbols = symbols.filter((s) => { const ext = extname(s.file).toLowerCase(); return langExtensions.has(ext); }); // Filter by symbol types if (options.symbolTypes?.length) { symbols = symbols.filter((s) => options.symbolTypes!.includes(s.type)); } return { indexed: symbols.length, symbols, indexDuration: 0, languages, }; } // For non-cached case, find and index files const files = this.findSourceFiles(resolvedRoot, ['typescript', 'javascript', 'python']); // Always scan all const allSymbols: SymbolInfo[] = []; const detectedLanguages = new Set<string>(); for (const filePath of files) { try { const language = this.getLanguage(filePath); if (!language) continue; const content = readFileSync(filePath, 'utf-8'); const symbols = this.extractSymbols(content, filePath, language); allSymbols.push(...symbols); if (symbols.length > 0) { detectedLanguages.add(language); } } catch { // Skip files we can't read } } // Cache the unfiltered results (all languages) this.cache.set(cacheKey, { symbols: allSymbols, timestamp: Date.now(), root: resolvedRoot, }); // Now filter by requested languages and symbol types let filteredSymbols = allSymbols.filter((s) => { const ext = extname(s.file).toLowerCase(); return langExtensions.has(ext); }); if (options.symbolTypes?.length) { filteredSymbols = filteredSymbols.filter((s) => options.symbolTypes!.includes(s.type)); } const duration = Math.max(0.001, performance.now() - startTime); return { indexed: filteredSymbols.length, symbols: filteredSymbols, indexDuration: duration, languages: Array.from(detectedLanguages).filter((lang) => languages.includes(lang)), }; }