lint-staged 17.0.7 → 17.1.0
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 -24
- package/bin/lint-staged.js +5 -5
- package/lib/colors.js +26 -8
- package/lib/debug.js +2 -2
- package/lib/execGit.js +3 -17
- 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 +190 -113
- package/lib/index.js +14 -12
- 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 +9 -0
- package/package.json +20 -25
- package/lib/getRenderer.js +0 -63
package/README.md
CHANGED
|
@@ -13,27 +13,21 @@ npm install --save-dev lint-staged # requires further setup
|
|
|
13
13
|
```
|
|
14
14
|
$ git commit
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
16
|
+
⋯ Backing up original state…
|
|
17
|
+
✔ Done backing up original state (1f4c047d)!
|
|
18
|
+
⋯ Running tasks for staged files…
|
|
19
|
+
*.{json,md} — 1 file
|
|
20
|
+
⋯ prettier --write
|
|
21
|
+
|
|
22
|
+
✔ prettier --write
|
|
23
|
+
|
|
24
|
+
✔ Done running tasks for staged files!
|
|
25
|
+
⋯ Staging changes from tasks…
|
|
26
|
+
✔ Done staging changes from tasks!
|
|
27
|
+
⋯ Cleaning up temporary files…
|
|
28
|
+
✔ Done cleaning up temporary files!
|
|
28
29
|
```
|
|
29
30
|
|
|
30
|
-
<details>
|
|
31
|
-
<summary>See asciinema video</summary>
|
|
32
|
-
|
|
33
|
-
[](https://asciinema.org/a/199934)
|
|
34
|
-
|
|
35
|
-
</details>
|
|
36
|
-
|
|
37
31
|
> [!Tip]
|
|
38
32
|
> Do you only want to check staged files for errors, but not edit them automatically?
|
|
39
33
|
> You might be interested in this simpler shell script: [`lint-staged.sh`](https://github.com/lint-staged/lint-staged.sh).
|
|
@@ -154,11 +148,7 @@ Change the working directory _lint-staged_ runs tasks in. Defaults to `process.c
|
|
|
154
148
|
|
|
155
149
|
#### `--debug`
|
|
156
150
|
|
|
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)
|
|
151
|
+
Log additional information about staged files, commands being executed, location of binaries, etc.
|
|
162
152
|
|
|
163
153
|
#### `--diff`
|
|
164
154
|
|
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/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/execGit.js
CHANGED
|
@@ -4,9 +4,6 @@ import { createDebug } from './debug.js'
|
|
|
4
4
|
|
|
5
5
|
const debugLog = createDebug('lint-staged:execGit')
|
|
6
6
|
|
|
7
|
-
/** @example "warning: in the working copy of 'README.md', LF will be replaced by CRLF the next time Git touches it" */
|
|
8
|
-
const GIT_CRLF_WARNING = /^warning.*CRLF.*the next time Git touches it/i
|
|
9
|
-
|
|
10
7
|
/**
|
|
11
8
|
* Explicitly never recurse commands into submodules, overriding local/global configuration.
|
|
12
9
|
* @see https://git-scm.com/docs/git-config#Documentation/git-config.txt-submodulerecurse
|
|
@@ -19,27 +16,16 @@ export const GIT_GLOBAL_OPTIONS = [...NO_SUBMODULE_RECURSE]
|
|
|
19
16
|
/** @type {(cmd: string[], options?: { cwd?: string }) => Promise<string>} */
|
|
20
17
|
export const execGit = async (cmd, options) => {
|
|
21
18
|
debugLog('Running git command:', cmd)
|
|
22
|
-
const result = exec('git', [...NO_SUBMODULE_RECURSE, ...cmd], {
|
|
19
|
+
const result = await exec('git', [...NO_SUBMODULE_RECURSE, ...cmd], {
|
|
23
20
|
nodeOptions: {
|
|
24
21
|
env: options?.env,
|
|
25
22
|
cwd: options?.cwd,
|
|
26
23
|
},
|
|
27
24
|
})
|
|
28
25
|
|
|
29
|
-
let output = ''
|
|
30
|
-
for await (const line of result) {
|
|
31
|
-
if (GIT_CRLF_WARNING.test(line)) {
|
|
32
|
-
debugLog('Stripped Git CRLF warning: %s', line)
|
|
33
|
-
continue
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
output += line + '\n'
|
|
37
|
-
}
|
|
38
|
-
output = output.trimEnd()
|
|
39
|
-
|
|
40
26
|
if (result.exitCode > 0) {
|
|
41
|
-
throw new Error(
|
|
27
|
+
throw new Error(result.stderr.trimEnd(), { cause: result })
|
|
42
28
|
}
|
|
43
29
|
|
|
44
|
-
return
|
|
30
|
+
return result.stdout.trimEnd()
|
|
45
31
|
}
|
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
|
|