tsc-alias has bad baseUrl when project name matches folder in external alias
TL; DR: When an aliased subdirectory has the same name as the project folder, tsc-alias can fail to replace import aliases, causing imports to fail at runtime.
I use tsc-alias to bundle a @shared/ library between my client and server code. Recently this broke when I tried adding @shared/ to my service which happens to live under games/pool/.
The problem is that the shared library also has a folder that includes a folder named pool. This causes getProjectDirPathInOutDir to return a bad array with an incorrect path:
[
"/home/acorn/cloud/Projects/js/foony/services/games/pool/lib/services/games/pool",
"/home/acorn/cloud/Projects/js/foony/services/games/pool/lib/shared/src/games/pool"
]
The correct path should be:
[
"/home/acorn/cloud/Projects/js/foony/services/games/pool/lib/services/games/pool"
]
This causes an incorrect path in relativeOutPathToConfigDir to be returned, which then results in bad values for basePath, for example: /home/acorn/cloud/Projects/js/foony/services/games/pool/lib/shared/src/games/pool instead of '/home/acorn/cloud/Projects/js/foony/services/games/pool/lib/services/games/pool'
My project structure looks like this:
shared/
- tsconfig.json
- src/games/pool/
services/games/pool/
- tsconfig.json
- src/
This example code seems to fix it, at least for my use case:
function getProjectDirPathInOutDir(
outDir: string,
projectDir: string
): string | undefined {
const posixOutput = outDir.replace(/\\/g, '/');
const dirs = sync(
[
`${posixOutput}/**/${projectDir}`,
`!${posixOutput}/**/${projectDir}/**/${projectDir}`,
`!${posixOutput}/**/node_modules`
],
{
dot: true,
onlyDirectories: true
}
);
// Find the longest path
const posixOutParts = posixOutput.split('/');
const lastIndex = posixOutParts.lastIndexOf(projectDir);
return dirs.reduce((longest, dir) => {
const parts = dir.split('/');
let length = 0;
for (let i = parts.length - 1; i >= 0; --i) {
if (parts[i] === posixOutParts[lastIndex - length]) {
++length;
} else {
break;
}
}
return longest.matchLength > length ? longest : {matchLength: length, dir};
}, {matchLength: 0, dir: ''}).dir;
}