justkey007 / tsc-alias

Replace alias paths with relative paths after typescript compilation
MIT License
894 stars 62 forks source link

tsc-alias has bad baseUrl when project name matches folder in external alias #205

Open acorn1010 opened 9 months ago

acorn1010 commented 9 months ago

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/
acorn1010 commented 9 months ago

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;
}