TS Patch
Directly patch typescript installation to allow custom transformers (plugins).
- Plugins are specified in
tsconfig.json
, or provided programmatically in CompilerOptions
. - Based on ttypescript - Fully compatible + offers more features
Features
- Patch / unpatch any version of typescript (4.0+)
- Advanced options for patching individual libraries, specific locations, etc. (see
ts-patch /?
) - (New) Supports 'transforming' the
Program
instance during creation. (see: Transforming Program) - (New) Add, remove, or modify diagnostics! (see: Altering Diagnostics)
Setup
- Install package
<yarn|npm|pnpm> add -D ts-patch
- Patch typescript
# For advanced options, see: ts-patch /?
ts-patch install
- Add
prepare
script (keeps patch persisted after npm install)
package.json
{
/* ... */
"scripts": {
"prepare": "ts-patch install -s"
}
}
Rewrite Coming Soon...
With a couple years of hindsight, it's time for a much needed redesign to make a more complete plugin ecosystem! The new
design will also be friendlier for the various package management apps.
Development is already underway, but my time to work on it is limited! To follow progress, see this discussion.
Notes —
- The new version will be a major release
- It will still support all legacy packages and config
- Previous major version will be maintained and patched for any issues for at least one year
Table of Contents
Configuring
tsconfig.json
Add transformers to compilerOptions
in plugins
array.
Examples
{
"compilerOptions": {
"plugins": [
// Source Transformer: 'type' defaults to 'program'
{ "transform": "transformer-module", "someOption1": 123, "someOption2": 321 },
// Source Transformer: program signature
{ "transform": "./transformers/my-transformer.ts", "type": "program" },
// Source Transformer: program signature, applies after TS transformers
{ "transform": "transformer-module1", "type": "config", "after": true },
// Source Transformer: checker signature, applies to TS declarations
{ "transform": "transformer-module2", "type": "checker", "afterDeclarations": true },
// Source Transformer: raw signature
{ "transform": "transformer-module3", "type": "raw" },
// Source Transformer: compilerOptions signature
{ "transform": "transformer-module4", "type": "compilerOptions" },
// Program Transformer: Only has one signature - no type specified, because it does not apply
{ "transform": "transformer-module5", "transformProgram": true }
]
}
}
Plugin Options
Option | Type | Description |
---|
transform | string | Module name or path to transformer (*.ts or *.js) |
type | string | Source Transformer entry point signature (see: Source Transformer Signatures) |
import | string | Name of exported transformer function (defaults to default export) |
tsConfig | string | tsconfig.json file for transformer (allows specifying compileOptions, path mapping support, etc) |
after | boolean | Apply transformer after stock TS transformers. |
afterDeclarations | boolean | Apply transformer to declaration (*.d.ts) files (TypeScript 2.9+). |
transformProgram | boolean | Transform Program during ts.createProgram() (see: Transforming Program) |
... | | Provide your own custom options, which will be passed to the transformer |
Note: Required options are bold
Source Transformer Signatures
The following are the possible values for the type
option and their corresponding entry point signatures.
Note: These apply to Source Transformers only.
program (default)
Signature with ts.Program
instance:
(program: ts.Program, config: PluginConfig, extras: TransformerExtras) => ts.TransformerFactory
ts.TransformerFactory >>> (context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile
TransformerExtras >>> See Type Declaration
Note: This is not the configuration for a Program Transformer.
config
Signature with transformer's config:
(config: PluginConfig) => ts.TransformerFactory
checker
Signature with ts.TypeChecker
:
(checker: ts.TypeChecker, config: PluginConfig) => ts.TransformerFactory
raw
Signature without ts-patch
wrapper:
(context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile
compilerOptions
(compilerOpts: ts.CompilerOptions, config: PluginConfig) => ts.TransformerFactory
Usage
Transforming AST Nodes
Transformers can be written in JS or TS.
import * as ts from 'typescript';
export default function(program: ts.Program, pluginOptions: any) {
return (ctx: ts.TransformationContext) => {
return (sourceFile: ts.SourceFile) => {
function visitor(node: ts.Node): ts.Node {
return ts.visitEachChild(node, visitor, ctx);
}
return ts.visitEachChild(sourceFile, visitor, ctx);
};
};
}
Example Node Transformers
{ transform: "typescript-transform-paths" }
{ transform: "typescript-is/lib/transform-inline/transformer" }
{ transform: "ts-transform-img/dist/transform", type: "config" }
{ transform: "ts-transform-css-modules/dist/transform", type: "config" }
{ transform: "ts-transform-react-intl/dist/transform", import: "transform", type: "config" }
{ transform: "ts-nameof", type: "raw" }
{ transform: "typescript-transform-jsx" }
{ transform: "ts-transformer-minify-privates" }
Transforming Program
Sometimes you want to do more than just transform source code. For example you may want to:
- TypeCheck code after it's been transformed
- Generate code and add it to the program
- Add or remove emit files during transformation
For this, we've introduced what we call a Program Transformer. The transform action takes place during ts.createProgram
, and allows
re-creating the Program
instance that typescript uses.
Configuring Program Transformer
To configure a Program Transformer, supply "transformProgram": true
in the config transformer entry.
Note: The type
, before
, and after
options do not apply to a Program Transformer and will be ignored
See Config Example
Signature
There is only one possible signature for a Program Transformer entry point.
(program: ts.Program, host: ts.CompilerHost | undefined, options: PluginConfig, extras: ProgramTransformerExtras) => ts.Program
ProgramTransformerExtras >>> See Type Declaration
Example Program Transformer
import * as ts from 'typescript';
import * as path from 'path';
import { ProgramTransformerExtras, PluginConfig } from 'ts-patch';
export const newFile = path.resolve(__dirname, 'added-file.ts');
export default function (
program: ts.Program,
host: ts.CompilerHost | undefined,
options: PluginConfig,
{ ts: tsInstance }: ProgramTransformerExtras
) {
return tsInstance.createProgram(
program.getRootFileNames().concat([ newFile ]),
program.getCompilerOptions(),
host,
program
);
}
Note: For a more complete example, see Transforming Program with additional AST transformations
Altering Diagnostics
Diagnostics can be altered in a Source Transformer.
To alter diagnostics, use the program type signature, and use the following properties from the
TransformerExtras
parameter
property | description |
---|
diagnostics | Reference to Diagnostic array |
addDiagnostic() | Directly add Diagnostic to diagnostics array |
removeDiagnostic() | Directly remove Diagnostic from diagnostics array (uses splice, for safe removal) |
Notes
- This alters diagnostics during emit only. If you want to alter diagnostics in your IDE as well, you'll need to create a LanguageService plugin to accompany your source transformer
Resources
Recommended Reading
Recommended Tools
Tool | Type | Description |
---|
TS AST Viewer | Website | Allows you to see the Node structure and other TS properties of your source code. |
ts-query | NPM Package | Perform fast CSS-like queries on AST to find specific nodes (by attribute, kind, name, etc) |
ts-query Playground | Website | Test ts-query in realtime |
ts-expose-internals | NPM Package | Exposes internal types and methods of the TS compiler API |
Credit
HALP!!!
License
This project is licensed under the MIT License, as described in LICENSE.md