UNPKG

typescript-to-lua

Version:

A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua!

175 lines 7.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.stripParenthesisExpressionsTransformer = exports.noImplicitSelfTransformer = void 0; exports.getTransformers = getTransformers; const ts = require("typescript"); // TODO: Don't depend on CLI? const cliDiagnostics = require("../cli/diagnostics"); const diagnosticFactories = require("./diagnostics"); const utils_1 = require("./utils"); function getTransformers(program, diagnostics, customTransformers, onSourceFile) { var _a, _b, _c, _d, _e, _f; const luaTransformer = () => sourceFile => { onSourceFile(sourceFile); return ts.createSourceFile(sourceFile.fileName, "", ts.ScriptTarget.ESNext); }; const transformersFromOptions = loadTransformersFromOptions(program, diagnostics); const afterDeclarations = [ ...((_a = transformersFromOptions.afterDeclarations) !== null && _a !== void 0 ? _a : []), ...((_b = customTransformers.afterDeclarations) !== null && _b !== void 0 ? _b : []), ]; const options = program.getCompilerOptions(); if (options.noImplicitSelf) { afterDeclarations.unshift(exports.noImplicitSelfTransformer); } return { afterDeclarations, before: [ ...((_c = customTransformers.before) !== null && _c !== void 0 ? _c : []), ...((_d = transformersFromOptions.before) !== null && _d !== void 0 ? _d : []), ...((_e = transformersFromOptions.after) !== null && _e !== void 0 ? _e : []), ...((_f = customTransformers.after) !== null && _f !== void 0 ? _f : []), exports.stripParenthesisExpressionsTransformer, luaTransformer, ], }; } const noImplicitSelfTransformer = () => node => { const transformSourceFile = node => { const empty = ts.factory.createNotEmittedStatement(undefined); ts.addSyntheticLeadingComment(empty, ts.SyntaxKind.MultiLineCommentTrivia, "* @noSelfInFile ", true); return ts.factory.updateSourceFile(node, [empty, ...node.statements], node.isDeclarationFile); }; return ts.isBundle(node) ? ts.factory.updateBundle(node, node.sourceFiles.map(transformSourceFile)) : transformSourceFile(node); }; exports.noImplicitSelfTransformer = noImplicitSelfTransformer; const stripParenthesisExpressionsTransformer = context => sourceFile => { // Remove parenthesis expressions before transforming to Lua, so transpiler is not hindered by extra ParenthesizedExpression nodes function unwrapParentheses(node) { while (ts.isParenthesizedExpression(node) && !ts.isOptionalChain(node.expression)) { node = node.expression; } return node; } function visit(node) { // For now only call expressions strip their expressions of parentheses, there could be more cases where this is required if (ts.isCallExpression(node)) { return ts.factory.updateCallExpression(node, unwrapParentheses(node.expression), node.typeArguments, node.arguments); } else if (ts.isVoidExpression(node)) { return ts.factory.updateVoidExpression(node, unwrapParentheses(node.expression)); } else if (ts.isDeleteExpression(node)) { return ts.factory.updateDeleteExpression(node, unwrapParentheses(node.expression)); } return ts.visitEachChild(node, visit, context); } return ts.visitEachChild(sourceFile, visit, context); }; exports.stripParenthesisExpressionsTransformer = stripParenthesisExpressionsTransformer; function loadTransformersFromOptions(program, diagnostics) { const customTransformers = { before: [], after: [], afterDeclarations: [], }; const options = program.getCompilerOptions(); if (options.plugins) { for (const [index, transformerImport] of options.plugins.entries()) { if (!("transform" in transformerImport)) continue; const optionName = `compilerOptions.plugins[${index}]`; const { error: resolveError, result: factory } = (0, utils_1.resolvePlugin)("transformer", `${optionName}.transform`, (0, utils_1.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) diagnostics.push(loadError); if (transformer === undefined) continue; if (transformer.before) { customTransformers.before.push(transformer.before); } if (transformer.after) { customTransformers.after.push(transformer.after); } if (transformer.afterDeclarations) { customTransformers.afterDeclarations.push(transformer.afterDeclarations); } } } if (options.jsx === ts.JsxEmit.React) { customTransformers.before.push(context => { // if target < ES2017, typescript generates some unnecessary additional transformations in transformJSX. // We can't control the target compiler option, so we override here. const patchedContext = { ...context, getCompilerOptions: () => ({ ...context.getCompilerOptions(), target: ts.ScriptTarget.ESNext, }), }; return ts.transformJsx(patchedContext); }); } return customTransformers; } function loadTransformer(optionPath, program, factory, { transform, after = false, afterDeclarations = false, type = "program", ...extraOptions }) { var _a, _b; let transformer; switch (type) { case "program": transformer = factory(program, extraOptions); break; case "config": transformer = factory(extraOptions); break; case "checker": transformer = factory(program.getTypeChecker(), extraOptions); break; case "raw": transformer = factory; break; case "compilerOptions": transformer = factory(program.getCompilerOptions(), extraOptions); break; default: { const optionName = `--${optionPath}.type`; return { error: cliDiagnostics.argumentForOptionMustBe(optionName, "program") }; } } if (typeof after !== "boolean") { const optionName = `${optionPath}.after`; return { error: cliDiagnostics.compilerOptionRequiresAValueOfType(optionName, "boolean") }; } if (typeof afterDeclarations !== "boolean") { const optionName = `${optionPath}.afterDeclarations`; return { error: cliDiagnostics.compilerOptionRequiresAValueOfType(optionName, "boolean") }; } if (typeof transformer === "function") { let wrappedTransformer; if (after) { wrappedTransformer = { after: transformer }; } else if (afterDeclarations) { wrappedTransformer = { afterDeclarations: transformer }; } else { wrappedTransformer = { before: transformer }; } return { transformer: wrappedTransformer }; } else { const isValidGroupTransformer = typeof transformer === "object" && ((_b = (_a = transformer.before) !== null && _a !== void 0 ? _a : transformer.after) !== null && _b !== void 0 ? _b : transformer.afterDeclarations) !== undefined; if (!isValidGroupTransformer) { return { error: diagnosticFactories.transformerShouldBeATsTransformerFactory(transform) }; } } return { transformer }; } //# sourceMappingURL=transformers.js.map