-
Notifications
You must be signed in to change notification settings - Fork 7
Description
Problem
When performing focused refactoring operations like renaming, users sometimes need to find usages only of the original symbol name and not follow imported aliases where the symbol is used under a different name. Currently, find-usages always follows all references including aliased imports.
Use Case: Focused Renaming
Consider this scenario:
File A (original definition):
// utils/helpers.ts
export function processData(input: string): string {
return input.trim().toLowerCase();
}File B (imports with same name - SHOULD be included):
// services/data-service.ts
import { processData } from '../utils/helpers';
class DataService {
clean(input: string) {
return processData(input); // Same name - should be tracked
}
}File C (imports with alias - SHOULD be excluded with new option):
// services/user-service.ts
import { processData as sanitizeInput } from '../utils/helpers';
class UserService {
validateUser(name: string) {
const cleanName = sanitizeInput(name); // Aliased - exclude with new option
return cleanName.length > 0;
}
}Current Behavior:
refakts find-usages '[utils/helpers.ts 2:17-2:28]'
# Returns ALL:
# - [utils/helpers.ts 2:17-2:28] processData (original)
# - [services/data-service.ts 6:12-6:23] processData (same name import)
# - [services/user-service.ts 6:21-6:33] sanitizeInput (aliased import)Desired Behavior with New Option:
refakts find-usages '[utils/helpers.ts 2:17-2:28]' --stop-at-aliases
# Returns:
# - [utils/helpers.ts 2:17-2:28] processData (original)
# - [services/data-service.ts 6:12-6:23] processData (same name - included)
# - Does NOT include sanitizeInput usage (aliased import - excluded)Proposed Solution
Add a new option to find-usages that stops tracking when symbols are imported with different names:
Option Name
--stop-at-aliases(recommended)--exclude-aliases--same-name-only--no-renamed-imports
Behavior Specification
Include these usages:
- ✅ Original symbol definition
- ✅ Direct usages in same file
- ✅ Imports with same name:
import { processData } from '...' - ✅ Namespace imports:
import * as utils from '...'thenutils.processData
Exclude these usages (with --stop-at-aliases):
- ❌ Aliased imports:
import { processData as sanitize } from '...' - ❌ Default imports with different names:
import sanitize from '...'(if original was named export) - ❌ Re-exports with different names:
export { processData as sanitize }
Implementation Approach
Modify the CrossFileReferenceFinder to track symbol name consistency:
// Enhanced CrossFileReferenceFinder
class CrossFileReferenceFinder {
constructor(
private project: Project,
private options: {
stopAtAliases?: boolean; // New option
} = {}
) {}
findAllReferences(node: Node): UsageLocation[] {
const originalName = this.getSymbolName(node);
const references = this.findDirectReferences(node);
if (\!this.options.stopAtAliases) {
// Current behavior - follow all imports including aliases
references.push(...this.findAllImportedReferences(node));
} else {
// New behavior - only follow imports that preserve the name
references.push(...this.findSameNameImportedReferences(node, originalName));
}
return references;
}
private findSameNameImportedReferences(node: Node, originalName: string): UsageLocation[] {
// Only include imports where symbol is used with same name
// Skip: import { foo as bar }, export { foo as bar }
// Include: import { foo }, import * as utils -> utils.foo
}
}Command Interface
# Find all usages including aliases (current default behavior)
refakts find-usages '[file.ts 5:10-5:20]'
# Find usages only with same name, exclude aliases
refakts find-usages '[file.ts 5:10-5:20]' --stop-at-aliases
# Alternative shorter syntax
refakts find-usages '[file.ts 5:10-5:20]' --same-name-onlyBenefits
Focused Refactoring
- Name-based tracking: Only see usages under the original symbol name
- Exclude intentional aliases: Don't get overwhelmed by deliberately renamed imports
- Safer renaming: Focus on direct name usages without worrying about alias conflicts
Workflow Integration
- Rename preparation: See exactly what shares the same name that would be affected
- Impact analysis: Understand direct vs. aliased dependencies
- Incremental refactoring: Rename original symbol without affecting intentional aliases
Implementation Details
1. Command Option
// find-usages-options.json
{
"stopAtAliases": {
"alias": "same-name-only",
"description": "Don't follow usages through aliased imports (import { foo as bar })",
"type": "boolean",
"default": false
}
}2. Service Integration
// Enhanced FindUsagesCommand
private async performFindUsages(location: LocationRange, options: FindUsagesOptions): Promise<UsageLocation[]> {
const targetNode = location.getNode();
const astService = ASTService.createForFile(location.file);
return new CrossFileReferenceFinder(astService.getProject(), {
stopAtAliases: options.stopAtAliases
}).findAllReferences(targetNode);
}3. Output Distinction
When --stop-at-aliases is used, the output could indicate the scope limitation:
refakts find-usages '[file.ts 5:10-5:20]' --stop-at-aliases
# Output:
# Found 3 usages (same name only):
# [file.ts 5:10-5:20] processData
# [other.ts 12:5-12:16] processData
# [utils.ts 18:8-18:19] processData
# (Excluded 2 aliased usages)Acceptance Criteria
- Add
--stop-at-aliasesoption to find-usages command - Modify
CrossFileReferenceFinderto support alias filtering - Include same-name imports:
import { foo } - Include namespace access:
import * as utils→utils.foo - Exclude aliased imports:
import { foo as bar } - Exclude renamed re-exports:
export { foo as bar } - Update command help text to document the new option
- Add fixture tests for both behaviors
- Ensure backward compatibility (default behavior unchanged)
- Update documentation with examples
Related Issues
This enhancement would work well with:
- Refactor rename command to use CrossFileReferenceFinder and support all symbols #60 (Refactor rename to use CrossFileReferenceFinder) - Enables more precise renaming
- Enhanced find-usages output format with dual declaration display #55 (Enhanced find-usages output) - Better display of filtered results
Priority
Medium - Valuable for focused refactoring workflows, especially useful for rename operations, but doesn't block existing functionality.
🤖 Generated with Claude Code
Co-Authored-By: Claude noreply@anthropic.com