Section 2.5.1Source:
server/src/parser/extractors/SymbolExtractor.tsSymbol Stack & Scoping Hierarchy
Tracking container nesting context during AST traversal using symbolStack, path.setData invariants, and deterministic ID formation.
Source:
server/src/parser/extractors/SymbolExtractor.tsThe Symbol Stack Mechanism
As Babel traverses nested syntax trees, inner symbols need to know their enclosing parent container (for example, a method needs to link to its enclosing class). Rather than building a deeply nested tree, CodeGraph maintains a flat symbols: ParsedSymbol[] array where each symbol carries aparentSymbolId pointer.
This is coordinated by symbolStack: ParsedSymbol[]:
Lifecycle Visitor Pattern
1234567891011121314151617181920212223private createContainerVisitor<T extends SupportedSymbolNode>( parsedFile: ParsedFile, symbolKind: SymbolKind, getExtraParams?: (path: NodePath<T>) => SymbolExtraParams ) { return { enter: (path: NodePath<T>) => { const extraParams = getExtraParams?.(path); const symbol = this.extractSymbol({ path, parsedFile, symbolKind, ...extraParams }); if (symbol) { this.symbolStack.push(symbol); path.setData("symbolPushed", true); // Guard invariant } }, exit: (path: NodePath<T>) => { if (path.getData("symbolPushed")) { this.symbolStack.pop(); } } }; }
Deterministic Symbol ID Generation
Every symbol ID is guaranteed to be stable and reproducible across runs:
Deterministic ID Formula
1234// ID Format: ${filePath}:${startLine}:${startColumn}:${name} private buildSymbolId(parsedFile: ParsedFile, name: string, location: SymbolLocation): string { return `${parsedFile.filePath}:${location.startLine}:${location.startColumn}:${name}`; }
path.setData Stack Invariant
The
path.setData("symbolPushed", true) pattern guarantees that the exact same AST path node that pushed a container onto the stack is the one that pops it on exit. This prevents stack corruption if an anonymous or unnamable container returned undefined on enter.