@@ -4,6 +4,7 @@ import { CompositeDisposable } from 'atom';
44// eslint-disable-next-line import/no-unresolved
55import { shell } from 'electron' ;
66import Path from 'path' ;
7+ import { diff } from 'deep-object-diff' ;
78
89import console from './console' ;
910import Config from './config' ;
@@ -47,6 +48,7 @@ function eventInvolvesEslintrc (event) {
4748export default {
4849
4950 shouldAutoFix ( textEditor ) {
51+ if ( this . inactive ) { return false ; }
5052 if ( textEditor . isModified ( ) ) { return false ; }
5153 if ( ! Config . get ( 'autofix.fixOnSave' ) ) { return false ; }
5254 if ( ! helpers . hasValidScope ( textEditor , this . scopes ) ) { return false ; }
@@ -58,10 +60,21 @@ export default {
5860 } ,
5961
6062 async activate ( ) {
61- Config . initialize ( atom . project . getPaths ( ) [ 0 ] ) ;
63+ Config . initialize ( ) ;
6264 this . workerPath = Path . join ( __dirname , 'worker.js' ) ;
6365 this . jobManager = new JobManager ( ) ;
6466
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+
6578 // Keep track of whether the user has seen certain notifications. Absent
6679 // any user-initiated changes, they should see each of these no more than
6780 // once per session.
@@ -90,13 +103,17 @@ export default {
90103 ) ,
91104
92105 // 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+ } ) ,
94110
95111 // React to changes that happen either in a .linter-eslint file or the
96112 // base package settings.
97113 Config . onConfigDidChange (
98114 ( config , prevConfig ) => {
99- console . debug ( 'Config changed:' , config , prevConfig ) ;
115+ this . inactive = false ;
116+ console . debug ( 'Config changed:' , config , prevConfig , diff ( prevConfig , config ) ) ;
100117 if ( helpers . configShouldInvalidateWorkerCache ( config , prevConfig ) ) {
101118 this . clearESLintCache ( ) ;
102119 }
@@ -115,6 +132,7 @@ export default {
115132 this . jobManager . createWorker ( ) ;
116133 } )
117134 . catch ( ( ) => {
135+ this . inactive = true ;
118136 this . notifyAboutInvalidNodeBin ( ) ;
119137 } ) ;
120138 }
@@ -138,19 +156,13 @@ export default {
138156 if ( event . path . includes ( 'node_modules' ) ) { return false ; }
139157
140158 if ( eventInvolvesFile ( event , '.linter-eslint' ) ) {
159+ this . inactive = false ;
141160 Config . rescan ( ) ;
142161 }
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 ) ) {
154166 this . clearESLintCache ( ) ;
155167 }
156168 }
@@ -205,13 +217,8 @@ export default {
205217 this . notified . invalidNodeBin = true ;
206218 } ,
207219
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- //
213220 clearESLintCache ( ) {
214- console . warn ( 'Telling the worker to clear its cache! ' ) ;
221+ console . debug ( 'Telling the worker to clear its cache' ) ;
215222 this . jobManager . send ( { type : 'clear-cache' } ) ;
216223 } ,
217224
@@ -309,8 +316,8 @@ export default {
309316 let debugMessage = [
310317 `Atom version: ${ debug . atomVersion } ` ,
311318 `linter-eslint-node version: ${ debug . packageVersion } ` ,
312- `Node path: ${ debug . nodePath } ` ,
313319 `Node version: ${ debug . nodeVersion } ` ,
320+ `Node path: ${ debug . nodePath } ` ,
314321 `ESLint version: ${ debug . eslintVersion } ` ,
315322 `ESLint location: ${ debug . eslintPath } ` ,
316323 `Linting in this project performed by: ${ whichPackageWillLint } ` ,
@@ -324,9 +331,19 @@ export default {
324331 'linter-eslint-node debug information' ,
325332 {
326333 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+ ]
328343 }
329344 ) ;
345+
346+ return debug ;
330347 } ,
331348
332349 // Here we're operating entirely outside the purview of the `linter` package.
@@ -343,6 +360,10 @@ export default {
343360 return ;
344361 }
345362
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+
346367 if ( textEditor . isModified ( ) ) {
347368 atom . notifications . addError (
348369 `linter-eslint-node: Please save before fixing.`
@@ -391,11 +412,13 @@ export default {
391412 // this session), we should do nothing here so that an invalid worker
392413 // behaves as though no linter is present at all.
393414 this . notifyAboutInvalidNodeBin ( ) ;
415+ this . inactive = true ;
394416 return null ;
395417 }
396418
397419 if ( err . type && err . type === 'config-not-found' ) {
398420 if ( Config . get ( 'disabling.disableWhenNoEslintConfig' ) ) {
421+ this . inactive = true ;
399422 return [ ] ;
400423 }
401424 if ( type === 'fix' ) {
@@ -431,12 +454,14 @@ export default {
431454
432455 if ( err . type && err . type === 'no-project' ) {
433456 // No project means nowhere to look for an `.eslintrc`.
457+ this . inactive = true ;
434458 return null ;
435459 }
436460
437461 if ( err . type && err . type === 'version-overlap' ) {
438462 // This is an easy one: we don't need to lint this file because
439463 // `linter-eslint` is present and can handle it. Do nothing.
464+ this . inactive = true ;
440465 return null ;
441466 }
442467
@@ -449,6 +474,7 @@ export default {
449474 // this window has been open; no use spamming it on every lint attempt.
450475 let linterEslintPresent = this . isLegacyPackagePresent ( ) ;
451476 let didNotify = this . notified . incompatibleVersion ;
477+ this . inactive = true ;
452478 if ( linterEslintPresent || didNotify || ! Config . get ( 'warnAboutOldEslint' ) ) {
453479 return null ;
454480 } else {
@@ -471,17 +497,19 @@ export default {
471497 }
472498 ) ;
473499 this . notified . incompatibleVersion = true ;
500+ return null ;
474501 }
475- } else {
476- atom . notifications . addError (
477- `linter-eslint-node Error` ,
478- {
479- description : err . error ,
480- dismissable : true
481- }
482- ) ;
483- return null ;
484502 }
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 ;
485513 } ,
486514
487515 provideLinter ( ) {
@@ -495,6 +523,10 @@ export default {
495523 if ( ! atom . workspace . isTextEditor ( textEditor ) ) {
496524 return null ;
497525 }
526+ if ( this . inactive ) {
527+ console . debug ( 'Inactive; skipping lint' ) ;
528+ return null ;
529+ }
498530 const filePath = textEditor . getPath ( ) ;
499531 if ( ! filePath ) {
500532 // Can't report messages back to Linter without a path.
0 commit comments