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