Skip to content

Commit a24708e

Browse files
committed
Fixed problem with lua sibling files
1 parent 7a79881 commit a24708e

File tree

9 files changed

+62
-31
lines changed

9 files changed

+62
-31
lines changed

src/transpilation/resolve.ts

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,43 +10,52 @@ import { couldNotReadDependency, couldNotResolveRequire } from "./diagnostics";
1010

1111
const resolver = resolve.ResolverFactory.createResolver({
1212
extensions: [".lua"],
13-
enforceExtension: true, // Must be a lua file
13+
enforceExtension: true, // Resolved file must be a lua file
1414
fileSystem: { ...new resolve.CachedInputFileSystem(fs) },
1515
useSyncFileSystemCalls: true,
1616
});
1717

18-
const projectFiles = new Map<string, string>();
19-
2018
interface ResolutionResult {
2119
resolvedFiles: ProcessedFile[];
2220
diagnostics: ts.Diagnostic[];
2321
}
2422

23+
// Cache for getting source files from the program
24+
const projectFileCache = new Set<string>();
25+
function isProjectFile(file: string): boolean {
26+
// Check if file is in the project ts.program
27+
return projectFileCache.has(path.normalize(file));
28+
}
29+
2530
export function resolveDependencies(program: ts.Program, files: ProcessedFile[], emitHost: EmitHost): ResolutionResult {
26-
const outFiles: ProcessedFile[] = [];
31+
const outFiles: ProcessedFile[] = [...files];
2732
const diagnostics: ts.Diagnostic[] = [];
2833

34+
// Add files to project cache
2935
const projectRoot = getProjectRoot(program);
3036
for (const sourceFile of program.getSourceFiles()) {
3137
const filePath = path.isAbsolute(sourceFile.fileName)
3238
? path.normalize(sourceFile.fileName)
3339
: path.resolve(projectRoot, sourceFile.fileName);
34-
projectFiles.set(filePath, sourceFile.text);
40+
projectFileCache.add(filePath);
3541
}
3642

43+
// Resolve dependencies for all processed files
3744
for (const file of files) {
3845
const resolutionResult = resolveFileDependencies(file, program, emitHost);
39-
outFiles.push(file, ...resolutionResult.resolvedFiles);
46+
outFiles.push(...resolutionResult.resolvedFiles);
4047
diagnostics.push(...resolutionResult.diagnostics);
4148
}
4249

4350
return { resolvedFiles: outFiles, diagnostics };
4451
}
4552

