(
filePath: string,
want: {
isDefault: boolean;
isNamespace: boolean;
exportedName: string;
memberName: string | null;
},
language: Language,
context: ResolutionContext,
visited: Set<string>,
depth: number
)
| 2110 | } |
| 2111 | |
| 2112 | function findExportedSymbolWalk( |
| 2113 | filePath: string, |
| 2114 | want: { |
| 2115 | isDefault: boolean; |
| 2116 | isNamespace: boolean; |
| 2117 | exportedName: string; |
| 2118 | memberName: string | null; |
| 2119 | }, |
| 2120 | language: Language, |
| 2121 | context: ResolutionContext, |
| 2122 | visited: Set<string>, |
| 2123 | depth: number |
| 2124 | ): Node | undefined { |
| 2125 | if (depth > REEXPORT_MAX_DEPTH) return undefined; |
| 2126 | if (visited.has(filePath)) return undefined; |
| 2127 | visited.add(filePath); |
| 2128 | |
| 2129 | const exportIndex = getFileExportIndex(filePath, context); |
| 2130 | |
| 2131 | // 1. Direct hit: the symbol is declared in this file. |
| 2132 | if (want.isDefault) { |
| 2133 | // Svelte/Vue single-file components ARE the module's default export, |
| 2134 | // but are extracted as kind 'component' (not function/class). Prefer |
| 2135 | // the component node; fall back to an exported function/class for the |
| 2136 | // `.ts`/`.tsx` `export default fn`/`class` case. Without the component |
| 2137 | // branch, an `export { default as X } from './X.svelte'` barrel never |
| 2138 | // resolves and the component shows a false 0 callers (#629). |
| 2139 | const direct = exportIndex.defaultComponent ?? exportIndex.defaultFnClass; |
| 2140 | if (direct) return direct; |
| 2141 | } else if (want.isNamespace && want.memberName) { |
| 2142 | const direct = exportIndex.byName.get(want.memberName); |
| 2143 | if (direct) return direct; |
| 2144 | } else { |
| 2145 | const direct = exportIndex.byName.get(want.exportedName); |
| 2146 | if (direct) return direct; |
| 2147 | } |
| 2148 | |
| 2149 | // 2. Re-export hit: the file forwards the symbol to another module. |
| 2150 | const reExports = context.getReExports?.(filePath, language) ?? []; |
| 2151 | if (reExports.length === 0) return undefined; |
| 2152 | |
| 2153 | // Look for explicit `export { want } from './other'` (with optional rename). |
| 2154 | const targetName = want.isDefault ? 'default' : want.exportedName; |
| 2155 | for (const rex of reExports) { |
| 2156 | if (rex.kind === 'named' && rex.exportedName === targetName) { |
| 2157 | const next = resolveImportPath(rex.source, filePath, language, context); |
| 2158 | if (!next) continue; |
| 2159 | // After rename: `export { foo as bar } from './x'` — to chase |
| 2160 | // `bar`, we look for `foo` in `./x`. |
| 2161 | const chained = findExportedSymbol( |
| 2162 | next, |
| 2163 | { |
| 2164 | isDefault: rex.originalName === 'default', |
| 2165 | isNamespace: false, |
| 2166 | exportedName: rex.originalName, |
| 2167 | memberName: null, |
| 2168 | }, |
| 2169 | language, |
no test coverage detected