UNPKG

3.34 kBJavaScriptView Raw
1'use strict'
2
3const dedent = require('dedent')
4const cosmiconfig = require('cosmiconfig')
5const stringifyObject = require('stringify-object')
6const printErrors = require('./printErrors')
7const runAll = require('./runAll')
8const validateConfig = require('./validateConfig')
9
10const debugLog = require('debug')('lint-staged')
11
12const errConfigNotFound = new Error('Config could not be found')
13
14function resolveConfig(configPath) {
15 try {
16 return require.resolve(configPath)
17 } catch (ignore) {
18 return configPath
19 }
20}
21
22function loadConfig(configPath) {
23 const explorer = cosmiconfig('lint-staged', {
24 searchPlaces: [
25 'package.json',
26 '.lintstagedrc',
27 '.lintstagedrc.json',
28 '.lintstagedrc.yaml',
29 '.lintstagedrc.yml',
30 '.lintstagedrc.js',
31 'lint-staged.config.js'
32 ]
33 })
34
35 return configPath ? explorer.load(resolveConfig(configPath)) : explorer.search()
36}
37
38/**
39 * @typedef {(...any) => void} LogFunction
40 * @typedef {{ error: LogFunction, log: LogFunction, warn: LogFunction }} Logger
41 *
42 * Root lint-staged function that is called from `bin/lint-staged`.
43 *
44 * @param {object} options
45 * @param {string} [options.configPath] - Path to configuration file
46 * @param {boolean} [options.shell] - Use execa’s shell mode to execute linter commands
47 * @param {boolean} [options.quiet] - Use Listr’s silent renderer
48 * @param {boolean} [options.debug] - Enable debug mode
49 * @param {Logger} [logger]
50 *
51 * @returns {Promise<boolean>} Promise of whether the linting passed or failed
52 */
53module.exports = function lintStaged(
54 { configPath, shell = false, quiet = false, debug = false } = {},
55 logger = console
56) {
57 debugLog('Loading config using `cosmiconfig`')
58
59 return loadConfig(configPath)
60 .then(result => {
61 if (result == null) throw errConfigNotFound
62
63 debugLog('Successfully loaded config from `%s`:\n%O', result.filepath, result.config)
64 // result.config is the parsed configuration object
65 // result.filepath is the path to the config file that was found
66 const config = validateConfig(result.config)
67 if (debug) {
68 // Log using logger to be able to test through `consolemock`.
69 logger.log('Running lint-staged with the following config:')
70 logger.log(stringifyObject(config, { indent: ' ' }))
71 } else {
72 // We might not be in debug mode but `DEBUG=lint-staged*` could have
73 // been set.
74 debugLog('Normalized config:\n%O', config)
75 }
76
77 return runAll(config, shell, quiet, debug, logger)
78 .then(() => {
79 debugLog('linters were executed successfully!')
80 return Promise.resolve(true)
81 })
82 .catch(error => {
83 printErrors(error, logger)
84 return Promise.resolve(false)
85 })
86 })
87 .catch(err => {
88 if (err === errConfigNotFound) {
89 logger.error(`${err.message}.`)
90 } else {
91 // It was probably a parsing error
92 logger.error(dedent`
93 Could not parse lint-staged config.
94
95 ${err}
96 `)
97 }
98 logger.error() // empty line
99 // Print helpful message for all errors
100 logger.error(dedent`
101 Please make sure you have created it correctly.
102 See https://github.com/okonet/lint-staged#configuration.
103 `)
104
105 return Promise.reject(err)
106 })
107}