Hone logo
Hone
Problems

Angular Rename Provider Implementation

This challenge focuses on building a crucial feature for IDE-like experiences within an Angular application: a rename provider. A rename provider allows users to rename a symbol (like a variable, function, or class) across their entire codebase, ensuring all references are updated automatically. This is essential for maintaining code integrity and developer productivity.

Problem Description

Your task is to implement a basic rename provider functionality for a simplified Angular component system. You will be given a representation of a TypeScript file and need to provide a mechanism to rename a specific symbol found within that file. The rename provider should identify all occurrences of the target symbol and suggest updates to change its name.

Key Requirements:

  1. Symbol Identification: Given a file content and a cursor position, identify the symbol at that position (e.g., a variable name, a method name).
  2. Reference Finding: Find all direct references (occurrences) of the identified symbol within the provided file content. This includes declarations and usages.
  3. Rename Suggestion Generation: For each found reference, generate a proposed rename operation. This operation should specify the original text, the new text, and the start and end positions of the text to be replaced.
  4. Handling Scope (Simplified): For this challenge, you can assume a simplified scope. We are only concerned with renaming within the provided single file content. More complex scoping (across multiple files, modules, etc.) is out of scope.
  5. Case Sensitivity: Renames should be case-sensitive.

Expected Behavior:

When provided with a TypeScript file content and a cursor position pointing to a symbol, the rename provider should return an array of potential rename operations. Each operation details how to replace an instance of the old symbol with the new one.

Edge Cases to Consider:

  • Cursor not pointing to a valid symbol.
  • Symbol with no other references (only its declaration).
  • Symbols with similar but not identical names (e.g., myVar vs. myVariable). The provider should only rename exact matches.

Examples

Example 1:

Input:
File Content:
```typescript
function greet(name: string): string {
  const message = `Hello, ${name}!`;
  return message;
}

const userName: string = "Alice";
console.log(greet(userName));

Cursor Position: 12 (pointing to the 'n' in 'name' within the greet function parameter) New Name: personName

Output:

[
  {
    "oldText": "name",
    "newText": "personName",
    "start": 9,
    "end": 13
  },
  {
    "oldText": "name",
    "newText": "personName",
    "start": 35,
    "end": 39
  }
]

Explanation: The cursor is on the name parameter within the greet function. The rename provider identifies name as the symbol. It finds two references:

  1. The parameter declaration itself (index 9-13).
  2. Its usage within the template literal (index 35-39). The output is an array of objects, each specifying the original text, the new text, and the start/end positions of the text to be replaced.

Example 2:

Input:
File Content:
```typescript
class UserProfile {
  constructor(private userName: string) {}

  displayGreeting(): string {
    return `Welcome, ${this.userName}`;
  }
}

const user = new UserProfile("Bob");
console.log(user.displayGreeting());

Cursor Position: 53 (pointing to the 'U' in 'UserProfile' in the class declaration) New Name: AccountProfile

Output:

[
  {
    "oldText": "UserProfile",
    "newText": "AccountProfile",
    "start": 6,
    "end": 17
  },
  {
    "oldText": "UserProfile",
    "newText": "AccountProfile",
    "start": 68,
    "end": 79
  }
]

Explanation: The cursor is on the UserProfile class name. The provider identifies UserProfile as the symbol. It finds two references:

  1. The class declaration (index 6-17).
  2. The instantiation of the class (index 68-79).

Example 3: (Edge Case)

Input:
File Content:
```typescript
let counter: number = 0;
function increment(): void {
  counter++;
}
increment();

Cursor Position: 100 (pointing to a space character) New Name: count

Output:

[]

Explanation: The cursor is not pointing to a valid symbol (it's in a space). The rename provider should return an empty array, indicating no rename operation can be performed.

Constraints

  • The input fileContent will be a string representing valid TypeScript code.
  • The cursorPosition will be a non-negative integer.
  • The newName will be a valid string that can be used as an identifier in TypeScript.
  • The maximum length of fileContent is 10,000 characters.
  • The number of symbols and references within a file will not exceed 500.
  • Your implementation should aim for reasonable performance, with rename operations typically completing within 100ms for the given constraints.

Notes

  • This challenge simplifies many aspects of a real-world rename provider. For instance, it doesn't involve parsing complex Abstract Syntax Trees (ASTs), handling different types of symbols (imports, exports, class members), or performing static analysis across multiple files.
  • You will likely need to use regular expressions or string manipulation techniques to find symbols and their occurrences. Consider how to accurately identify whole words and avoid partial matches.
  • The output format for rename operations is a JSON array of objects, each with oldText, newText, start, and end properties.
  • Focus on correctly identifying the symbol at the cursor and then finding all exact string matches for that symbol within the fileContent.
Loading editor...
typescript