UNPKG

4.13 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 {
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 {Object} [options.allowEmpty] - Allow empty commits when tasks revert all staged changes
46 * @param {boolean | number} [options.concurrent] - The number of tasks to run concurrently, or false to run tasks serially
47 * @param {object} [options.config] - Object with configuration for programmatic API
48 * @param {string} [options.configPath] - Path to configuration file
49 * @param {number} [options.maxArgLength] - Maximum argument string length
50 * @param {boolean} [options.relative] - Pass relative filepaths to tasks
51 * @param {boolean} [options.shell] - Skip parsing of tasks for better shell support
52 * @param {boolean} [options.quiet] - Disable lint-staged’s own console output
53 * @param {boolean} [options.debug] - Enable debug mode
54 * @param {boolean | number} [options.concurrent] - The number of tasks to run concurrently, or false to run tasks serially
55 * @param {Logger} [logger]
56 *
57 * @returns {Promise<boolean>} Promise of whether the linting passed or failed
58 */
59module.exports = async function lintStaged(
60 {
61 allowEmpty = false,
62 concurrent = true,
63 config: configObject,
64 configPath,
65 maxArgLength,
66 relative = false,
67 shell = false,
68 quiet = false,
69 debug = false
70 } = {},
71 logger = console
72) {
73 try {
74 debugLog('Loading config using `cosmiconfig`')
75
76 const resolved = configObject
77 ? { config: configObject, filepath: '(input)' }
78 : await loadConfig(configPath)
79 if (resolved == null) throw errConfigNotFound
80
81 debugLog('Successfully loaded config from `%s`:\n%O', resolved.filepath, resolved.config)
82 // resolved.config is the parsed configuration object
83 // resolved.filepath is the path to the config file that was found
84 const config = validateConfig(resolved.config)
85 if (debug) {
86 // Log using logger to be able to test through `consolemock`.
87 logger.log('Running lint-staged with the following config:')
88 logger.log(stringifyObject(config, { indent: ' ' }))
89 } else {
90 // We might not be in debug mode but `DEBUG=lint-staged*` could have
91 // been set.
92 debugLog('lint-staged config:\n%O', config)
93 }
94
95 try {
96 await runAll(
97 { allowEmpty, concurrent, config, debug, maxArgLength, quiet, relative, shell },
98 logger
99 )
100 debugLog('tasks were executed successfully!')
101 return true
102 } catch (runAllError) {
103 printErrors(runAllError, logger)
104 return false
105 }
106 } catch (lintStagedError) {
107 if (lintStagedError === errConfigNotFound) {
108 logger.error(`${lintStagedError.message}.`)
109 } else {
110 // It was probably a parsing error
111 logger.error(dedent`
112 Could not parse lint-staged config.
113
114 ${lintStagedError}
115 `)
116 }
117 logger.error() // empty line
118 // Print helpful message for all errors
119 logger.error(dedent`
120 Please make sure you have created it correctly.
121 See https://github.com/okonet/lint-staged#configuration.
122 `)
123
124 throw lintStagedError
125 }
126}