Package Exports
- ts-patch
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (ts-patch) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
TS Patch
Directly patch typescript installation to allow custom transformers (plugins).
- Plugins are specified in
tsconfig.json, or provided programmatically inCompilerOptions. - Based on ttypescript - 100% compatibility in configuration & transformers.
Features
- Patch / unpatch any version of typescript (2.7+)
- Advanced options for patching individual libraries, specific locations, etc. (see
ts-patch /?) - (New) Supports 'transforming' the
Programinstance 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
ts-patch install
# For advanced options, see: ts-patch /?- Add
preparescript (keeps patch persisted after npm installations)
package.json
{
/* ... */
"scripts": {
"prepare": "ts-patch install -s"
}
}V2 Coming Soon...
With a couple years of hindsight, it's time for a much needed redesign to make a more complete plugin ecosystem that is more multi-package manager friendly. The development of v2 is underway. To follow that progress, see this discussion.
In the mean time, v1 will still be maintained and patched for any issues, and its end of life will be no earlier than 2023.
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 - notice 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.TransformerFactoryts.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.TransformerFactorychecker
Signature with ts.TypeChecker:
(checker: ts.TypeChecker, config: PluginConfig) => ts.TransformerFactoryraw
Signature without ts-patch wrapper:
/* ts.TransformerFactory */
(context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFilecompilerOptions
(compilerOpts: ts.CompilerOptions, config: PluginConfig) => ts.TransformerFactoryUsage
Transforming AST Nodes
Transformers can be written in JS or TS.
// transformer1-module
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 {
// if (ts.isCallExpression(node)) {
// return ts.createLiteral('call');
// }
return ts.visitEachChild(node, visitor, ctx);
}
return ts.visitEachChild(sourceFile, visitor, ctx);
};
};
}
Example Node Transformers
{ 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: "typescript-transform-paths" }
{ transform: "ts-transformer-minify-privates" }
Transforming Program
There are some cases where a transformer isn't enough. Several examples are if you want to:
- TypeCheck code after it's been transformed
- 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
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.ProgramProgramTransformerExtras >>> See Type Declaration
Example Program Transformer
/**
* Add a file to Program
*/
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(
/* rootNames */ program.getRootFileNames().concat([ newFile ]),
program.getCompilerOptions(),
host,
/* oldProgram */ 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[] created during ts.emitFilesAndReportErrors() (works with tsc also) |
| 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, create a LanguageService plugin
- If an emit method other than
ts.emitFilesAndReportErrors()is used, any diagnostics added viaaddDiagnostic()will still be merged into the result ofprogram.emit() -> diagnostics
Resources
Recommended Reading
- Advice for working with the TS Compiler API (must read)
- TypeScript Transformer Handbook (must read)
- Article: How to Write a TypeScript Transform (Plugin)
- Article: Creating a TypeScript Transformer
Recommended Tools
| Tool | Type | Description |
|---|---|---|
| TS AST Viewer | Website | Allows you to see the Node structure of any TS/JS source, including Flags, Type, and Symbol. This is the go-to tool for all things TypeScript AST. |
| 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
| Author | Module |
|---|---|
| Ron S. | ts-patch |
| cevek | ttypescript |
HALP!!!
- Start here: Recommended Reading
- Ask on StackOverflow with the
#typescript-compiler-apitag - Read the handbook and still stuck? Ask in Discussions - someone may answer if they have time.
- Check out the
#compilerroom on the TypeScript Discord Server.
License
This project is licensed under the MIT License