Skip to content

Commit 3f30817

Browse files
committed
replace dots with underscores in output paths instead of expanding to nested directories
1 parent b85b5de commit 3f30817

File tree

3 files changed

+11
-14
lines changed

3 files changed

+11
-14
lines changed

src/transpilation/diagnostics.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,5 @@ export const pathsWithoutBaseUrl = createDiagnosticFactory(
6363
export const emitPathCollision = createDiagnosticFactory(
6464
(outputPath: string, file1: string, file2: string) =>
6565
`Output path '${outputPath}' is used by both '${file1}' and '${file2}'. ` +
66-
`Dots in file/directory names are expanded to nested directories for Lua module resolution.`
66+
`Dots in file/directory names are replaced with underscores for Lua module resolution.`
6767
);

src/transpilation/transpiler.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ export class Transpiler {
144144
diagnostics.push(...bundleDiagnostics);
145145
emitPlan = [bundleFile];
146146
} else {
147-
// Check for output path collisions caused by dot expansion
148147
const outputPathMap = new Map<string, string>();
149148
emitPlan = resolutionResult.resolvedFiles.map(file => {
150149
const outputPath = getEmitPath(file.fileName, program);
@@ -198,13 +197,12 @@ export function getEmitPathRelativeToOutDir(fileName: string, program: ts.Progra
198197
emitPathSplits[0] = "lua_modules";
199198
}
200199

201-
// Expand dots in path segments into nested directories so that Lua's require()
202-
// resolves correctly (e.g. "Foo.Bar/index.ts" -> "Foo/Bar/index.lua").
203-
// Dots are path separators in Lua's module system, so a file at "Foo.Bar/index.lua"
204-
// would be unreachable via require("Foo.Bar.index") since Lua looks for "Foo/Bar/index.lua".
205-
// Strip the source extension first, split all dots, then re-add the output extension.
200+
// Replace dots with underscores in path segments so that Lua's require()
201+
// resolves correctly. Dots are path separators in Lua's module system, so
202+
// "Foo.Bar/index.lua" would be unreachable via require("Foo.Bar.index")
203+
// since Lua interprets it as "Foo/Bar/index.lua".
206204
emitPathSplits[emitPathSplits.length - 1] = trimExtension(emitPathSplits[emitPathSplits.length - 1]);
207-
emitPathSplits = emitPathSplits.flatMap(segment => segment.split("."));
205+
emitPathSplits = emitPathSplits.map(segment => segment.replace(/\./g, "_"));
208206

209207
// Set extension
210208
const extension = ((program.getCompilerOptions() as CompilerOptions).extension ?? "lua").trim();

test/unit/modules/resolution.spec.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as path from "path";
12
import * as ts from "typescript";
23
import { couldNotResolveRequire, emitPathCollision } from "../../../src/transpilation/diagnostics";
34
import * as util from "../../util";
@@ -170,8 +171,7 @@ test.each([
170171
// Can't test this via execution because the test harness uses package.preload
171172
// instead of real filesystem resolution, so require() always finds the module
172173
// regardless of output path. We check the output path directly instead.
173-
// TODO: test via actual Lua execution once the harness supports filesystem resolution.
174-
test("dots in directory names emit to nested directories", () => {
174+
test("dots in directory names are replaced with underscores in output", () => {
175175
const { transpiledFiles } = util.testModule`
176176
import { answer } from "./Foo.Bar";
177177
export const result = answer;
@@ -180,21 +180,20 @@ test("dots in directory names emit to nested directories", () => {
180180
.setOptions({ rootDir: "." })
181181
.getLuaResult();
182182

183-
// Foo.Bar/index.ts should emit to Foo/Bar/index.lua, not Foo.Bar/index.lua
184183
const dottedFile = transpiledFiles.find(f => f.lua?.includes("answer = 42"));
185184
expect(dottedFile).toBeDefined();
186-
expect(dottedFile!.outPath).toContain("Foo/Bar/index.lua");
185+
expect(dottedFile!.outPath).toContain(path.join("Foo_Bar", "index.lua"));
187186
expect(dottedFile!.outPath).not.toContain("Foo.Bar");
188187
});
189188

190189
test("dots in paths that collide with existing paths produce a diagnostic", () => {
191190
util.testModule`
192191
import { a } from "./Foo.Bar";
193-
import { b } from "./Foo/Bar";
192+
import { b } from "./Foo_Bar";
194193
export const result = a + b;
195194
`
196195
.addExtraFile("Foo.Bar/index.ts", "export const a = 1;")
197-
.addExtraFile("Foo/Bar/index.ts", "export const b = 2;")
196+
.addExtraFile("Foo_Bar/index.ts", "export const b = 2;")
198197
.setOptions({ rootDir: "." })
199198
.expectToHaveDiagnostics([emitPathCollision.code]);
200199
});

0 commit comments

Comments
 (0)