Hone logo
Hone
Problems

Angular Dead Code Elimination Tool

This challenge asks you to build a simplified tool that simulates dead code elimination within an Angular project. Understanding and implementing dead code elimination is crucial for optimizing application performance and reducing bundle sizes, leading to faster load times and a better user experience.

Problem Description

You need to create a TypeScript-based tool that analyzes Angular component TypeScript files and identifies code that is likely unreachable or unused based on specific patterns. The tool should then report these potential dead code sections.

What needs to be achieved: Develop a program that parses Angular component TypeScript files and flags specific types of unused code.

Key requirements:

  1. Component Detection: Identify Angular components (classes decorated with @Component).
  2. Template Interaction Analysis (Simplified): Analyze the component's template (or a simplified representation of it) to determine which methods and properties are directly referenced.
  3. Dead Code Identification: Flag methods and properties within the component's class that are not referenced in the component's template.
  4. Outputting Results: Generate a report listing the identified dead code, including the file path and the name of the unused member.

Expected behavior:

  • The tool should accept a path to an Angular component's TypeScript file as input.
  • It should parse the TypeScript code to extract the component's class, methods, and properties.
  • It should simulate parsing a simple HTML template associated with the component to find references to class members.
  • For each component, it should list methods and properties that are declared but not referenced in the simulated template.

Important edge cases to consider:

  • Private members: These are generally considered "dead" from an external template perspective unless explicitly called within the component itself. For this challenge, assume private members not called internally are dead code if not referenced in the template.
  • Lifecycle hooks (e.g., ngOnInit, ngOnDestroy): These are implicitly used by Angular and should generally not be flagged as dead code.
  • Methods/properties used by other methods within the component: This is a complex dependency analysis. For this simplified challenge, we will focus only on direct references from the template. Internal component calls will not be considered for survival.
  • Template syntax: For simplicity, assume basic property binding ({{ myProp }}) and event binding ((click)="myMethod()") are the primary ways members are referenced.

Examples

Example 1:

Input:

// src/app/my-component.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-my-component',
  template: `
    <div>{{ greeting }}</div>
    <button (click)="sayHello()">Click Me</button>
  `
})
export class MyComponent {
  greeting: string = 'Hello!';
  private secretMessage: string = 'shh';

  sayHello(): void {
    console.log('Hello!');
  }

  unusedMethod(): void {
    console.log('This is never called.');
  }

  private internalHelper(): void {
    console.log('Used internally.');
  }

  anotherUnusedProperty: number = 42;
}

Output:

src/app/my-component.component.ts:
  - unusedMethod
  - anotherUnusedProperty
  - secretMessage (private members not referenced in template are considered dead)

Explanation: The greeting property and sayHello method are referenced in the template ({{ greeting }} and (click)="sayHello()"). unusedMethod and anotherUnusedProperty are declared but not used. secretMessage is private and not referenced in the template, so it's flagged. internalHelper is not referenced in the template, and per the simplified rules, it will be flagged.

Example 2:

Input:

// src/app/another-component.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-another-component',
  template: `
    <p>{{ title }}</p>
    <button (click)="handleClick()">Handle</button>
  `
})
export class AnotherComponent implements OnInit {
  title: string = 'Angular DCE';
  data: any[] = []; // Not used in template
  counter: number = 0; // Not used in template

  ngOnInit(): void {
    console.log('Component initialized');
    this.loadData(); // Internal call, not directly template reference
  }

  handleClick(): void {
    this.counter++;
    console.log('Clicked!');
  }

  loadData(): void {
    this.data = [1, 2, 3];
    console.log('Data loaded');
  }
}

Output:

src/app/another-component.component.ts:
  - data
  - counter

Explanation: title and handleClick are used in the template. ngOnInit is a lifecycle hook and is implicitly handled by Angular, so it's not flagged. data and counter are declared but not referenced in the template. loadData is called internally by ngOnInit but not directly from the template, so it's flagged.

Example 3: (Edge Case - Lifecycle Hooks)

Input:

// src/app/lifecycle-component.component.ts
import { Component, OnDestroy, OnInit } from '@angular/core';

@Component({
  selector: 'app-lifecycle-component',
  template: `<div>Lifecycle Demo</div>`
})
export class LifecycleComponent implements OnInit, OnDestroy {
  private internalState: boolean = false;

  ngOnInit(): void {
    console.log('Initializing');
    this.internalState = true;
  }

  ngOnDestroy(): void {
    console.log('Destroying');
  }

  unusedMethod(): void {
    console.log('This should not be flagged.');
  }
}

Output:

src/app/lifecycle-component.component.ts:
  - unusedMethod

Explanation: ngOnInit and ngOnDestroy are lifecycle hooks and are implicitly handled by Angular, thus they are not flagged. internalState is private and not referenced in the template, so it is flagged. unusedMethod is also not referenced and is flagged.

Constraints

  • The tool should be written in TypeScript.
  • The tool should accept a single file path as input.
  • The tool should focus on analyzing the class definition and a simplified representation of the template string embedded within the @Component decorator. Deep AST analysis of the template is not required for this challenge; simple string searching for {{ ... }} and (...)="..." patterns is sufficient.
  • Performance is not a primary concern for this challenge, but the solution should be reasonably efficient for analyzing a single file.

Notes

  • You will need to leverage TypeScript's Abstract Syntax Tree (AST) capabilities to parse the TypeScript code. Libraries like @babel/parser or the native TypeScript compiler API can be used.
  • For template analysis, a robust solution would involve a dedicated HTML parser. For this challenge, you can get away with regular expressions or simple string manipulation to find member names within the template string.
  • Remember to handle cases where the template property might be missing or is a reference to an external template URL. For this challenge, assume the template is always a string literal directly in the decorator.
  • The goal is to create a basic dead code elimination mechanism. Real-world tools are significantly more sophisticated and involve complex control flow analysis.
Loading editor...
typescript