1import path from 'path'; 2import resolveFrom from 'resolve-from'; 3 4export function evaluateTsConfig(ts: typeof import('typescript'), tsConfigPath: string) { 5 const formatDiagnosticsHost: import('typescript').FormatDiagnosticsHost = { 6 getNewLine: () => require('os').EOL, 7 getCurrentDirectory: ts.sys.getCurrentDirectory, 8 getCanonicalFileName: (fileName: string) => fileName, 9 }; 10 11 try { 12 const { config, error } = ts.readConfigFile(tsConfigPath, ts.sys.readFile); 13 14 if (error) { 15 throw new Error(ts.formatDiagnostic(error, formatDiagnosticsHost)); 16 } 17 18 const jsonFileContents = ts.parseJsonConfigFileContent( 19 config, 20 { 21 ...ts.sys, 22 readDirectory: (_, ext) => [ext ? `file${ext[0]}` : `file.ts`], 23 }, 24 path.dirname(tsConfigPath) 25 ); 26 27 if (jsonFileContents.errors) { 28 // filter out "no inputs were found in config file" error 29 jsonFileContents.errors = jsonFileContents.errors.filter(({ code }) => code !== 18003); 30 } 31 32 if (jsonFileContents.errors?.length) { 33 throw new Error(ts.formatDiagnostic(jsonFileContents.errors[0], formatDiagnosticsHost)); 34 } 35 36 return { compilerOptions: jsonFileContents.options, raw: config.raw }; 37 } catch (error: any) { 38 if (error?.name === 'SyntaxError') { 39 throw new Error('tsconfig.json is invalid:\n' + (error.message ?? '')); 40 } 41 throw error; 42 } 43} 44 45export function importTypeScriptFromProjectOptionally( 46 projectRoot: string 47): typeof import('typescript') | null { 48 const resolvedPath = resolveFrom.silent(projectRoot, 'typescript'); 49 if (!resolvedPath) { 50 return null; 51 } 52 return require(resolvedPath); 53} 54