@@ -4,6 +4,7 @@ import { CompositeDisposable } from 'atom';
4
4
// eslint-disable-next-line import/no-unresolved
5
5
import { shell } from 'electron' ;
6
6
import Path from 'path' ;
7
+ import { diff } from 'deep-object-diff' ;
7
8
8
9
import console from './console' ;
9
10
import Config from './config' ;
@@ -47,6 +48,7 @@ function eventInvolvesEslintrc (event) {
47
48
export default {
48
49
49
50
shouldAutoFix ( textEditor ) {
51
+ if ( this . inactive ) { return false ; }
50
52
if ( textEditor . isModified ( ) ) { return false ; }
51
53
if ( ! Config . get ( 'autofix.fixOnSave' ) ) { return false ; }
52
54
if ( ! helpers . hasValidScope ( textEditor , this . scopes ) ) { return false ; }
@@ -58,10 +60,21 @@ export default {
58
60
} ,
59
61
60
62
async activate ( ) {
61
- Config . initialize ( atom . project . getPaths ( ) [ 0 ] ) ;
63
+ Config . initialize ( ) ;
62
64
this . workerPath = Path . join ( __dirname , 'worker.js' ) ;
63
65
this . jobManager = new JobManager ( ) ;
64
66
67
+ // Inactive is the mode we enter when (a) there is no ESLint for this
68
+ // project, or (b) there is a too-old ESLint, or (c) there is a v7 ESLint
69
+ // that we're letting the legacy package handle. We don't bother to send
70
+ // jobs to the worker in this mode; no use making the round-trip. But we
71
+ // will wake up if literally anything changes about the project that might
72
+ // invalidate our assumptions.
73
+ //
74
+ // TODO: Consider killing the worker in inactive mode and restarting it
75
+ // if we leave?
76
+ this . inactive = false ;
77
+
65
78
// Keep track of whether the user has seen certain notifications. Absent
66
79
// any user-initiated changes, they should see each of these no more than
67
80
// once per session.
@@ -90,13 +103,17 @@ export default {
90
103
) ,
91
104
92
105
// Scan for new .linter-eslint config files when project paths change.
93
- atom . project . onDidChangePaths ( ( ) => Config . rescan ( ) ) ,
106
+ atom . project . onDidChangePaths ( ( ) => {
107
+ this . inactive = false ;
108
+ Config . rescan ( ) ;
109
+ } ) ,
94
110
95
111
// React to changes that happen either in a .linter-eslint file or the
96
112
// base package settings.
97
113
Config . onConfigDidChange (
98
114
( config , prevConfig ) => {
99
- console . debug ( 'Config changed:' , config , prevConfig ) ;
115
+ this . inactive = false ;
116
+ console . debug ( 'Config changed:' , config , prevConfig , diff ( prevConfig , config ) ) ;
100
117
if ( helpers . configShouldInvalidateWorkerCache ( config , prevConfig ) ) {
101
118
this . clearESLintCache ( ) ;
102
119
}
@@ -115,6 +132,7 @@ export default {
115
132
this . jobManager . createWorker ( ) ;
116
133
} )
117
134
. catch ( ( ) => {
135
+ this . inactive = true ;
118
136
this . notifyAboutInvalidNodeBin ( ) ;
119
137
} ) ;
120
138
}
@@ -138,19 +156,13 @@ export default {
138
156
if ( event . path . includes ( 'node_modules' ) ) { return false ; }
139
157
140
158
if ( eventInvolvesFile ( event , '.linter-eslint' ) ) {
159
+ this . inactive = false ;
141
160
Config . rescan ( ) ;
142
161
}
143
- // Any creation, deletion, renaming, or modification of an
144
- // `.eslintignore` file anywhere in this project will affect which
145
- // files this linter should ignore, and will confuse old instances of
146
- // `ESLint` inside the worker script because they seem to cache too
147
- // aggressively. So in these cases we've got to clear our cache and
148
- // force new `ESLint` instances to be created.
149
- if ( eventInvolvesFile ( event , '.eslintignore' ) ) {
150
- this . clearESLintCache ( ) ;
151
- }
152
-
153
- if ( eventInvolvesEslintrc ( event ) ) {
162
+ // Instances of `ESLint` cache whatever configuration details were
163
+ // present at instantiation time. If any config changes, we can't
164
+ // re-use old instances.
165
+ if ( eventInvolvesFile ( event , '.eslintignore' ) || eventInvolvesEslintrc ( event ) ) {
154
166
this . clearESLintCache ( ) ;
155
167
}
156
168
}
@@ -205,13 +217,8 @@ export default {
205
217
this . notified . invalidNodeBin = true ;
206
218
} ,
207
219
208
- // We need to tell the worker to clear its cache when
209
- // - any .eslintignore file is changed;
210
- // - certain options are changed that must be declared at `ESLint`
211
- // instantiation time.
212
- //
213
220
clearESLintCache ( ) {
214
- console . warn ( 'Telling the worker to clear its cache! ' ) ;
221
+ console . debug ( 'Telling the worker to clear its cache' ) ;
215
222
this . jobManager . send ( { type : 'clear-cache' } ) ;
216
223
} ,
217
224
@@ -309,8 +316,8 @@ export default {
309
316
let debugMessage = [
310
317
`Atom version: ${ debug . atomVersion } ` ,
311
318
`linter-eslint-node version: ${ debug . packageVersion } ` ,
312
- `Node path: ${ debug . nodePath } ` ,
313
319
`Node version: ${ debug . nodeVersion } ` ,
320
+ `Node path: ${ debug . nodePath } ` ,
314
321
`ESLint version: ${ debug . eslintVersion } ` ,
315
322
`ESLint location: ${ debug . eslintPath } ` ,
316
323
`Linting in this project performed by: ${ whichPackageWillLint } ` ,
@@ -324,9 +331,19 @@ export default {
324
331
'linter-eslint-node debug information' ,
325
332
{
326
333
detail : debugMessage . join ( '\n' ) ,
327
- dismissable : true
334
+ dismissable : true ,
335
+ buttons : [
336
+ {
337
+ text : 'Copy' ,
338
+ onDidClick ( ) {
339
+ atom . clipboard . write ( debugMessage . join ( '\n' ) ) ;
340
+ }
341
+ }
342
+ ]
328
343
}
329
344
) ;
345
+
346
+ return debug ;
330
347
} ,
331
348
332
349
// Here we're operating entirely outside the purview of the `linter` package.
@@ -343,6 +360,10 @@ export default {
343
360
return ;
344
361
}
345
362
363
+ // If we're in inactive mode and we get this far, it's because the user
364
+ // explicitly ran the `Fix Job` command, so we should wake up.
365
+ this . inactive = false ;
366
+
346
367
if ( textEditor . isModified ( ) ) {
347
368
atom . notifications . addError (
348
369
`linter-eslint-node: Please save before fixing.`
@@ -391,11 +412,13 @@ export default {
391
412
// this session), we should do nothing here so that an invalid worker
392
413
// behaves as though no linter is present at all.
393
414
this . notifyAboutInvalidNodeBin ( ) ;
415
+ this . inactive = true ;
394
416
return null ;
395
417
}
396
418
397
419
if ( err . type && err . type === 'config-not-found' ) {
398
420
if ( Config . get ( 'disabling.disableWhenNoEslintConfig' ) ) {
421
+ this . inactive = true ;
399
422
return [ ] ;
400
423
}
401
424
if ( type === 'fix' ) {
@@ -431,12 +454,14 @@ export default {
431
454
432
455
if ( err . type && err . type === 'no-project' ) {
433
456
// No project means nowhere to look for an `.eslintrc`.
457
+ this . inactive = true ;
434
458
return null ;
435
459
}
436
460
437
461
if ( err . type && err . type === 'version-overlap' ) {
438
462
// This is an easy one: we don't need to lint this file because
439
463
// `linter-eslint` is present and can handle it. Do nothing.
464
+ this . inactive = true ;
440
465
return null ;
441
466
}
442
467
@@ -449,6 +474,7 @@ export default {
449
474
// this window has been open; no use spamming it on every lint attempt.
450
475
let linterEslintPresent = this . isLegacyPackagePresent ( ) ;
451
476
let didNotify = this . notified . incompatibleVersion ;
477
+ this . inactive = true ;
452
478
if ( linterEslintPresent || didNotify || ! Config . get ( 'warnAboutOldEslint' ) ) {
453
479
return null ;
454
480
} else {
@@ -471,17 +497,19 @@ export default {
471
497
}
472
498
) ;
473
499
this . notified . incompatibleVersion = true ;
500
+ return null ;
474
501
}
475
- } else {
476
- atom . notifications . addError (
477
- `linter-eslint-node Error` ,
478
- {
479
- description : err . error ,
480
- dismissable : true
481
- }
482
- ) ;
483
- return null ;
484
502
}
503
+
504
+ // Unknown/unhandled error from the worker.
505
+ atom . notifications . addError (
506
+ `linter-eslint-node Error` ,
507
+ {
508
+ description : err . error ,
509
+ dismissable : true
510
+ }
511
+ ) ;
512
+ return null ;
485
513
} ,
486
514
487
515
provideLinter ( ) {
@@ -495,6 +523,10 @@ export default {
495
523
if ( ! atom . workspace . isTextEditor ( textEditor ) ) {
496
524
return null ;
497
525
}
526
+ if ( this . inactive ) {
527
+ console . debug ( 'Inactive; skipping lint' ) ;
528
+ return null ;
529
+ }
498
530
const filePath = textEditor . getPath ( ) ;
499
531
if ( ! filePath ) {
500
532
// Can't report messages back to Linter without a path.
0 commit comments