1 | import debug from 'debug'
|
2 |
|
3 | import {
|
4 | PREVENTED_EMPTY_COMMIT,
|
5 | GIT_ERROR,
|
6 | RESTORE_STASH_EXAMPLE,
|
7 | NO_CONFIGURATION,
|
8 | } from './messages.js'
|
9 | import { printTaskOutput } from './printTaskOutput.js'
|
10 | import { runAll } from './runAll.js'
|
11 | import {
|
12 | ApplyEmptyCommitError,
|
13 | ConfigNotFoundError,
|
14 | GetBackupStashError,
|
15 | GitError,
|
16 | } from './symbols.js'
|
17 | import { validateOptions } from './validateOptions.js'
|
18 |
|
19 | const debugLog = debug('lint-staged')
|
20 |
|
21 | /**
|
22 | * Get the maximum length of a command-line argument string based on current platform
|
23 | *
|
24 | * https://serverfault.com/questions/69430/what-is-the-maximum-length-of-a-command-line-in-mac-os-x
|
25 | * https://support.microsoft.com/en-us/help/830473/command-prompt-cmd-exe-command-line-string-limitation
|
26 | * https://unix.stackexchange.com/a/120652
|
27 | */
|
28 | const getMaxArgLength = () => {
|
29 | switch (process.platform) {
|
30 | case 'darwin':
|
31 | return 262144
|
32 | case 'win32':
|
33 | return 8191
|
34 | default:
|
35 | return 131072
|
36 | }
|
37 | }
|
38 |
|
39 | /**
|
40 | * @typedef {(...any) => void} LogFunction
|
41 | * @typedef {{ error: LogFunction, log: LogFunction, warn: LogFunction }} Logger
|
42 | *
|
43 | * Root lint-staged function that is called from `bin/lint-staged`.
|
44 | *
|
45 | * @param {object} options
|
46 | * @param {Object} [options.allowEmpty] - Allow empty commits when tasks revert all staged changes
|
47 | * @param {boolean | number} [options.concurrent] - The number of tasks to run concurrently, or false to run tasks serially
|
48 | * @param {object} [options.config] - Object with configuration for programmatic API
|
49 | * @param {string} [options.configPath] - Path to configuration file
|
50 | * @param {Object} [options.cwd] - Current working directory
|
51 | * @param {boolean} [options.debug] - Enable debug mode
|
52 | * @param {string} [options.diff] - Override the default "--staged" flag of "git diff" to get list of files
|
53 | * @param {string} [options.diffFilter] - Override the default "--diff-filter=ACMR" flag of "git diff" to get list of files
|
54 | * @param {number} [options.maxArgLength] - Maximum argument string length
|
55 | * @param {boolean} [options.quiet] - Disable lint-staged’s own console output
|
56 | * @param {boolean} [options.relative] - Pass relative filepaths to tasks
|
57 | * @param {boolean|string} [options.shell] - Skip parsing of tasks for better shell support
|
58 | * @param {boolean} [options.stash] - Enable the backup stash, and revert in case of errors
|
59 | * @param {boolean} [options.verbose] - Show task output even when tasks succeed; by default only failed output is shown
|
60 | * @param {Logger} [logger]
|
61 | *
|
62 | * @returns {Promise<boolean>} Promise of whether the linting passed or failed
|
63 | */
|
64 | const lintStaged = async (
|
65 | {
|
66 | allowEmpty = false,
|
67 | concurrent = true,
|
68 | config: configObject,
|
69 | configPath,
|
70 | cwd,
|
71 | debug = false,
|
72 | diff,
|
73 | diffFilter,
|
74 | maxArgLength = getMaxArgLength() / 2,
|
75 | quiet = false,
|
76 | relative = false,
|
77 | shell = false,
|
78 | stash = true,
|
79 | verbose = false,
|
80 | } = {},
|
81 | logger = console
|
82 | ) => {
|
83 | await validateOptions({ cwd, shell }, logger)
|
84 |
|
85 | // Unset GIT_LITERAL_PATHSPECS to not mess with path interpretation
|
86 | debugLog('Unset GIT_LITERAL_PATHSPECS (was `%s`)', process.env.GIT_LITERAL_PATHSPECS)
|
87 | delete process.env.GIT_LITERAL_PATHSPECS
|
88 |
|
89 | const options = {
|
90 | allowEmpty,
|
91 | concurrent,
|
92 | configObject,
|
93 | configPath,
|
94 | cwd,
|
95 | debug,
|
96 | diff,
|
97 | diffFilter,
|
98 | maxArgLength,
|
99 | quiet,
|
100 | relative,
|
101 | shell,
|
102 | stash,
|
103 | verbose,
|
104 | }
|
105 |
|
106 | try {
|
107 | const ctx = await runAll(options, logger)
|
108 | debugLog('Tasks were executed successfully!')
|
109 | printTaskOutput(ctx, logger)
|
110 | return true
|
111 | } catch (runAllError) {
|
112 | if (runAllError?.ctx?.errors) {
|
113 | const { ctx } = runAllError
|
114 |
|
115 | if (ctx.errors.has(ConfigNotFoundError)) {
|
116 | logger.error(NO_CONFIGURATION)
|
117 | } else if (ctx.errors.has(ApplyEmptyCommitError)) {
|
118 | logger.warn(PREVENTED_EMPTY_COMMIT)
|
119 | } else if (ctx.errors.has(GitError) && !ctx.errors.has(GetBackupStashError)) {
|
120 | logger.error(GIT_ERROR)
|
121 | if (ctx.shouldBackup) {
|
122 | // No sense to show this if the backup stash itself is missing.
|
123 | logger.error(RESTORE_STASH_EXAMPLE)
|
124 | }
|
125 | }
|
126 |
|
127 | printTaskOutput(ctx, logger)
|
128 | return false
|
129 | }
|
130 |
|
131 | // Probably a compilation error in the config js file. Pass it up to the outer error handler for logging.
|
132 | throw runAllError
|
133 | }
|
134 | }
|
135 |
|
136 | export default lintStaged
|