diff --git a/.eslintignore b/.eslintignore index 492195f96..a1a50129e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,5 +3,6 @@ /test/cli/errors /test/cli/watch /test/transpile/directories -/test/transpile/module-resolution/*/node_modules +/test/transpile/module-resolution/**/node_modules +/test/transpile/module-resolution/**/dist /test/transpile/outFile diff --git a/.gitignore b/.gitignore index e9fe7f092..fc3920330 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ node_modules /dist /coverage +/test/transpile/module-resolution/**/dist +/test/transpile/module-resolution/**/tsconfig.tsbuildinfo yarn.lock .vscode diff --git a/.prettierignore b/.prettierignore index 23b85e3bd..656f1a4d6 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,3 +2,5 @@ /coverage /test/translation/transformation/characterEscapeSequence.ts /benchmark/dist +/test/transpile/module-resolution/**/node_modules +/test/transpile/module-resolution/**/dist diff --git a/src/transpilation/resolve.ts b/src/transpilation/resolve.ts index c7ea38dd1..fa0a5200a 100644 --- a/src/transpilation/resolve.ts +++ b/src/transpilation/resolve.ts @@ -15,6 +15,7 @@ const resolver = resolve.ResolverFactory.createResolver({ enforceExtension: true, // Resolved file must be a lua file fileSystem: { ...new resolve.CachedInputFileSystem(fs) }, useSyncFileSystemCalls: true, + conditionNames: ["require", "node", "default"], symlinks: false, // Do not resolve symlinks to their original paths (that breaks node_modules detection) }); diff --git a/test/transpile/module-resolution.spec.ts b/test/transpile/module-resolution.spec.ts index 8f8cc0230..f9e1894d5 100644 --- a/test/transpile/module-resolution.spec.ts +++ b/test/transpile/module-resolution.spec.ts @@ -2,6 +2,7 @@ import * as path from "path"; import * as tstl from "../../src"; import * as util from "../util"; import * as ts from "typescript"; +import * as fs from "fs-extra"; import { BuildMode } from "../../src"; import { normalizeSlashes } from "../../src/utils"; import { pathsWithoutBaseUrl } from "../../src/transpilation/diagnostics"; @@ -272,6 +273,52 @@ describe("module resolution project with dependencies built by tstl library mode }); }); +describe("module resolution project with dependencies built by tstl library mode and has exports field", () => { + const projectPath = path.resolve(__dirname, "module-resolution", "project-with-tstl-library-has-exports-field"); + const appPath = path.join(projectPath, "app"); + + // First compile dependencies into node_modules. NOTE: Actually writing to disk, very slow + const dependency1Path = path.join(projectPath, "dependency1-ts"); + tstl.transpileProject(path.join(dependency1Path, "tsconfig.json")); + + // Install dependencies. This will create node_modules folder with dependency1-ts in it. + const nodeModulesPath = path.join(appPath, "node_modules"); + fs.ensureDirSync(nodeModulesPath); + fs.ensureSymlinkSync(dependency1Path, path.join(nodeModulesPath, "dependency1"), "dir"); + + const expectedResult = { + dependency1IndexResult: "function in dependency 1 index: dependency1OtherFileFunc in dependency1/d1otherfile", + dependency1OtherFileFuncResult: "dependency1OtherFileFunc in dependency1/d1otherfile", + }; + + test("can resolve lua dependencies", () => { + const transpileResult = util + .testProject(path.join(appPath, "tsconfig.json")) + .setMainFileName(path.join(appPath, "main.ts")) + .setOptions({ outDir: "tstl-out", moduleResolution: ts.ModuleResolutionKind.Node16 }) + .expectToEqual(expectedResult) + .getLuaResult(); + + // Assert node_modules file requires the correct lualib_bundle + const requiringLuaFile = path.join("lua_modules", "dependency1", "dist", "index.lua"); + const lualibRequiringFile = transpileResult.transpiledFiles.find(f => f.outPath.endsWith(requiringLuaFile)); + expect(lualibRequiringFile).toBeDefined(); + expect(lualibRequiringFile?.lua).toContain('require("lualib_bundle")'); + }); + + test("can resolve dependencies and bundle", () => { + const mainFile = path.join(appPath, "main.ts"); + util.testProject(path.join(appPath, "tsconfig.json")) + .setMainFileName(mainFile) + .setOptions({ + luaBundle: "bundle.lua", + luaBundleEntry: mainFile, + moduleResolution: ts.ModuleResolutionKind.Node16, + }) + .expectToEqual(expectedResult); + }); +}); + // Test fix for https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1037 describe("module resolution with tsx", () => { const projectPath = path.resolve(__dirname, "module-resolution", "project-with-tsx"); diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/main.ts b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/main.ts new file mode 100644 index 000000000..3421911f2 --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/main.ts @@ -0,0 +1,5 @@ +import { dependency1IndexFunc } from "dependency1/sub"; +import { dependency1OtherFileFunc } from "dependency1/sub/d1otherfile"; + +export const dependency1IndexResult = dependency1IndexFunc(); +export const dependency1OtherFileFuncResult = dependency1OtherFileFunc(); diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/package.json b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/package.json new file mode 100644 index 000000000..b88dc4bc0 --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/package.json @@ -0,0 +1,7 @@ +{ + "name": "app", + "version": "0.0.1", + "dependencies": { + "dependency1": "file:../dependency1-ts" + } +} diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/tsconfig.json b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/tsconfig.json new file mode 100644 index 000000000..7b0969155 --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "moduleResolution": "node16" + }, + "references": [{ "path": "./node_modules/dependency1" }] +} diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/package.json b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/package.json new file mode 100644 index 000000000..c74b862a1 --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/package.json @@ -0,0 +1,14 @@ +{ + "name": "dependency1", + "version": "0.0.1", + "exports": { + "./sub": { + "require": "./dist/index", + "types": "./dist/index.d.ts" + }, + "./sub/*": { + "require": "./dist/*", + "types": "./dist/*.d.ts" + } + } +} diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/src/d1otherfile.ts b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/src/d1otherfile.ts new file mode 100644 index 000000000..3877a1c52 --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/src/d1otherfile.ts @@ -0,0 +1,3 @@ +export function dependency1OtherFileFunc() { + return "dependency1OtherFileFunc in dependency1/d1otherfile"; +} diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/src/index.ts b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/src/index.ts new file mode 100644 index 000000000..03cff47c5 --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/src/index.ts @@ -0,0 +1,10 @@ +import { dependency1OtherFileFunc } from "./d1otherfile"; + +export function dependency1IndexFunc() { + return "function in dependency 1 index: " + dependency1OtherFileFunc(); +} + +export function squares(nums: number[]) { + // Require lualib functionality + return nums.map(n => n * n); +} diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/tsconfig.json b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/tsconfig.json new file mode 100644 index 000000000..d6ffcdc0c --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "composite": true + }, + "tstl": { + "buildMode": "library" + } +}