<!-- This file was generated by @travetto/doc and should not be modified directly -->
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/transformer/DOC.tsx and execute "npx trv doc" to rebuild -->
# Transformation

## Functionality for AST transformations, with transformer registration, and general utils

**Install: @travetto/transformer**
```bash
npm install @travetto/transformer

# or

yarn add @travetto/transformer
```

This module provides support for enhanced AST transformations, and declarative transformer registration, with common patterns to support all the transformers used throughout the framework. Transformations are located by `support/transformer.<name>.ts` as the filename. 

The module is primarily aimed at extremely advanced usages for things that cannot be detected at runtime.  The [Registry](https://github.com/travetto/travetto/tree/main/module/registry#readme "Patterns and utilities for handling registration of metadata and functionality for run-time use") module already has knowledge of all `class`es and `field`s, and is able to listen to changes there.  Many of the modules build upon work by some of the foundational transformers defined in [Manifest](https://github.com/travetto/travetto/tree/main/module/manifest#readme "Support for project indexing, manifesting, along with file watching"), [Registry](https://github.com/travetto/travetto/tree/main/module/registry#readme "Patterns and utilities for handling registration of metadata and functionality for run-time use"), [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.") and [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support.").  These all center around defining a registry of classes, and associated type information. 

Because working with the [Typescript](https://typescriptlang.org) API can be delicate (and open to breaking changes), creating new transformers should be done cautiously.

## Monorepos and Idempotency
Within the framework, any build or compile step will target the entire workspace, and for mono-repo projects, will include all modules.  The optimization this provides is great, but comes with a strict requirement that all compilation processes need to be idempotent.  This means that compiling a module directly, versus as a dependency should always produce the same output. This produces a requirement that all transformers are opt-in by the source code, and which transformers are needed in a file should be code-evident.  This also means that no transformers are optional, as that could produce different output depending on the dependency graph for a given module.

## Custom Transformer
Below is an example of a transformer that upper cases all `class`, `method` and `param` declarations.  This will break any code that depends upon it as we are redefining all the identifiers at compile time.

**Code: Sample Transformer - Upper case all declarations**
```typescript
import type ts from 'typescript';

import { TransformerHandler, type TransformerState } from '@travetto/transformer';

export class MakeUpper {

  static isValid(state: TransformerState): boolean {
    return state.importName !== '@travetto/transformer/doc/upper.ts';
  }

  static {
    TransformerHandler(this, this.handleClass, 'before', 'class');
    TransformerHandler(this, this.handleMethod, 'before', 'method');
    TransformerHandler(this, this.handleProperty, 'before', 'property');
  }

  static handleProperty(state: TransformerState, node: ts.PropertyDeclaration): ts.PropertyDeclaration {
    return !this.isValid(state) ? node : state.factory.updatePropertyDeclaration(
      node,
      node.modifiers,
      node.name.getText().toUpperCase(),
      undefined,
      node.type,
      node.initializer ?? state.createIdentifier('undefined')
    );
  }

  static handleClass(state: TransformerState, node: ts.ClassDeclaration): ts.ClassDeclaration {
    return !this.isValid(state) ? node : state.factory.updateClassDeclaration(
      node,
      node.modifiers,
      state.createIdentifier(node.name!.getText().toUpperCase()),
      node.typeParameters,
      node.heritageClauses,
      node.members
    );
  }

  static handleMethod(state: TransformerState, node: ts.MethodDeclaration): ts.MethodDeclaration {
    return !this.isValid(state) ? node : state.factory.updateMethodDeclaration(
      node,
      node.modifiers,
      undefined,
      state.createIdentifier(node.name.getText().toUpperCase()),
      undefined,
      node.typeParameters,
      node.parameters,
      node.type,
      node.body
    );
  }
}
```

**Note**: This should be a strong indicator that it is very easy to break code in unexpected ways.

**Code: Sample Input**
```typescript
export class Test {
  name: string;
  age: number;
  dob: Date;

  computeAge(): void {
    this['age'] = (Date.now() - this.dob.getTime());
  }
}
```

**Code: Sample Output**
```javascript
import * as Δfunction from "@travetto/runtime/src/function.js";
const Δm_1 = ["@travetto/transformer", "doc/upper.ts"];
export class TEST {
    static { Δfunction.registerFunction(TEST, Δm_1, { hash: 649563175, lines: [1, 9] }, { COMPUTEAGE: { hash: 1286718349, lines: [6, 8, 7] } }, false); }
    NAME;
    AGE;
    DOB;
    COMPUTEAGE() {
        this['AGE'] = (Date.now() - this.DOB.getTime());
    }
}
```
