11import * as path from 'path' ;
2- import * as pkgConf from 'pkg-conf' ;
3- import {
4- ScriptTarget ,
5- ModuleResolutionKind ,
6- flattenDiagnosticMessageText ,
7- CompilerOptions ,
8- createProgram ,
9- JsxEmit ,
10- SyntaxKind ,
11- SourceFile ,
12- Diagnostic as TSDiagnostic
13- } from 'typescript' ;
14- import { Diagnostic , DiagnosticCode , Context , Position } from './interfaces' ;
2+ import { flattenDiagnosticMessageText , createProgram , SyntaxKind , Diagnostic as TSDiagnostic , Program , SourceFile } from 'typescript' ;
3+ import { Diagnostic , DiagnosticCode , Context , Location } from './interfaces' ;
154
165// List of diagnostic codes that should be ignored
176const ignoredDiagnostics = new Set < number > ( [
187 DiagnosticCode . AwaitIsOnlyAllowedInAsyncFunction
198] ) ;
209
21- const loadConfig = ( cwd : string ) : CompilerOptions => {
22- const config = pkgConf . sync ( 'tsd-check' , {
23- cwd,
24- defaults : {
25- compilerOptions : {
26- strict : true ,
27- jsx : JsxEmit . React ,
28- target : ScriptTarget . ES2017
29- }
30- }
31- } ) ;
32-
33- return {
34- ...config . compilerOptions ,
35- ...{
36- moduleResolution : ModuleResolutionKind . NodeJs ,
37- skipLibCheck : true
38- }
39- } ;
40- } ;
10+ const diagnosticCodesToIgnore = new Set < DiagnosticCode > ( [
11+ DiagnosticCode . ArgumentTypeIsNotAssignableToParameterType ,
12+ DiagnosticCode . PropertyDoesNotExistOnType ,
13+ DiagnosticCode . CannotAssignToReadOnlyProperty
14+ ] ) ;
4115
4216/**
4317 * Extract all the `expectError` statements and convert it to a range map.
4418 *
45- * @param sourceFile - File to extract the statements from .
19+ * @param program - The TypeScript program .
4620 */
47- const extractExpectErrorRanges = ( sourceFile : SourceFile ) => {
48- const expectedErrors = new Map < Position , Pick < Diagnostic , 'fileName' | 'line' | 'column' > > ( ) ;
21+ const extractExpectErrorRanges = ( program : Program ) => {
22+ const expectedErrors = new Map < Location , Pick < Diagnostic , 'fileName' | 'line' | 'column' > > ( ) ;
4923
50- for ( const statement of sourceFile . statements ) {
51- if ( statement . kind !== SyntaxKind . ExpressionStatement || ! statement . getText ( ) . startsWith ( 'expectError' ) ) {
52- continue ;
53- }
24+ for ( const sourceFile of program . getSourceFiles ( ) ) {
25+ for ( const statement of sourceFile . statements ) {
26+ if ( statement . kind !== SyntaxKind . ExpressionStatement || ! statement . getText ( ) . startsWith ( 'expectError' ) ) {
27+ continue ;
28+ }
5429
55- const position = {
56- start : statement . getStart ( ) ,
57- end : statement . getEnd ( )
58- } ;
30+ const location = {
31+ fileName : statement . getSourceFile ( ) . fileName ,
32+ start : statement . getStart ( ) ,
33+ end : statement . getEnd ( )
34+ } ;
5935
60- const pos = statement . getSourceFile ( ) . getLineAndCharacterOfPosition ( statement . getStart ( ) ) ;
36+ const pos = statement . getSourceFile ( ) . getLineAndCharacterOfPosition ( statement . getStart ( ) ) ;
6137
62- expectedErrors . set ( position , {
63- fileName : statement . getSourceFile ( ) . fileName ,
64- line : pos . line + 1 ,
65- column : pos . character
66- } ) ;
38+ expectedErrors . set ( location , {
39+ fileName : location . fileName ,
40+ line : pos . line + 1 ,
41+ column : pos . character
42+ } ) ;
43+ }
6744 }
6845
6946 return expectedErrors ;
7047} ;
7148
72- const diagnosticCodesToIgnore = [
73- DiagnosticCode . ArgumentTypeIsNotAssignableToParameterType ,
74- DiagnosticCode . PropertyDoesNotExistOnType ,
75- DiagnosticCode . CannotAssignToReadOnlyProperty
76- ] ;
77-
7849/**
7950 * Check if the provided diagnostic should be ignored.
8051 *
8152 * @param diagnostic - The diagnostic to validate.
8253 * @param expectedErrors - Map of the expected errors.
8354 * @return Boolean indicating if the diagnostic should be ignored or not.
8455 */
85- const ignoreDiagnostic = ( diagnostic : TSDiagnostic , expectedErrors : Map < Position , any > ) : boolean => {
56+ const ignoreDiagnostic = ( diagnostic : TSDiagnostic , expectedErrors : Map < Location , any > ) : boolean => {
8657 if ( ignoredDiagnostics . has ( diagnostic . code ) ) {
8758 // Filter out diagnostics which are present in the `ignoredDiagnostics` set
8859 return true ;
8960 }
9061
91- if ( ! diagnosticCodesToIgnore . includes ( diagnostic . code ) ) {
62+ if ( ! diagnosticCodesToIgnore . has ( diagnostic . code ) ) {
9263 return false ;
9364 }
9465
95- for ( const [ range ] of expectedErrors ) {
66+ const diagnosticFileName = ( diagnostic . file as SourceFile ) . fileName ;
67+
68+ for ( const [ location ] of expectedErrors ) {
9669 const start = diagnostic . start as number ;
9770
98- if ( start > range . start && start < range . end ) {
71+ if ( diagnosticFileName === location . fileName && start > location . start && start < location . end ) {
9972 // Remove the expected error from the Map so it's not being reported as failure
100- expectedErrors . delete ( range ) ;
73+ expectedErrors . delete ( location ) ;
10174 return true ;
10275 }
10376 }
@@ -112,19 +85,17 @@ const ignoreDiagnostic = (diagnostic: TSDiagnostic, expectedErrors: Map<Position
11285 * @returns List of diagnostics
11386 */
11487export const getDiagnostics = ( context : Context ) : Diagnostic [ ] => {
115- const compilerOptions = loadConfig ( context . cwd ) ;
116-
117- const fileName = path . join ( context . cwd , context . testFile ) ;
88+ const fileNames = context . testFiles . map ( fileName => path . join ( context . cwd , fileName ) ) ;
11889
11990 const result : Diagnostic [ ] = [ ] ;
12091
121- const program = createProgram ( [ fileName ] , compilerOptions ) ;
92+ const program = createProgram ( fileNames , context . config . compilerOptions ) ;
12293
12394 const diagnostics = program
12495 . getSemanticDiagnostics ( )
12596 . concat ( program . getSyntacticDiagnostics ( ) ) ;
12697
127- const expectedErrors = extractExpectErrorRanges ( program . getSourceFile ( fileName ) as SourceFile ) ;
98+ const expectedErrors = extractExpectErrorRanges ( program ) ;
12899
129100 for ( const diagnostic of diagnostics ) {
130101 if ( ! diagnostic . file || ignoreDiagnostic ( diagnostic , expectedErrors ) ) {
0 commit comments