typescript-to-lua
Version:
A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua!
168 lines • 8.19 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Transpiler = void 0;
exports.getEmitPath = getEmitPath;
exports.getEmitPathRelativeToOutDir = getEmitPathRelativeToOutDir;
exports.getSourceDir = getSourceDir;
exports.getEmitOutDir = getEmitOutDir;
exports.getProjectRoot = getProjectRoot;
const path = require("path");
const ts = require("typescript");
const CompilerOptions_1 = require("../CompilerOptions");
const LuaLib_1 = require("../LuaLib");
const utils_1 = require("../utils");
const bundle_1 = require("./bundle");
const plugins_1 = require("./plugins");
const resolve_1 = require("./resolve");
const transpile_1 = require("./transpile");
const performance = require("../measure-performance");
class Transpiler {
constructor({ emitHost = ts.sys } = {}) {
this.emitHost = emitHost;
}
emit(emitOptions) {
const { program, writeFile = this.emitHost.writeFile, plugins: optionsPlugins = [] } = emitOptions;
const { diagnostics: getPluginsDiagnostics, plugins: configPlugins } = (0, plugins_1.getPlugins)(program);
const plugins = [...optionsPlugins, ...configPlugins];
const { diagnostics: transpileDiagnostics, transpiledFiles: freshFiles } = (0, transpile_1.getProgramTranspileResult)(this.emitHost, writeFile, {
...emitOptions,
plugins,
});
const { emitPlan } = this.getEmitPlan(program, transpileDiagnostics, freshFiles, plugins);
const emitDiagnostics = this.emitFiles(program, plugins, emitPlan, writeFile);
return {
diagnostics: getPluginsDiagnostics.concat(transpileDiagnostics, emitDiagnostics),
emitSkipped: emitPlan.length === 0,
};
}
emitFiles(program, plugins, emitPlan, writeFile) {
var _a, _b, _c;
performance.startSection("emit");
const options = program.getCompilerOptions();
if (options.tstlVerbose) {
console.log("Emitting output");
}
const diagnostics = [];
for (const plugin of plugins) {
if (plugin.beforeEmit) {
const beforeEmitPluginDiagnostics = (_a = plugin.beforeEmit(program, options, this.emitHost, emitPlan)) !== null && _a !== void 0 ? _a : [];
diagnostics.push(...beforeEmitPluginDiagnostics);
}
}
const emitBOM = (_b = options.emitBOM) !== null && _b !== void 0 ? _b : false;
for (const { outputPath, code, sourceMap, sourceFiles } of emitPlan) {
if (options.tstlVerbose) {
console.log(`Emitting ${(0, utils_1.normalizeSlashes)(outputPath)}`);
}
writeFile(outputPath, code, emitBOM, undefined, sourceFiles);
if (options.sourceMap && sourceMap !== undefined) {
writeFile(outputPath + ".map", sourceMap, emitBOM, undefined, sourceFiles);
}
}
for (const plugin of plugins) {
if (plugin.afterEmit) {
const afterEmitPluginDiagnostics = (_c = plugin.afterEmit(program, options, this.emitHost, emitPlan)) !== null && _c !== void 0 ? _c : [];
diagnostics.push(...afterEmitPluginDiagnostics);
}
}
if (options.tstlVerbose) {
console.log("Emit finished!");
}
performance.endSection("emit");
return diagnostics;
}
getEmitPlan(program, diagnostics, files, plugins) {
performance.startSection("getEmitPlan");
const options = program.getCompilerOptions();
if (options.tstlVerbose) {
console.log("Constructing emit plan");
}
// Resolve imported modules and modify output Lua requires
const resolutionResult = (0, resolve_1.resolveDependencies)(program, files, this.emitHost, plugins);
diagnostics.push(...resolutionResult.diagnostics);
const lualibRequired = resolutionResult.resolvedFiles.some(f => f.fileName === "lualib_bundle");
if (lualibRequired) {
// Remove lualib placeholders from resolution result
resolutionResult.resolvedFiles = resolutionResult.resolvedFiles.filter(f => f.fileName !== "lualib_bundle");
if (options.tstlVerbose) {
console.log("Including lualib bundle");
}
// Add lualib bundle to source dir 'virtually', will be moved to correct output dir in emitPlan
const fileName = (0, utils_1.normalizeSlashes)(path.resolve(getSourceDir(program), "lualib_bundle.lua"));
const code = this.getLuaLibBundleContent(options, resolutionResult.resolvedFiles);
resolutionResult.resolvedFiles.unshift({ fileName, code });
}
let emitPlan;
if ((0, CompilerOptions_1.isBundleEnabled)(options)) {
const [bundleDiagnostics, bundleFile] = (0, bundle_1.getBundleResult)(program, resolutionResult.resolvedFiles);
diagnostics.push(...bundleDiagnostics);
emitPlan = [bundleFile];
}
else {
emitPlan = resolutionResult.resolvedFiles.map(file => ({
...file,
outputPath: getEmitPath(file.fileName, program),
}));
}
performance.endSection("getEmitPlan");
return { emitPlan };
}
getLuaLibBundleContent(options, resolvedFiles) {
var _a;
const luaTarget = (_a = options.luaTarget) !== null && _a !== void 0 ? _a : CompilerOptions_1.LuaTarget.Universal;
if (options.luaLibImport === CompilerOptions_1.LuaLibImportKind.RequireMinimal) {
const usedFeatures = (0, LuaLib_1.findUsedLualibFeatures)(luaTarget, this.emitHost, resolvedFiles.map(f => f.code));
return (0, LuaLib_1.buildMinimalLualibBundle)(usedFeatures, luaTarget, this.emitHost);
}
else {
return (0, LuaLib_1.getLuaLibBundle)(luaTarget, this.emitHost);
}
}
}
exports.Transpiler = Transpiler;
function getEmitPath(file, program) {
const relativeOutputPath = getEmitPathRelativeToOutDir(file, program);
const outDir = getEmitOutDir(program);
return path.join(outDir, relativeOutputPath);
}
function getEmitPathRelativeToOutDir(fileName, program) {
var _a;
const sourceDir = getSourceDir(program);
// Default output path is relative path in source dir
let emitPathSplits = path.relative(sourceDir, fileName).split(path.sep);
// If source is in a parent directory of source dir, move it into the source dir
emitPathSplits = emitPathSplits.filter(s => s !== "..");
// To avoid overwriting lua sources in node_modules, emit into lua_modules
if (emitPathSplits[0] === "node_modules") {
emitPathSplits[0] = "lua_modules";
}
// Set extension
const extension = ((_a = program.getCompilerOptions().extension) !== null && _a !== void 0 ? _a : "lua").trim();
const trimmedExtension = extension.startsWith(".") ? extension.substring(1) : extension;
emitPathSplits[emitPathSplits.length - 1] =
(0, utils_1.trimExtension)(emitPathSplits[emitPathSplits.length - 1]) + "." + trimmedExtension;
return path.join(...emitPathSplits);
}
function getSourceDir(program) {
const rootDir = program.getCompilerOptions().rootDir;
if (rootDir && rootDir.length > 0) {
return path.isAbsolute(rootDir) ? rootDir : path.resolve(getProjectRoot(program), rootDir);
}
// If no rootDir is given, source is relative to the project root
return getProjectRoot(program);
}
function getEmitOutDir(program) {
const outDir = program.getCompilerOptions().outDir;
if (outDir && outDir.length > 0) {
return path.isAbsolute(outDir) ? outDir : path.resolve(getProjectRoot(program), outDir);
}
// If no outDir is provided, emit in project root
return getProjectRoot(program);
}
function getProjectRoot(program) {
// Try to get the directory the tsconfig is in
const tsConfigPath = program.getCompilerOptions().configFilePath;
// If no tsconfig is known, use common source directory
return tsConfigPath ? path.dirname(tsConfigPath) : program.getCommonSourceDirectory();
}
//# sourceMappingURL=transpiler.js.map