ts-patch
    TypeScript icon, indicating that this package has built-in type declarations

    1.4.5 • Public • Published

    npm version NPM Downloads Build Status Coverage Status

    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 - 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 Program instance during creation. (see: Transforming Program)
    • (New) Add, remove, or modify diagnostics! (see: Altering Diagnostics)

    Setup

    1. Install package
    <yarn|npm|pnpm> add -D ts-patch
    1. Patch typescript
    ts-patch install
    # For advanced options, see: ts-patch /?
    1. Add prepare script (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! The new design will also be friendlier for the various package management apps.

    The development of v2 is already underway! To follow that progress, see this discussion.

    That said —

    • The new v2 will still support all legacy packages and config
    • v1 will be maintained and patched for any issues, having an end of life 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.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:

    /* ts.TransformerFactory */ 
    (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.

    // 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

    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

    /** 
     * 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 via addDiagnostic() will still be merged into the result of program.emit() -> diagnostics

    Resources

    Recommended Reading

    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!!!

    License

    This project is licensed under the MIT License

    Install

    npm i ts-patch

    DownloadsWeekly Downloads

    5,613

    Version

    1.4.5

    License

    MIT

    Unpacked Size

    210 kB

    Total Files

    49

    Last publish

    Collaborators

    • nonara