@@ -24,6 +24,7 @@ const fs = require('fs');
24
24
const remapIstanbul = require ( 'remap-istanbul' ) ;
25
25
const istanbul = require ( 'istanbul' ) ;
26
26
const glob = require ( 'glob' ) ;
27
+ const _ = require ( 'lodash' ) ;
27
28
28
29
/**
29
30
* Hygiene works by creating cascading subsets of all our files and
@@ -41,7 +42,6 @@ const all = [
41
42
42
43
const tsFilter = [
43
44
'src/**/*.ts' ,
44
- 'src/client/**/*.ts' ,
45
45
] ;
46
46
47
47
const indentationFilter = [
@@ -60,7 +60,7 @@ const tslintFilter = [
60
60
'!resources/**/*' ,
61
61
'!snippets/**/*' ,
62
62
'!syntaxes/**/*' ,
63
- '!**/typings/**/*' ,
63
+ '!**/typings/**/*'
64
64
] ;
65
65
66
66
const copyrightHeader = [
@@ -78,7 +78,7 @@ gulp.task('watch', ['hygiene-modified', 'hygiene-watch']);
78
78
79
79
gulp . task ( 'debugger-coverage' , ( ) => buildDebugAdapterCoverage ( ) ) ;
80
80
81
- gulp . task ( 'hygiene-watch' , ( ) => gulp . watch ( tsFilter , debounce ( ( ) => run ( { mode : 'changes' } ) , 1000 ) ) ) ;
81
+ gulp . task ( 'hygiene-watch' , ( ) => gulp . watch ( tsFilter , debounce ( ( ) => run ( { mode : 'changes' , skipFormatCheck : true , skipIndentationCheck : true , skipCopyrightCheck : true } ) , 100 ) ) ) ;
82
82
83
83
gulp . task ( 'hygiene-all' , ( ) => run ( { mode : 'all' } ) ) ;
84
84
@@ -131,20 +131,52 @@ function buildDebugAdapterCoverage() {
131
131
* @property {'changes'|'staged'|'all'|'compile' } [mode=] - Mode.
132
132
* @property {boolean= } skipIndentationCheck - Skip indentation checks.
133
133
* @property {boolean= } skipFormatCheck - Skip format checks.
134
+ * @property {boolean= } skipCopyrightCheck - Skip copyright checks.
134
135
* @property {boolean= } skipLinter - Skip linter.
135
136
*/
136
137
138
+ const tsProjectMap = { } ;
139
+ /**
140
+ *
141
+ * @param {hygieneOptions } options
142
+ */
143
+ function getTsProject ( options ) {
144
+ const tsOptions = options . mode === 'compile' ? undefined : { strict : true , noImplicitAny : false , noImplicitThis : false } ;
145
+ const mode = tsOptions && tsOptions . mode ? tsOptions . mode : '' ;
146
+ return tsProjectMap [ mode ] ? tsProjectMap [ mode ] : tsProjectMap [ mode ] = ts . createProject ( 'tsconfig.json' , tsOptions ) ;
147
+ }
148
+
149
+ let configuration ;
150
+ let program ;
151
+ let linter ;
152
+ /**
153
+ *
154
+ * @param {hygieneOptions } options
155
+ */
156
+ function getLinter ( options ) {
157
+ configuration = configuration ? configuration : tslint . Configuration . findConfiguration ( null , '.' ) ;
158
+ program = program ? program : tslint . Linter . createProgram ( './tsconfig.json' ) ;
159
+ linter = linter ? linter : new tslint . Linter ( { formatter : 'json' } , program ) ;
160
+ return { linter, configuration } ;
161
+ }
162
+ let compilationInProgress = false ;
163
+ let reRunCompilation = false ;
137
164
/**
138
165
*
139
166
* @param {hygieneOptions } options
140
167
* @returns {NodeJS.ReadWriteStream }
141
168
*/
142
169
const hygiene = ( options ) => {
170
+ if ( compilationInProgress ) {
171
+ reRunCompilation = true ;
172
+ return ;
173
+ }
174
+ const started = new Date ( ) . getTime ( ) ;
175
+ compilationInProgress = true ;
143
176
options = options || { } ;
144
177
let errorCount = 0 ;
145
- const addedFiles = getAddedFilesSync ( ) ;
178
+ const addedFiles = options . skipCopyrightCheck ? [ ] : getAddedFilesSync ( ) ;
146
179
console . log ( colors . blue ( 'Hygiene started.' ) ) ;
147
-
148
180
const copyrights = es . through ( function ( file ) {
149
181
if ( addedFiles . indexOf ( file . path ) !== - 1 && file . contents . toString ( 'utf8' ) . indexOf ( copyrightHeader ) !== 0 ) {
150
182
// Use tslint format.
@@ -228,15 +260,16 @@ const hygiene = (options) => {
228
260
. filter ( reported => reported === true )
229
261
. length > 0 ;
230
262
}
231
- const configuration = tslint . Configuration . findConfiguration ( null , '.' ) ;
232
- const program = tslint . Linter . createProgram ( './tsconfig.json' ) ;
233
- const linter = new tslint . Linter ( { formatter : 'json' } , program ) ;
263
+
264
+ const { linter, configuration } = getLinter ( options ) ;
234
265
const tsl = es . through ( function ( file ) {
235
266
const contents = file . contents . toString ( 'utf8' ) ;
236
267
// Don't print anything to the console, we'll do that.
237
268
// Yes this is a hack, but tslinter doesn't provide an option to prevent this.
238
269
const oldWarn = console . warn ;
239
270
console . warn = ( ) => { } ;
271
+ linter . failures = [ ] ;
272
+ linter . fixes = [ ] ;
240
273
linter . lint ( file . relative , contents , configuration . results ) ;
241
274
console . warn = oldWarn ;
242
275
const result = linter . getResult ( ) ;
@@ -259,8 +292,7 @@ const hygiene = (options) => {
259
292
this . emit ( 'data' , file ) ;
260
293
} ) ;
261
294
262
- const tsOptions = options . mode === 'compile' ? undefined : { strict : true , noImplicitAny : false , noImplicitThis : false } ;
263
- const tsProject = ts . createProject ( 'tsconfig.json' , tsOptions ) ;
295
+ const tsProject = getTsProject ( options ) ;
264
296
265
297
const tsc = function ( ) {
266
298
function customReporter ( ) {
@@ -294,8 +326,11 @@ const hygiene = (options) => {
294
326
}
295
327
296
328
result = result
297
- . pipe ( filter ( tslintFilter ) )
298
- . pipe ( copyrights ) ;
329
+ . pipe ( filter ( tslintFilter ) ) ;
330
+
331
+ if ( ! options . skipCopyrightCheck ) {
332
+ result = result . pipe ( copyrights ) ;
333
+ }
299
334
300
335
if ( ! options . skipFormatCheck ) {
301
336
// result = result
@@ -306,7 +341,7 @@ const hygiene = (options) => {
306
341
result = result
307
342
. pipe ( tsl ) ;
308
343
}
309
-
344
+ let totalTime = 0 ;
310
345
result = result
311
346
. pipe ( tscFilesTracker )
312
347
. pipe ( sourcemaps . init ( ) )
@@ -323,15 +358,22 @@ const hygiene = (options) => {
323
358
. pipe ( gulp . dest ( dest ) )
324
359
. pipe ( es . through ( null , function ( ) {
325
360
if ( errorCount > 0 ) {
326
- const errorMessage = `Hygiene failed with errors 👎 . Check 'gulpfile.js'.` ;
361
+ const errorMessage = `Hygiene failed with errors 👎 . Check 'gulpfile.js' (completed in ${ new Date ( ) . getTime ( ) - started } ms) .` ;
327
362
console . error ( colors . red ( errorMessage ) ) ;
328
363
exitHandler ( options ) ;
329
364
} else {
330
- console . log ( colors . green ( ' Hygiene passed with 0 errors 👍.' ) ) ;
365
+ console . log ( colors . green ( ` Hygiene passed with 0 errors 👍 (completed in ${ new Date ( ) . getTime ( ) - started } ms).` ) ) ;
331
366
}
332
367
// Reset error counter.
333
368
errorCount = 0 ;
334
369
reportedLinterFailures = [ ] ;
370
+ compilationInProgress = false ;
371
+ if ( reRunCompilation ) {
372
+ reRunCompilation = false ;
373
+ setTimeout ( ( ) => {
374
+ hygiene ( options ) ;
375
+ } , 10 ) ;
376
+ }
335
377
this . emit ( 'end' ) ;
336
378
} ) )
337
379
. on ( 'error' , exitHandler . bind ( this , options ) ) ;
@@ -346,6 +388,7 @@ const hygiene = (options) => {
346
388
* @property {string[]= } files - Optional list of files to be modified.
347
389
* @property {boolean= } skipIndentationCheck - Skip indentation checks.
348
390
* @property {boolean= } skipFormatCheck - Skip format checks.
391
+ * @property {boolean= } skipCopyrightCheck - Skip copyright checks.
349
392
* @property {boolean= } skipLinter - Skip linter.
350
393
* @property {boolean= } watch - Watch mode.
351
394
*/
@@ -391,7 +434,15 @@ function getAddedFilesSync() {
391
434
return out
392
435
. split ( / \r ? \n / )
393
436
. filter ( l => ! ! l )
394
- . filter ( l => l . startsWith ( 'A' ) || l . startsWith ( '??' ) )
437
+ . filter ( l => _ . intersection ( [ 'A' , '?' ] , l . substring ( 0 , 2 ) . trim ( ) . split ( ) ) . length > 0 )
438
+ . map ( l => path . join ( __dirname , l . substring ( 2 ) . trim ( ) ) ) ;
439
+ }
440
+ function getModifiedFilesSync ( ) {
441
+ const out = cp . execSync ( 'git status -u -s' , { encoding : 'utf8' } ) ;
442
+ return out
443
+ . split ( / \r ? \n / )
444
+ . filter ( l => ! ! l )
445
+ . filter ( l => _ . intersection ( [ 'M' , 'A' , 'R' , 'C' ] , l . substring ( 0 , 2 ) . trim ( ) . split ( ) ) . length > 0 )
395
446
. map ( l => path . join ( __dirname , l . substring ( 2 ) . trim ( ) ) ) ;
396
447
}
397
448
@@ -404,8 +455,7 @@ function getFilesToProcess(options) {
404
455
405
456
// If we need only modified files, then filter the glob.
406
457
if ( options && options . mode === 'changes' ) {
407
- return gulp . src ( all , gulpSrcOptions )
408
- . pipe ( gitmodified ( [ 'M' , 'A' , 'AM' , 'D' , 'R' , 'C' , 'U' , '??' ] ) ) ;
458
+ return gulp . src ( getModifiedFilesSync ( ) , gulpSrcOptions ) ;
409
459
}
410
460
411
461
if ( options && options . mode === 'staged' ) {
0 commit comments