Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions src/core/commands/extract-variable-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ export class ExtractVariableCommand implements RefactoringCommand {
this.validateOptions(options);
const location = LocationRange.from(options.location as LocationRange);
this.astService = ASTService.createForFile(file);
await this.performExtraction(this.astService.findNodeByLocation(location), options);
const count = await this.performExtraction(this.astService.findNodeByLocation(location), options);
await this.astService.saveSourceFile(this.astService.loadSourceFile(file));
return new RefactoringCommandResult();
const variableName = options.name as string;
const message = options.all
? `Successfully extracted variable '${variableName}' (${count} occurrence${count === 1 ? '' : 's'} replaced)`
: `Successfully extracted variable '${variableName}'`;
return new RefactoringCommandResult(message);
}

validateOptions(options: CommandOptions): void {
Expand All @@ -43,11 +47,12 @@ export class ExtractVariableCommand implements RefactoringCommand {
return '\nExamples:\n refakts extract-variable "[src/file.ts 8:15-8:29]" --name "result"';
}

private async performExtraction(targetNode: Node, options: CommandOptions): Promise<void> {
private async performExtraction(targetNode: Node, options: CommandOptions): Promise<number> {
if (options.all) {
await this.extractAllOccurrences(targetNode, options.name as string);
return await this.extractAllOccurrences(targetNode, options.name as string);
} else {
await this.extractSingleOccurrence(targetNode, options.name as string);
return 1;
}
}

Expand All @@ -59,12 +64,13 @@ export class ExtractVariableCommand implements RefactoringCommand {
targetNode.replaceWithText(uniqueName);
}

private async extractAllOccurrences(targetNode: Node, variableName: string): Promise<void> {
private async extractAllOccurrences(targetNode: Node, variableName: string): Promise<number> {
this.validateExpressionNode(targetNode);
const allExpressions = this.expressionMatcher.findAllMatchingExpressions(targetNode);
this.validateExpressionsFound(allExpressions);

this.extractInEachScope(this.expressionMatcher.groupExpressionsByScope(allExpressions), variableName);
return allExpressions.length;
}

private validateExpressionNode(node: Node): void {
Expand Down
23 changes: 16 additions & 7 deletions src/core/commands/rename-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ export class RenameCommand implements RefactoringCommand {
this.astService = ASTService.createForFile(file);
this.variableLocator = new VariableLocator(this.astService.getProject());
this.nameValidator = new VariableNameValidator();
await this.performRename(this.astService.findNodeByLocation(location), options.to as string);
const result = await this.performRename(this.astService.findNodeByLocation(location), options.to as string);
await this.astService.saveSourceFile(this.astService.loadSourceFile(file));
return new RefactoringCommandResult();
return result;
}

validateOptions(options: CommandOptions): void {
Expand All @@ -44,13 +44,22 @@ export class RenameCommand implements RefactoringCommand {
return '\nExamples:\n refakts rename "[src/file.ts 5:8-5:18]" --to newName';
}

private async performRename(node: Node, newName: string): Promise<void> {
private async performRename(node: Node, newName: string): Promise<RefactoringCommandResult> {
NodeAnalyzer.validateIdentifierNode(node);
const sourceFile = node.getSourceFile();
const nodeResult = this.findVariableNodesAtPosition(node, sourceFile);

const nodeResult = this.findVariableNodesAtPosition(node, node.getSourceFile());
this.validateNewName(nodeResult.declaration, newName);
await this.createRenameTransformation(nodeResult, newName).transform(sourceFile);
return this.applyRename(nodeResult, nodeResult.variable, newName);
}

private async applyRename(nodeResult: VariableNodeResult, oldName: string, newName: string): Promise<RefactoringCommandResult> {
const transformResult = await this.createRenameTransformation(nodeResult, newName).transformWithResult();
if (!transformResult.success) {
throw new Error(transformResult.message || 'Rename transformation failed');
}
const count = transformResult.changesCount;
return new RefactoringCommandResult(
`Successfully renamed '${oldName}' to '${newName}' (${count} occurrence${count === 1 ? '' : 's'} renamed)`
);
}

private findVariableNodesAtPosition(node: Node, sourceFile: SourceFile) {
Expand Down
17 changes: 11 additions & 6 deletions src/core/commands/sort-methods-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ export class SortMethodsCommand implements RefactoringCommand {
this.validateOptions(options);
const location = LocationRange.from(options.location as LocationRange);
this.astService = ASTService.createForFile(file);
await this.performMethodSorting(this.findTargetClass(this.astService.findNodeByLocation(location)));
const targetClass = this.findTargetClass(this.astService.findNodeByLocation(location));
const { className, methodCount } = await this.performMethodSorting(targetClass);
await this.astService.saveSourceFile(this.astService.loadSourceFile(file));
return new RefactoringCommandResult();
return new RefactoringCommandResult(
`Successfully sorted ${methodCount} method${methodCount === 1 ? '' : 's'} in class '${className}'`
);
Comment on lines +26 to +30
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command always returns a "Successfully sorted …" message, even when no sorting is performed (e.g., classes with 0–1 methods, where shouldSkipSorting() prevents any reordering). This yields misleading outputs like "Successfully sorted 0/1 methods". Consider returning a flag/result from performMethodSorting indicating whether sorting actually happened (or the pre-sort method count) and emit a more accurate message such as "No sorting needed" when skipped.

Copilot uses AI. Check for mistakes.
}

private findTargetClass(targetNode: Node): ClassDeclaration {
Expand Down Expand Up @@ -60,11 +63,13 @@ export class SortMethodsCommand implements RefactoringCommand {
this.consoleOutput = consoleOutput;
}

private async performMethodSorting(targetClass: ClassDeclaration): Promise<void> {
private async performMethodSorting(targetClass: ClassDeclaration): Promise<{ className: string; methodCount: number }> {
const methods = this.methodFinder.findMethods(targetClass);
if (this.shouldSkipSorting(methods)) return;

this.reorderMethodsInClass(targetClass, this.getSortedMethods(methods));
const className = targetClass.getName() ?? 'unknown';
if (!this.shouldSkipSorting(methods)) {
this.reorderMethodsInClass(targetClass, this.getSortedMethods(methods));
}
return { className, methodCount: targetClass.getMethods().length };
}

private shouldSkipSorting(methods: MethodInfo[]): boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'sum'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'upperName'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'upperName' (2 occurrences replaced)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'upperName'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'upperName' (2 occurrences replaced)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'userAge'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'toUpperCase' (2 occurrences replaced)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'result'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'formattedName' (2 occurrences replaced)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'substringMethod' (2 occurrences replaced)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'product' (3 occurrences replaced)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'product'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'sum'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'sum' (2 occurrences replaced)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully extracted variable 'area'
1 change: 1 addition & 0 deletions tests/fixtures/commands/rename/arrow-function.expected.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully renamed 'x' to 'value' (3 occurrences renamed)
1 change: 1 addition & 0 deletions tests/fixtures/commands/rename/block-scope.expected.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully renamed 'temp' to 'temporaryValue' (3 occurrences renamed)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully renamed 'oldParam' to 'newParam' (3 occurrences renamed)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully renamed 'temp' to 'newName' (2 occurrences renamed)
1 change: 1 addition & 0 deletions tests/fixtures/commands/rename/nested-scopes.expected.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully renamed 'items' to 'itemList' (5 occurrences renamed)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully renamed 'data' to 'processedData' (2 occurrences renamed)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully renamed 'oldName' to 'newName' (2 occurrences renamed)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully sorted 2 methods in class 'MathProcessor'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Successfully sorted 4 methods in class 'Calculator'
Loading