From a95af7b202c57299d4e8ee35a9681cf417b7c439 Mon Sep 17 00:00:00 2001 From: MCJack123 Date: Mon, 19 Sep 2022 15:49:47 -0400 Subject: [PATCH 1/3] Added luaLibName option to control lualib_bundle --- src/CompilerOptions.ts | 1 + src/LuaLib.ts | 5 +++-- src/LuaPrinter.ts | 3 ++- src/cli/parse.ts | 5 +++++ src/lualib-build/plugin.ts | 2 +- src/transpilation/bundle.ts | 2 +- src/transpilation/resolve.ts | 4 ++-- src/transpilation/transpiler.ts | 6 +++--- test/util.ts | 4 ++-- tsconfig-schema.json | 5 +++++ 10 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/CompilerOptions.ts b/src/CompilerOptions.ts index 7f5562c07..affd0590a 100644 --- a/src/CompilerOptions.ts +++ b/src/CompilerOptions.ts @@ -46,6 +46,7 @@ export interface TypeScriptToLuaOptions { tstlVerbose?: boolean; lua51AllowTryCatchInAsyncAwait?: boolean; measurePerformance?: boolean; + luaLibName?: string; } export type CompilerOptions = OmitIndexSignature & diff --git a/src/LuaLib.ts b/src/LuaLib.ts index 6320bc99c..fe28645b2 100644 --- a/src/LuaLib.ts +++ b/src/LuaLib.ts @@ -229,7 +229,8 @@ export function loadInlineLualibFeatures( export function loadImportedLualibFeatures( features: Iterable, luaTarget: LuaTarget, - emitHost: EmitHost + emitHost: EmitHost, + luaLibName: string ): lua.Statement[] { const luaLibModuleInfo = getLuaLibModulesInfo(luaTarget, emitHost); @@ -239,7 +240,7 @@ export function loadImportedLualibFeatures( } const requireCall = lua.createCallExpression(lua.createIdentifier("require"), [ - lua.createStringLiteral("lualib_bundle"), + lua.createStringLiteral(luaLibName), ]); const luaLibId = lua.createIdentifier("____lualib"); diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index b0a02dfaf..4f42b3c03 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -235,13 +235,14 @@ export class LuaPrinter { const luaTarget = this.options.luaTarget ?? LuaTarget.Universal; const luaLibImport = this.options.luaLibImport ?? LuaLibImportKind.Require; + const luaLibName = this.options.luaLibName ?? "lualib_bundle"; if ( (luaLibImport === LuaLibImportKind.Require || luaLibImport === LuaLibImportKind.RequireMinimal) && file.luaLibFeatures.size > 0 ) { // Import lualib features sourceChunks = this.printStatementArray( - loadImportedLualibFeatures(file.luaLibFeatures, luaTarget, this.emitHost) + loadImportedLualibFeatures(file.luaLibFeatures, luaTarget, this.emitHost, luaLibName) ); } else if (luaLibImport === LuaLibImportKind.Inline && file.luaLibFeatures.size > 0) { // Inline lualib features diff --git a/src/cli/parse.ts b/src/cli/parse.ts index ca4f039ad..47dfb9d0c 100644 --- a/src/cli/parse.ts +++ b/src/cli/parse.ts @@ -51,6 +51,11 @@ export const optionDeclarations: CommandLineOption[] = [ type: "enum", choices: Object.values(LuaLibImportKind), }, + { + name: "luaLibName", + description: "The name of the file to store Lua library features in.", + type: "string", + }, { name: "luaTarget", aliases: ["lt"], diff --git a/src/lualib-build/plugin.ts b/src/lualib-build/plugin.ts index 79233f3df..31a4433fd 100644 --- a/src/lualib-build/plugin.ts +++ b/src/lualib-build/plugin.ts @@ -70,7 +70,7 @@ class LuaLibPlugin implements tstl.Plugin { let lualibBundle = orderedFeatures.map(f => exportedLualibFeatures.get(LuaLibFeature[f])).join("\n"); const exports = allFeatures.flatMap(feature => luaLibModuleInfo[feature].exports); lualibBundle += getLualibBundleReturn(exports); - result.push({ fileName: "lualib_bundle.lua", code: lualibBundle }); + result.push({ fileName: (options.luaLibName ?? "lualib_bundle") + ".lua", code: lualibBundle }); return diagnostics; } diff --git a/src/transpilation/bundle.ts b/src/transpilation/bundle.ts index 1e0436c35..2e6947b43 100644 --- a/src/transpilation/bundle.ts +++ b/src/transpilation/bundle.ts @@ -115,7 +115,7 @@ export function getBundleResult(program: ts.Program, files: ProcessedFile[]): [t const footers: string[] = []; if (options.sourceMapTraceback) { // Generates SourceMapTraceback for the entire file - footers.push('local __TS__SourceMapTraceBack = require("lualib_bundle").__TS__SourceMapTraceBack\n'); + footers.push(`local __TS__SourceMapTraceBack = require("${options.luaLibName ?? "lualib_bundle"}").__TS__SourceMapTraceBack\n`); footers.push(`${sourceMapTracebackBundlePlaceholder}\n`); } diff --git a/src/transpilation/resolve.ts b/src/transpilation/resolve.ts index bd16773e9..59d0f538e 100644 --- a/src/transpilation/resolve.ts +++ b/src/transpilation/resolve.ts @@ -68,8 +68,8 @@ class ResolutionContext { public resolveImport(file: ProcessedFile, required: LuaRequire): void { // Do no resolve lualib - always use the lualib of the application entry point, not the lualib from external packages - if (required.requirePath === "lualib_bundle") { - this.resolvedFiles.set("lualib_bundle", { fileName: "lualib_bundle", code: "" }); + if (required.requirePath === (this.options.luaLibName ?? "lualib_bundle")) { + this.resolvedFiles.set(this.options.luaLibName ?? "lualib_bundle", { fileName: this.options.luaLibName ?? "lualib_bundle", code: "" }); return; } diff --git a/src/transpilation/transpiler.ts b/src/transpilation/transpiler.ts index 9bac1f5bf..74c01f982 100644 --- a/src/transpilation/transpiler.ts +++ b/src/transpilation/transpiler.ts @@ -123,16 +123,16 @@ export class Transpiler { const resolutionResult = resolveDependencies(program, files, this.emitHost, plugins); diagnostics.push(...resolutionResult.diagnostics); - const lualibRequired = resolutionResult.resolvedFiles.some(f => f.fileName === "lualib_bundle"); + const lualibRequired = resolutionResult.resolvedFiles.some(f => f.fileName === (options.luaLibName ?? "lualib_bundle")); if (lualibRequired) { // Remove lualib placeholders from resolution result - resolutionResult.resolvedFiles = resolutionResult.resolvedFiles.filter(f => f.fileName !== "lualib_bundle"); + resolutionResult.resolvedFiles = resolutionResult.resolvedFiles.filter(f => f.fileName !== (options.luaLibName ?? "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 = normalizeSlashes(path.resolve(getSourceDir(program), "lualib_bundle.lua")); + const fileName = normalizeSlashes(path.resolve(getSourceDir(program), (options.luaLibName ?? "lualib_bundle") + ".lua")); const code = this.getLuaLibBundleContent(options, resolutionResult.resolvedFiles); resolutionResult.resolvedFiles.unshift({ fileName, code }); } diff --git a/test/util.ts b/test/util.ts index 501b24bfb..6f6828998 100644 --- a/test/util.ts +++ b/test/util.ts @@ -456,9 +456,9 @@ export abstract class TestBuilder { // Lua lib if ( this.options.luaLibImport === tstl.LuaLibImportKind.Require || - mainFile.includes('require("lualib_bundle")') + mainFile.includes(`require("${(this.options.luaLibName ?? "lualib_bundle")}")`) ) { - this.injectLuaFile(L, lua, lauxlib, "lualib_bundle", readLuaLib(luaTarget)); + this.injectLuaFile(L, lua, lauxlib, (this.options.luaLibName ?? "lualib_bundle"), readLuaLib(luaTarget)); } // Load all transpiled files into Lua's package cache diff --git a/tsconfig-schema.json b/tsconfig-schema.json index 87366ea76..670acb50b 100644 --- a/tsconfig-schema.json +++ b/tsconfig-schema.json @@ -46,6 +46,11 @@ "default": "require", "enum": ["none", "inline", "require", "require-minimal"] }, + "luaLibName": { + "description": "The name of the file to store Lua library features in.", + "type": "string", + "default": "lualib_bundle" + }, "luaTarget": { "description": "Specifies the Lua version you want to generate code for.", "type": "string", From 68b8faa7886bdbb829cfc67e3dd61900193fcaf7 Mon Sep 17 00:00:00 2001 From: MCJack123 Date: Sun, 12 Oct 2025 00:23:04 -0400 Subject: [PATCH 2/3] Added option to suppress emitting lualib --- src/CompilerOptions.ts | 1 + src/cli/parse.ts | 5 +++++ src/transpilation/transpiler.ts | 8 +++++--- tsconfig-schema.json | 5 +++++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/CompilerOptions.ts b/src/CompilerOptions.ts index affd0590a..c60e5e353 100644 --- a/src/CompilerOptions.ts +++ b/src/CompilerOptions.ts @@ -47,6 +47,7 @@ export interface TypeScriptToLuaOptions { lua51AllowTryCatchInAsyncAwait?: boolean; measurePerformance?: boolean; luaLibName?: string; + luaLibEmit?: boolean; } export type CompilerOptions = OmitIndexSignature & diff --git a/src/cli/parse.ts b/src/cli/parse.ts index 47dfb9d0c..716f8bf30 100644 --- a/src/cli/parse.ts +++ b/src/cli/parse.ts @@ -56,6 +56,11 @@ export const optionDeclarations: CommandLineOption[] = [ description: "The name of the file to store Lua library features in.", type: "string", }, + { + name: "luaLibEmit", + description: "Whether the Lua library file is emitted with the code. Only effective when luaLibImport is require.", + type: "boolean", + }, { name: "luaTarget", aliases: ["lt"], diff --git a/src/transpilation/transpiler.ts b/src/transpilation/transpiler.ts index 74c01f982..2c00cde93 100644 --- a/src/transpilation/transpiler.ts +++ b/src/transpilation/transpiler.ts @@ -132,9 +132,11 @@ export class Transpiler { console.log("Including lualib bundle"); } // Add lualib bundle to source dir 'virtually', will be moved to correct output dir in emitPlan - const fileName = normalizeSlashes(path.resolve(getSourceDir(program), (options.luaLibName ?? "lualib_bundle") + ".lua")); - const code = this.getLuaLibBundleContent(options, resolutionResult.resolvedFiles); - resolutionResult.resolvedFiles.unshift({ fileName, code }); + if (options.luaLibEmit !== false) { + const fileName = normalizeSlashes(path.resolve(getSourceDir(program), (options.luaLibName ?? "lualib_bundle") + ".lua")); + const code = this.getLuaLibBundleContent(options, resolutionResult.resolvedFiles); + resolutionResult.resolvedFiles.unshift({ fileName, code }); + } } let emitPlan: EmitFile[]; diff --git a/tsconfig-schema.json b/tsconfig-schema.json index 670acb50b..c0d2358e0 100644 --- a/tsconfig-schema.json +++ b/tsconfig-schema.json @@ -51,6 +51,11 @@ "type": "string", "default": "lualib_bundle" }, + "luaLibEmit": { + "description": "Whether the Lua library file is emitted with the code. Only effective when luaLibImport is require.", + "type": "boolean", + "default": true + }, "luaTarget": { "description": "Specifies the Lua version you want to generate code for.", "type": "string", From 2bad0273b3af0f55f4f3adb8f56d80a067f8d39e Mon Sep 17 00:00:00 2001 From: MCJack123 Date: Sun, 12 Oct 2025 01:35:52 -0400 Subject: [PATCH 3/3] Added tests, fixed linting --- src/cli/parse.ts | 3 ++- src/transpilation/bundle.ts | 6 +++++- src/transpilation/resolve.ts | 5 ++++- src/transpilation/transpiler.ts | 12 +++++++++--- test/cli/parse.spec.ts | 4 ++++ test/transpile/lualib.spec.ts | 19 +++++++++++++++++++ test/util.ts | 4 ++-- 7 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/cli/parse.ts b/src/cli/parse.ts index 716f8bf30..7509a176e 100644 --- a/src/cli/parse.ts +++ b/src/cli/parse.ts @@ -58,7 +58,8 @@ export const optionDeclarations: CommandLineOption[] = [ }, { name: "luaLibEmit", - description: "Whether the Lua library file is emitted with the code. Only effective when luaLibImport is require.", + description: + "Whether the Lua library file is emitted with the code. Only effective when luaLibImport is require.", type: "boolean", }, { diff --git a/src/transpilation/bundle.ts b/src/transpilation/bundle.ts index 2e6947b43..9fab0c1d1 100644 --- a/src/transpilation/bundle.ts +++ b/src/transpilation/bundle.ts @@ -115,7 +115,11 @@ export function getBundleResult(program: ts.Program, files: ProcessedFile[]): [t const footers: string[] = []; if (options.sourceMapTraceback) { // Generates SourceMapTraceback for the entire file - footers.push(`local __TS__SourceMapTraceBack = require("${options.luaLibName ?? "lualib_bundle"}").__TS__SourceMapTraceBack\n`); + footers.push( + `local __TS__SourceMapTraceBack = require("${ + options.luaLibName ?? "lualib_bundle" + }").__TS__SourceMapTraceBack\n` + ); footers.push(`${sourceMapTracebackBundlePlaceholder}\n`); } diff --git a/src/transpilation/resolve.ts b/src/transpilation/resolve.ts index 59d0f538e..c9f6086bb 100644 --- a/src/transpilation/resolve.ts +++ b/src/transpilation/resolve.ts @@ -69,7 +69,10 @@ class ResolutionContext { public resolveImport(file: ProcessedFile, required: LuaRequire): void { // Do no resolve lualib - always use the lualib of the application entry point, not the lualib from external packages if (required.requirePath === (this.options.luaLibName ?? "lualib_bundle")) { - this.resolvedFiles.set(this.options.luaLibName ?? "lualib_bundle", { fileName: this.options.luaLibName ?? "lualib_bundle", code: "" }); + this.resolvedFiles.set(this.options.luaLibName ?? "lualib_bundle", { + fileName: this.options.luaLibName ?? "lualib_bundle", + code: "", + }); return; } diff --git a/src/transpilation/transpiler.ts b/src/transpilation/transpiler.ts index 2c00cde93..43da95aa3 100644 --- a/src/transpilation/transpiler.ts +++ b/src/transpilation/transpiler.ts @@ -123,17 +123,23 @@ export class Transpiler { const resolutionResult = resolveDependencies(program, files, this.emitHost, plugins); diagnostics.push(...resolutionResult.diagnostics); - const lualibRequired = resolutionResult.resolvedFiles.some(f => f.fileName === (options.luaLibName ?? "lualib_bundle")); + const lualibRequired = resolutionResult.resolvedFiles.some( + f => f.fileName === (options.luaLibName ?? "lualib_bundle") + ); if (lualibRequired) { // Remove lualib placeholders from resolution result - resolutionResult.resolvedFiles = resolutionResult.resolvedFiles.filter(f => f.fileName !== (options.luaLibName ?? "lualib_bundle")); + resolutionResult.resolvedFiles = resolutionResult.resolvedFiles.filter( + f => f.fileName !== (options.luaLibName ?? "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 if (options.luaLibEmit !== false) { - const fileName = normalizeSlashes(path.resolve(getSourceDir(program), (options.luaLibName ?? "lualib_bundle") + ".lua")); + const fileName = normalizeSlashes( + path.resolve(getSourceDir(program), (options.luaLibName ?? "lualib_bundle") + ".lua") + ); const code = this.getLuaLibBundleContent(options, resolutionResult.resolvedFiles); resolutionResult.resolvedFiles.unshift({ fileName, code }); } diff --git a/test/cli/parse.spec.ts b/test/cli/parse.spec.ts index e06a8fafd..2b931c328 100644 --- a/test/cli/parse.spec.ts +++ b/test/cli/parse.spec.ts @@ -121,6 +121,8 @@ describe("command line", () => { ["luaLibImport", "none", { luaLibImport: tstl.LuaLibImportKind.None }], ["luaLibImport", "inline", { luaLibImport: tstl.LuaLibImportKind.Inline }], ["luaLibImport", "require", { luaLibImport: tstl.LuaLibImportKind.Require }], + ["luaLibName", "typescript", { luaLibName: "typescript" }], + ["luaLibEmit", "false", { luaLibEmit: false }], ["luaTarget", "universal", { luaTarget: tstl.LuaTarget.Universal }], ["luaTarget", "5.1", { luaTarget: tstl.LuaTarget.Lua51 }], @@ -240,6 +242,8 @@ describe("tsconfig", () => { ["luaLibImport", "none", { luaLibImport: tstl.LuaLibImportKind.None }], ["luaLibImport", "inline", { luaLibImport: tstl.LuaLibImportKind.Inline }], ["luaLibImport", "require", { luaLibImport: tstl.LuaLibImportKind.Require }], + ["luaLibName", "typescript", { luaLibName: "typescript" }], + ["luaLibEmit", false, { luaLibEmit: false }], ["luaTarget", "universal", { luaTarget: tstl.LuaTarget.Universal }], ["luaTarget", "5.0", { luaTarget: tstl.LuaTarget.Lua50 }], diff --git a/test/transpile/lualib.spec.ts b/test/transpile/lualib.spec.ts index 20288bd8a..03d4d23bd 100644 --- a/test/transpile/lualib.spec.ts +++ b/test/transpile/lualib.spec.ts @@ -29,3 +29,22 @@ test("Lualib bundle does not assign globals", () => { .withLanguageExtensions() .expectNoExecutionError(); }); + +test("Lualib bundle can be renamed", () => { + const result = util + .testExpression("[1, 2, 3, 4].map(n => n*n).join(' ')") + .setOptions({ luaLibName: "typescript" }) + .expectNoExecutionError() + .getLuaResult(); + expect(result.transpiledFiles.some(file => file.outPath.match(/lualib_bundle.lua$/))).toBeFalsy(); + expect(result.transpiledFiles.some(file => file.outPath.match(/typescript.lua$/))).toBeTruthy(); +}); + +test("Lualib bundle emission can be disabled", () => { + const result = util + .testExpression("[1, 2, 3, 4].map(n => n*n).join(' ')") + .setOptions({ luaLibEmit: false }) + .expectNoTranspileException() + .getLuaResult(); + expect(result.transpiledFiles.some(file => file.outPath.match(/lualib_bundle.lua$/))).toBeFalsy(); +}); diff --git a/test/util.ts b/test/util.ts index 6f6828998..42ef8128f 100644 --- a/test/util.ts +++ b/test/util.ts @@ -456,9 +456,9 @@ export abstract class TestBuilder { // Lua lib if ( this.options.luaLibImport === tstl.LuaLibImportKind.Require || - mainFile.includes(`require("${(this.options.luaLibName ?? "lualib_bundle")}")`) + mainFile.includes(`require("${this.options.luaLibName ?? "lualib_bundle"}")`) ) { - this.injectLuaFile(L, lua, lauxlib, (this.options.luaLibName ?? "lualib_bundle"), readLuaLib(luaTarget)); + this.injectLuaFile(L, lua, lauxlib, this.options.luaLibName ?? "lualib_bundle", readLuaLib(luaTarget)); } // Load all transpiled files into Lua's package cache