@@ -2,28 +2,31 @@ const fs = require('fs')
2
2
const globby = require ( 'globby' )
3
3
4
4
const renamedArrayArgs = {
5
- ext : 'extensions' ,
6
- env : 'envs' ,
7
- global : 'globals' ,
8
- rulesdir : 'rulePaths' ,
9
- plugin : 'plugins' ,
10
- 'ignore-pattern' : 'ignorePattern'
5
+ ext : [ 'extensions' ] ,
6
+ rulesdir : [ 'rulePaths' ] ,
7
+ plugin : [ 'overrideConfig' , 'plugins' ] ,
8
+ 'ignore-pattern' : [ 'overrideConfig' , 'ignorePatterns' ]
9
+ }
10
+
11
+ const renamedObjectArgs = {
12
+ env : { key : [ 'overrideConfig' , 'env' ] , def : true } ,
13
+ global : { key : [ 'overrideConfig' , 'globals' ] , def : false }
11
14
}
12
15
13
16
const renamedArgs = {
14
- 'inline-config' : 'allowInlineConfig' ,
15
- rule : ' rules',
16
- eslintrc : 'useEslintrc' ,
17
- c : 'configFile' ,
18
- config : 'configFile' ,
19
- 'output-file' : 'outputFile'
17
+ 'inline-config' : [ 'allowInlineConfig' ] ,
18
+ rule : [ 'overrideConfig' , ' rules'] ,
19
+ eslintrc : [ 'useEslintrc' ] ,
20
+ c : [ 'overrideConfigFile' ] ,
21
+ config : [ 'overrideConfigFile' ] ,
22
+ 'output-file' : [ 'outputFile' ]
20
23
}
21
24
22
- module . exports = function lint ( args = { } , api ) {
25
+ module . exports = async function lint ( args = { } , api ) {
23
26
const path = require ( 'path' )
24
27
const cwd = api . resolve ( '.' )
25
28
const { log, done, exit, chalk, loadModule } = require ( '@vue/cli-shared-utils' )
26
- const { CLIEngine } = loadModule ( 'eslint' , cwd , true ) || require ( 'eslint' )
29
+ const { ESLint } = loadModule ( 'eslint' , cwd , true ) || require ( 'eslint' )
27
30
const extensions = require ( './eslintOptions' ) . extensions ( api )
28
31
29
32
const argsConfig = normalizeConfig ( args )
@@ -37,34 +40,71 @@ module.exports = function lint (args = {}, api) {
37
40
const noFixWarningsPredicate = ( lintResult ) => lintResult . severity === 2
38
41
config . fix = config . fix && ( noFixWarnings ? noFixWarningsPredicate : true )
39
42
40
- if ( ! fs . existsSync ( api . resolve ( '.eslintignore' ) ) && ! config . ignorePattern ) {
43
+ if ( ! config . overrideConfig ) {
44
+ config . overrideConfig = { }
45
+ }
46
+
47
+ if ( ! fs . existsSync ( api . resolve ( '.eslintignore' ) ) && ! config . overrideConfig . ignorePatterns ) {
41
48
// .eslintrc.js files (ignored by default)
42
49
// However, we need to lint & fix them so as to make the default generated project's
43
50
// code style consistent with user's selected eslint config.
44
51
// Though, if users provided their own `.eslintignore` file, we don't want to
45
52
// add our own customized ignore pattern here (in eslint, ignorePattern is
46
53
// an addition to eslintignore, i.e. it can't be overridden by user),
47
54
// following the principle of least astonishment.
48
- config . ignorePattern = [
55
+ config . overrideConfig . ignorePatterns = [
49
56
'!.*.js' ,
50
57
'!{src,tests}/**/.*.js'
51
58
]
52
59
}
53
-
54
- const engine = new CLIEngine ( config )
55
-
56
- const defaultFilesToLint = [
60
+ /** @type {import('eslint').ESLint } */
61
+ const eslint = new ESLint ( Object . fromEntries ( [
62
+
63
+ // File enumeration
64
+ 'cwd' ,
65
+ 'errorOnUnmatchedPattern' ,
66
+ 'extensions' ,
67
+ 'globInputPaths' ,
68
+ 'ignore' ,
69
+ 'ignorePath' ,
70
+
71
+ // Linting
72
+ 'allowInlineConfig' ,
73
+ 'baseConfig' ,
74
+ 'overrideConfig' ,
75
+ 'overrideConfigFile' ,
76
+ 'plugins' ,
77
+ 'reportUnusedDisableDirectives' ,
78
+ 'resolvePluginsRelativeTo' ,
79
+ 'rulePaths' ,
80
+ 'useEslintrc' ,
81
+
82
+ // Autofix
83
+ 'fix' ,
84
+ 'fixTypes' ,
85
+
86
+ // Cache-related
87
+ 'cache' ,
88
+ 'cacheLocation' ,
89
+ 'cacheStrategy'
90
+ ] . map ( k => [ k , config [ k ] ] ) ) )
91
+
92
+ const defaultFilesToLint = [ ]
93
+
94
+ for ( const pattern of [
57
95
'src' ,
58
96
'tests' ,
59
97
// root config files
60
98
'*.js' ,
61
99
'.*.js'
62
- ]
63
- . filter ( pattern =>
64
- globby
65
- . sync ( pattern , { cwd, absolute : true } )
66
- . some ( p => ! engine . isPathIgnored ( p ) )
67
- )
100
+ ] ) {
101
+ if ( ( await Promise . all ( globby
102
+ . sync ( pattern , { cwd, absolute : true } )
103
+ . map ( p => eslint . isPathIgnored ( p ) ) ) )
104
+ . some ( r => ! r ) ) {
105
+ defaultFilesToLint . push ( pattern )
106
+ }
107
+ }
68
108
69
109
const files = args . _ && args . _ . length
70
110
? args . _
@@ -79,51 +119,53 @@ module.exports = function lint (args = {}, api) {
79
119
if ( ! api . invoking ) {
80
120
process . cwd = ( ) => cwd
81
121
}
82
- const report = engine . executeOnFiles ( files )
122
+ const resultResults = await eslint . lintFiles ( files )
123
+ const reportErrorCount = resultResults . reduce ( ( p , c ) => p + c . errorCount , 0 )
124
+ const reportWarningCount = resultResults . reduce ( ( p , c ) => p + c . warningCount , 0 )
83
125
process . cwd = processCwd
84
126
85
- const formatter = engine . getFormatter ( args . format || 'codeframe' )
127
+ const formatter = await eslint . loadFormatter ( args . format || 'codeframe' )
86
128
87
129
if ( config . outputFile ) {
88
130
const outputFilePath = path . resolve ( config . outputFile )
89
131
try {
90
- fs . writeFileSync ( outputFilePath , formatter ( report . results ) )
132
+ fs . writeFileSync ( outputFilePath , formatter . format ( resultResults ) )
91
133
log ( `Lint results saved to ${ chalk . blue ( outputFilePath ) } ` )
92
134
} catch ( err ) {
93
135
log ( `Error saving lint results to ${ chalk . blue ( outputFilePath ) } : ${ chalk . red ( err ) } ` )
94
136
}
95
137
}
96
138
97
139
if ( config . fix ) {
98
- CLIEngine . outputFixes ( report )
140
+ await ESLint . outputFixes ( resultResults )
99
141
}
100
142
101
143
const maxErrors = argsConfig . maxErrors || 0
102
144
const maxWarnings = typeof argsConfig . maxWarnings === 'number' ? argsConfig . maxWarnings : Infinity
103
- const isErrorsExceeded = report . errorCount > maxErrors
104
- const isWarningsExceeded = report . warningCount > maxWarnings
145
+ const isErrorsExceeded = reportErrorCount > maxErrors
146
+ const isWarningsExceeded = reportWarningCount > maxWarnings
105
147
106
148
if ( ! isErrorsExceeded && ! isWarningsExceeded ) {
107
149
if ( ! args . silent ) {
108
- const hasFixed = report . results . some ( f => f . output )
150
+ const hasFixed = resultResults . some ( f => f . output )
109
151
if ( hasFixed ) {
110
152
log ( `The following files have been auto-fixed:` )
111
153
log ( )
112
- report . results . forEach ( f => {
154
+ resultResults . forEach ( f => {
113
155
if ( f . output ) {
114
156
log ( ` ${ chalk . blue ( path . relative ( cwd , f . filePath ) ) } ` )
115
157
}
116
158
} )
117
159
log ( )
118
160
}
119
- if ( report . warningCount || report . errorCount ) {
120
- console . log ( formatter ( report . results ) )
161
+ if ( reportWarningCount || reportErrorCount ) {
162
+ console . log ( formatter . format ( resultResults ) )
121
163
} else {
122
164
done ( hasFixed ? `All lint errors auto-fixed.` : `No lint errors found!` )
123
165
}
124
166
}
125
167
} else {
126
- console . log ( formatter ( report . results ) )
168
+ console . log ( formatter . format ( resultResults ) )
127
169
if ( isErrorsExceeded && typeof argsConfig . maxErrors === 'number' ) {
128
170
log ( `Eslint found too many errors (maximum: ${ argsConfig . maxErrors } ).` )
129
171
}
@@ -138,14 +180,35 @@ function normalizeConfig (args) {
138
180
const config = { }
139
181
for ( const key in args ) {
140
182
if ( renamedArrayArgs [ key ] ) {
141
- config [ renamedArrayArgs [ key ] ] = args [ key ] . split ( ',' )
183
+ applyConfig ( renamedArrayArgs [ key ] , args [ key ] . split ( ',' ) )
184
+ } else if ( renamedObjectArgs [ key ] ) {
185
+ const obj = arrayToBoolObject ( args [ key ] . split ( ',' ) , renamedObjectArgs [ key ] . def )
186
+ applyConfig ( renamedObjectArgs [ key ] . key , obj )
142
187
} else if ( renamedArgs [ key ] ) {
143
- config [ renamedArgs [ key ] ] = args [ key ]
188
+ applyConfig ( renamedArgs [ key ] , args [ key ] )
144
189
} else if ( key !== '_' ) {
145
190
config [ camelize ( key ) ] = args [ key ]
146
191
}
147
192
}
148
193
return config
194
+
195
+ function applyConfig ( [ ...keyPaths ] , value ) {
196
+ let targetConfig = config
197
+ const lastKey = keyPaths . pop ( )
198
+ for ( const k of keyPaths ) {
199
+ targetConfig = targetConfig [ k ] || ( targetConfig [ k ] = { } )
200
+ }
201
+ targetConfig [ lastKey ] = value
202
+ }
203
+
204
+ function arrayToBoolObject ( array , defaultBool ) {
205
+ const object = { }
206
+ for ( const element of array ) {
207
+ const [ key , value ] = element . split ( ':' )
208
+ object [ key ] = value != null ? value === 'true' : defaultBool
209
+ }
210
+ return object
211
+ }
149
212
}
150
213
151
214
function camelize ( str ) {
0 commit comments