lint-staged 17.0.8 β 17.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -28
- package/bin/lint-staged.js +5 -5
- package/lib/chunkFiles.js +2 -2
- package/lib/cli.js +17 -12
- package/lib/colors.js +26 -8
- package/lib/debug.js +2 -2
- package/lib/figures.js +9 -5
- package/lib/getFunctionTask.js +13 -4
- package/lib/getSpawnedTask.js +9 -9
- package/lib/getSpawnedTasks.js +3 -6
- package/lib/gitWorkflow.js +188 -112
- package/lib/index.js +23 -20
- package/lib/messages.js +36 -29
- package/lib/parseGitZOutput.js +1 -1
- package/lib/printTaskOutput.js +2 -2
- package/lib/runAll.js +103 -103
- package/lib/runParallelTasks.js +112 -0
- package/lib/state.js +14 -9
- package/lib/validateOptions.js +30 -3
- package/package.json +20 -25
- package/lib/getRenderer.js +0 -63
package/README.md
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
# π«π© lint-staged
|
|
2
2
|
|
|
3
|
-
[](https://badge.fury.io/js/lint-staged)
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
3
|
Run tasks like formatters and linters against staged git files and don't let :poop: slip into your code base!
|
|
8
4
|
|
|
9
5
|
```bash
|
|
@@ -13,26 +9,20 @@ npm install --save-dev lint-staged # requires further setup
|
|
|
13
9
|
```
|
|
14
10
|
$ git commit
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
β Ή prettier --write
|
|
22
|
-
β packages/backend/.lintstagedrc.json β 2 files
|
|
23
|
-
β― *.js β 2 files
|
|
24
|
-
β Ό eslint --fix
|
|
25
|
-
β *.{json,md} β no files [SKIPPED]
|
|
26
|
-
βΌ Updating Git index again...
|
|
27
|
-
βΌ Cleaning up temporary files...
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
<details>
|
|
31
|
-
<summary>See asciinema video</summary>
|
|
12
|
+
β― Backing up original stateβ¦
|
|
13
|
+
β Done backing up original state (1f4c047d)!
|
|
14
|
+
β― Running tasks for staged filesβ¦
|
|
15
|
+
*.{json,md} β 1 file
|
|
16
|
+
β― prettier --write
|
|
32
17
|
|
|
33
|
-
|
|
18
|
+
β prettier --write
|
|
34
19
|
|
|
35
|
-
|
|
20
|
+
β Done running tasks for staged files!
|
|
21
|
+
β― Staging changes from tasksβ¦
|
|
22
|
+
β Done staging changes from tasks!
|
|
23
|
+
β― Cleaning up temporary filesβ¦
|
|
24
|
+
β Done cleaning up temporary files!
|
|
25
|
+
```
|
|
36
26
|
|
|
37
27
|
> [!Tip]
|
|
38
28
|
> Do you only want to check staged files for errors, but not edit them automatically?
|
|
@@ -154,11 +144,7 @@ Change the working directory _lint-staged_ runs tasks in. Defaults to `process.c
|
|
|
154
144
|
|
|
155
145
|
#### `--debug`
|
|
156
146
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
- log additional information about staged files, commands being executed, location of binaries, etc.
|
|
160
|
-
- uses [`verbose` renderer](https://listr2.kilic.dev/renderers/verbose-renderer/) for `listr2`; this causes serial, uncoloured output to the terminal, instead of the default (beautified, dynamic) output.
|
|
161
|
-
(the [`verbose` renderer](https://listr2.kilic.dev/renderers/verbose-renderer/) can also be activated by setting the `TERM=dumb` or `NODE_ENV=test` environment variables)
|
|
147
|
+
Log additional information about staged files, commands being executed, location of binaries, etc.
|
|
162
148
|
|
|
163
149
|
#### `--diff`
|
|
164
150
|
|
|
@@ -178,7 +164,7 @@ By default changes made by tasks are automatically staged and added to the commi
|
|
|
178
164
|
|
|
179
165
|
#### `--max-arg-length [number]`
|
|
180
166
|
|
|
181
|
-
|
|
167
|
+
The list of staged files are appended to configured tasks as arguments, and the resulting string might be too long for the current shell, especially on Windows. _Lint-staged_ tries to avoid this by splitting the list of staged files into chunks resulting in the commands being run multiple times. This behavior affects all tasks, including functions. Use the `--max-arg-length` to override the platform-specific default value if you want to avoid this. Setting `--max-arg-length=Infinity` will disable chunking completely.
|
|
182
168
|
|
|
183
169
|
#### `--no-stash`
|
|
184
170
|
|
package/bin/lint-staged.js
CHANGED
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
import { userInfo } from 'node:os'
|
|
4
4
|
|
|
5
5
|
import { getVersionNumber, parseCliOptions, printHelpText } from '../lib/cli.js'
|
|
6
|
+
import { enableColors } from '../lib/colors.js'
|
|
6
7
|
import { createDebug, enableDebug } from '../lib/debug.js'
|
|
7
8
|
import lintStaged from '../lib/index.js'
|
|
8
|
-
import { CONFIG_STDIN_ERROR } from '../lib/messages.js'
|
|
9
9
|
import { readStdin } from '../lib/readStdin.js'
|
|
10
10
|
|
|
11
|
+
enableColors(!!process.stdout.hasColors?.())
|
|
11
12
|
const debugLog = createDebug('lint-staged:bin')
|
|
12
13
|
|
|
13
|
-
//
|
|
14
|
+
// SIGINT handled by an AbortController
|
|
14
15
|
process.on('SIGINT', () => {})
|
|
15
16
|
|
|
16
17
|
const cliOptions = parseCliOptions(process.argv)
|
|
@@ -44,9 +45,8 @@ if (cliOptions.configPath === '-') {
|
|
|
44
45
|
debugLog('Reading config from stdin')
|
|
45
46
|
cliOptions.config = JSON.parse(await readStdin())
|
|
46
47
|
} catch (error) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
process.exit(1)
|
|
48
|
+
console.error('Failed to read config from stdin!')
|
|
49
|
+
throw error
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
package/lib/chunkFiles.js
CHANGED
|
@@ -46,8 +46,8 @@ export const chunkFiles = ({ files, baseDir, maxArgLength = null, relative = fal
|
|
|
46
46
|
}
|
|
47
47
|
})
|
|
48
48
|
|
|
49
|
-
if (!maxArgLength) {
|
|
50
|
-
debugLog(
|
|
49
|
+
if (!maxArgLength || maxArgLength === Infinity) {
|
|
50
|
+
debugLog(`Skip chunking files because of maxArgLength is ${maxArgLength}`)
|
|
51
51
|
return [normalizedFiles] // wrap in an array to return a single chunk
|
|
52
52
|
}
|
|
53
53
|
|
package/lib/cli.js
CHANGED
|
@@ -91,7 +91,7 @@ const CLI_OPTIONS = [
|
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
flag: 'max-arg-length',
|
|
94
|
-
type: 'string', // Parsed with `
|
|
94
|
+
type: 'string', // Parsed with `Number()` below
|
|
95
95
|
positional: '[number]',
|
|
96
96
|
description: 'maximum length of the command-line argument string (default: 0)',
|
|
97
97
|
},
|
|
@@ -128,6 +128,20 @@ const CLI_OPTIONS = [
|
|
|
128
128
|
},
|
|
129
129
|
]
|
|
130
130
|
|
|
131
|
+
/** @type {(value: string |undefined) => number | boolean | null | undefined} */
|
|
132
|
+
const parseBoolOrNumber = (value) => {
|
|
133
|
+
switch (value) {
|
|
134
|
+
case undefined:
|
|
135
|
+
return undefined
|
|
136
|
+
case 'true':
|
|
137
|
+
return true
|
|
138
|
+
case 'false':
|
|
139
|
+
return false
|
|
140
|
+
default:
|
|
141
|
+
return Number(value)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
131
145
|
/** @param {string[]} argv */
|
|
132
146
|
export const parseCliOptions = (argv) => {
|
|
133
147
|
const options = CLI_OPTIONS.reduce((acc, current) => {
|
|
@@ -167,18 +181,9 @@ export const parseCliOptions = (argv) => {
|
|
|
167
181
|
values['hide-unstaged'] = false // becomes redundant
|
|
168
182
|
}
|
|
169
183
|
|
|
170
|
-
const maxArgLength =
|
|
171
|
-
values['max-arg-length'] !== undefined ? parseInt(values['max-arg-length'], 10) : undefined
|
|
172
|
-
|
|
173
|
-
if (Number.isNaN(maxArgLength)) {
|
|
174
|
-
throw new TypeError(`Option '--mar-arg-length' takes a numeric argument`, {
|
|
175
|
-
cause: { '--max-arg-length': values['max-arg-length'] },
|
|
176
|
-
})
|
|
177
|
-
}
|
|
178
|
-
|
|
179
184
|
return {
|
|
180
185
|
allowEmpty: values['allow-empty'] ?? false,
|
|
181
|
-
concurrent: values.concurrent
|
|
186
|
+
concurrent: parseBoolOrNumber(values.concurrent) ?? true,
|
|
182
187
|
configPath: values.config,
|
|
183
188
|
continueOnError: !!values['continue-on-error'],
|
|
184
189
|
cwd: values.cwd,
|
|
@@ -190,7 +195,7 @@ export const parseCliOptions = (argv) => {
|
|
|
190
195
|
hidePartiallyStaged: values['hide-partially-staged'] ?? true,
|
|
191
196
|
hideUnstaged: !!values['hide-unstaged'],
|
|
192
197
|
hideAll: !!values['hide-all'],
|
|
193
|
-
maxArgLength,
|
|
198
|
+
maxArgLength: parseBoolOrNumber(values['max-arg-length']),
|
|
194
199
|
quiet: !!values.quiet,
|
|
195
200
|
relative: !!values.relative,
|
|
196
201
|
revert: values.revert ?? true,
|
package/lib/colors.js
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
|
-
/* eslint-disable n/no-unsupported-features/node-builtins */
|
|
2
|
-
|
|
3
1
|
import util from 'node:util'
|
|
4
2
|
|
|
5
|
-
export
|
|
3
|
+
export let COLORS_ENABLED = false
|
|
4
|
+
|
|
5
|
+
/** @param {boolean} [enabled] */
|
|
6
|
+
export const enableColors = (enabled) => {
|
|
7
|
+
if (enabled) {
|
|
8
|
+
COLORS_ENABLED = true
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {util.InspectColor | readonly util.InspectColor[]} format
|
|
14
|
+
* @returns {(text: string) => string}
|
|
15
|
+
*/
|
|
16
|
+
const styleText = (format) => (text) =>
|
|
17
|
+
COLORS_ENABLED ? util.styleText(format, text, { validateStream: false }) : text
|
|
18
|
+
|
|
19
|
+
export const green = styleText('green')
|
|
20
|
+
|
|
21
|
+
export const red = styleText('red')
|
|
22
|
+
|
|
23
|
+
export const yellow = styleText('yellow')
|
|
24
|
+
|
|
25
|
+
export const blue = styleText('blue')
|
|
26
|
+
|
|
27
|
+
export const dim = styleText('dim')
|
|
6
28
|
|
|
7
|
-
export const
|
|
8
|
-
export const yellow = (text) => (SUPPORTS_COLOR ? util.styleText('yellow', text) : text)
|
|
9
|
-
export const blue = (text) => (SUPPORTS_COLOR ? util.styleText('blue', text) : text)
|
|
10
|
-
export const dim = (text) => (SUPPORTS_COLOR ? util.styleText('dim', text) : text)
|
|
11
|
-
export const bold = (text) => (SUPPORTS_COLOR ? util.styleText('bold', text) : text)
|
|
29
|
+
export const bold = styleText('bold')
|
package/lib/debug.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { formatWithOptions } from 'node:util'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { COLORS_ENABLED, dim } from './colors.js'
|
|
4
4
|
|
|
5
|
-
const format = (...args) => formatWithOptions({ colors:
|
|
5
|
+
const format = (...args) => formatWithOptions({ colors: COLORS_ENABLED }, ...args)
|
|
6
6
|
|
|
7
7
|
let activeLogger
|
|
8
8
|
|
package/lib/figures.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { blue, dim, green, red, yellow } from './colors.js'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export const wip = () => blue('β―')
|
|
4
4
|
|
|
5
|
-
export const
|
|
5
|
+
export const done = () => green('β')
|
|
6
6
|
|
|
7
|
-
export const
|
|
7
|
+
export const info = () => blue('β')
|
|
8
8
|
|
|
9
|
-
export const
|
|
9
|
+
export const error = () => red('β')
|
|
10
|
+
|
|
11
|
+
export const warning = () => yellow('β ')
|
|
12
|
+
|
|
13
|
+
export const cancelled = () => dim('β')
|
package/lib/getFunctionTask.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createDebug } from './debug.js'
|
|
2
|
+
import { Signal } from './getAbortController.js'
|
|
2
3
|
import { createTaskError } from './getSpawnedTask.js'
|
|
3
4
|
|
|
4
5
|
const debugLog = createDebug('lint-staged:getFunctionTasks')
|
|
@@ -13,17 +14,25 @@ export const isFunctionTask = (commands) => typeof commands === 'object' && !Arr
|
|
|
13
14
|
/**
|
|
14
15
|
* Handles function configuration and pushes the tasks into the task array
|
|
15
16
|
*
|
|
16
|
-
* @param {object}
|
|
17
|
-
* @param {
|
|
17
|
+
* @param {object} options
|
|
18
|
+
* @param {AbortController} options.abortController
|
|
19
|
+
* @param {FunctionTask} options.command
|
|
20
|
+
* @param {boolean} options.continueOnError
|
|
21
|
+
* @param {import('./getStagedFiles.js').StagedFile[]} options.files
|
|
18
22
|
* @throws {Error} If the function configuration is not valid
|
|
19
23
|
*/
|
|
20
|
-
export const getFunctionTask = async (command, files) => {
|
|
21
|
-
debugLog('Creating
|
|
24
|
+
export const getFunctionTask = async ({ abortController, command, continueOnError, files }) => {
|
|
25
|
+
debugLog('Creating task for function %o', command)
|
|
22
26
|
|
|
23
27
|
const task = async (ctx) => {
|
|
24
28
|
try {
|
|
25
29
|
await command.task(files.map((file) => file.filepath))
|
|
26
30
|
} catch (e) {
|
|
31
|
+
if (continueOnError !== true) {
|
|
32
|
+
/** Other tasks should be killed */
|
|
33
|
+
abortController.abort(Signal.SIGKILL)
|
|
34
|
+
}
|
|
35
|
+
|
|
27
36
|
throw createTaskError(command.title, e, ctx)
|
|
28
37
|
}
|
|
29
38
|
}
|
package/lib/getSpawnedTask.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { parseArgsStringToArgv } from 'string-argv'
|
|
2
2
|
import { exec } from 'tinyexec'
|
|
3
3
|
|
|
4
|
-
import { dim, red } from './colors.js'
|
|
4
|
+
import { COLORS_ENABLED, dim, red } from './colors.js'
|
|
5
5
|
import { createDebug } from './debug.js'
|
|
6
|
-
import
|
|
6
|
+
import * as figures from './figures.js'
|
|
7
7
|
import { Signal } from './getAbortController.js'
|
|
8
8
|
import { killSubProcesses } from './killSubprocesses.js'
|
|
9
9
|
import { getInitialState } from './state.js'
|
|
@@ -22,7 +22,9 @@ const debugLog = createDebug('lint-staged:getSpawnedTask')
|
|
|
22
22
|
*/
|
|
23
23
|
const handleTaskOutput = (command, output, ctx, signal, errorResult) => {
|
|
24
24
|
if (output) {
|
|
25
|
-
const outputTitle = errorResult
|
|
25
|
+
const outputTitle = errorResult
|
|
26
|
+
? red(`${figures.error()} ${command}:`)
|
|
27
|
+
: `${figures.info()} ${command}:`
|
|
26
28
|
ctx.output.push([...(ctx.quiet ? [] : ['', outputTitle]), output].join('\n'))
|
|
27
29
|
return
|
|
28
30
|
}
|
|
@@ -32,11 +34,11 @@ const handleTaskOutput = (command, output, ctx, signal, errorResult) => {
|
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
if (signal === 'SIGINT') {
|
|
35
|
-
ctx.output.push(red(`\n${error} Task interrupted: ${command}`))
|
|
37
|
+
ctx.output.push(red(`\n${figures.error()} Task interrupted: ${command}`))
|
|
36
38
|
} else if (signal === 'SIGKILL') {
|
|
37
|
-
ctx.output.push(red(`\n${error} Task killed: ${command}`))
|
|
39
|
+
ctx.output.push(red(`\n${figures.error()} Task killed: ${command}`))
|
|
38
40
|
} else if (errorResult) {
|
|
39
|
-
ctx.output.push(red(`\n${error} Task failed to spawn: ${command}`), signal)
|
|
41
|
+
ctx.output.push(red(`\n${figures.error()} Task failed to spawn: ${command}`), signal)
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
44
|
|
|
@@ -59,7 +61,6 @@ export const createTaskError = (command, result, ctx, signal = 'FAILED') => {
|
|
|
59
61
|
*
|
|
60
62
|
* @param {Object} options
|
|
61
63
|
* @param {AbortController} options.abortController
|
|
62
|
-
* @param {boolean} [options.color]
|
|
63
64
|
* @param {string} options.command β Linter task
|
|
64
65
|
* @param {string} [options.continueOnError]
|
|
65
66
|
* @param {string} [options.cwd]
|
|
@@ -71,7 +72,6 @@ export const createTaskError = (command, result, ctx, signal = 'FAILED') => {
|
|
|
71
72
|
*/
|
|
72
73
|
export const getSpawnedTask = ({
|
|
73
74
|
abortController,
|
|
74
|
-
color,
|
|
75
75
|
command,
|
|
76
76
|
continueOnError = false,
|
|
77
77
|
cwd = process.cwd(),
|
|
@@ -90,7 +90,7 @@ export const getSpawnedTask = ({
|
|
|
90
90
|
// Only use topLevelDir as CWD if we are using the git binary
|
|
91
91
|
// e.g `npm` should run tasks in the actual CWD
|
|
92
92
|
cwd: /^git(\.exe)?/i.test(cmd) ? topLevelDir : cwd,
|
|
93
|
-
env:
|
|
93
|
+
env: COLORS_ENABLED ? { FORCE_COLOR: 'true' } : { NO_COLOR: 'true' },
|
|
94
94
|
},
|
|
95
95
|
}
|
|
96
96
|
|
package/lib/getSpawnedTasks.js
CHANGED
|
@@ -5,11 +5,10 @@ import { configurationError } from './messages.js'
|
|
|
5
5
|
const debugLog = createDebug('lint-staged:getSpawnedTasks')
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Creates and returns an array of
|
|
8
|
+
* Creates and returns an array of tasks which map to the given commands.
|
|
9
9
|
*
|
|
10
10
|
* @param {object} options
|
|
11
11
|
* @param {AbortController} options.abortController
|
|
12
|
-
* @param {boolean} [options.color]
|
|
13
12
|
* @param {Array<string|Function>|string|Function} options.commands
|
|
14
13
|
* @param {string} options.continueOnError
|
|
15
14
|
* @param {string} options.cwd
|
|
@@ -19,7 +18,6 @@ const debugLog = createDebug('lint-staged:getSpawnedTasks')
|
|
|
19
18
|
*/
|
|
20
19
|
export const getSpawnedTasks = async ({
|
|
21
20
|
abortController,
|
|
22
|
-
color,
|
|
23
21
|
commands,
|
|
24
22
|
continueOnError,
|
|
25
23
|
cwd,
|
|
@@ -27,7 +25,7 @@ export const getSpawnedTasks = async ({
|
|
|
27
25
|
topLevelDir,
|
|
28
26
|
verbose,
|
|
29
27
|
}) => {
|
|
30
|
-
debugLog('Creating
|
|
28
|
+
debugLog('Creating tasks for commands %o', commands)
|
|
31
29
|
const cmdTasks = []
|
|
32
30
|
|
|
33
31
|
const commandArray = Array.isArray(commands) ? commands : [commands]
|
|
@@ -58,7 +56,6 @@ export const getSpawnedTasks = async ({
|
|
|
58
56
|
|
|
59
57
|
const task = getSpawnedTask({
|
|
60
58
|
abortController,
|
|
61
|
-
color,
|
|
62
59
|
command,
|
|
63
60
|
continueOnError,
|
|
64
61
|
cwd,
|
|
@@ -68,7 +65,7 @@ export const getSpawnedTasks = async ({
|
|
|
68
65
|
verbose,
|
|
69
66
|
})
|
|
70
67
|
|
|
71
|
-
cmdTasks.push({ title: command,
|
|
68
|
+
cmdTasks.push({ title: command, task })
|
|
72
69
|
}
|
|
73
70
|
}
|
|
74
71
|
|