diff --git a/packages/typescript-estree/src/tsconfig-parser.ts b/packages/typescript-estree/src/tsconfig-parser.ts index 135bbdfbc04..d953b39d8ea 100644 --- a/packages/typescript-estree/src/tsconfig-parser.ts +++ b/packages/typescript-estree/src/tsconfig-parser.ts @@ -50,6 +50,12 @@ function diagnosticReporter(diagnostic: ts.Diagnostic): void { const noopFileWatcher = { close: () => {} }; +function getTsconfigPath(tsconfigPath: string, extra: Extra): string { + return path.isAbsolute(tsconfigPath) + ? tsconfigPath + : path.join(extra.tsconfigRootDir || process.cwd(), tsconfigPath); +} + /** * Calculate project environments using options provided by consumer and paths from config * @param code The code being linted @@ -64,7 +70,6 @@ export function calculateProjectParserOptions( extra: Extra, ): ts.Program[] { const results = []; - const tsconfigRootDir = extra.tsconfigRootDir; // preserve reference to code and file being linted currentLintOperationState.code = code; @@ -77,11 +82,8 @@ export function calculateProjectParserOptions( watchCallback(filePath, ts.FileWatcherEventKind.Changed); } - for (let tsconfigPath of extra.projects) { - // if absolute paths aren't provided, make relative to tsconfigRootDir - if (!path.isAbsolute(tsconfigPath)) { - tsconfigPath = path.join(tsconfigRootDir, tsconfigPath); - } + for (let rawTsconfigPath of extra.projects) { + const tsconfigPath = getTsconfigPath(rawTsconfigPath, extra); const existingWatch = knownWatchProgramMap.get(tsconfigPath); @@ -193,12 +195,7 @@ export function createProgram(code: string, filePath: string, extra: Extra) { return undefined; } - let tsconfigPath = extra.projects[0]; - - // if absolute paths aren't provided, make relative to tsconfigRootDir - if (!path.isAbsolute(tsconfigPath)) { - tsconfigPath = path.join(extra.tsconfigRootDir, tsconfigPath); - } + const tsconfigPath = getTsconfigPath(extra.projects[0], extra); const commandLine = ts.getParsedCommandLineOfConfigFile( tsconfigPath, diff --git a/packages/typescript-estree/tests/lib/semanticInfo.ts b/packages/typescript-estree/tests/lib/semanticInfo.ts index ab7df7278a0..df3fed691a4 100644 --- a/packages/typescript-estree/tests/lib/semanticInfo.ts +++ b/packages/typescript-estree/tests/lib/semanticInfo.ts @@ -48,6 +48,21 @@ describe('semanticInfo', () => { ); }); + it(`should cache the created ts.program`, () => { + const filename = testFiles[0]; + const code = readFileSync(filename, 'utf8'); + const options = createOptions(filename); + const optionsProjectString = { + ...options, + project: './tsconfig.json', + }; + expect( + parseAndGenerateServices(code, optionsProjectString).services.program, + ).toBe( + parseAndGenerateServices(code, optionsProjectString).services.program, + ); + }); + it(`should handle "project": "./tsconfig.json" and "project": ["./tsconfig.json"] the same`, () => { const filename = testFiles[0]; const code = readFileSync(filename, 'utf8'); @@ -65,6 +80,38 @@ describe('semanticInfo', () => { ); }); + it(`should resolve absolute and relative tsconfig paths the same`, () => { + const filename = testFiles[0]; + const code = readFileSync(filename, 'utf8'); + const options = createOptions(filename); + const optionsAbsolutePath = { + ...options, + project: `${__dirname}/../fixtures/semanticInfo/tsconfig.json`, + }; + const optionsRelativePath = { + ...options, + project: `./tsconfig.json`, + }; + const absolutePathResult = parseAndGenerateServices( + code, + optionsAbsolutePath, + ); + const relativePathResult = parseAndGenerateServices( + code, + optionsRelativePath, + ); + if (absolutePathResult.services.program === undefined) { + throw new Error('Unable to create ts.program for absolute tsconfig'); + } else if (relativePathResult.services.program === undefined) { + throw new Error('Unable to create ts.program for relative tsconfig'); + } + expect( + absolutePathResult.services.program.getResolvedProjectReferences(), + ).toEqual( + relativePathResult.services.program.getResolvedProjectReferences(), + ); + }); + // case-specific tests it('isolated-file tests', () => { const fileName = resolve(FIXTURES_DIR, 'isolated-file.src.ts');