Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

ts-patch

nonara627kMIT3.3.0TypeScript support: included

Patch typescript to support custom transformers in tsconfig.json

typescript, transform, transformer, plugin, config, ast

readme

npm version NPM Downloads Build Status

ts-patch

Patch typescript to allow custom transformers (plugins) during build.

Plugins are specified in tsconfig.json, or provided programmatically in CompilerOptions.

Migrating from ttypescript is easy! See: Method 1: Live Compiler

Features

  • Patch typescript installation via on-the-fly, in-memory patching or as a persistent patch
  • Can patch individual libraries (see ts-patch /?)
  • Hook build process by transforming the Program (see: Transforming Program)
  • Add, remove, or modify diagnostics (see: Altering Diagnostics)
  • Fully compatible with legacy ttypescript projects
  • (new) Experimental support for ES Module based transformers

Table of Contents

Installation

  1. Install package
    <yarn|npm|pnpm> add -D ts-patch

Usage

Method 1: Live Compiler

The live compiler patches on-the-fly, each time it is run.

Via commandline: Simply use tspc (instead of tsc)

With tools such as ts-node, webpack, ts-jest, etc: specify the compiler as ts-patch/compiler

Method 2: Persistent Patch

Persistent patch modifies the typescript installation within the node_modules path. It requires additional configuration to remain persisted, but it carries less load time and complexity compared to the live compiler.

  1. Install the patch
# For advanced options, see: ts-patch /?
ts-patch install
  1. Add prepare script (keeps patch persisted after npm install)

package.json

{
  /* ... */
  "scripts": {
    "prepare": "ts-patch install -s"
  }
}

Configuration

tsconfig.json: Add transformers to compilerOptions in plugins array.

Examples

{
    "compilerOptions": {
        "plugins": [
            // Source Transformers
            { "transform": "transformer-module" },
            { "transform": "transformer2", "extraOption": 123 },
            { "transform": "trans-with-mapping", "resolvePathAliases": true },
            { "transform": "esm-transformer", "isEsm": true },

            // Program Transformer
            { "transform": "transformer-module5", "transformProgram": true }
        ]
    }
}

Plugin Options

Option Type Description
transform string Module name or path to transformer (*.ts or *.js)
after boolean Apply transformer after stock TS transformers
afterDeclarations boolean Apply transformer to declaration (*.d.ts) files
transformProgram boolean Transform Program during ts.createProgram() (see: Program Transformers)
isEsm boolean Transformer is ES Module (note: experimental — requires esm)
resolvePathAliases boolean Resolve path aliases in transformer (requires tsconfig-paths)
type string See: Source Transformer Entry Point (default: 'program')
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)
... | Provide your own custom options, which will be passed to the transformer

Note: Required options are bold

Writing Transformers

For an overview of the typescript compiler (such as what a SourceFile and Program is) see: Typescript Compiler Notes.

Source Transformers

Source Transformers will transform the AST of SourceFiles during compilation, allowing you to alter the output of the JS or declarations files.

Source Transformer Entry Point

(program: ts.Program, config: PluginConfig, extras: TransformerExtras) => ts.TransformerFactory

