diff --git a/CHANGELOG.md b/CHANGELOG.md index 12a8fda3b..1a81be4d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## 0.40.0 - Added support for using external Lua code in your project. This means you can create and install node_modules packages containing Lua code. It also lets you include Lua source files as part of your source files. Used Lua will automatically be added to your output. For more information, see the [External Lua Code](https://typescripttolua.github.io/docs/external-lua-code) page in the docs. -- **[Breaking]** Removed support for deprecated annotations that have been replaced with language extensions: `/** @luaIterator */`, `/** @vararg */`, `/** @luatable */` and `/** forRange */`. If you were still using these, see [the docs](https://typescripttolua.github.io/docs/advanced/compiler-annotations#vararg) for instructions how to upgrade. +- **[Breaking]** Removed support for deprecated annotations that have been replaced with language extensions: `/** @luaIterator */`, `/** @vararg */`, `/** @luatable */` and `/** forRange */`. If you were still using these, see [the docs](https://typescripttolua.github.io/docs/advanced/compiler-annotations) for instructions how to upgrade. - Added support for `array.entries()`. - Added support for `LuaTable.has(key)` and `LuaTable.delete(key)` to the language extensions. See [docs](https://typescripttolua.github.io/docs/advanced/language-extensions#lua-table-types) for more info. - Made language extension types more strict, disallowing `null` and `undefined` in some places where they would cause problems in Lua. diff --git a/src/transpilation/bundle.ts b/src/transpilation/bundle.ts index 31d58b27b..579e84ee1 100644 --- a/src/transpilation/bundle.ts +++ b/src/transpilation/bundle.ts @@ -3,7 +3,7 @@ import { SourceNode } from "source-map"; import * as ts from "typescript"; import { CompilerOptions } from "../CompilerOptions"; import { escapeString, tstlHeader } from "../LuaPrinter"; -import { cast, formatPathToLuaPath, isNonNull, normalizeSlashes, trimExtension } from "../utils"; +import { cast, formatPathToLuaPath, isNonNull, trimExtension } from "../utils"; import { couldNotFindBundleEntryPoint } from "./diagnostics"; import { getEmitOutDir, getEmitPathRelativeToOutDir, getSourceDir } from "./transpiler"; import { EmitFile, ProcessedFile } from "./utils"; @@ -42,7 +42,7 @@ export function getBundleResult(program: ts.Program, files: ProcessedFile[]): [t // Resolve project settings relative to project file. const resolvedEntryModule = path.resolve(getSourceDir(program), entryModule); - const outputPath = normalizeSlashes(path.resolve(getEmitOutDir(program), bundleFile)); + const outputPath = path.resolve(getEmitOutDir(program), bundleFile); if (program.getSourceFile(resolvedEntryModule) === undefined && program.getSourceFile(entryModule) === undefined) { diagnostics.push(couldNotFindBundleEntryPoint(entryModule)); diff --git a/src/transpilation/transpiler.ts b/src/transpilation/transpiler.ts index 7b5eb0f3f..2dc5a9fc7 100644 --- a/src/transpilation/transpiler.ts +++ b/src/transpilation/transpiler.ts @@ -122,7 +122,9 @@ export function getEmitOutDir(program: ts.Program): string { if (outDir && outDir.length > 0) { return path.isAbsolute(outDir) ? outDir : path.resolve(getProjectRoot(program), outDir); } - return program.getCommonSourceDirectory(); + + // If no outDir is provided, emit in project root + return getProjectRoot(program); } export function getProjectRoot(program: ts.Program): string { diff --git a/test/transpile/bundle.spec.ts b/test/transpile/bundle.spec.ts index 69c86406e..718e1b112 100644 --- a/test/transpile/bundle.spec.ts +++ b/test/transpile/bundle.spec.ts @@ -12,7 +12,7 @@ test("should transpile into one file", () => { const { outPath, lua } = transpiledFiles[0]; // Verify the name is as specified in tsconfig - expect(outPath.endsWith("bundle/bundle.lua")).toBe(true); + expect(outPath.endsWith(path.join("bundle", "bundle.lua"))).toBe(true); // Verify exported module by executing // Use an empty TS string because we already transpiled the TS project util.testModule("").setLuaHeader(lua!).expectToEqual({ myNumber: 3 }); diff --git a/test/transpile/paths.spec.ts b/test/transpile/paths.spec.ts new file mode 100644 index 000000000..33d4f6258 --- /dev/null +++ b/test/transpile/paths.spec.ts @@ -0,0 +1,120 @@ +import * as path from "path"; +import * as ts from "typescript"; +import { getSourceDir } from "../../src"; +import * as util from "../util"; + +const cwd = process.cwd(); + +// Path for project tsconfig.json to resolve for +const configFilePath = path.join(cwd, "tsconfig.json"); + +describe("getSourceDir", () => { + test("with rootDir", () => { + const program = ts.createProgram(["main.ts", "src/otherfile.ts"], { configFilePath, rootDir: "src" }); + + // getCommonSourceDirectory does not work right so mock it + jest.spyOn(program, "getCommonSourceDirectory").mockReturnValue(cwd); + + expect(getSourceDir(program)).toBe(path.join(cwd, "src")); + }); + + test("without rootDir", () => { + const program = ts.createProgram(["main.ts", "src/otherfile.ts"], { configFilePath }); + + // getCommonSourceDirectory does not work right so mock it + jest.spyOn(program, "getCommonSourceDirectory").mockReturnValue(cwd); + + // Common sources directory is project root + expect(normalize(getSourceDir(program))).toBe(cwd); + }); + + test("without rootDir in src dir", () => { + const program = ts.createProgram([path.join(cwd, "src", "main.ts"), path.join(cwd, "src", "otherfile.ts")], { + configFilePath, + }); + + // getCommonSourceDirectory does not work right so mock it + jest.spyOn(program, "getCommonSourceDirectory").mockReturnValue(path.join(cwd, "src")); + + // Common sources directory is src + expect(normalize(getSourceDir(program))).toBe(path.join(cwd, "src")); + }); +}); + +describe("getEmitPath", () => { + test("puts files next to input without options", () => { + const { transpiledFiles } = util.testModule`` + .setMainFileName("main.ts") + .addExtraFile("dir/extra.ts", "") + .expectToHaveNoDiagnostics() + .getLuaResult(); + + const fileNames = transpiledFiles.map(f => f.outPath); + expect(fileNames).toContain("main.lua"); + expect(fileNames).toContain(path.join("dir", "extra.lua")); + }); + + test("puts files in outdir", () => { + const outDir = path.join(cwd, "tstl-out"); + const { transpiledFiles } = util.testModule`` + .setMainFileName("main.ts") + .addExtraFile("dir/extra.ts", "") + .setOptions({ outDir }) + .expectToHaveNoDiagnostics() + .getLuaResult(); + + const fileNames = transpiledFiles.map(f => f.outPath); + expect(fileNames).toContain(path.join(outDir, "main.lua")); + expect(fileNames).toContain(path.join(outDir, "dir", "extra.lua")); + }); + + test("puts files from rootDir in outdir", () => { + const outDir = path.join(cwd, "tstl-out"); + const { transpiledFiles } = util.testModule`` + .setMainFileName("src/main.ts") + .addExtraFile("src/extra.ts", "") + .setOptions({ rootDir: "src", outDir }) + .expectToHaveNoDiagnostics() + .getLuaResult(); + + const fileNames = transpiledFiles.map(f => f.outPath); + expect(fileNames).toContain(path.join(outDir, "main.lua")); + expect(fileNames).toContain(path.join(outDir, "extra.lua")); + }); + + test("puts bundle relative to project root", () => { + const { transpiledFiles } = util.testModule`` + .setMainFileName("src/main.ts") + .addExtraFile("src/extra.ts", "") + .setOptions({ configFilePath, rootDir: "src", luaBundle: "out/bundle.lua", luaBundleEntry: "src/main.ts" }) + .expectToHaveNoDiagnostics() + .getLuaResult(); + + const fileNames = transpiledFiles.map(f => f.outPath); + expect(fileNames).toHaveLength(1); + expect(fileNames).toContain(path.join(cwd, "out", "bundle.lua")); + }); + + test("puts bundle relative to outdir", () => { + const { transpiledFiles } = util.testModule`` + .setMainFileName("src/main.ts") + .addExtraFile("src/extra.ts", "") + .setOptions({ + configFilePath, + rootDir: "src", + outDir: "out1", + luaBundle: "out2/bundle.lua", + luaBundleEntry: "src/main.ts", + }) + .expectToHaveNoDiagnostics() + .getLuaResult(); + + const fileNames = transpiledFiles.map(f => f.outPath); + expect(fileNames).toHaveLength(1); + expect(fileNames).toContain(path.join(cwd, "out1", "out2", "bundle.lua")); + }); +}); + +function normalize(path: string) { + return path.endsWith("/") ? path.slice(0, path.length - 1) : path; +}