diff --git a/src/index.ts b/src/index.ts index 2817d42..4490118 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,17 +20,47 @@ const isPathPattern = /^\.{0,2}\//; const isTsFilePatten = /\.[cm]?tsx?$/; const nodeModulesPath = `${path.sep}node_modules${path.sep}`; -const tsconfig = ( - process.env.ESBK_TSCONFIG_PATH - ? { - path: path.resolve(process.env.ESBK_TSCONFIG_PATH), - config: parseTsconfig(process.env.ESBK_TSCONFIG_PATH), - } - : getTsconfig() -); +function getProjectsMap(tsconfigPath?: string, projectsMap?: Map; + tsconfigPathsMatcher: ReturnType; + fileMatcher: ReturnType; +}>) { + if (!projectsMap) { + projectsMap = new Map(); + } + + const tsconfig = ( + tsconfigPath + ? { + path: path.resolve(tsconfigPath), + config: parseTsconfig(tsconfigPath), + } + : getTsconfig() + ); + + if (!tsconfig) { + return projectsMap; + } + + if (projectsMap.has(tsconfig.path)) { + return projectsMap; + } -const fileMatcher = tsconfig && createFilesMatcher(tsconfig); -const tsconfigPathsMatcher = tsconfig && createPathsMatcher(tsconfig); + projectsMap.set(tsconfig.path, { + tsconfig, + tsconfigPathsMatcher: tsconfig && createPathsMatcher(tsconfig), + fileMatcher: tsconfig && createFilesMatcher(tsconfig), + }); + + tsconfig?.config?.references?.forEach((reference) => { + const referencedTsconfigPath = reference.path.endsWith('.json') ? reference.path : path.join(reference.path, 'tsconfig.json'); + projectsMap = getProjectsMap(referencedTsconfigPath, projectsMap); + }); + + return projectsMap; +} + +export const projectsMap = getProjectsMap(process.env.ESBK_TSCONFIG_PATH); const applySourceMap = installSourceMapSupport(); @@ -67,11 +97,18 @@ function transformer( code = applySourceMap(transformed, filePath); } } else { + let tsconfigRaw: TransformOptions['tsconfigRaw']; + for (const project of projectsMap.values()) { + tsconfigRaw = project.fileMatcher(filePath) as TransformOptions['tsconfigRaw']; + if (tsconfigRaw) { + break; + } + } const transformed = transformSync( code, filePath, { - tsconfigRaw: fileMatcher?.(filePath) as TransformOptions['tsconfigRaw'], + tsconfigRaw, }, ); @@ -131,7 +168,7 @@ Module._resolveFilename = function (request, parent, isMain, options) { } if ( - tsconfigPathsMatcher + projectsMap.size > 0 // bare specifier && !isPathPattern.test(request) @@ -139,7 +176,15 @@ Module._resolveFilename = function (request, parent, isMain, options) { // Dependency paths should not be resolved using tsconfig.json && !parent?.filename?.includes(nodeModulesPath) ) { - const possiblePaths = tsconfigPathsMatcher(request); + const possiblePaths: string[] = []; + projectsMap.forEach((project) => { + if (project.tsconfigPathsMatcher) { + const possibleProjectPaths = project.tsconfigPathsMatcher(request); + if (possibleProjectPaths) { + possiblePaths.push(...possibleProjectPaths); + } + } + }); for (const possiblePath of possiblePaths) { const tsFilename = resolveTsFilename.call(this, possiblePath, parent, isMain, options); @@ -155,7 +200,7 @@ Module._resolveFilename = function (request, parent, isMain, options) { isMain, options, ); - } catch {} + } catch { } } } diff --git a/tests/fixtures/tsconfig/dependency-resolve-project-reference.ts b/tests/fixtures/tsconfig/dependency-resolve-project-reference.ts new file mode 100644 index 0000000..41964bc --- /dev/null +++ b/tests/fixtures/tsconfig/dependency-resolve-project-reference.ts @@ -0,0 +1,3 @@ +import { resolve } from "resolve-project-reference"; + +console.log(resolve); \ No newline at end of file diff --git a/tests/fixtures/tsconfig/resolve-project-reference/package.json b/tests/fixtures/tsconfig/resolve-project-reference/package.json new file mode 100644 index 0000000..6a22b7b --- /dev/null +++ b/tests/fixtures/tsconfig/resolve-project-reference/package.json @@ -0,0 +1,3 @@ +{ + "main": "src/index.ts" +} \ No newline at end of file diff --git a/tests/fixtures/tsconfig/resolve-project-reference/src/index.ts b/tests/fixtures/tsconfig/resolve-project-reference/src/index.ts new file mode 100644 index 0000000..2e62b04 --- /dev/null +++ b/tests/fixtures/tsconfig/resolve-project-reference/src/index.ts @@ -0,0 +1 @@ +export * from "~/resolve"; \ No newline at end of file diff --git a/tests/fixtures/tsconfig/resolve-project-reference/src/resolve.ts b/tests/fixtures/tsconfig/resolve-project-reference/src/resolve.ts new file mode 100644 index 0000000..1326533 --- /dev/null +++ b/tests/fixtures/tsconfig/resolve-project-reference/src/resolve.ts @@ -0,0 +1 @@ +export const resolve = "resolved"; \ No newline at end of file diff --git a/tests/fixtures/tsconfig/resolve-project-reference/tsconfig.json b/tests/fixtures/tsconfig/resolve-project-reference/tsconfig.json new file mode 100644 index 0000000..f6bfa42 --- /dev/null +++ b/tests/fixtures/tsconfig/resolve-project-reference/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "composite": true, + "baseUrl": ".", + "paths": { + "~/*": [ + "src/*", + ], + }, + }, +} \ No newline at end of file diff --git a/tests/fixtures/tsconfig/tsconfig.json b/tests/fixtures/tsconfig/tsconfig.json index 9d0c412..267cad9 100644 --- a/tests/fixtures/tsconfig/tsconfig.json +++ b/tests/fixtures/tsconfig/tsconfig.json @@ -5,9 +5,23 @@ "jsxFragmentFactory": "null", "baseUrl": "./src", "paths": { - "paths-exact-match": ["resolve-target"], - "p/*": ["utils/*"], - "*/s": ["utils/*"] + "paths-exact-match": [ + "resolve-target" + ], + "p/*": [ + "utils/*" + ], + "*/s": [ + "utils/*" + ], + "resolve-project-reference": [ + "../resolve-project-reference/src/index.ts" + ] }, }, -} + "references": [ + { + "path": "./resolve-project-reference" + } + ] +} \ No newline at end of file diff --git a/tests/specs/typescript/tsconfig.ts b/tests/specs/typescript/tsconfig.ts index 20882eb..a8e7892 100644 --- a/tests/specs/typescript/tsconfig.ts +++ b/tests/specs/typescript/tsconfig.ts @@ -181,6 +181,13 @@ export default testSuite(async ({ describe }, node: NodeApis) => { }); expect(nodeProcess.stdout).toBe('resolved'); }); + + test('should resolve project reference', async () => { + const nodeProcess = await node.load('./dependency-resolve-project-reference', { + cwd: './tsconfig', + }); + expect(nodeProcess.stdout).toBe('resolved'); + }); }); }); });