1
0

tsconfig-utils.ts 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import fs from 'fs-extra';
  2. import path from 'path';
  3. import { CompilerOptions } from 'typescript';
  4. import { Logger, TransformTsConfigPathMappingsFn } from '../types.js';
  5. export interface TsConfigPathsConfig {
  6. baseUrl: string;
  7. paths: Record<string, string[]>;
  8. }
  9. /**
  10. * Finds and parses tsconfig files in the given directory and its parent directories.
  11. */
  12. export async function findTsConfigPaths(
  13. configPath: string,
  14. logger: Logger,
  15. phase: 'compiling' | 'loading',
  16. transformTsConfigPathMappings: TransformTsConfigPathMappingsFn,
  17. ): Promise<TsConfigPathsConfig | undefined> {
  18. let currentDir = path.dirname(configPath);
  19. while (currentDir !== path.parse(currentDir).root) {
  20. try {
  21. const files = await fs.readdir(currentDir);
  22. const tsConfigFiles = files.filter(file => /^tsconfig(\..*)?\.json$/.test(file));
  23. for (const fileName of tsConfigFiles) {
  24. const tsConfigFilePath = path.join(currentDir, fileName);
  25. try {
  26. const { paths, baseUrl } = await getCompilerOptionsFromFile(tsConfigFilePath);
  27. if (paths) {
  28. const tsConfigBaseUrl = path.resolve(currentDir, baseUrl || '.');
  29. const pathMappings = getTransformedPathMappings(
  30. paths,
  31. phase,
  32. transformTsConfigPathMappings,
  33. );
  34. return { baseUrl: tsConfigBaseUrl, paths: pathMappings };
  35. }
  36. } catch (e) {
  37. logger.warn(
  38. `Could not read or parse tsconfig file ${tsConfigFilePath}: ${e instanceof Error ? e.message : String(e)}`,
  39. );
  40. }
  41. }
  42. } catch (e) {
  43. logger.warn(
  44. `Could not read directory ${currentDir}: ${e instanceof Error ? e.message : String(e)}`,
  45. );
  46. }
  47. currentDir = path.dirname(currentDir);
  48. }
  49. return undefined;
  50. }
  51. async function getCompilerOptionsFromFile(tsConfigFilePath: string): Promise<CompilerOptions> {
  52. const tsConfigContent = await fs.readFile(tsConfigFilePath, 'utf-8');
  53. const tsConfig = JSON.parse(tsConfigContent);
  54. return tsConfig.compilerOptions || {};
  55. }
  56. function getTransformedPathMappings(
  57. paths: Required<CompilerOptions>['paths'],
  58. phase: 'compiling' | 'loading',
  59. transformTsConfigPathMappings: TransformTsConfigPathMappingsFn,
  60. ) {
  61. const pathMappings: Record<string, string[]> = {};
  62. for (const [alias, patterns] of Object.entries(paths)) {
  63. const normalizedPatterns = patterns.map(pattern => pattern.replace(/\\/g, '/'));
  64. pathMappings[alias] = transformTsConfigPathMappings({
  65. phase,
  66. alias,
  67. patterns: normalizedPatterns,
  68. });
  69. }
  70. return pathMappings;
  71. }