4653
function resolveFileDependencies(file: ProcessedFile, program: ts.Program, emitHost: EmitHost): ResolutionResult {
47-
const projectRootDir = getSourceDir(program);
4854
const dependencies: ProcessedFile[] = [];
4955
const diagnostics: ts.Diagnostic[] = [];
56+
57+
const projectRootDir = getSourceDir(program);
58+
5059
for (const required of findRequiredPaths(file.code)) {
5160
// Do no resolve lualib
5261
if (required === "lualib_bundle") {
@@ -63,23 +72,23 @@ function resolveFileDependencies(file: ProcessedFile, program: ts.Program, emitH
6372

6473
// Try to resolve the import starting from the directory `file` is in
6574
const fileDir = path.dirname(file.fileName);
66-
const resolvedDependency = resolveDependency(fileDir, projectRootDir, required);
75+
const resolvedDependency = resolveDependency(fileDir, projectRootDir, required, emitHost);
6776
if (resolvedDependency) {
68-
// If dependency resolved successfully, read its content
69-
const dependencyContent = projectFiles.get(resolvedDependency) ?? emitHost.readFile(resolvedDependency);
70-
if (dependencyContent === undefined) {
71-
diagnostics.push(couldNotReadDependency(resolvedDependency));
72-
continue;
73-
}
74-
7577
// Figure out resolved require path and dependency output path
7678
const resolvedRequire = getEmitPathRelativeToOutDir(resolvedDependency, program);
7779

7880
replaceRequireInCode(file, required, resolvedRequire);
7981
replaceRequireInSourceMap(file, required, resolvedRequire);
8082

81-
// If dependency is not part of sources, add dependency to output and resolve its dependencies recursively
82-
if (!projectFiles.has(resolvedDependency)) {
83+
// If dependency is not part of project, add dependency to output and resolve its dependencies recursively
84+
if (!isProjectFile(resolvedDependency)) {
85+
// If dependency resolved successfully, read its content
86+
const dependencyContent = emitHost.readFile(resolvedDependency);
87+
if (dependencyContent === undefined) {
88+
diagnostics.push(couldNotReadDependency(resolvedDependency));
89+
continue;
90+
}
91+
8392
const dependency = {
8493
fileName: resolvedDependency,
8594
code: dependencyContent,
@@ -100,12 +109,12 @@ function resolveFileDependencies(file: ProcessedFile, program: ts.Program, emitH
100109
return { resolvedFiles: dependencies, diagnostics };
101110
}
102111

103-
function replaceRequireInCode(file: ProcessedFile, originalRequire: string, newRequire: string) {
112+
function replaceRequireInCode(file: ProcessedFile, originalRequire: string, newRequire: string): void {
104113
const requirePath = formatPathToLuaPath(newRequire.replace(".lua", ""));
105114
file.code = file.code.replace(`require("${originalRequire}")`, `require("${requirePath}")`);
106115
}
107116

108-
function replaceRequireInSourceMap(file: ProcessedFile, originalRequire: string, newRequire: string) {
117+
function replaceRequireInSourceMap(file: ProcessedFile, originalRequire: string, newRequire: string): void {
109118
const requirePath = formatPathToLuaPath(newRequire.replace(".lua", ""));
110119
if (file.sourceMapNode) {
111120
replaceInSourceMap(file.sourceMapNode, file.sourceMapNode, `"${originalRequire}"`, `"${requirePath}"`);
@@ -142,20 +151,32 @@ function findRequiredPaths(code: string): string[] {
142151
return paths;
143152
}
144153

145-
function resolveDependency(fileDirectory: string, rootDirectory: string, dependency: string): string | undefined {
146-
// Check if file is a TS file in the project
154+
function resolveDependency(
155+
fileDirectory: string,
156+
rootDirectory: string,
157+
dependency: string,
158+
emitHost: EmitHost
159+
): string | undefined {
160+
// Check if file is a file in the project
147161
const resolvedPath = path.resolve(fileDirectory, dependency);
148162

149163
const resolvedFile = resolvedPath + ".ts";
150-
if (projectFiles.has(resolvedFile)) {
164+
if (isProjectFile(resolvedFile)) {
151165
return resolvedFile;
152166
}
153167

154168
const projectIndexPath = path.resolve(resolvedPath, "index.ts");
155-
if (projectFiles.has(projectIndexPath)) {
169+
if (isProjectFile(projectIndexPath)) {
156170
return projectIndexPath;
157171
}
158172

173+
// Check if this is a sibling of a required lua file
174+
const luaFilePath = path.resolve(fileDirectory, dependency + ".lua");
175+
if (emitHost.fileExists(luaFilePath)) {
176+
return luaFilePath;
177+
}
178+
179+
// Not a TS file in our project sources, use resolver to check if we can find dependency
159180
try {
160181
const resolveResult = resolver.resolveSync({}, rootDirectory, dependency);
161182
if (resolveResult) {

test/transpile/module-resolution.spec.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ describe("basic module resolution", () => {
8484

8585
describe("module resolution with chained dependencies", () => {
8686
const projectPath = path.resolve(__dirname, "module-resolution", "project-with-dependency-chain");
87-
const expectedResult = { result: "dependency3" };
87+
const expectedResult = { result: "dependency3", result2: "someFunc from otherfile.lua" };
8888

8989
test("can resolve dependencies in chain", () => {
9090
util.testProject(path.join(projectPath, "tsconfig.json"))
@@ -103,7 +103,7 @@ describe("module resolution with chained dependencies", () => {
103103

104104
describe("module resolution with outDir", () => {
105105
const projectPath = path.resolve(__dirname, "module-resolution", "project-with-dependency-chain");
106-
const expectedResult = { result: "dependency3" };
106+
const expectedResult = { result: "dependency3", result2: "someFunc from otherfile.lua" };
107107

108108
test("emits files in outDir", () => {
109109
const builder = util
@@ -114,10 +114,11 @@ describe("module resolution with outDir", () => {
114114

115115
// Get the output paths relative to the project path
116116
const outPaths = builder.getLuaResult().transpiledFiles.map(f => path.relative(projectPath, f.outPath));
117-
expect(outPaths).toHaveLength(4);
117+
expect(outPaths).toHaveLength(5);
118118
expect(outPaths).toContain(path.join("tstl-out", "main.lua"));
119119
// Note: outputs to lua_modules
120120
expect(outPaths).toContain(path.join("tstl-out", "lua_modules", "dependency1", "index.lua"));
121+
expect(outPaths).toContain(path.join("tstl-out", "lua_modules", "dependency1", "otherfile.lua"));
121122
expect(outPaths).toContain(path.join("tstl-out", "lua_modules", "dependency2", "index.lua"));
122123
expect(outPaths).toContain(path.join("tstl-out", "lua_modules", "dependency3", "index.lua"));
123124
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import * as dependency1 from "dependency1";
22

33
export const result = dependency1.f1();
4+
export const result2 = dependency1.otherFileFromDependency1();

test/transpile/module-resolution/project-with-dependency-chain/node_modules/dependency1/index.d.ts

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/transpile/module-resolution/project-with-dependency-chain/node_modules/dependency1/index.lua

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/transpile/module-resolution/project-with-dependency-chain/node_modules/dependency1/otherfile.lua

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/transpile/module-resolution/project-with-sourceDir/src/subdir/otherfile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ export function func() {
22
return "non-node_modules import";
33
}
44

5-
export { nestedFunc } from "./subdirofsubdir/nestedfile";
5+
export { nestedFunc } from "./subdirofsubdir/nestedfile";
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export function func2() {
22
return "non-node_modules import 2";
3-
}
3+
}

test/transpile/module-resolution/project-with-sourceDir/src/subdir/subdirofsubdir/nestedfile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ export function nestedFunc() {
66

77
export function nestedFuncUsingParent() {
88
return `nested func: ${func2()}`;
9-
}
9+
}

0 commit comments

Comments
 (0)