1import JsonFile from '@expo/json-file'; 2import path from 'path'; 3 4import { fileExistsAsync } from '../dir'; 5import { evaluateTsConfig, importTypeScriptFromProjectOptionally } from './evaluateTsConfig'; 6 7export type TsConfigPaths = { 8 paths?: Record<string, string[]>; 9 baseUrl: string; 10}; 11 12type ConfigReadResults = [ 13 string, 14 { 15 compilerOptions?: { 16 baseUrl?: string; 17 paths?: Record<string, string[]>; 18 }; 19 } 20]; 21 22const debug = require('debug')('expo:utils:tsconfig:load') as typeof console.log; 23 24export async function loadTsConfigPathsAsync(dir: string): Promise<TsConfigPaths | null> { 25 const options = (await readTsconfigAsync(dir)) ?? (await readJsconfigAsync(dir)); 26 if (options) { 27 const [filepath, config] = options; 28 if (config.compilerOptions?.baseUrl) { 29 return { 30 paths: config.compilerOptions?.paths, 31 baseUrl: path.resolve(dir, config.compilerOptions.baseUrl), 32 }; 33 } 34 debug(`No baseUrl found in ${filepath}`); 35 return { 36 paths: config.compilerOptions?.paths, 37 baseUrl: dir, 38 }; 39 } 40 return null; 41} 42 43async function readJsconfigAsync(projectRoot: string): Promise<null | ConfigReadResults> { 44 const configPath = path.join(projectRoot, 'jsconfig.json'); 45 if (await fileExistsAsync(configPath)) { 46 const config = await JsonFile.readAsync(configPath, { json5: true }); 47 if (config) { 48 return [configPath, config]; 49 } 50 } 51 return null; 52} 53 54// TODO: Refactor for speed 55export async function readTsconfigAsync(projectRoot: string): Promise<null | ConfigReadResults> { 56 const configPath = path.join(projectRoot, 'tsconfig.json'); 57 if (await fileExistsAsync(configPath)) { 58 // We need to fully evaluate the tsconfig to get the baseUrl and paths in case they were applied in `extends`. 59 const ts = importTypeScriptFromProjectOptionally(projectRoot); 60 if (ts) { 61 return [configPath, evaluateTsConfig(ts, configPath)]; 62 } 63 debug(`typescript module not found in: ${projectRoot}`); 64 } 65 return null; 66} 67