@@ -2,28 +2,31 @@ const fs = require('fs')
22const globby = require ( 'globby' )
33
44const 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 }
1114}
1215
1316const 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' ]
2023}
2124
22- module . exports = function lint ( args = { } , api ) {
25+ module . exports = async function lint ( args = { } , api ) {
2326 const path = require ( 'path' )
2427 const cwd = api . resolve ( '.' )
2528 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' )
2730 const extensions = require ( './eslintOptions' ) . extensions ( api )
2831
2932 const argsConfig = normalizeConfig ( args )
@@ -37,34 +40,71 @@ module.exports = function lint (args = {}, api) {
3740 const noFixWarningsPredicate = ( lintResult ) => lintResult . severity === 2
3841 config . fix = config . fix && ( noFixWarnings ? noFixWarningsPredicate : true )
3942
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 ) {
4148 // .eslintrc.js files (ignored by default)
4249 // However, we need to lint & fix them so as to make the default generated project's
4350 // code style consistent with user's selected eslint config.
4451 // Though, if users provided their own `.eslintignore` file, we don't want to
4552 // add our own customized ignore pattern here (in eslint, ignorePattern is
4653 // an addition to eslintignore, i.e. it can't be overridden by user),
4754 // following the principle of least astonishment.
48- config . ignorePattern = [
55+ config . overrideConfig . ignorePatterns = [
4956 '!.*.js' ,
5057 '!{src,tests}/**/.*.js'
5158 ]
5259 }
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 [
5795 'src' ,
5896 'tests' ,
5997 // root config files
6098 '*.js' ,
6199 '.*.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+ }
68108
69109 const files = args . _ && args . _ . length
70110 ? args . _
@@ -79,51 +119,53 @@ module.exports = function lint (args = {}, api) {
79119 if ( ! api . invoking ) {
80120 process . cwd = ( ) => cwd
81121 }
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 )
83125 process . cwd = processCwd
84126
85- const formatter = engine . getFormatter ( args . format || 'codeframe' )
127+ const formatter = await eslint . loadFormatter ( args . format || 'codeframe' )
86128
87129 if ( config . outputFile ) {
88130 const outputFilePath = path . resolve ( config . outputFile )
89131 try {
90- fs . writeFileSync ( outputFilePath , formatter ( report . results ) )
132+ fs . writeFileSync ( outputFilePath , formatter . format ( resultResults ) )
91133 log ( `Lint results saved to ${ chalk . blue ( outputFilePath ) } ` )
92134 } catch ( err ) {
93135 log ( `Error saving lint results to ${ chalk . blue ( outputFilePath ) } : ${ chalk . red ( err ) } ` )
94136 }
95137 }
96138
97139 if ( config . fix ) {
98- CLIEngine . outputFixes ( report )
140+ await ESLint . outputFixes ( resultResults )
99141 }
100142
101143 const maxErrors = argsConfig . maxErrors || 0
102144 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
105147
106148 if ( ! isErrorsExceeded && ! isWarningsExceeded ) {
107149 if ( ! args . silent ) {
108- const hasFixed = report . results . some ( f => f . output )
150+ const hasFixed = resultResults . some ( f => f . output )
109151 if ( hasFixed ) {
110152 log ( `The following files have been auto-fixed:` )
111153 log ( )
112- report . results . forEach ( f => {
154+ resultResults . forEach ( f => {
113155 if ( f . output ) {
114156 log ( ` ${ chalk . blue ( path . relative ( cwd , f . filePath ) ) } ` )
115157 }
116158 } )
117159 log ( )
118160 }
119- if ( report . warningCount || report . errorCount ) {
120- console . log ( formatter ( report . results ) )
161+ if ( reportWarningCount || reportErrorCount ) {
162+ console . log ( formatter . format ( resultResults ) )
121163 } else {
122164 done ( hasFixed ? `All lint errors auto-fixed.` : `No lint errors found!` )
123165 }
124166 }
125167 } else {
126- console . log ( formatter ( report . results ) )
168+ console . log ( formatter . format ( resultResults ) )
127169 if ( isErrorsExceeded && typeof argsConfig . maxErrors === 'number' ) {
128170 log ( `Eslint found too many errors (maximum: ${ argsConfig . maxErrors } ).` )
129171 }
@@ -138,14 +180,35 @@ function normalizeConfig (args) {
138180 const config = { }
139181 for ( const key in args ) {
140182 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 )
142187 } else if ( renamedArgs [ key ] ) {
143- config [ renamedArgs [ key ] ] = args [ key ]
188+ applyConfig ( renamedArgs [ key ] , args [ key ] )
144189 } else if ( key !== '_' ) {
145190 config [ camelize ( key ) ] = args [ key ]
146191 }
147192 }
148193 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+ }
149212}
150213
151214function camelize ( str ) {
0 commit comments