1
1
var eslint = require ( "eslint" )
2
2
var assign = require ( "object-assign" )
3
3
var loaderUtils = require ( "loader-utils" )
4
- var crypto = require ( "crypto" )
5
- var fs = require ( "fs" )
6
- var findCacheDir = require ( "find-cache-dir" )
7
4
var 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" )
9
8
10
9
var engines = { }
11
- var rules = { }
12
- var cache = null
13
- var cachePath = null
14
10
15
11
/**
16
- * linter
12
+ * printLinterOutput
17
13
*
18
- * @param {String|Buffer } input JavaScript string
14
+ * @param {Object } eslint.executeOnText return value
19
15
* @param {Object } config eslint configuration
20
16
* @param {Object } webpack webpack instance
21
17
* @return {void }
22
18
*/
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 ) {
74
20
// 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
+ ) {
81
27
// quiet filter done now
82
28
// eslint allow rules to be specified in the input between comments
83
29
// so we can found warnings defined in the input itself
84
30
if ( res . warningCount && config . quiet ) {
85
31
res . warningCount = 0
86
32
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
+ } )
91
38
}
92
39
93
40
// if enabled, use eslint auto-fixing where possible
@@ -128,19 +75,21 @@ function lint(input, config, webpack) {
128
75
if ( emitter ) {
129
76
emitter ( messages )
130
77
if ( config . failOnError && res . errorCount ) {
131
- throw new Error ( "Module failed because of a eslint error.\n"
132
- + messages )
78
+ throw new Error (
79
+ "Module failed because of a eslint error.\n" + messages
80
+ )
133
81
}
134
82
else if ( config . failOnWarning && res . warningCount ) {
135
- throw new Error ( "Module failed because of a eslint warning.\n"
136
- + messages )
83
+ throw new Error (
84
+ "Module failed because of a eslint warning.\n" + messages
85
+ )
137
86
}
138
87
}
139
88
else {
140
89
throw new Error (
141
90
"Your module system doesn't support emitWarning. " +
142
- "Update available? \n" +
143
- messages
91
+ "Update available? \n" +
92
+ messages
144
93
)
145
94
}
146
95
}
@@ -155,45 +104,72 @@ function lint(input, config, webpack) {
155
104
* @return {void }
156
105
*/
157
106
module . exports = function ( input , map ) {
107
+ var webpack = this
158
108
var config = assign (
159
109
// loader defaults
160
110
{
161
111
formatter : require ( "eslint/lib/formatters/stylish" ) ,
112
+ cacheIdentifier : JSON . stringify ( {
113
+ "eslint-loader" : pkg . version ,
114
+ eslint : eslint . version ,
115
+ } ) ,
162
116
} ,
163
117
// user defaults
164
118
this . options . eslint || { } ,
165
119
// loader query string
166
120
loaderUtils . getOptions ( this )
167
121
)
168
- this . cacheable ( )
122
+
123
+ var cacheDirectory = config . cacheDirectory
124
+ var cacheIdentifier = config . cacheIdentifier
125
+
126
+ delete config . cacheDirectory
127
+ delete config . cacheIdentifier
169
128
170
129
// Create the engine only once per config
171
130
var configHash = objectHash ( config )
172
131
if ( ! engines [ configHash ] ) {
173
132
engines [ configHash ] = new eslint . CLIEngine ( config )
174
133
}
175
134
176
- // Read the cached information only once and if enable
177
- if ( cache === null ) {
178
- if ( config . cache ) {
179
- var thunk = findCacheDir ( {
180
- name : "eslint-loader" ,
181
- thunk : true ,
182
- create : true ,
183
- } )
184
- cachePath = thunk ( "data.json" ) || os . tmpdir ( ) + "/data.json"
185
- try {
186
- cache = require ( cachePath )
187
- }
188
- catch ( e ) {
189
- cache = { }
135
+ this . cacheable ( )
136
+
137
+ var resourcePath = webpack . resourcePath
138
+ var cwd = process . cwd ( )
139
+
140
+ // remove cwd from resource path in case webpack has been started from project
141
+ // root, to allow having relative paths in .eslintignore
142
+ if ( resourcePath . indexOf ( cwd ) === 0 ) {
143
+ resourcePath = resourcePath . substr ( cwd . length + 1 )
144
+ }
145
+
146
+ var engine = engines [ configHash ]
147
+ // return early if cached
148
+ if ( config . cache ) {
149
+ var callback = this . async ( )
150
+ return cache (
151
+ {
152
+ directory : cacheDirectory ,
153
+ identifier : cacheIdentifier ,
154
+ options : config ,
155
+ source : input ,
156
+ transform : function ( ) {
157
+ return lint ( engine , input , resourcePath )
158
+ } ,
159
+ } ,
160
+ function ( err , res ) {
161
+ if ( err ) {
162
+ return callback ( err )
163
+ }
164
+ printLinterOutput ( res || { } , config , webpack )
165
+ return callback ( null , input , map )
190
166
}
191
- }
192
- else {
193
- cache = false
194
- }
167
+ )
195
168
}
169
+ printLinterOutput ( lint ( engine , input , resourcePath ) , config , this )
170
+ this . callback ( input , map )
171
+ }
196
172
197
- lint ( input , config , this )
198
- this . callback ( null , input , map )
173
+ function lint ( engine , input , resourcePath ) {
174
+ return engine . executeOnText ( input , resourcePath , true )
199
175
}
0 commit comments