diff --git a/CHANGELOG.md b/CHANGELOG.md index ef3c2229d..b7ff3a76b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,6 +81,16 @@ end ``` +- Added `tstl.luaPlugins` option, allowing to specify plugins in a `tsconfig.json` file: + + ```json + { + "tstl": { + "luaPlugins": [{ "name": "./plugin.ts" }] + } + } + ``` + ## 0.31.0 - **Breaking:** The old annotation syntax (`/* !varArg */`) **no longer works**, the only currently supported syntax is: diff --git a/src/CompilerOptions.ts b/src/CompilerOptions.ts index 48c8abe82..5a6291098 100644 --- a/src/CompilerOptions.ts +++ b/src/CompilerOptions.ts @@ -18,6 +18,11 @@ export interface TransformerImport { [option: string]: any; } +export interface LuaPluginImport { + name: string; + import?: string; +} + export type CompilerOptions = OmitIndexSignature & { noImplicitSelf?: boolean; noHeader?: boolean; @@ -26,6 +31,7 @@ export type CompilerOptions = OmitIndexSignature & { luaTarget?: LuaTarget; luaLibImport?: LuaLibImportKind; sourceMapTraceback?: boolean; + luaPlugins?: LuaPluginImport[]; plugins?: Array; [option: string]: any; }; diff --git a/src/cli/parse.ts b/src/cli/parse.ts index 9f05f2f9c..ce0985913 100644 --- a/src/cli/parse.ts +++ b/src/cli/parse.ts @@ -17,15 +17,11 @@ interface CommandLineOptionOfEnum extends CommandLineOptionBase { choices: string[]; } -interface CommandLineOptionOfBoolean extends CommandLineOptionBase { - type: "boolean"; +interface CommandLineOptionOfPrimitive extends CommandLineOptionBase { + type: "boolean" | "string" | "object"; } -interface CommandLineOptionOfString extends CommandLineOptionBase { - type: "string"; -} - -type CommandLineOption = CommandLineOptionOfEnum | CommandLineOptionOfBoolean | CommandLineOptionOfString; +type CommandLineOption = CommandLineOptionOfEnum | CommandLineOptionOfPrimitive; export const optionDeclarations: CommandLineOption[] = [ { @@ -66,6 +62,11 @@ export const optionDeclarations: CommandLineOption[] = [ description: "Applies the source map to show source TS files and lines in error tracebacks.", type: "boolean", }, + { + name: "luaPlugins", + description: "List of TypeScriptToLua plugins.", + type: "object", + }, ]; export function updateParsedConfigFile(parsedConfigFile: ts.ParsedCommandLine): ParsedCommandLine { @@ -173,8 +174,9 @@ function readValue(option: CommandLineOption, value: unknown): ReadValueResult { if (value === null) return { value }; switch (option.type) { + case "boolean": case "string": - case "boolean": { + case "object": { if (typeof value !== option.type) { return { value: undefined, diff --git a/src/transpilation/diagnostics.ts b/src/transpilation/diagnostics.ts index 9467bb606..80b68088e 100644 --- a/src/transpilation/diagnostics.ts +++ b/src/transpilation/diagnostics.ts @@ -4,17 +4,18 @@ import { createSerialDiagnosticFactory } from "../utils"; const createDiagnosticFactory = (getMessage: (...args: TArgs) => string) => createSerialDiagnosticFactory((...args: TArgs) => ({ messageText: getMessage(...args) })); -export const toLoadTransformerItShouldBeTranspiled = createDiagnosticFactory( - (transform: string) => - `To load "${transform}" transformer it should be transpiled or "ts-node" should be installed.` +export const toLoadItShouldBeTranspiled = createDiagnosticFactory( + (kind: string, transform: string) => + `To load "${transform}" ${kind} it should be transpiled or "ts-node" should be installed.` ); -export const couldNotResolveTransformerFrom = createDiagnosticFactory( - (transform: string, base: string) => `Could not resolve "${transform}" transformer from "${base}".` +export const couldNotResolveFrom = createDiagnosticFactory( + (kind: string, transform: string, base: string) => `Could not resolve "${transform}" ${kind} from "${base}".` ); -export const transformerShouldHaveAExport = createDiagnosticFactory( - (transform: string, importName: string) => `"${transform}" transformer should have a "${importName}" export.` +export const shouldHaveAExport = createDiagnosticFactory( + (kind: string, transform: string, importName: string) => + `"${transform}" ${kind} should have a "${importName}" export.` ); export const transformerShouldBeATsTransformerFactory = createDiagnosticFactory( diff --git a/src/transpilation/index.ts b/src/transpilation/index.ts index 530fbdd4c..1d15e59c4 100644 --- a/src/transpilation/index.ts +++ b/src/transpilation/index.ts @@ -7,6 +7,7 @@ import { emitTranspiledFiles, OutputFile } from "./emit"; import { transpile, TranspiledFile, TranspileResult } from "./transpile"; export * from "./emit"; +export { Plugin } from "./plugins"; export * from "./transpile"; export interface TranspileFilesResult { diff --git a/src/transpilation/plugins.ts b/src/transpilation/plugins.ts index 8731211d6..0311efbbd 100644 --- a/src/transpilation/plugins.ts +++ b/src/transpilation/plugins.ts @@ -1,6 +1,8 @@ import * as ts from "typescript"; +import { CompilerOptions } from "../CompilerOptions"; import { Printer } from "../LuaPrinter"; import { Visitors } from "../transformation/context"; +import { getConfigDirectory, resolvePlugin } from "./utils"; export interface Plugin { /** @@ -18,10 +20,27 @@ export interface Plugin { printer?: Printer; } -export function getPlugins( - _program: ts.Program, - _diagnostics: ts.Diagnostic[], - pluginsFromOptions: Plugin[] -): Plugin[] { - return pluginsFromOptions; +export function getPlugins(program: ts.Program, diagnostics: ts.Diagnostic[], customPlugins: Plugin[]): Plugin[] { + const pluginsFromOptions: Plugin[] = []; + const options = program.getCompilerOptions() as CompilerOptions; + + for (const [index, pluginOption] of (options.luaPlugins ?? []).entries()) { + const optionName = `tstl.luaPlugins[${index}]`; + + const { error: resolveError, result: factory } = resolvePlugin( + "plugin", + `${optionName}.name`, + getConfigDirectory(options), + pluginOption.name, + pluginOption.import + ); + + if (resolveError) diagnostics.push(resolveError); + if (factory === undefined) continue; + + const plugin = typeof factory === "function" ? factory(pluginOption) : factory; + pluginsFromOptions.push(plugin); + } + + return [...customPlugins, ...pluginsFromOptions]; } diff --git a/src/transpilation/transformers.ts b/src/transpilation/transformers.ts index 71371e208..cefb4dd90 100644 --- a/src/transpilation/transformers.ts +++ b/src/transpilation/transformers.ts @@ -1,10 +1,9 @@ -import * as path from "path"; -import * as resolve from "resolve"; import * as ts from "typescript"; // TODO: Don't depend on CLI? import * as cliDiagnostics from "../cli/diagnostics"; import { CompilerOptions, TransformerImport } from "../CompilerOptions"; import * as diagnosticFactories from "./diagnostics"; +import { getConfigDirectory, resolvePlugin } from "./utils"; export const noImplicitSelfTransformer: ts.TransformerFactory = () => node => { const transformSourceFile: ts.Transformer = node => { @@ -18,7 +17,7 @@ export const noImplicitSelfTransformer: ts.TransformerFactory = { before: [], after: [], @@ -64,19 +63,23 @@ function loadTransformersFromOptions(program: ts.Program, allDiagnostics: ts.Dia const options = program.getCompilerOptions() as CompilerOptions; if (!options.plugins) return customTransformers; - const configFileName = options.configFilePath as string | undefined; - const basedir = configFileName ? path.dirname(configFileName) : process.cwd(); - for (const [index, transformerImport] of options.plugins.entries()) { if (!("transform" in transformerImport)) continue; const optionName = `compilerOptions.plugins[${index}]`; - const { error: resolveError, factory } = resolveTransformerFactory(basedir, optionName, transformerImport); - if (resolveError) allDiagnostics.push(resolveError); + const { error: resolveError, result: factory } = resolvePlugin( + "transformer", + `${optionName}.transform`, + getConfigDirectory(options), + transformerImport.transform, + transformerImport.import + ); + + if (resolveError) diagnostics.push(resolveError); if (factory === undefined) continue; const { error: loadError, transformer } = loadTransformer(optionName, program, factory, transformerImport); - if (loadError) allDiagnostics.push(loadError); + if (loadError) diagnostics.push(loadError); if (transformer === undefined) continue; if (transformer.before) { @@ -103,12 +106,6 @@ type CompilerOptionsTransformerFactory = ( ) => Transformer; type TypeCheckerTransformerFactory = (typeChecker: ts.TypeChecker, options: Record) => Transformer; type RawTransformerFactory = Transformer; -type TransformerFactory = - | ProgramTransformerFactory - | ConfigTransformerFactory - | CompilerOptionsTransformerFactory - | TypeCheckerTransformerFactory - | RawTransformerFactory; type Transformer = GroupTransformer | ts.TransformerFactory; interface GroupTransformer { @@ -117,48 +114,10 @@ interface GroupTransformer { afterDeclarations?: ts.TransformerFactory; } -function resolveTransformerFactory( - basedir: string, - transformerOptionPath: string, - { transform, import: importName = "default" }: TransformerImport -): { error?: ts.Diagnostic; factory?: TransformerFactory } { - if (typeof transform !== "string") { - const optionName = `${transformerOptionPath}.transform`; - return { error: cliDiagnostics.compilerOptionRequiresAValueOfType(optionName, "string") }; - } - - let resolved: string; - try { - resolved = resolve.sync(transform, { basedir, extensions: [".js", ".ts", ".tsx"] }); - } catch (err) { - if (err.code !== "MODULE_NOT_FOUND") throw err; - return { error: diagnosticFactories.couldNotResolveTransformerFrom(transform, basedir) }; - } - - // tslint:disable-next-line: deprecation - const hasNoRequireHook = require.extensions[".ts"] === undefined; - if (hasNoRequireHook && (resolved.endsWith(".ts") || resolved.endsWith(".tsx"))) { - try { - const tsNode: typeof import("ts-node") = require("ts-node"); - tsNode.register({ transpileOnly: true }); - } catch (err) { - if (err.code !== "MODULE_NOT_FOUND") throw err; - return { error: diagnosticFactories.toLoadTransformerItShouldBeTranspiled(transform) }; - } - } - - const factory: TransformerFactory = require(resolved)[importName]; - if (factory === undefined) { - return { error: diagnosticFactories.transformerShouldHaveAExport(transform, importName) }; - } - - return { factory }; -} - function loadTransformer( - transformerOptionPath: string, + optionPath: string, program: ts.Program, - factory: TransformerFactory, + factory: unknown, { transform, after = false, afterDeclarations = false, type = "program", ...extraOptions }: TransformerImport ): { error?: ts.Diagnostic; transformer?: GroupTransformer } { let transformer: Transformer; @@ -179,18 +138,18 @@ function loadTransformer( transformer = (factory as CompilerOptionsTransformerFactory)(program.getCompilerOptions(), extraOptions); break; default: { - const optionName = `--${transformerOptionPath}.type`; + const optionName = `--${optionPath}.type`; return { error: cliDiagnostics.argumentForOptionMustBe(optionName, "program") }; } } if (typeof after !== "boolean") { - const optionName = `${transformerOptionPath}.after`; + const optionName = `${optionPath}.after`; return { error: cliDiagnostics.compilerOptionRequiresAValueOfType(optionName, "boolean") }; } if (typeof afterDeclarations !== "boolean") { - const optionName = `${transformerOptionPath}.afterDeclarations`; + const optionName = `${optionPath}.afterDeclarations`; return { error: cliDiagnostics.compilerOptionRequiresAValueOfType(optionName, "boolean") }; } diff --git a/src/transpilation/transpile.ts b/src/transpilation/transpile.ts index df8214718..9046477e8 100644 --- a/src/transpilation/transpile.ts +++ b/src/transpilation/transpile.ts @@ -7,7 +7,7 @@ import { createVisitorMap, transformSourceFile } from "../transformation"; import { isNonNull } from "../utils"; import { bundleTranspiledFiles } from "./bundle"; import { getPlugins, Plugin } from "./plugins"; -import { getCustomTransformers } from "./transformers"; +import { getTransformers } from "./transformers"; export interface TranspiledFile { fileName: string; @@ -42,7 +42,7 @@ export function transpile({ program, sourceFiles: targetSourceFiles, customTransformers = {}, - plugins: pluginsFromOptions = [], + plugins: customPlugins = [], emitHost = ts.sys, }: TranspileOptions): TranspileResult { const options = program.getCompilerOptions() as CompilerOptions; @@ -85,7 +85,7 @@ export function transpile({ } } - const plugins = getPlugins(program, diagnostics, pluginsFromOptions); + const plugins = getPlugins(program, diagnostics, customPlugins); const visitorMap = createVisitorMap(plugins.map(p => p.visitors).filter(isNonNull)); const printer = createPrinter(plugins.map(p => p.printer).filter(isNonNull)); const processSourceFile = (sourceFile: ts.SourceFile) => { @@ -107,7 +107,7 @@ export function transpile({ } }; - const transformers = getCustomTransformers(program, diagnostics, customTransformers, processSourceFile); + const transformers = getTransformers(program, diagnostics, customTransformers, processSourceFile); const writeFile: ts.WriteFileCallback = (fileName, data, _bom, _onError, sourceFiles = []) => { for (const sourceFile of sourceFiles) { diff --git a/src/transpilation/utils.ts b/src/transpilation/utils.ts new file mode 100644 index 000000000..e6f975be4 --- /dev/null +++ b/src/transpilation/utils.ts @@ -0,0 +1,51 @@ +import * as path from "path"; +import * as resolve from "resolve"; +import * as ts from "typescript"; +// TODO: Don't depend on CLI? +import * as cliDiagnostics from "../cli/diagnostics"; +import * as diagnosticFactories from "./diagnostics"; + +export const getConfigDirectory = (options: ts.CompilerOptions) => + options.configFilePath ? path.dirname(options.configFilePath) : process.cwd(); + +export function resolvePlugin( + kind: string, + optionName: string, + basedir: string, + query: string, + importName = "default" +): { error?: ts.Diagnostic; result?: unknown } { + if (typeof query !== "string") { + return { error: cliDiagnostics.compilerOptionRequiresAValueOfType(optionName, "string") }; + } + + let resolved: string; + try { + resolved = resolve.sync(query, { basedir, extensions: [".js", ".ts", ".tsx"] }); + } catch (err) { + if (err.code !== "MODULE_NOT_FOUND") throw err; + return { error: diagnosticFactories.couldNotResolveFrom(kind, query, basedir) }; + } + + // tslint:disable-next-line: deprecation + const hasNoRequireHook = require.extensions[".ts"] === undefined; + if (hasNoRequireHook && (resolved.endsWith(".ts") || resolved.endsWith(".tsx"))) { + try { + const tsNodePath = resolve.sync("ts-node", { basedir }); + const tsNode: typeof import("ts-node") = require(tsNodePath); + tsNode.register({ transpileOnly: true }); + } catch (err) { + if (err.code !== "MODULE_NOT_FOUND") throw err; + return { error: diagnosticFactories.toLoadItShouldBeTranspiled(kind, query) }; + } + } + + const commonjsModule = require(resolved); + const factoryModule = commonjsModule.__esModule ? commonjsModule : { default: commonjsModule }; + const result = factoryModule[importName]; + if (result === undefined) { + return { error: diagnosticFactories.shouldHaveAExport(kind, query, importName) }; + } + + return { result }; +} diff --git a/test/transpile/plugins/plugins.spec.ts b/test/transpile/plugins/plugins.spec.ts new file mode 100644 index 000000000..ce2ebc7a6 --- /dev/null +++ b/test/transpile/plugins/plugins.spec.ts @@ -0,0 +1,24 @@ +import * as path from "path"; +import * as util from "../../util"; + +test("printer", () => { + util.testModule`` + .setOptions({ luaPlugins: [{ name: path.join(__dirname, "printer.ts") }] }) + .tap(builder => expect(builder.getMainLuaCodeChunk()).toMatch("Plugin")); +}); + +test("visitor", () => { + util.testFunction` + return false; + ` + .setOptions({ luaPlugins: [{ name: path.join(__dirname, "visitor.ts") }] }) + .expectToEqual(true); +}); + +test("visitor using super", () => { + util.testFunction` + return "foo"; + ` + .setOptions({ luaPlugins: [{ name: path.join(__dirname, "visitor-super.ts") }] }) + .expectToEqual("bar"); +}); diff --git a/test/transpile/plugins/printer.ts b/test/transpile/plugins/printer.ts new file mode 100644 index 000000000..771f0f4a6 --- /dev/null +++ b/test/transpile/plugins/printer.ts @@ -0,0 +1,12 @@ +import * as tstl from "../../../src"; + +const plugin: tstl.Plugin = { + printer: (program, emitHost, fileName, ...args) => { + const result = new tstl.LuaPrinter(program.getCompilerOptions(), emitHost, fileName).print(...args); + result.code = `-- Plugin\n${result.code}`; + return result; + }, +}; + +// tslint:disable-next-line: no-default-export +export default plugin; diff --git a/test/transpile/plugins/visitor-super.ts b/test/transpile/plugins/visitor-super.ts new file mode 100644 index 000000000..87f665749 --- /dev/null +++ b/test/transpile/plugins/visitor-super.ts @@ -0,0 +1,19 @@ +import * as ts from "typescript"; +import * as tstl from "../../../src"; + +const plugin: tstl.Plugin = { + visitors: { + [ts.SyntaxKind.StringLiteral]: (node, context) => { + const result = context.superTransformExpression(node); + + if (tstl.isStringLiteral(result)) { + result.value = "bar"; + } + + return result; + }, + }, +}; + +// tslint:disable-next-line: no-default-export +export default plugin; diff --git a/test/transpile/plugins/visitor.ts b/test/transpile/plugins/visitor.ts new file mode 100644 index 000000000..fdbf50782 --- /dev/null +++ b/test/transpile/plugins/visitor.ts @@ -0,0 +1,11 @@ +import * as ts from "typescript"; +import * as tstl from "../../../src"; + +const plugin: tstl.Plugin = { + visitors: { + [ts.SyntaxKind.ReturnStatement]: () => tstl.createReturnStatement([tstl.createBooleanLiteral(true)]), + }, +}; + +// tslint:disable-next-line: no-default-export +export default plugin; diff --git a/test/transpile/resolve-plugin/cjs.js b/test/transpile/resolve-plugin/cjs.js new file mode 100644 index 000000000..ec01c2c14 --- /dev/null +++ b/test/transpile/resolve-plugin/cjs.js @@ -0,0 +1 @@ +module.exports = true; diff --git a/test/transpile/resolve-plugin/import.ts b/test/transpile/resolve-plugin/import.ts new file mode 100644 index 000000000..3d831e6ad --- /dev/null +++ b/test/transpile/resolve-plugin/import.ts @@ -0,0 +1 @@ +export const named = true; diff --git a/test/transpile/resolve-plugin/resolve-plugin.spec.ts b/test/transpile/resolve-plugin/resolve-plugin.spec.ts new file mode 100644 index 000000000..7b48bad8f --- /dev/null +++ b/test/transpile/resolve-plugin/resolve-plugin.spec.ts @@ -0,0 +1,27 @@ +import * as path from "path"; +import { resolvePlugin } from "../../../src/transpilation/utils"; + +test("resolve relative module paths", () => { + const result = resolvePlugin("test", "test", __dirname, "./ts.ts"); + expect(result).toMatchObject({ result: true }); +}); + +test("load .ts modules", () => { + const result = resolvePlugin("test", "test", __dirname, path.join(__dirname, "ts.ts")); + expect(result).toMatchObject({ result: true }); +}); + +test("load CJS .js modules", () => { + const result = resolvePlugin("test", "test", __dirname, path.join(__dirname, "cjs.js")); + expect(result).toMatchObject({ result: true }); +}); + +test("load transpiled ESM .js modules", () => { + const result = resolvePlugin("test", "test", __dirname, path.join(__dirname, "transpiled-esm.js")); + expect(result).toMatchObject({ result: true }); +}); + +test('"import" option', () => { + const result = resolvePlugin("test", "test", __dirname, path.join(__dirname, "import.ts"), "named"); + expect(result).toMatchObject({ result: true }); +}); diff --git a/test/transpile/resolve-plugin/transpiled-esm.js b/test/transpile/resolve-plugin/transpiled-esm.js new file mode 100644 index 000000000..ebf774058 --- /dev/null +++ b/test/transpile/resolve-plugin/transpiled-esm.js @@ -0,0 +1,2 @@ +module.exports.__esModule = true; +module.exports.default = true; diff --git a/test/transpile/resolve-plugin/ts.ts b/test/transpile/resolve-plugin/ts.ts new file mode 100644 index 000000000..0622167b7 --- /dev/null +++ b/test/transpile/resolve-plugin/ts.ts @@ -0,0 +1,2 @@ +// tslint:disable-next-line: no-default-export +export default true; diff --git a/test/unit/transformers/types.ts b/test/transpile/transformers/fixtures.ts similarity index 73% rename from test/unit/transformers/types.ts rename to test/transpile/transformers/fixtures.ts index dc8ecf71c..c998d6efc 100644 --- a/test/unit/transformers/types.ts +++ b/test/transpile/transformers/fixtures.ts @@ -1,3 +1,4 @@ +import * as assert from "assert"; import * as ts from "typescript"; import * as tstl from "../../../src"; import { visitAndReplace } from "./utils"; @@ -7,7 +8,7 @@ export const program = (program: ts.Program, options: { value: any }): ts.Transf export const config = ({ value }: { value: any }): ts.TransformerFactory => context => file => visitAndReplace(context, file, node => { - if (!ts.isReturnStatement(node) || node.expression) return; + if (!ts.isReturnStatement(node)) return; return ts.updateReturn(node, ts.createLiteral(value)); }); @@ -24,19 +25,16 @@ export const checker = ( export const raw: ts.TransformerFactory = context => file => visitAndReplace(context, file, node => { - if (!ts.isReturnStatement(node) || node.expression) return; + if (!ts.isReturnStatement(node)) return; return ts.updateReturn(node, ts.createLiteral(true)); }); -export const compilerOptions = ({ - luaTarget, -}: tstl.CompilerOptions): ts.TransformerFactory => context => file => { - if (luaTarget !== tstl.LuaTarget.LuaJIT) { - throw new Error("Transformer supports only LuaJIT target"); - } - +export const compilerOptions = ( + options: tstl.CompilerOptions +): ts.TransformerFactory => context => file => { + assert(options.plugins?.length === 1); return visitAndReplace(context, file, node => { - if (!ts.isReturnStatement(node) || node.expression) return; + if (!ts.isReturnStatement(node)) return; return ts.updateReturn(node, ts.createLiteral(true)); }); }; diff --git a/test/transpile/transformers/transformers.spec.ts b/test/transpile/transformers/transformers.spec.ts new file mode 100644 index 000000000..e166198bd --- /dev/null +++ b/test/transpile/transformers/transformers.spec.ts @@ -0,0 +1,36 @@ +import * as path from "path"; +import * as util from "../../util"; + +test("ignore language service plugins", () => { + util.testFunction` + return false; + ` + .setOptions({ plugins: [{ name: path.join(__dirname, "types.ts") }] }) + .expectToEqual(false); +}); + +test("default type", () => { + util.testFunction` + return false; + ` + .setOptions({ plugins: [{ transform: path.join(__dirname, "fixtures.ts"), import: "program", value: true }] }) + .expectToEqual(true); +}); + +test("transformer resolution error", () => { + util.testModule`` + .setOptions({ plugins: [{ transform: path.join(__dirname, "error.ts") }] }) + .expectToHaveDiagnostics(); +}); + +describe("factory types", () => { + test.each(["program", "config", "checker", "raw", "compilerOptions"] as const)("%s", type => { + util.testFunction` + return false; + ` + .setOptions({ + plugins: [{ transform: path.join(__dirname, "fixtures.ts"), type, import: type, value: true }], + }) + .expectToEqual(true); + }); +}); diff --git a/test/unit/transformers/utils.ts b/test/transpile/transformers/utils.ts similarity index 100% rename from test/unit/transformers/utils.ts rename to test/transpile/transformers/utils.ts diff --git a/test/unit/transformers/import.ts b/test/unit/transformers/import.ts deleted file mode 100644 index 8dafa5886..000000000 --- a/test/unit/transformers/import.ts +++ /dev/null @@ -1,9 +0,0 @@ -import * as ts from "typescript"; -import { visitAndReplace } from "./utils"; - -// tslint:disable-next-line: no-default-export -export const transformer = (): ts.TransformerFactory => context => file => - visitAndReplace(context, file, node => { - if (!ts.isReturnStatement(node) || node.expression) return; - return ts.updateReturn(node, ts.createLiteral(true)); - }); diff --git a/test/unit/transformers/resolve.js b/test/unit/transformers/resolve.js deleted file mode 100644 index 3ba87c73f..000000000 --- a/test/unit/transformers/resolve.js +++ /dev/null @@ -1,11 +0,0 @@ -const ts = require("typescript"); - -module.exports.default = () => context => file => { - const replaceNode = node => { - if (!ts.isReturnStatement(node) || node.expression) return; - return ts.updateReturn(node, ts.createLiteral(true)); - }; - - const visit = node => replaceNode(node) || ts.visitEachChild(node, visit, context); - return ts.visitNode(file, visit); -}; diff --git a/test/unit/transformers/resolve.ts b/test/unit/transformers/resolve.ts deleted file mode 100644 index 8b0aacff7..000000000 --- a/test/unit/transformers/resolve.ts +++ /dev/null @@ -1,9 +0,0 @@ -import * as ts from "typescript"; -import { visitAndReplace } from "./utils"; - -// tslint:disable-next-line: no-default-export -export default (): ts.TransformerFactory => context => file => - visitAndReplace(context, file, node => { - if (!ts.isReturnStatement(node) || node.expression) return; - return ts.updateReturn(node, ts.createLiteral(true)); - }); diff --git a/test/unit/transformers/transformers.spec.ts b/test/unit/transformers/transformers.spec.ts deleted file mode 100644 index db36c27dc..000000000 --- a/test/unit/transformers/transformers.spec.ts +++ /dev/null @@ -1,87 +0,0 @@ -import * as path from "path"; -import * as tstl from "../../../src"; -import * as util from "../../util"; - -const optionsOfTransformer = (transformer: tstl.TransformerImport): tstl.CompilerOptions => ({ - plugins: [transformer], -}); - -test("should ignore language service plugins", () => { - const options: tstl.CompilerOptions = { - plugins: [{ name: path.join(__dirname, "resolve.ts") }], - }; - - expect(util.transpileAndExecute("return", options)).toBe(undefined); -}); - -describe("resolution", () => { - const testTransform = (transformer: tstl.TransformerImport) => { - const options = optionsOfTransformer(transformer); - expect(util.transpileAndExecute("return", options)).toBe(true); - }; - - test("should resolve relative transformer paths", () => { - jest.spyOn(process, "cwd").mockReturnValue(__dirname); - testTransform({ transform: "./resolve.ts" }); - }); - - test("should load js transformers", () => { - testTransform({ transform: path.join(__dirname, "resolve.js") }); - }); - - test("should load ts transformers", () => { - testTransform({ transform: path.join(__dirname, "resolve.ts") }); - }); - - test('should support "import" option', () => { - testTransform({ - transform: path.join(__dirname, "import.ts"), - import: "transformer", - }); - }); - - test("should error if transformer could not be resolved", () => { - const transform = path.join(__dirname, "error.ts"); - const options = optionsOfTransformer({ transform }); - const { diagnostics } = util.transpileStringResult("", options); - expect(diagnostics).toHaveDiagnostics(); - }); -}); - -describe("factory types", () => { - const value = "foo"; - const getOptions = (options: Partial) => - optionsOfTransformer({ - transform: path.join(__dirname, "types.ts"), - ...options, - }); - - test('should support "program" type', () => { - const options = getOptions({ type: "program", import: "program", value }); - expect(util.transpileAndExecute("return false", options)).toBe(value); - }); - - test('should support "config" type', () => { - const options = getOptions({ type: "config", import: "config", value }); - expect(util.transpileAndExecute("return", options)).toBe(value); - }); - - test('should support "checker" type', () => { - const options = getOptions({ type: "checker", import: "checker", value }); - expect(util.transpileAndExecute("return false", options)).toBe(value); - }); - - test('should support "raw" type', () => { - const options = getOptions({ type: "raw", import: "raw" }); - expect(util.transpileAndExecute("return", options)).toBe(true); - }); - - test('should support "compilerOptions" type', () => { - const options: tstl.CompilerOptions = { - ...getOptions({ type: "compilerOptions", import: "compilerOptions" }), - luaTarget: tstl.LuaTarget.LuaJIT, - }; - - expect(util.transpileAndExecute("return", options)).toBe(true); - }); -});