Awesome
simple-ts-transform - Library to help create simple typescript transformers
This package provides a simple API to build TypeScript transformers, based on a shared context and multiple node visitors.
For usage examples, you can look at:
You may also be interrested in:
Language/langue
Documents, messages, code (including variable names and comments), are in English.
Anyway, because Slune is French firm, all documents and important messages must also be provided in French. Other translations are welcome.
:fr: Une version française de ce document se trouve ici.
Installation
Installation is done using npm install
command:
$ npm install --save simple-ts-transform
Usage
Context
First, create the context class. You can put in it whatever you need for your visitors. The context is created when the compilation starts and is updated for each file. Your node visitors can access the context, and of course, can also modify it if needed.
The context class constructor will be called with:
- a
ts.Program
parameter, - an
unknown
object containing the configuration provided to the transformer.
The context class must also implement the initNewFile(context: TransformationContext, sourceFile: SourceFile): void
method, called before visiting each new file.
// MyContext.ts
import type { NodeVisitorContext } from 'simple-ts-transform'
import type { NodeFactory, Program, SourceFile, TransformationContext } from 'typescript'
export default class MyContext implements NodeVisitorContext {
public readonly basePath: string
public factory!: NodeFactory
public fileName!: string
public constructor(program: Program, public readonly _configuration: unknown) {
this.basePath = program.getCompilerOptions().rootDir || program.getCurrentDirectory()
}
public initNewFile(context: TransformationContext, sourceFile: SourceFile): void {
this.factory = context.factory
this.fileName = sourceFile.fileName
}
}
Node visitors
Then, you can create the node visitors. The node visitors are created for each file after the context is initialized and before starting the visit.
Because each node visitor is only managing one single type of node, this node type must be given as generic parameter N
to the implemented interface.
The visitor constructor will be called with your context as single parameter.
Your visitor must implement the following methods:
- The method
wants(node: Node): node is N
make some basic checks on the node to indicate if the visitor will manage it or not. This method also serves as a type guard to ensure the node is of appropriate type. - The method
visit(node: N): Node[]
is given the node to visit in order to work on it. This method returns an array of 0, 1 or more nodes, so it can remove, update or create nodes. The nodes created by this visitor will be visited by all the following provided visitors.
// MyFileNameInserter.ts
import type { NodeVisitor } from 'simple-ts-transform'
import type { Node, StringLiteral } from 'typescript'
import { isStringLiteral } from 'typescript'
import type { MyContext } from './MyContext'
export default class MyFileNameInserter implements NodeVisitor<StringLiteral> {
private readonly fileName: string
public constructor(private readonly context: MyContext) {
this.fileName = context.fileName
}
public wants(node: Node): node is StringLiteral {
return isStringLiteral(node)
}
public visit(node: StringLiteral) {
const { createStringLiteral } = this.context.factory
return [createStringLiteral(this.fileName + ': ' + node.getText().slice(1, -1)]
}
}
Transformer
You finally can create the transformer. For this, simply call buildTransformer
and provide the context class and the node visitors in the order they have to be executed.
// index.ts
import buildTransformer from 'simple-ts-transform'
import MyContext from './MyContext'
import MyFileNameInserter from './MyFileNameInserter'
import OtherVisitor from './OtherVisitor'
const transformer = buildTransformer(MyContext, [MyFileNameInserter, OtherVisitor])
export default transformer
Call
There is currently no way of declaring a transformer in the vanilla TypeScript compiler. If you do not want to write your own compiler using the typescript
API, you can use the ttypescript wrapper. The configuration then is made in tsconfig.json
:
{
"compilerOptions": {
"plugins": [
{
"transform": "my-transformer",
"my-config-entry": "hello",
"another-config": true
}
]
}
}
Note that the built transformer is of type program
which is the default for ttypescript
. That's why you don't need to add a type
entry in the configuration.
Contributing
Even though we cannot guarantee a response time, please feel free to file an issue if you have any question or problem using the package.
Pull Requests are welcome. You can, of course, submit corrections or improvements for code, but do not hesitate to also improve documentation, even for small spell or grammar errors.