11var eslint = require ( "eslint" )
22var assign = require ( "object-assign" )
33var loaderUtils = require ( "loader-utils" )
4- var crypto = require ( "crypto" )
5- var fs = require ( "fs" )
6- var findCacheDir = require ( "find-cache-dir" )
74var objectHash = require ( "object-hash" )
8- var os = require ( "os" )
5+ var pkg = require ( "./package.json" )
6+ var createCache = require ( "loader-fs-cache" )
7+ var cache = createCache ( "eslint-loader" )
98
109var engines = { }
11- var rules = { }
12- var cache = null
13- var cachePath = null
1410
1511/**
16- * linter
12+ * printLinterOutput
1713 *
18- * @param {String|Buffer } input JavaScript string
14+ * @param {Object } eslint.executeOnText return value
1915 * @param {Object } config eslint configuration
2016 * @param {Object } webpack webpack instance
2117 * @return {void }
2218 */
23- function lint ( input , config , webpack ) {
24- var resourcePath = webpack . resourcePath
25- var cwd = process . cwd ( )
26-
27- // remove cwd from resource path in case webpack has been started from project
28- // root, to allow having relative paths in .eslintignore
29- if ( resourcePath . indexOf ( cwd ) === 0 ) {
30- resourcePath = resourcePath . substr ( cwd . length + 1 )
31- }
32-
33- // get engine
34- var configHash = objectHash ( config )
35- var engine = engines [ configHash ]
36- var rulesHash = rules [ configHash ]
37-
38- var res
39- // If cache is enable and the data are the same as in the cache, just
40- // use them
41- if ( config . cache ) {
42- // just get rules hash once per engine for performance reasons
43- if ( ! rulesHash ) {
44- rulesHash = objectHash ( engine . getConfigForFile ( resourcePath ) )
45- rules [ configHash ] = rulesHash
46- }
47- var inputMD5 = crypto . createHash ( "md5" ) . update ( input ) . digest ( "hex" )
48- if (
49- cache [ resourcePath ] &&
50- cache [ resourcePath ] . hash === inputMD5 &&
51- cache [ resourcePath ] . rules === rulesHash
52- ) {
53- res = cache [ resourcePath ] . res
54- }
55- }
56-
57- // Re-lint the text if the cache off or miss
58- if ( ! res ) {
59- res = engine . executeOnText ( input , resourcePath , true )
60-
61- // Save new results in the cache
62- if ( config . cache ) {
63- cache [ resourcePath ] = {
64- hash : inputMD5 ,
65- rules : rulesHash ,
66- res : res ,
67- }
68- fs . writeFileSync ( cachePath , JSON . stringify ( cache ) )
69- }
70- }
71-
72- // executeOnText ensure we will have res.results[0] only
73-
19+ function printLinterOutput ( res , config , webpack ) {
7420 // skip ignored file warning
75- if ( ! (
76- res . warningCount === 1 &&
77- res . results [ 0 ] . messages [ 0 ] &&
78- res . results [ 0 ] . messages [ 0 ] . message &&
79- res . results [ 0 ] . messages [ 0 ] . message . indexOf ( "ignore" ) > 1
80- ) ) {
21+ if (
22+ ! ( res . warningCount === 1 &&
23+ res . results [ 0 ] . messages [ 0 ] &&
24+ res . results [ 0 ] . messages [ 0 ] . message &&
25+ res . results [ 0 ] . messages [ 0 ] . message . indexOf ( "ignore" ) > 1 )
26+ ) {
8127 // quiet filter done now
8228 // eslint allow rules to be specified in the input between comments
8329 // so we can found warnings defined in the input itself
8430 if ( res . warningCount && config . quiet ) {
8531 res . warningCount = 0
8632 res . results [ 0 ] . warningCount = 0
87- res . results [ 0 ] . messages = res . results [ 0 ] . messages
88- . filter ( function ( message ) {
89- return message . severity !== 1
90- } )
33+ res . results [ 0 ] . messages = res . results [ 0 ] . messages . filter ( function (
34+ message
35+ ) {
36+ return message . severity !== 1
37+ } )
9138 }
9239
9340 // if enabled, use eslint auto-fixing where possible
@@ -135,19 +82,21 @@ function lint(input, config, webpack) {
13582 if ( emitter ) {
13683 emitter ( messages )
13784 if ( config . failOnError && res . errorCount ) {
138- throw new Error ( "Module failed because of a eslint error.\n"
139- + messages )
85+ throw new Error (
86+ "Module failed because of a eslint error.\n" + messages
87+ )
14088 }
14189 else if ( config . failOnWarning && res . warningCount ) {
142- throw new Error ( "Module failed because of a eslint warning.\n"
143- + messages )
90+ throw new Error (
91+ "Module failed because of a eslint warning.\n" + messages
92+ )
14493 }
14594 }
14695 else {
14796 throw new Error (
14897 "Your module system doesn't support emitWarning. " +
149- "Update available? \n" +
150- messages
98+ "Update available? \n" +
99+ messages
151100 )
152101 }
153102 }
@@ -162,45 +111,72 @@ function lint(input, config, webpack) {
162111 * @return {void }
163112 */
164113module . exports = function ( input , map ) {
114+ var webpack = this
165115 var config = assign (
166116 // loader defaults
167117 {
168118 formatter : require ( "eslint/lib/formatters/stylish" ) ,
119+ cacheIdentifier : JSON . stringify ( {
120+ "eslint-loader" : pkg . version ,
121+ eslint : eslint . version ,
122+ } ) ,
169123 } ,
170124 // user defaults
171125 this . options . eslint || { } ,
172126 // loader query string
173127 loaderUtils . getOptions ( this )
174128 )
175- this . cacheable ( )
129+
130+ var cacheDirectory = config . cache
131+ var cacheIdentifier = config . cacheIdentifier
132+
133+ delete config . cacheDirectory
134+ delete config . cacheIdentifier
176135
177136 // Create the engine only once per config
178137 var configHash = objectHash ( config )
179138 if ( ! engines [ configHash ] ) {
180139 engines [ configHash ] = new eslint . CLIEngine ( config )
181140 }
182141
183- // Read the cached information only once and if enable
184- if ( cache === null ) {
185- if ( config . cache ) {
186- var thunk = findCacheDir ( {
187- name : "eslint-loader" ,
188- thunk : true ,
189- create : true ,
190- } )
191- cachePath = thunk ( "data.json" ) || os . tmpdir ( ) + "/data.json"
192- try {
193- cache = require ( cachePath )
194- }
195- catch ( e ) {
196- cache = { }
197- }
198- }
199- else {
200- cache = false
201- }
142+ this . cacheable ( )
143+
144+ var resourcePath = webpack . resourcePath
145+ var cwd = process . cwd ( )
146+
147+ // remove cwd from resource path in case webpack has been started from project
148+ // root, to allow having relative paths in .eslintignore
149+ if ( resourcePath . indexOf ( cwd ) === 0 ) {
150+ resourcePath = resourcePath . substr ( cwd . length + 1 )
202151 }
203152
204- lint ( input , config , this )
153+ var engine = engines [ configHash ]
154+ // return early if cached
155+ if ( config . cache ) {
156+ var callback = this . async ( )
157+ return cache (
158+ {
159+ directory : cacheDirectory ,
160+ identifier : cacheIdentifier ,
161+ options : config ,
162+ source : input ,
163+ transform : function ( ) {
164+ return lint ( engine , input , resourcePath )
165+ } ,
166+ } ,
167+ function ( err , res ) {
168+ if ( err ) {
169+ return callback ( err )
170+ }
171+ printLinterOutput ( res || { } , config , webpack )
172+ return callback ( null , input , map )
173+ }
174+ )
175+ }
176+ printLinterOutput ( lint ( engine , input , resourcePath ) , config , this )
205177 this . callback ( null , input , map )
206178}
179+
180+ function lint ( engine , input , resourcePath ) {
181+ return engine . executeOnText ( input , resourcePath , true )
182+ }
0 commit comments