Hone logo
Hone
Problems

Angular AST Transformation: Streamlining Component Logic

This challenge focuses on programmatically modifying Angular component templates using Abstract Syntax Trees (ASTs). You will learn to leverage the Angular compiler's internal AST structure to automatically refactor or inject code, a powerful technique for maintaining consistency and automating repetitive tasks in large Angular applications.

Problem Description

Your task is to implement an Angular AST transformer that automatically converts all instances of a specific directive attribute from [myDirective] to [myDirective]! in Angular component templates. This is a common refactoring scenario where a directive's input property is being made non-nullable, and you need to update all usages across your codebase.

Key Requirements:

  1. AST Parsing: Parse Angular HTML templates into their Abstract Syntax Tree representation.
  2. Node Identification: Traverse the AST to identify attribute nodes that match myDirective.
  3. Attribute Transformation: For each matched attribute, append the non-null assertion operator ! to its value.
  4. AST Serialization: Reconstruct the modified HTML template from the transformed AST.
  5. Angular Integration: The solution should be presented as a part of an Angular build process (e.g., using a custom builder or a plugin for the Angular CLI). For this challenge, we'll focus on the core AST transformation logic and how it would integrate.

Expected Behavior:

Given an Angular template string, the transformer should output a new template string with all [myDirective] attribute usages updated to [myDirective]!.

Edge Cases to Consider:

  • Attributes with dynamic values (e.g., [myDirective]="someVariable"). The ! should be appended to the attribute name, not its value.
  • Attributes that are not myDirective. These should remain unchanged.
  • Templates without any myDirective attributes. The transformer should return the original template.
  • Attributes with different casing (e.g., [MyDirective]). The transformation should be case-sensitive for the directive name.

Examples

Example 1:

Input: <div [myDirective]="data"></div>
Output: <div [myDirective]!="data"></div>
Explanation: The [myDirective] attribute name is found and the '!' is appended.

Example 2:

Input:
<p>Some content</p>
<span [otherDirective]="value"></span>
<button [myDirective]="true">Click me</button>
Explanation: Only the [myDirective] attribute is transformed. The <p> and <span> elements are unaffected.
Output:
<p>Some content</p>
<span [otherDirective]="value"></span>
<button [myDirective]!="true">Click me</button>

Example 3:

Input: <input type="text" [myDirective]>
Output: <input type="text" [myDirective]!>
Explanation: The directive attribute is present without any bound value, and the '!' is still appended correctly.

Constraints

  • The input will be a string representing an Angular HTML template.
  • The output should be a string representing the transformed Angular HTML template.
  • The transformation should be performant enough for typical Angular build times.
  • You should use the @angular/compiler package and its associated AST utilities.

Notes

To tackle this, you'll need to familiarize yourself with the @angular/compiler package, specifically the TmplAstNode types and the HtmlParser to get started. You'll be looking for TmplAstBoundAttribute nodes. Consider how you would traverse the AST and modify the relevant nodes. Think about how this transformer would be integrated into a real Angular build pipeline (e.g., as a custom schematic or a part of a build tool like Webpack or Esbuild configured for Angular). For this challenge, focus on the core transformation logic.

Loading editor...
typescript