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