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
@@ -135,19 +82,21 @@ function lint(input, config, webpack) {
135
82
if ( emitter ) {
136
83
emitter ( messages )
137
84
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
+ )
140
88
}
141
89
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
+ )
144
93
}
145
94
}
146
95
else {
147
96
throw new Error (
148
97
"Your module system doesn't support emitWarning. " +
149
- "Update available? \n" +
150
- messages
98
+ "Update available? \n" +
99
+ messages
151
100
)
152
101
}
153
102
}
@@ -162,45 +111,72 @@ function lint(input, config, webpack) {
162
111
* @return {void }
163
112
*/
164
113
module . exports = function ( input , map ) {
114
+ var webpack = this
165
115
var config = assign (
166
116
// loader defaults
167
117
{
168
118
formatter : require ( "eslint/lib/formatters/stylish" ) ,
119
+ cacheIdentifier : JSON . stringify ( {
120
+ "eslint-loader" : pkg . version ,
121
+ eslint : eslint . version ,
122
+ } ) ,
169
123
} ,
170
124
// user defaults
171
125
this . options . eslint || { } ,
172
126
// loader query string
173
127
loaderUtils . getOptions ( this )
174
128
)
175
- this . cacheable ( )
129
+
130
+ var cacheDirectory = config . cache
131
+ var cacheIdentifier = config . cacheIdentifier
132
+
133
+ delete config . cacheDirectory
134
+ delete config . cacheIdentifier
176
135
177
136
// Create the engine only once per config
178
137
var configHash = objectHash ( config )
179
138
if ( ! engines [ configHash ] ) {
180
139
engines [ configHash ] = new eslint . CLIEngine ( config )
181
140
}
182
141
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 )
202
151
}
203
152
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 )
205
177
this . callback ( null , input , map )
206
178
}
179
+
180
+ function lint ( engine , input , resourcePath ) {
181
+ return engine . executeOnText ( input , resourcePath , true )
182
+ }
0 commit comments