You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(move-file): parse local exports in index export cache (#318)
Implementing index export cache to parse local exports in addition to
re-exports
## Plan
- [x] Create IndexExports type and interface in export-management
- [x] Create getIndexExports function to parse local exports using AST
- [x] Update isFileExported to use the new cache system
- [x] Add comprehensive unit tests for getIndexExports
- [x] Add benchmark tests for performance validation
- [x] Update existing tests to cover local export scenarios
- [x] Run linting, build, and all tests
- [x] Format code
- [x] Update documentation
- [x] Address code review feedback
- [x] Update JSDoc comments to reflect cache usage
## Recent Changes
Updated documentation in `isFileExported()` to clarify:
- Function now uses the index exports cache system
- Cache parses local declarations but function only checks re-exports
- This addresses review feedback about outdated documentation
The distinction is important: `isFileExported()` checks if a **file** is
re-exported (e.g., `export * from './lib/utils'`), not if **symbols**
from that file are present as local exports in the index.
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
----
*This section details on the original issue you should resolve*
<issue_title>feat(move-file): parse local exports in index export
cache</issue_title>
<issue_description>## Summary
Enhance the index exports cache to parse and record *local* export
declarations in entrypoint (index) files in addition to existing
re-export ("export ... from") patterns.
Currently `getIndexExports()` only captures reexports and leaves
`exports` empty, forcing callers (e.g. `isFileExported`) to rely solely
on `reexports`. This prevents accurate detection of locally defined
exports (e.g. `export { foo, bar }`, `export const X = ...`, `export
function fn() {}`, `export class C {}`, and `export default ...`).
Supporting these will improve correctness of move-file validation
(unexported dependency checks, alias conversions) and reduce false
warnings.
## Motivation / Problem
When a project’s public surface is defined via local declarations in
`index.ts` rather than re-exporting from leaf modules, the current cache
misses them. As a result:
- `isFileExported()` incorrectly reports a file as unexported if it’s
aggregated via local declarations copied into the index.
- Move-file generator may warn about supposedly unexported relative
dependencies.
- Potential future optimizations (e.g., differentiating default vs named
exports) are blocked.
## Scope
Add robust parsing of local export declarations for
TypeScript/JavaScript index files, keeping the lightweight approach
(regex or jscodeshift) while maintaining performance. Preserve
separation between `exports` and `reexports` (per review feedback in PR
#316).
## Proposed Design
1. Reuse existing AST caching (jscodeshift + `astCache`) for structural
accuracy while minimizing parse cost.
2. Collect and normalize local export specifiers:
- Named declarations: `export const A`, `export function b`, `export
class C`, `export interface D`, `export type E`, `export enum F`.
- Named list: `export { a, b as c }` (without `from`).
- Default exports: `export default X`, `export default function() {}`,
`export default class {}`.
3. Represent cache structure:
```ts
interface IndexExports {
exports: Set<string>; // local named export identifiers (normalized)
reexports: Set<string>; // existing re-export specifiers ('./lib/util')
defaultExport?: string; // identifier or synthetic marker
('<anonymous>') if unnamed default
}
```
4. Normalization Rules:
- Local identifiers stored exactly as defined (no extension logic
needed).
- Anonymous default exports mapped to a sentinel (e.g. `<default>` or
`<anonymous-default>`).
5. Backwards compatibility: existing callers using `reexports` remain
unchanged; add helper `isLocalSymbolExported(name)` if needed later.
6. Performance Strategy:
- Parse AST once via `astCache.getAST`; fall back to regex only if AST
unavailable.
- Skip expensive symbol resolution—pure syntactic discovery.
- Maintain content snapshot invalidation (existing logic).
7. Update `isFileExported` logic:
- If import specifier points to a file path: keep current re-export
check.
- If validation wants to infer export of an internal symbol (future),
can consult `exports` set.
## Tasks
- [ ] Extend `IndexExports` interface (add `defaultExport` field).
- [ ] Implement local export parsing function
(`collectLocalExports(ast): { names: Set<string>; default?: string }`).
- [ ] Integrate parsing into `getIndexExports` (only when content
contains `export`).
- [ ] Add unit tests covering:
- Basic named exports (const/function/class/interface/type/enum).
- Named list / alias exports (with `as`).
- Default exports (named and anonymous).
- Mixed local + re-exports in same file.
- Empty index file (returns empty sets, undefined default).
- Cache hit behavior (content unchanged).
- Cache invalidation (content change updates sets).
- [ ] Update `is-file-exported.spec.ts` to include a scenario with local
declarations.
- [ ] Add benchmark cases to `export-management.bench.ts` for local
export detection (ensure negligible regression; target <5% throughput
impact).
- [ ] Update PR/Documentation: mention difference between local exports
and reexports.
## Acceptance Criteria
- All new tests pass; existing 770 tests remain green.
- Benchmarks show <5% performance degradation for export detection suite
or an offsetting improvement if AST parsing reduces regex overhead.
- `isFileExported` correctly returns true for files represented by local
declarations (when those files exist or are logically aggregated).
- No conflation between `exports` and `reexports`; clear docs in
`index-exports-cache.ts`.
## Performance Considerations
- AST parsing is already cached; incremental cost is node filtering for
export declarations.
- Provide fallback to fast regex ONLY if AST is unavailable (e.g., parse
error).
- Keep operations allocation-light (pre-size arrays where possible,
avoid repeated string normaliz...
</details>
- Fixes#317
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
0 commit comments