/
useProvidedPrograms.ts
97 lines (86 loc) · 2.98 KB
/
useProvidedPrograms.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import debug from 'debug';
import * as fs from 'fs';
import * as path from 'path';
import * as ts from 'typescript';
import { Extra } from '../parser-options';
import {
ASTAndProgram,
CORE_COMPILER_OPTIONS,
getAstFromProgram,
} from './shared';
const log = debug('typescript-eslint:typescript-estree:useProvidedProgram');
function useProvidedPrograms(
programInstances: ts.Program[] | Iterable<ts.Program>,
extra: Extra,
): ASTAndProgram | undefined {
log(
'Retrieving ast for %s from provided program instance(s)',
extra.filePath,
);
let astAndProgram: ASTAndProgram | undefined;
for (const programInstance of programInstances) {
astAndProgram = getAstFromProgram(programInstance, extra);
// Stop at the first applicable program instance
if (astAndProgram) {
break;
}
}
if (!astAndProgram) {
const relativeFilePath = path.relative(
extra.tsconfigRootDir || process.cwd(),
extra.filePath,
);
const errorLines = [
'"parserOptions.programs" has been provided for @typescript-eslint/parser.',
`The file was not found in any of the provided program instance(s): ${relativeFilePath}`,
];
throw new Error(errorLines.join('\n'));
}
astAndProgram.program.getTypeChecker(); // ensure parent pointers are set in source files
return astAndProgram;
}
/**
* Utility offered by parser to help consumers construct their own program instance.
*
* @param configFile the path to the tsconfig.json file, relative to `projectDirectory`
* @param projectDirectory the project directory to use as the CWD, defaults to `process.cwd()`
*/
function createProgramFromConfigFile(
configFile: string,
projectDirectory?: string,
): ts.Program {
if (ts.sys === undefined) {
throw new Error(
'`createProgramFromConfigFile` is only supported in a Node-like environment.',
);
}
const parsed = ts.getParsedCommandLineOfConfigFile(
configFile,
CORE_COMPILER_OPTIONS,
{
onUnRecoverableConfigFileDiagnostic: diag => {
throw new Error(formatDiagnostics([diag])); // ensures that `parsed` is defined.
},
fileExists: fs.existsSync,
getCurrentDirectory: () =>
(projectDirectory && path.resolve(projectDirectory)) || process.cwd(),
readDirectory: ts.sys.readDirectory,
readFile: file => fs.readFileSync(file, 'utf-8'),
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
},
);
const result = parsed!; // parsed is not undefined, since we throw on failure.
if (result.errors.length) {
throw new Error(formatDiagnostics(result.errors));
}
const host = ts.createCompilerHost(result.options, true);
return ts.createProgram(result.fileNames, result.options, host);
}
function formatDiagnostics(diagnostics: ts.Diagnostic[]): string | undefined {
return ts.formatDiagnostics(diagnostics, {
getCanonicalFileName: f => f,
getCurrentDirectory: process.cwd,
getNewLine: () => '\n',
});
}
export { useProvidedPrograms, createProgramFromConfigFile };