-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
fix(typescript-estree): adds support for project services using extended config files #9306
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
JoshuaKGoldberg
merged 22 commits into
typescript-eslint:v8
from
higherorderfunctor:fix/9205-project-service-extends-issue
Jul 28, 2024
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
69aa3c9
refactor(typescript-estree): refactors default project config and add…
higherorderfunctor d32c1e5
test(typescript-estree): fix original failing unit tests
higherorderfunctor 148a9d0
chore(typescript-estree): cleans up PR submission
higherorderfunctor 8bc4b40
chore: merge remote-tracking branch 'upstream/v8' into fix/9205-proje…
higherorderfunctor b6718a1
chore(typescript-estree): fixes test names to use the new function name
higherorderfunctor bde1a26
test(typescript-estree): adds additional tests for coverage
higherorderfunctor 3315345
test(typescript-estree): fixes test for windows
higherorderfunctor 2859ef9
test(typescript-estree): fixes test name typo
higherorderfunctor f01fe0e
chore(typescript-estree): minor cleanup to comments and variables
higherorderfunctor 73e2c78
style(typescript-estree): unifies how compiler options are defined in…
higherorderfunctor 4b8c010
chore(typescript-estree): updates create-program/getParsedConfigFile.…
higherorderfunctor 4f0e2de
chore: merge upstream/v8
higherorderfunctor abd0095
test(typescript-estree): adds initial getParsedConfigFile tests
higherorderfunctor c563b8d
test(typescript-estree): updates createProjectService tests
higherorderfunctor 4d043be
chore: merge upstream/v8
higherorderfunctor c7181b9
test(typescript-estree): cleans up PR
higherorderfunctor 6d23cb1
Merge remote-tracking branch 'upstream/v8' into fix/9205-project-serv…
higherorderfunctor 45551dc
test(typescript-estree): fixes snapshot tests
higherorderfunctor d5f06c5
style(typescript-estree): applies suggestions from code review
higherorderfunctor 1dd15bf
style(typescript-estree): applies manual suggestions from code review
higherorderfunctor ac8c9bc
fixes(typescript-estree): fixes linting errors
higherorderfunctor 4478aea
Update packages/typescript-estree/src/create-program/createProjectSer…
JoshuaKGoldberg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
packages/typescript-estree/src/create-program/getParsedConfigFile.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import * as fs from 'fs'; | ||
import * as path from 'path'; | ||
import type * as ts from 'typescript/lib/tsserverlibrary'; | ||
|
||
import { CORE_COMPILER_OPTIONS } from './shared'; | ||
|
||
/** | ||
* Utility offered by parser to help consumers parse a config file. | ||
* | ||
* @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 getParsedConfigFile( | ||
tsserver: typeof ts, | ||
configFile: string, | ||
projectDirectory?: string, | ||
): ts.ParsedCommandLine { | ||
higherorderfunctor marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition | ||
if (tsserver.sys === undefined) { | ||
throw new Error( | ||
'`getParsedConfigFile` is only supported in a Node-like environment.', | ||
); | ||
} | ||
|
||
const parsed = tsserver.getParsedCommandLineOfConfigFile( | ||
configFile, | ||
CORE_COMPILER_OPTIONS, | ||
{ | ||
onUnRecoverableConfigFileDiagnostic: diag => { | ||
throw new Error(formatDiagnostics([diag])); // ensures that `parsed` is defined. | ||
}, | ||
fileExists: fs.existsSync, | ||
getCurrentDirectory, | ||
readDirectory: tsserver.sys.readDirectory, | ||
readFile: file => fs.readFileSync(file, 'utf-8'), | ||
useCaseSensitiveFileNames: tsserver.sys.useCaseSensitiveFileNames, | ||
}, | ||
); | ||
|
||
if (parsed?.errors.length) { | ||
throw new Error(formatDiagnostics(parsed.errors)); | ||
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
return parsed!; | ||
|
||
function getCurrentDirectory(): string { | ||
return projectDirectory ? path.resolve(projectDirectory) : process.cwd(); | ||
} | ||
|
||
function formatDiagnostics(diagnostics: ts.Diagnostic[]): string | undefined { | ||
return tsserver.formatDiagnostics(diagnostics, { | ||
getCanonicalFileName: f => f, | ||
getCurrentDirectory, | ||
getNewLine: () => '\n', | ||
}); | ||
} | ||
} | ||
|
||
export { getParsedConfigFile }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 112 additions & 0 deletions
112
packages/typescript-estree/tests/lib/getParsedConfigFile.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import path from 'node:path'; | ||
|
||
import * as ts from 'typescript'; | ||
|
||
import { getParsedConfigFile } from '../../src/create-program/getParsedConfigFile'; | ||
|
||
const mockGetParsedCommandLineOfConfigFile = jest.fn(); | ||
|
||
const mockTsserver: typeof ts = { | ||
sys: {} as ts.System, | ||
formatDiagnostics: ts.formatDiagnostics, | ||
getParsedCommandLineOfConfigFile: mockGetParsedCommandLineOfConfigFile, | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
} as any; | ||
|
||
describe('getParsedConfigFile', () => { | ||
afterEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
it('throws an error when tsserver.sys is undefined', () => { | ||
expect(() => | ||
getParsedConfigFile({} as typeof ts, './tsconfig.json'), | ||
).toThrow( | ||
'`getParsedConfigFile` is only supported in a Node-like environment.', | ||
); | ||
}); | ||
|
||
it('uses the cwd as the default project directory', () => { | ||
getParsedConfigFile(mockTsserver, './tsconfig.json'); | ||
expect(mockGetParsedCommandLineOfConfigFile).toHaveBeenCalledTimes(1); | ||
const [_configFileName, _optionsToExtend, host] = | ||
mockGetParsedCommandLineOfConfigFile.mock.calls[0]; | ||
expect(host.getCurrentDirectory()).toBe(process.cwd()); | ||
}); | ||
|
||
it('resolves a relative project directory when passed', () => { | ||
getParsedConfigFile( | ||
mockTsserver, | ||
'./tsconfig.json', | ||
path.relative('./', path.dirname(__filename)), | ||
); | ||
expect(mockGetParsedCommandLineOfConfigFile).toHaveBeenCalledTimes(1); | ||
const [_configFileName, _optionsToExtend, host] = | ||
mockGetParsedCommandLineOfConfigFile.mock.calls[0]; | ||
expect(host.getCurrentDirectory()).toBe(path.dirname(__filename)); | ||
}); | ||
|
||
it('resolves an absolute project directory when passed', () => { | ||
getParsedConfigFile(mockTsserver, './tsconfig.json', __dirname); | ||
expect(mockGetParsedCommandLineOfConfigFile).toHaveBeenCalledTimes(1); | ||
const [_configFileName, _optionsToExtend, host] = | ||
mockGetParsedCommandLineOfConfigFile.mock.calls[0]; | ||
expect(host.getCurrentDirectory()).toBe(__dirname); | ||
}); | ||
|
||
it('throws a diagnostic error when getParsedCommandLineOfConfigFile returns an error', () => { | ||
mockGetParsedCommandLineOfConfigFile.mockReturnValue({ | ||
errors: [ | ||
{ | ||
category: ts.DiagnosticCategory.Error, | ||
code: 1234, | ||
file: ts.createSourceFile('./tsconfig.json', '', { | ||
languageVersion: ts.ScriptTarget.Latest, | ||
}), | ||
start: 0, | ||
length: 0, | ||
messageText: 'Oh no!', | ||
}, | ||
] satisfies ts.Diagnostic[], | ||
}); | ||
expect(() => getParsedConfigFile(mockTsserver, './tsconfig.json')).toThrow( | ||
/.+ error TS1234: Oh no!/, | ||
); | ||
}); | ||
|
||
it('throws a diagnostic error when getParsedCommandLineOfConfigFile throws an error', () => { | ||
mockGetParsedCommandLineOfConfigFile.mockImplementation( | ||
( | ||
...[_configFileName, _optionsToExtend, host]: Parameters< | ||
typeof ts.getParsedCommandLineOfConfigFile | ||
> | ||
) => { | ||
return host.onUnRecoverableConfigFileDiagnostic({ | ||
category: ts.DiagnosticCategory.Error, | ||
code: 1234, | ||
file: ts.createSourceFile('./tsconfig.json', '', { | ||
languageVersion: ts.ScriptTarget.Latest, | ||
}), | ||
start: 0, | ||
length: 0, | ||
messageText: 'Oh no!', | ||
} satisfies ts.Diagnostic); | ||
}, | ||
); | ||
expect(() => getParsedConfigFile(mockTsserver, './tsconfig.json')).toThrow( | ||
/.+ error TS1234: Oh no!/, | ||
); | ||
}); | ||
|
||
it('uses compiler options when parsing a config file succeeds', () => { | ||
const parsedConfigFile = { | ||
options: { strict: true }, | ||
raw: { compilerOptions: { strict: true } }, | ||
errors: [], | ||
}; | ||
mockGetParsedCommandLineOfConfigFile.mockReturnValue(parsedConfigFile); | ||
expect(getParsedConfigFile(mockTsserver, 'tsconfig.json')).toEqual( | ||
expect.objectContaining(parsedConfigFile), | ||
); | ||
}); | ||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.