lint.js 4.1 KB

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