ts-patch
ts-patch copied to clipboard
In-program compiling for unit tests. `preparePluginsFromCompilerOptions` discards `transformProgram` ?
Hello!
I've been using ts-patch for quite a while now (it's very good) and I've decided to upgrade my usage by creating unit tests for the transformers so that I can verify that they work when new versions of the compiler release.
I am using vitest (though that's not particularly important) and am trying to run the typescript
file as an imported script, but I've run into a snag.
It looks like calling the transpileModule
function directly in the patched typescript
doesn't allow for transformers to run. This appears to be because preparePluginsFromCompilerOptions
adds all transformers with a stripped-down config (either just { transform: string }
or { transform: string, after: true }
but TspPlugin
's constructor wants { transform: string, transformProgram: true }
.
As preparePluginsFromCompilerOptions
is called immediately before new tsp.PluginCreator
in tsp's createProgram
I don't see a way to change the property of the plugin to allow for program transformers so that my transformers can operate when calling transpileModule
.
This is the entire code that I have so far in attempting to do this:
import { MatcherState } from "@vitest/expect";
import Path from "node:path";
import { expect } from "vitest";
import * as ts from "typescript";
import { getTsPackage } from "ts-patch/ts-package.js";
import * as tspatch from "ts-patch/patch/get-patched-source.js";
import * as tsmodule from "ts-patch/module/ts-module.js";
const tsPackage = getTsPackage(Path.join(process.cwd(), "./node_modules/typescript/"));
const tsModule = tsmodule.getTsModule(tsPackage, "typescript.js" as any);
const tspSource = tspatch.getPatchedSource(tsModule, { log: console.log.bind(console) });
const tsp: typeof ts = eval(tspSource.js);
const extensions = {
toCompileTo(this: MatcherState, received: string, expected: string): {message: () => string, pass: boolean} {
const source = "let x: string = 'string'";
let result = tsp.transpileModule(received, {
compilerOptions: {
module: ts.ModuleKind.ES2022,
target: ts.ScriptTarget.ES2022,
strict: true,
skipLibCheck: true,
skipDefaultLibCheck: true,
noErrorTruncation: true,
noEmitOnError: false,
experimentalDecorators: true,
plugins: [
{ "customTransformers": {after: ["../Compiler/Transformers/MixinTransformer.js"], transformProgram: true } }
] as any
}
});
let resultMessage = { message: () => `expected raw code to compile into provided sample (view diff)`, actual: result.outputText.trim(), expected: expected.trim() };
return {
...resultMessage,
pass: result.outputText.trim() === expected.trim()
};
}
};
expect.extend(extensions);
If you have vitest configured it can be called like so:
import { test, expect } from "vitest";
test("Test my custom transformer works", ()=> {
expect(`some code`).toCompileTo(`some output`);
});