UNPKG

4.36 kBJavaScriptView Raw
1import debug from 'debug'
2import inspect from 'object-inspect'
3
4import { loadConfig } from './loadConfig.js'
5import { PREVENTED_EMPTY_COMMIT, GIT_ERROR, RESTORE_STASH_EXAMPLE } from './messages.js'
6import { printTaskOutput } from './printTaskOutput.js'
7import { runAll } from './runAll.js'
8import {
9 ApplyEmptyCommitError,
10 ConfigNotFoundError,
11 GetBackupStashError,
12 GitError,
13} from './symbols.js'
14import { validateConfig } from './validateConfig.js'
15import { validateOptions } from './validateOptions.js'
16
17const debugLog = debug('lint-staged')
18
19/**
20 * @typedef {(...any) => void} LogFunction
21 * @typedef {{ error: LogFunction, log: LogFunction, warn: LogFunction }} Logger
22 *
23 * Root lint-staged function that is called from `bin/lint-staged`.
24 *
25 * @param {object} options
26 * @param {Object} [options.allowEmpty] - Allow empty commits when tasks revert all staged changes
27 * @param {boolean | number} [options.concurrent] - The number of tasks to run concurrently, or false to run tasks serially
28 * @param {object} [options.config] - Object with configuration for programmatic API
29 * @param {string} [options.configPath] - Path to configuration file
30 * @param {Object} [options.cwd] - Current working directory
31 * @param {boolean} [options.debug] - Enable debug mode
32 * @param {number} [options.maxArgLength] - Maximum argument string length
33 * @param {boolean} [options.quiet] - Disable lint-staged’s own console output
34 * @param {boolean} [options.relative] - Pass relative filepaths to tasks
35 * @param {boolean|string} [options.shell] - Skip parsing of tasks for better shell support
36 * @param {boolean} [options.stash] - Enable the backup stash, and revert in case of errors
37 * @param {boolean} [options.verbose] - Show task output even when tasks succeed; by default only failed output is shown
38 * @param {Logger} [logger]
39 *
40 * @returns {Promise<boolean>} Promise of whether the linting passed or failed
41 */
42const lintStaged = async (
43 {
44 allowEmpty = false,
45 concurrent = true,
46 config: configObject,
47 configPath,
48 cwd = process.cwd(),
49 debug = false,
50 maxArgLength,
51 quiet = false,
52 relative = false,
53 shell = false,
54 stash = true,
55 verbose = false,
56 } = {},
57 logger = console
58) => {
59 await validateOptions({ shell }, logger)
60
61 debugLog('Loading config using `lilconfig`')
62
63 const resolved = configObject
64 ? { config: configObject, filepath: '(input)' }
65 : await loadConfig(configPath)
66
67 if (!resolved) {
68 logger.error(`${ConfigNotFoundError.message}.`)
69 throw ConfigNotFoundError
70 }
71
72 debugLog('Successfully loaded config from `%s`:\n%O', resolved.filepath, resolved.config)
73
74 const config = validateConfig(resolved.config, logger)
75
76 if (debug) {
77 // Log using logger to be able to test through `consolemock`.
78 logger.log('Running lint-staged with the following config:')
79 logger.log(inspect(config, { indent: 2 }))
80 } else {
81 // We might not be in debug mode but `DEBUG=lint-staged*` could have
82 // been set.
83 debugLog('lint-staged config:\n%O', config)
84 }
85
86 // Unset GIT_LITERAL_PATHSPECS to not mess with path interpretation
87 debugLog('Unset GIT_LITERAL_PATHSPECS (was `%s`)', process.env.GIT_LITERAL_PATHSPECS)
88 delete process.env.GIT_LITERAL_PATHSPECS
89
90 try {
91 const ctx = await runAll(
92 {
93 allowEmpty,
94 concurrent,
95 config,
96 cwd,
97 debug,
98 maxArgLength,
99 quiet,
100 relative,
101 shell,
102 stash,
103 verbose,
104 },
105 logger
106 )
107 debugLog('Tasks were executed successfully!')
108 printTaskOutput(ctx, logger)
109 return true
110 } catch (runAllError) {
111 if (runAllError && runAllError.ctx && runAllError.ctx.errors) {
112 const { ctx } = runAllError
113 if (ctx.errors.has(ApplyEmptyCommitError)) {
114 logger.warn(PREVENTED_EMPTY_COMMIT)
115 } else if (ctx.errors.has(GitError) && !ctx.errors.has(GetBackupStashError)) {
116 logger.error(GIT_ERROR)
117 if (ctx.shouldBackup) {
118 // No sense to show this if the backup stash itself is missing.
119 logger.error(RESTORE_STASH_EXAMPLE)
120 }
121 }
122
123 printTaskOutput(ctx, logger)
124 return false
125 }
126
127 // Probably a compilation error in the config js file. Pass it up to the outer error handler for logging.
128 throw runAllError
129 }
130}
131
132export default lintStaged