UNPKG

4.25 kBJavaScriptView Raw
1const fs = require('fs')
2const globby = require('globby')
3
4const renamedArrayArgs = {
5 ext: 'extensions',
6 env: 'envs',
7 global: 'globals',
8 rulesdir: 'rulePaths',
9 plugin: 'plugins',
10 'ignore-pattern': 'ignorePattern'
11}
12
13const renamedArgs = {
14 'inline-config': 'allowInlineConfig',
15 rule: 'rules',
16 eslintrc: 'useEslintrc',
17 c: 'configFile',
18 config: 'configFile'
19}
20
21module.exports = function lint (args = {}, api) {
22 const path = require('path')
23 const cwd = api.resolve('.')
24 const { log, done, exit, chalk, loadModule } = require('@megalo/cli-share-utils')
25 const { CLIEngine } = loadModule('eslint', cwd, true) || require('eslint')
26 const extensions = require('./eslintOptions').extensions(api)
27
28 const argsConfig = normalizeConfig(args)
29 const config = Object.assign({
30 extensions,
31 fix: true,
32 cwd
33 }, argsConfig)
34
35 const noFixWarnings = (argsConfig.fixWarnings === false)
36 const noFixWarningsPredicate = (lintResult) => lintResult.severity === 2
37 config.fix = config.fix && (noFixWarnings ? noFixWarningsPredicate : true)
38
39 if (!fs.existsSync(api.resolve('.eslintignore')) && !config.ignorePattern) {
40 // .eslintrc.js files (ignored by default)
41 // However, we need to lint & fix them so as to make the default generated project's
42 // code style consistent with user's selected eslint config.
43 // Though, if users provided their own `.eslintignore` file, we don't want to
44 // add our own customized ignore pattern here (in eslint, ignorePattern is
45 // an addition to eslintignore, i.e. it can't be overriden by user),
46 // following the principle of least astonishment.
47 config.ignorePattern = [
48 '!.*.js',
49 '!{src,tests}/**/.*.js'
50 ]
51 }
52
53 const engine = new CLIEngine(config)
54
55 const defaultFilesToLint = [
56 'src',
57 'tests',
58 // root config files
59 '*.js',
60 '.*.js'
61 ]
62 .filter(pattern =>
63 globby
64 .sync(path.join(cwd, pattern))
65 .some(p => !engine.isPathIgnored(p))
66 )
67
68 const files = args._ && args._.length
69 ? args._
70 : defaultFilesToLint
71
72 // mock process.cwd before executing
73 // See:
74 // https://github.com/vuejs/vue-cli/issues/2554
75 // https://github.com/benmosher/eslint-plugin-import/issues/602
76 // https://github.com/eslint/eslint/issues/11218
77 const processCwd = process.cwd
78 if (!api.invoking) {
79 process.cwd = () => cwd
80 }
81 const report = engine.executeOnFiles(files)
82 process.cwd = processCwd
83
84 const formatter = engine.getFormatter(args.format || 'codeframe')
85
86 if (config.fix) {
87 CLIEngine.outputFixes(report)
88 }
89
90 const maxErrors = argsConfig.maxErrors || 0
91 const maxWarnings = typeof argsConfig.maxWarnings === 'number' ? argsConfig.maxWarnings : Infinity
92 const isErrorsExceeded = report.errorCount > maxErrors
93 const isWarningsExceeded = report.warningCount > maxWarnings
94
95 if (!isErrorsExceeded && !isWarningsExceeded) {
96 if (!args.silent) {
97 const hasFixed = report.results.some(f => f.output)
98 if (hasFixed) {
99 log(`The following files have been auto-fixed:`)
100 log()
101 report.results.forEach(f => {
102 if (f.output) {
103 log(` ${chalk.blue(path.relative(cwd, f.filePath))}`)
104 }
105 })
106 log()
107 }
108 if (report.warningCount || report.errorCount) {
109 console.log(formatter(report.results))
110 } else {
111 done(hasFixed ? `All lint errors auto-fixed.` : `No lint errors found!`)
112 }
113 }
114 } else {
115 console.log(formatter(report.results))
116 if (isErrorsExceeded && typeof argsConfig.maxErrors === 'number') {
117 log(`Eslint found too many errors (maximum: ${argsConfig.maxErrors}).`)
118 }
119 if (isWarningsExceeded) {
120 log(`Eslint found too many warnings (maximum: ${argsConfig.maxWarnings}).`)
121 }
122 exit(1)
123 }
124}
125
126function normalizeConfig (args) {
127 const config = {}
128 for (const key in args) {
129 if (renamedArrayArgs[key]) {
130 config[renamedArrayArgs[key]] = args[key].split(',')
131 } else if (renamedArgs[key]) {
132 config[renamedArgs[key]] = args[key]
133 } else if (key !== '_') {
134 config[camelize(key)] = args[key]
135 }
136 }
137 return config
138}
139
140function camelize (str) {
141 return str.replace(/-(\w)/g, (_, c) => c ? c.toUpperCase() : '')
142}