MCPcopy
hub / github.com/colbymchenry/codegraph / findExportedSymbol

Function findExportedSymbol

src/resolution/import-resolver.ts:1831–1917  ·  view source on GitHub ↗

* Find an exported symbol in `filePath`, following `export { x } from * './other'` and `export * from './other'` chains until the original * declaration is reached. Cycle-safe via the `visited` set. * * Without this, every barrel-style import (`import { Foo } from * './index'` where `index.ts`

(
  filePath: string,
  want: {
    isDefault: boolean;
    isNamespace: boolean;
    exportedName: string;
    memberName: string | null;
  },
  language: Language,
  context: ResolutionContext,
  visited: Set<string>,
  depth = 0
)

Source from the content-addressed store, hash-verified

1829 * resolved file, not declarations the file forwarded.
1830 */
1831function findExportedSymbol(
1832 filePath: string,
1833 want: {
1834 isDefault: boolean;
1835 isNamespace: boolean;
1836 exportedName: string;
1837 memberName: string | null;
1838 },
1839 language: Language,
1840 context: ResolutionContext,
1841 visited: Set<string>,
1842 depth = 0
1843): Node | undefined {
1844 if (depth > REEXPORT_MAX_DEPTH) return undefined;
1845 if (visited.has(filePath)) return undefined;
1846 visited.add(filePath);
1847
1848 const nodesInFile = context.getNodesInFile(filePath);
1849
1850 // 1. Direct hit: the symbol is declared in this file.
1851 if (want.isDefault) {
1852 // Svelte/Vue single-file components ARE the module's default export,
1853 // but are extracted as kind 'component' (not function/class). Prefer
1854 // the component node; fall back to an exported function/class for the
1855 // `.ts`/`.tsx` `export default fn`/`class` case. Without the component
1856 // branch, an `export { default as X } from './X.svelte'` barrel never
1857 // resolves and the component shows a false 0 callers (#629).
1858 const direct =
1859 nodesInFile.find((n) => n.isExported && n.kind === 'component') ??
1860 nodesInFile.find(
1861 (n) => n.isExported && (n.kind === 'function' || n.kind === 'class')
1862 );
1863 if (direct) return direct;
1864 } else if (want.isNamespace && want.memberName) {
1865 const direct = nodesInFile.find(
1866 (n) => n.name === want.memberName && n.isExported
1867 );
1868 if (direct) return direct;
1869 } else {
1870 const direct = nodesInFile.find(
1871 (n) => n.name === want.exportedName && n.isExported
1872 );
1873 if (direct) return direct;
1874 }
1875
1876 // 2. Re-export hit: the file forwards the symbol to another module.
1877 const reExports = context.getReExports?.(filePath, language) ?? [];
1878 if (reExports.length === 0) return undefined;
1879
1880 // Look for explicit `export { want } from './other'` (with optional rename).
1881 const targetName = want.isDefault ? 'default' : want.exportedName;
1882 for (const rex of reExports) {
1883 if (rex.kind === 'named' && rex.exportedName === targetName) {
1884 const next = resolveImportPath(rex.source, filePath, language, context);
1885 if (!next) continue;
1886 // After rename: `export { foo as bar } from './x'` — to chase
1887 // `bar`, we look for `foo` in `./x`.
1888 const chained = findExportedSymbol(

Callers 1

resolveViaImportFunction · 0.85

Calls 4

resolveImportPathFunction · 0.85
hasMethod · 0.80
getReExportsMethod · 0.80
getNodesInFileMethod · 0.65

Tested by

no test coverage detected