PluginConfig: Type Declaration
TransformerExtras: Type Declaration
ts.TransformerFactory: (context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile

Note: Additional legacy signatures are supported, but it is not recommended to develop a new transformer using them.

Source Transformer Example

Transformers can be written in JS or TS.

import type * as ts from 'typescript';
import type { TransformerExtras, PluginConfig } from 'ts-patch';

/** Changes string literal 'before' to 'after' */
export default function (program: ts.Program, pluginConfig: PluginConfig, { ts: tsInstance }: TransformerExtras) {
  return (ctx: ts.TransformationContext) => {
    const { factory } = ctx;

    return (sourceFile: ts.SourceFile) => {
      function visit(node: ts.Node): ts.Node {
        if (tsInstance.isStringLiteral(node) && node.text === 'before') {
          return factory.createStringLiteral('after');
        }
        return tsInstance.visitEachChild(node, visit, ctx);
      }
      return tsInstance.visitNode(sourceFile, visit);
    };
  };
}

Live Examples:

{ transform: "typescript-transform-paths" }

{ transform: "typescript-is/lib/transform-inline/transformer" }

{ transform: "typia/lib/transform" } (💻playground)

{ transform: "@nestia/core/lib/transform" }

Altering Diagnostics

Diagnostics can be altered in a Source Transformer.

To alter diagnostics you can use the following, provided from the TransformerExtras parameter:

property description
diagnostics Reference to Diagnostic array
addDiagnostic() Safely add Diagnostic to diagnostics array
removeDiagnostic() Safely remove Diagnostic from diagnostics array

Note

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_

Program Transformers

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.

Program Transformer Entry Point

(program: ts.Program, host: ts.CompilerHost | undefined, options: PluginConfig, extras: ProgramTransformerExtras) => ts.Program

ProgramTransformerExtras >>> Type Declaration

Configuring Program Transformers

To configure a Program Transformer, supply "transformProgram": true in the config transformer entry.

Note: The before, after, and afterDeclarations options do not apply to a Program Transformer and will be ignored

See Config Example

Program Transformer Example

/** 
 * Add a file to Program
 */
import * as path from 'path';
import type * as ts from 'typescript';
import type { 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

Live Examples:

{ transform: "@typescript-virtual-barrel/compiler-plugin", transformProgram: true }

{ transform: "ts-overrides-plugin", transformProgram: true }

Plugin Package Configuration

The plugin package configuration allows you to specify custom options for your TypeScript plugin. This configuration is defined in the package.json of your plugin under the tsp property.

An example use case is enabling parseAllJsDoc if you require full JSDoc parsing in tsc for your transformer in TS v5.3+. (see: 5.3 JSDoc parsing changes)

For all available options, see the PluginPackageConfig type in plugin-types.ts

Example

{
  "name": "your-plugin-name",
  "version": "1.0.0",
  "tsp": {
    "tscOptions": {
      "parseAllJsDoc": true
    }
  }
}

Resources

Tool Type Description
TS AST Viewer Web App Allows you to see the Node structure and other TS properties of your source code.
ts-expose-internals NPM Package Exposes internal types and methods of the TS compiler API

Discussion

Advanced Options

(env) TSP_SKIP_CACHE

Skips patch cache when patching via cli or live compiler.

(env) TSP_COMPILER_TS_PATH

Specify typescript library path to use for ts-patch/compiler (defaults to require.resolve('typescript'))

(env) TSP_CACHE_DIR

Override patch cache directory

(cli) ts-patch clear-cache

Cleans patch cache & lockfiles

Maintainers


Ron S.

Help Wanted

If you're interested in helping and are knowledgeable with the TS compiler codebase, feel free to reach out!

License

This project is licensed under the MIT License, as described in LICENSE.md

changelog

Changelog

All notable changes to this project will be documented in this file. See standard-version for commit guidelines.

3.3.0 (2024-12-04)

Features

3.2.1 (2024-06-26)

Bug Fixes

3.2.0 (2024-06-03)

Features

  • Added support for TS 5.5 (2c4954d)

3.1.2 (2024-01-10)

Bug Fixes

  • don't break if other plugin is added (f2b591e)

3.1.1 (2023-12-06)

Bug Fixes

  • parseAllJsDoc breaking with < ts 5.3 (d21e02e)

3.1.0 (2023-12-05)

Features

  • Added Plugin Package Configuration + parseAllJsDoc (closes #134 closes #133) (15570d0)
  • Added support for chaining transformers in single factory (closes #122 closes #120) (aabf389)

Bug Fixes

  • TsExtras 'ts' type registering as 'any' (fixes #127) (069411e)
  • tsp.currentLibrary was not set (detail) (24d8031)

3.0.2 (2023-07-20)

Bug Fixes

  • Plugins returning TransformerBasePlugin not supported (fixes #113) (12ee3a2)

3.0.1 (2023-06-22)

Bug Fixes

  • Added explicit error if ts is patched and cached backup is removed (ac25743)
  • ESM temp files not cleaned up (8802054)
  • Lock file deletion check (#102) (cacf908)

3.0.0 (2023-06-13)

⚠ BREAKING CHANGES

Features

  • Added Live Compiler (on-the-fly, in-memory patching), which allows ttypescript migration
  • Added experimental ES Module support (closes #58)
  • Added mutex locks (closes #75)
  • Updated to support TS v5+ (closes #83 closes #93)
  • Added caching

Bug Fixes

  • Fixed patching for non-standard libraries (cannot guarantee they will work as expected in IDEs) (closes #85)

2.1.0 (2022-12-08)

Features

  • Updated to support TS 4.9 (26f6099)

2.0.2 (2022-08-10)

Changes

2.0.1 (2021-11-01)

Bug Fixes

  • Corrected path error in previous release (7c56d56)

2.0.0 (2021-11-01)

Summary

This is not the planned rewrite, but the codebase was in desperate need of an update. The patch build system with rollup was failing with newer versions and was hacky under the best of circumstances, anyway. This new version has a proper custom build system that produces a much leaner patch. Additionally, I reorganized the codebase, improved tests, and dropped old TS support.

Note: If you absolutely need it, it will still work with older TS. Simply fork and remove the version check

Changes

  • Soft deprecated --basedir (use --dir)
  • Zero bundled dependencies in patch (much lighter)
  • ⚠️ Hard deprecated --persist option (use package.json -> prepare script)
  • ⚠️ Requires TS >= 4.0

(⚠️ denotes potential "breaking" change)

Development Changes

  • Removed rollup and created light-weight custom build system
  • Cleaned up file structure
  • Improved test speed & methodology
  • Changed patch detection signature

1.4.5 (2021-10-25)

Bug Fixes

  • compilation fails if basedir resolves to cwd (#65) (9bac698)

1.4.4 (2021-08-27)

Bug Fixes

  • --basedir flag fails if dir is not a subdir of a package (5912288)

1.4.3 (2021-08-23)

Bug Fixes

  • Relative transform paths do not resolve from project root dir with compiler API (fixes #59) (e38655a)
  • ts 3.6.5 does not patch properly (fixes #55) (1babac9)

1.4.2 (2021-08-01)

Bug Fixes

  • Patch fails on ts v3.1 - 3.5 (fixes #54) (0fabe3c)

1.4.1 (2021-07-13)

Bug Fixes

  • Only patch 'tsc.js' and 'typescript.js' by default (closes #52) (4d029f6)

1.4.0 (2021-07-13)

Features

  • Add tsserver.js to supported libraries (08262ed)

Bug Fixes

  • Require ts-node installation to be handled by user (fixes #51) (979338c)

1.3.4 (2021-06-30)

Bug Fixes

  • Install adds ts-node to deps instead of devDeps (fixes #38) (a2d586b)

1.3.3 (2021-04-23)

Bug Fixes

  • patch: Patched emit does not pass all arguments (fixes #36) (9b130bc)

1.3.2 (2021-01-31)

1.3.1 (11-25-2020)

Fixed

  • Fixed #21 (Could not specify --basedir with dir name other than typescript - affected yarn aliasing)

1.3.0 (07-26-2020)

Added

  • Added ability to specify tsconfig.json file for transformer (tsConfig option) Note: This opens up the door to specify compilerOptions, which can be useful
  • Added path mapping support (requires tsconfig-paths)

1.2.2 (05-23-2020)

Fixed

  • Possible recursion issue with program transformer
  • In some older TS versions, tsc wasn't passing diagnostics array
  • Various CLI bugs

Added

  • Added 'library' to TspExtras
  • install and patch actions now will proceed to run if already patched but current version is out-dated

Code

  • Substantial re-design of certain parts (see release commit message for more)

1.2.0 (05-20-2020)

Changed: beforeEmit -> tranformProgram

The mechanism of action for Program transformation has been moved from inside program.emit() to ts.createProgram().

In the new methodology, the Program instance is transformed at the point of creation before it is returned from the factory function, which is a far better approach.

While the option name has been updated to reflect the new behaviour, the old beforeEmit can still function as an alias to the new behaviour, so this is not a breaking change.

Added: Inspect or alter diagnostics

Using the program type entry point, the extras field has been revised.

property status description
diagnostics new Reference to Diagnostic[] created during ts.emitFilesAndReportErrors() (works with tsc also)
addDiagnostic changed Directly add Diagnostic to diagnostics array
removeDiagnostic new Directly remove Diagnostic from diagnostics array (uses splice, for safe removal)

See README.md for full detail.

1.1.0 (05-08-2020)

Added

  • Added beforeEmit option, which allows 'transforming' Program instance before program.emit() is called.

1.0 (2019 - 2020)

Fixed

  • Updated for Node v14 (Addresses #7, shelljs/shelljs#991)
  • Adjusted ts-node compilerOptions to ES2018 (Fixes #7)
  • Exposed & fixed addDiagnostic helper (Fixes #6)
  • Rolled resolve package into patch (Fixes #5)
  • Converted EOL to LF (MacOS support) (Fixes #3 #4)
  • Edge cases occurred in which TypeScript based transformers using CommonJS were not being interpretted properly. (Should address issue #1)