@@ -8,6 +8,16 @@ import FilesWatcher = require('./FilesWatcher');
8
8
import WorkSet = require( './WorkSet' ) ;
9
9
import NormalizedMessage = require( './NormalizedMessage' ) ;
10
10
import CancellationToken = require( './CancellationToken' ) ;
11
+ import minimatch = require( 'minimatch' ) ;
12
+
13
+ // Need some augmentation here - linterOptions.exclude is not (yet) part of the official
14
+ // types for tslint.
15
+ interface ConfigurationFile extends tslintTypes . Configuration . IConfigurationFile {
16
+ linterOptions ?: {
17
+ typeCheck ?: boolean ;
18
+ exclude ?: string [ ] ;
19
+ } ;
20
+ }
11
21
12
22
class IncrementalChecker {
13
23
programConfigFile : string ;
@@ -19,7 +29,8 @@ class IncrementalChecker {
19
29
files : FilesRegister ;
20
30
21
31
linter : tslintTypes . Linter ;
22
- linterConfig : tslintTypes . Configuration . IConfigurationFile ;
32
+ linterConfig : ConfigurationFile ;
33
+ linterExclusions : minimatch . IMinimatch [ ] ;
23
34
24
35
program : ts . Program ;
25
36
programConfig : ts . ParsedCommandLine ;
@@ -39,6 +50,9 @@ class IncrementalChecker {
39
50
this . workNumber = workNumber || 0 ;
40
51
this . workDivision = workDivision || 1 ;
41
52
this . checkSyntacticErrors = checkSyntacticErrors || false ;
53
+ // Use empty array of exclusions in general to avoid having
54
+ // to check of its existence later on.
55
+ this . linterExclusions = [ ] ;
42
56
43
57
// it's shared between compilations
44
58
this . files = new FilesRegister ( ( ) => ( {
@@ -58,10 +72,10 @@ class IncrementalChecker {
58
72
) ;
59
73
}
60
74
61
- static loadLinterConfig ( configFile : string ) {
75
+ static loadLinterConfig ( configFile : string ) : ConfigurationFile {
62
76
const tslint : typeof tslintTypes = require ( 'tslint' ) ;
63
77
64
- return tslint . Configuration . loadConfigurationFromPath ( configFile ) ;
78
+ return tslint . Configuration . loadConfigurationFromPath ( configFile ) as ConfigurationFile ;
65
79
}
66
80
67
81
static createProgram (
@@ -110,6 +124,10 @@ class IncrementalChecker {
110
124
return new tslint . Linter ( { fix : false } , program ) ;
111
125
}
112
126
127
+ static isFileExcluded ( filePath : string , linterExclusions : minimatch . IMinimatch [ ] ) : boolean {
128
+ return endsWith ( filePath , '.d.ts' ) || linterExclusions . some ( matcher => matcher . match ( filePath ) ) ;
129
+ }
130
+
113
131
nextIteration ( ) {
114
132
if ( ! this . watcher ) {
115
133
this . watcher = new FilesWatcher ( this . watchPaths , [ '.ts' , '.tsx' ] ) ;
@@ -131,6 +149,13 @@ class IncrementalChecker {
131
149
132
150
if ( ! this . linterConfig && this . linterConfigFile ) {
133
151
this . linterConfig = IncrementalChecker . loadLinterConfig ( this . linterConfigFile ) ;
152
+
153
+ if ( this . linterConfig . linterOptions && this . linterConfig . linterOptions . exclude ) {
154
+ // Pre-build minimatch patterns to avoid additional overhead later on.
155
+ // Note: Resolving the path is required to properly match against the full file paths,
156
+ // and also deals with potential cross-platform problems regarding path separators.
157
+ this . linterExclusions = this . linterConfig . linterOptions . exclude . map ( pattern => new minimatch . Minimatch ( path . resolve ( pattern ) ) ) ;
158
+ }
134
159
}
135
160
136
161
this . program = IncrementalChecker . createProgram ( this . programConfig , this . files , this . watcher , this . program ) ;
@@ -179,7 +204,7 @@ class IncrementalChecker {
179
204
180
205
// select files to lint
181
206
const filesToLint = this . files . keys ( ) . filter ( filePath =>
182
- ! endsWith ( filePath , '.d.ts' ) && ! this . files . getData ( filePath ) . linted
207
+ ! this . files . getData ( filePath ) . linted && ! IncrementalChecker . isFileExcluded ( filePath , this . linterExclusions )
183
208
) ;
184
209
185
210
// calculate subset of work to do
0 commit comments