lint-staged 16.0.0 → 16.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/MIGRATION.md +3 -1
- package/README.md +26 -11
- package/bin/lint-staged.js +12 -15
- package/lib/chunkFiles.js +15 -7
- package/lib/generateTasks.js +31 -14
- package/lib/getFunctionTask.js +2 -2
- package/lib/getSpawnedTask.js +1 -1
- package/lib/getSpawnedTasks.js +5 -3
- package/lib/getStagedFiles.js +35 -5
- package/lib/gitWorkflow.js +10 -3
- package/lib/groupFilesByConfig.js +8 -1
- package/lib/index.d.ts +5 -0
- package/lib/index.js +10 -1
- package/lib/messages.js +7 -15
- package/lib/runAll.js +29 -14
- package/lib/state.js +11 -7
- package/package.json +14 -14
package/MIGRATION.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
#### Updated Node.js version requirement
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
For version `lint-staged@16.0.0` the lowest supported Node.js version is `20.19.0`, following requirements of `nano-spawn`. Please upgrade your Node.js version.
|
|
6
|
+
|
|
7
|
+
For version `lint-staged@16.1.0` this is lowered to `20.17.0`, again following `nano-spawn`.
|
|
6
8
|
|
|
7
9
|
#### Removed validation for removed advanced configuration file options
|
|
8
10
|
|
package/README.md
CHANGED
|
@@ -34,13 +34,28 @@ $ git commit
|
|
|
34
34
|
|
|
35
35
|
</details>
|
|
36
36
|
|
|
37
|
+
## Table of Contents
|
|
38
|
+
|
|
39
|
+
- [Why](#why)
|
|
40
|
+
- [Installation and setup](#installation-and-setup)
|
|
41
|
+
- [Changelog](#changelog)
|
|
42
|
+
- [Command line flags](#command-line-flags)
|
|
43
|
+
- [Configuration](#configuration)
|
|
44
|
+
- [Filtering files](#filtering-files)
|
|
45
|
+
- [What commands are supported?](#what-commands-are-supported)
|
|
46
|
+
- [Running multiple commands in a sequence](#running-multiple-commands-in-a-sequence)
|
|
47
|
+
- [Using JS configuration files](#using-js-configuration-files)
|
|
48
|
+
- [Reformatting the code](#reformatting-the-code)
|
|
49
|
+
- [Examples](#examples)
|
|
50
|
+
- [Frequently Asked Questions](#frequently-asked-questions)
|
|
51
|
+
|
|
37
52
|
## Why
|
|
38
53
|
|
|
39
54
|
Code quality tasks like formatters and linters make more sense when run before committing your code. By doing so you can ensure no errors go into the repository and enforce code style. But running a task on a whole project can be slow, and opinionated tasks such as linting can sometimes produce irrelevant results. Ultimately you only want to check files that will be committed.
|
|
40
55
|
|
|
41
56
|
This project contains a script that will run arbitrary shell tasks with a list of staged files as an argument, filtered by a specified glob pattern.
|
|
42
57
|
|
|
43
|
-
|
|
58
|
+
### Related blog posts and talks
|
|
44
59
|
|
|
45
60
|
- [Introductory Medium post - Andrey Okonetchnikov, 2016](https://medium.com/@okonetchnikov/make-linting-great-again-f3890e1ad6b8#.8qepn2b5l)
|
|
46
61
|
- [Running Jest Tests Before Each Git Commit - Ben McCormick, 2017](https://benmccormick.org/2017/02/26/running-jest-tests-before-each-git-commit/)
|
|
@@ -94,13 +109,12 @@ Options:
|
|
|
94
109
|
-c, --config [path] path to configuration file, or - to read from stdin
|
|
95
110
|
--cwd [path] run all tasks in specific directory, instead of the current
|
|
96
111
|
-d, --debug print additional debug information (default: false)
|
|
97
|
-
--diff [string] override the default "--staged" flag of "git diff" to get list of files.
|
|
98
|
-
|
|
99
|
-
--diff-filter [string] override the default "--diff-filter=ACMR" flag of "git diff" to get list of
|
|
100
|
-
files
|
|
112
|
+
--diff [string] override the default "--staged" flag of "git diff" to get list of files. Implies
|
|
113
|
+
"--no-stash".
|
|
114
|
+
--diff-filter [string] override the default "--diff-filter=ACMR" flag of "git diff" to get list of files
|
|
101
115
|
--max-arg-length [number] maximum length of the command-line argument string (default: 0)
|
|
102
|
-
--no-
|
|
103
|
-
|
|
116
|
+
--no-revert do not revert to original state in case of errors.
|
|
117
|
+
--no-stash disable the backup stash. Implies "--no-revert".
|
|
104
118
|
--no-hide-partially-staged disable hiding unstaged changes from partially staged files
|
|
105
119
|
-q, --quiet disable lint-staged’s own console output (default: false)
|
|
106
120
|
-r, --relative pass relative filepaths to tasks (default: false)
|
|
@@ -129,10 +143,11 @@ Any lost modifications can be restored from a git stash:
|
|
|
129
143
|
- **`--diff`**: By default tasks are filtered against all files staged in git, generated from `git diff --staged`. This option allows you to override the `--staged` flag with arbitrary revisions. For example to get a list of changed files between two branches, use `--diff="branch1...branch2"`. You can also read more from about [git diff](https://git-scm.com/docs/git-diff) and [gitrevisions](https://git-scm.com/docs/gitrevisions). This option also implies `--no-stash`.
|
|
130
144
|
- **`--diff-filter`**: By default only files that are _added_, _copied_, _modified_, or _renamed_ are included. Use this flag to override the default `ACMR` value with something else: _added_ (`A`), _copied_ (`C`), _deleted_ (`D`), _modified_ (`M`), _renamed_ (`R`), _type changed_ (`T`), _unmerged_ (`U`), _unknown_ (`X`), or _pairing broken_ (`B`). See also the `git diff` docs for [--diff-filter](https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---diff-filterACDMRTUXB82308203).
|
|
131
145
|
- **`--max-arg-length`**: long commands (a lot of files) are automatically split into multiple chunks when it detects the current shell cannot handle them. Use this flag to override the maximum length of the generated command string.
|
|
132
|
-
- **`--no-stash`**: By default a backup stash will be created before running the tasks, and all task modifications will be reverted in case of an error. This option will disable creating the stash, and instead leave all modifications in the index when aborting the commit.
|
|
133
|
-
- **`--no-hide-partially-staged`**: By default, unstaged changes from partially staged files will be hidden. This option will disable this behavior
|
|
134
|
-
- **`--quiet`**:
|
|
146
|
+
- **`--no-stash`**: By default a backup stash will be created before running the tasks, and all task modifications will be reverted in case of an error. This option will disable creating the stash, and instead leave all modifications in the index when aborting the commit.
|
|
147
|
+
- **`--no-hide-partially-staged`**: By default, unstaged changes from partially staged files will be hidden and applied back after running tasks. This option will disable this behavior, causing those changes to also be committed.
|
|
148
|
+
- **`--quiet`**: Suppress all CLI output, except from tasks.
|
|
135
149
|
- **`--relative`**: Pass filepaths relative to `process.cwd()` (where `lint-staged` runs) to tasks. Default is `false`.
|
|
150
|
+
- **`--no-revert`**: By default all task modifications will be reverted in case of an error. This option will disable the behavior, and apply task modifications to the index before aborting the commit.
|
|
136
151
|
- **`--verbose`**: Show task output even when tasks succeed. By default only failed output is shown.
|
|
137
152
|
|
|
138
153
|
## Configuration
|
|
@@ -998,7 +1013,7 @@ ESLint v8.51.0 introduced [`--no-warn-ignored` CLI flag](https://eslint.org/docs
|
|
|
998
1013
|
|
|
999
1014
|
When running `lint-staged` via Husky hooks, TypeScript may ignore `tsconfig.json`, leading to errors like:
|
|
1000
1015
|
|
|
1001
|
-
> **TS17004:** Cannot use JSX unless the '--jsx' flag is provided.
|
|
1016
|
+
> **TS17004:** Cannot use JSX unless the '--jsx' flag is provided.
|
|
1002
1017
|
> **TS1056:** Accessors are only available when targeting ECMAScript 5 and higher.
|
|
1003
1018
|
|
|
1004
1019
|
See issue [#825](https://github.com/okonet/lint-staged/issues/825) for more details.
|
package/bin/lint-staged.js
CHANGED
|
@@ -61,30 +61,26 @@ program.option(
|
|
|
61
61
|
program.option('--max-arg-length [number]', 'maximum length of the command-line argument string', 0)
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
* We don't want to show the `--
|
|
65
|
-
* negatable flag `--no-
|
|
64
|
+
* We don't want to show the `--revert` flag because it's on by default, and only show the
|
|
65
|
+
* negatable flag `--no-rever` instead. There seems to be a bug in Commander.js where
|
|
66
66
|
* configuring only the latter won't actually set the default value.
|
|
67
67
|
*/
|
|
68
68
|
program
|
|
69
69
|
.addOption(
|
|
70
|
-
new Option('--
|
|
71
|
-
.default(true)
|
|
72
|
-
.hideHelp()
|
|
70
|
+
new Option('--revert', 'revert to original state in case of errors').default(true).hideHelp()
|
|
73
71
|
)
|
|
74
72
|
.addOption(
|
|
75
|
-
new Option(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
new Option('--no-revert', 'do not revert to original state in case of errors.').default(false)
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
program
|
|
77
|
+
.addOption(new Option('--stash', 'enable the backup stash').default(true).hideHelp())
|
|
78
|
+
.addOption(
|
|
79
|
+
new Option('--no-stash', 'disable the backup stash. Implies "--no-revert".')
|
|
79
80
|
.default(false)
|
|
80
|
-
.implies({
|
|
81
|
+
.implies({ revert: false })
|
|
81
82
|
)
|
|
82
83
|
|
|
83
|
-
/**
|
|
84
|
-
* We don't want to show the `--hide-partially-staged` flag because it's on by default, and only show the
|
|
85
|
-
* negatable flag `--no-hide-partially-staged` in stead. There seems to be a bug in Commander.js where
|
|
86
|
-
* configuring only the latter won't actually set the default value.
|
|
87
|
-
*/
|
|
88
84
|
program
|
|
89
85
|
.addOption(
|
|
90
86
|
new Option('--hide-partially-staged', 'hide unstaged changes from partially staged files')
|
|
@@ -127,6 +123,7 @@ const options = {
|
|
|
127
123
|
maxArgLength: cliOptions.maxArgLength || undefined,
|
|
128
124
|
quiet: !!cliOptions.quiet,
|
|
129
125
|
relative: !!cliOptions.relative,
|
|
126
|
+
revert: !!cliOptions.revert, // commander inverts `no-<x>` flags to `!x`
|
|
130
127
|
stash: !!cliOptions.stash, // commander inverts `no-<x>` flags to `!x`
|
|
131
128
|
hidePartiallyStaged: !!cliOptions.hidePartiallyStaged, // commander inverts `no-<x>` flags to `!x`
|
|
132
129
|
verbose: !!cliOptions.verbose,
|
package/lib/chunkFiles.js
CHANGED
|
@@ -10,7 +10,7 @@ const debugLog = debug('lint-staged:chunkFiles')
|
|
|
10
10
|
* Chunk array into sub-arrays
|
|
11
11
|
* @param {Array} arr
|
|
12
12
|
* @param {Number} chunkCount
|
|
13
|
-
* @
|
|
13
|
+
* @returns {Array<Array>}
|
|
14
14
|
*/
|
|
15
15
|
const chunkArray = (arr, chunkCount) => {
|
|
16
16
|
if (chunkCount === 1) return [arr]
|
|
@@ -27,24 +27,32 @@ const chunkArray = (arr, chunkCount) => {
|
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Chunk files into sub-arrays based on the length of the resulting argument string
|
|
30
|
+
*
|
|
31
|
+
* @typedef {import('./getStagedFiles.js').StagedFile[]} StagedFile
|
|
32
|
+
*
|
|
30
33
|
* @param {Object} opts
|
|
31
|
-
* @param {Array<
|
|
34
|
+
* @param {Array<StagedFile>} opts.files
|
|
32
35
|
* @param {String} [opts.baseDir] The optional base directory to resolve relative paths.
|
|
33
36
|
* @param {number} [opts.maxArgLength] the maximum argument string length
|
|
34
37
|
* @param {Boolean} [opts.relative] whether files are relative to `topLevelDir` or should be resolved as absolute
|
|
35
|
-
* @returns {Array<Array<
|
|
38
|
+
* @returns {Array<Array<StagedFile>>}
|
|
36
39
|
*/
|
|
37
40
|
export const chunkFiles = ({ files, baseDir, maxArgLength = null, relative = false }) => {
|
|
38
|
-
const normalizedFiles = files.map((file) =>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
const normalizedFiles = files.map((file) => {
|
|
42
|
+
return {
|
|
43
|
+
filepath: normalizePath(
|
|
44
|
+
relative || !baseDir ? file.filepath : path.resolve(baseDir, file.filepath)
|
|
45
|
+
),
|
|
46
|
+
status: file.status,
|
|
47
|
+
}
|
|
48
|
+
})
|
|
41
49
|
|
|
42
50
|
if (!maxArgLength) {
|
|
43
51
|
debugLog('Skip chunking files because of undefined maxArgLength')
|
|
44
52
|
return [normalizedFiles] // wrap in an array to return a single chunk
|
|
45
53
|
}
|
|
46
54
|
|
|
47
|
-
const fileListLength = normalizedFiles.join(' ').length
|
|
55
|
+
const fileListLength = normalizedFiles.map((file) => file.filepath).join(' ').length
|
|
48
56
|
debugLog(
|
|
49
57
|
`Resolved an argument string length of ${fileListLength} characters from ${normalizedFiles.length} files`
|
|
50
58
|
)
|
package/lib/generateTasks.js
CHANGED
|
@@ -13,13 +13,17 @@ const debugLog = debug('lint-staged:generateTasks')
|
|
|
13
13
|
* @param {object} options
|
|
14
14
|
* @param {Object} [options.config] - Task configuration
|
|
15
15
|
* @param {Object} [options.cwd] - Current working directory
|
|
16
|
-
* @param {
|
|
16
|
+
* @param {import('./getStagedFiles.js').StagedFile[]} [options.files] - Staged filepaths
|
|
17
17
|
* @param {boolean} [options.relative] - Whether filepaths to should be relative to cwd
|
|
18
18
|
*/
|
|
19
19
|
export const generateTasks = ({ config, cwd = process.cwd(), files, relative = false }) => {
|
|
20
20
|
debugLog('Generating linter tasks')
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
/** @type {StagedFile[]} */
|
|
23
|
+
const relativeFiles = files.map((file) => ({
|
|
24
|
+
filepath: normalizePath(path.relative(cwd, file.filepath)),
|
|
25
|
+
status: file.status,
|
|
26
|
+
}))
|
|
23
27
|
|
|
24
28
|
return Object.entries(config).map(([pattern, commands]) => {
|
|
25
29
|
const isParentDirPattern = pattern.startsWith('../')
|
|
@@ -28,21 +32,34 @@ export const generateTasks = ({ config, cwd = process.cwd(), files, relative = f
|
|
|
28
32
|
// specifies that it concerns a parent directory.
|
|
29
33
|
const filteredFiles = relativeFiles.filter((file) => {
|
|
30
34
|
if (isParentDirPattern) return true
|
|
31
|
-
return !file.startsWith('..') && !path.isAbsolute(file)
|
|
35
|
+
return !file.filepath.startsWith('..') && !path.isAbsolute(file.filepath)
|
|
32
36
|
})
|
|
33
37
|
|
|
34
|
-
const matches = micromatch(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
const matches = micromatch(
|
|
39
|
+
filteredFiles.map((file) => file.filepath),
|
|
40
|
+
pattern,
|
|
41
|
+
{
|
|
42
|
+
cwd,
|
|
43
|
+
dot: true,
|
|
44
|
+
// If the pattern doesn't look like a path, enable `matchBase` to
|
|
45
|
+
// match against filenames in every directory. This makes `*.js`
|
|
46
|
+
// match both `test.js` and `subdirectory/test.js`.
|
|
47
|
+
matchBase: !pattern.includes('/'),
|
|
48
|
+
posixSlashes: true,
|
|
49
|
+
strictBrackets: true,
|
|
50
|
+
}
|
|
51
|
+
)
|
|
44
52
|
|
|
45
|
-
const fileList =
|
|
53
|
+
const fileList = filteredFiles.flatMap((file) =>
|
|
54
|
+
matches.includes(file.filepath)
|
|
55
|
+
? [
|
|
56
|
+
{
|
|
57
|
+
filepath: normalizePath(relative ? file.filepath : path.resolve(cwd, file.filepath)),
|
|
58
|
+
status: file.status,
|
|
59
|
+
},
|
|
60
|
+
]
|
|
61
|
+
: []
|
|
62
|
+
)
|
|
46
63
|
|
|
47
64
|
const task = { pattern, commands, fileList }
|
|
48
65
|
debugLog('Generated task: \n%O', task)
|
package/lib/getFunctionTask.js
CHANGED
|
@@ -15,7 +15,7 @@ export const isFunctionTask = (commands) => typeof commands === 'object' && !Arr
|
|
|
15
15
|
* Handles function configuration and pushes the tasks into the task array
|
|
16
16
|
*
|
|
17
17
|
* @param {object} command
|
|
18
|
-
* @param {
|
|
18
|
+
* @param {import('./getStagedFiles.js').StagedFile[]} files
|
|
19
19
|
* @throws {Error} If the function configuration is not valid
|
|
20
20
|
*/
|
|
21
21
|
export const getFunctionTask = async (command, files) => {
|
|
@@ -23,7 +23,7 @@ export const getFunctionTask = async (command, files) => {
|
|
|
23
23
|
|
|
24
24
|
const task = async (ctx) => {
|
|
25
25
|
try {
|
|
26
|
-
await command.task(files)
|
|
26
|
+
await command.task(files.map((file) => file.filepath))
|
|
27
27
|
} catch (e) {
|
|
28
28
|
throw makeErr(command.title, e, ctx)
|
|
29
29
|
}
|
package/lib/getSpawnedTask.js
CHANGED
|
@@ -116,7 +116,7 @@ export const makeErr = (command, error, ctx) => {
|
|
|
116
116
|
* @param {string} [options.cwd]
|
|
117
117
|
* @param {String} options.topLevelDir - Current git repo top-level path
|
|
118
118
|
* @param {Boolean} options.isFn - Whether the linter task is a function
|
|
119
|
-
* @param {
|
|
119
|
+
* @param {string[]} options.files — Filepaths to run the linter task against
|
|
120
120
|
* @param {Boolean} [options.verbose] — Always show task verbose
|
|
121
121
|
* @returns {() => Promise<Array<string>>}
|
|
122
122
|
*/
|
package/lib/getSpawnedTasks.js
CHANGED
|
@@ -11,7 +11,7 @@ const debugLog = debug('lint-staged:getSpawnedTasks')
|
|
|
11
11
|
* @param {object} options
|
|
12
12
|
* @param {Array<string|Function>|string|Function} options.commands
|
|
13
13
|
* @param {string} options.cwd
|
|
14
|
-
* @param {
|
|
14
|
+
* @param {import('./getStagedFiles.js').StagedFile[]} options.files
|
|
15
15
|
* @param {string} options.topLevelDir
|
|
16
16
|
* @param {Boolean} verbose
|
|
17
17
|
*/
|
|
@@ -21,12 +21,14 @@ export const getSpawnedTasks = async ({ commands, cwd, files, topLevelDir, verbo
|
|
|
21
21
|
|
|
22
22
|
const commandArray = Array.isArray(commands) ? commands : [commands]
|
|
23
23
|
|
|
24
|
+
const filepaths = files.map((f) => f.filepath)
|
|
25
|
+
|
|
24
26
|
for (const cmd of commandArray) {
|
|
25
27
|
// command function may return array of commands that already include `stagedFiles`
|
|
26
28
|
const isFn = typeof cmd === 'function'
|
|
27
29
|
|
|
28
30
|
/** Pass copy of file list to prevent mutation by function from config file. */
|
|
29
|
-
const resolved = isFn ? await cmd([...
|
|
31
|
+
const resolved = isFn ? await cmd([...filepaths]) : cmd
|
|
30
32
|
|
|
31
33
|
const resolvedArray = Array.isArray(resolved) ? resolved : [resolved] // Wrap non-array command as array
|
|
32
34
|
|
|
@@ -43,7 +45,7 @@ export const getSpawnedTasks = async ({ commands, cwd, files, topLevelDir, verbo
|
|
|
43
45
|
)
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
const task = getSpawnedTask({ command, cwd, files, topLevelDir, isFn, verbose })
|
|
48
|
+
const task = getSpawnedTask({ command, cwd, files: filepaths, topLevelDir, isFn, verbose })
|
|
47
49
|
cmdTasks.push({ title: command, command, task })
|
|
48
50
|
}
|
|
49
51
|
}
|
package/lib/getStagedFiles.js
CHANGED
|
@@ -5,6 +5,16 @@ import { getDiffCommand } from './getDiffCommand.js'
|
|
|
5
5
|
import { normalizePath } from './normalizePath.js'
|
|
6
6
|
import { parseGitZOutput } from './parseGitZOutput.js'
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {'A'|'C'|'D'|'M'|'R'|'T'|'U'|'X'} FileSatus
|
|
10
|
+
* @typedef { { filepath: string; status: FileSatus }} StagedFile
|
|
11
|
+
*
|
|
12
|
+
* @param {Object} args
|
|
13
|
+
* @param {string} [args.cwd]
|
|
14
|
+
* @param {string} [args.diff]
|
|
15
|
+
* @param {string} [args.diffFilter]
|
|
16
|
+
* @retuns {Promise<StagedFile[] | null>}
|
|
17
|
+
*/
|
|
8
18
|
export const getStagedFiles = async ({ cwd = process.cwd(), diff, diffFilter } = {}) => {
|
|
9
19
|
try {
|
|
10
20
|
/**
|
|
@@ -35,20 +45,40 @@ export const getStagedFiles = async ({ cwd = process.cwd(), diff, diffFilter } =
|
|
|
35
45
|
.split('\u0000:')
|
|
36
46
|
.map(parseGitZOutput)
|
|
37
47
|
.flatMap(([info, src, dst]) => {
|
|
38
|
-
const [, dstMode, , ,
|
|
48
|
+
const [, dstMode, , , statusWithScore] = info.split(' ')
|
|
39
49
|
|
|
40
50
|
/**
|
|
41
|
-
* Filter out
|
|
42
|
-
* @see https://github.com/git/git/blob/
|
|
51
|
+
* Filter out submodules and symlinks
|
|
52
|
+
* @see https://github.com/git/git/blob/cb96e1697ad6e54d11fc920c95f82977f8e438f8/Documentation/git-fast-import.adoc?plain=1#L634-L646
|
|
43
53
|
*/
|
|
44
|
-
if (dstMode === '160000') {
|
|
54
|
+
if (dstMode === '160000' || dstMode === '120000') {
|
|
45
55
|
return []
|
|
46
56
|
}
|
|
47
57
|
|
|
58
|
+
/**
|
|
59
|
+
* @example "M"
|
|
60
|
+
* @example "R86"
|
|
61
|
+
*
|
|
62
|
+
* - A: addition of a file
|
|
63
|
+
* - C: copy of a file into a new one
|
|
64
|
+
* - D: deletion of a file
|
|
65
|
+
* - M: modification of the contents or mode of a file
|
|
66
|
+
* - R: renaming of a file
|
|
67
|
+
* - T: change in the type of the file (regular file, symbolic link or submodule)
|
|
68
|
+
* - U: file is unmerged (you must complete the merge before it can be committed)
|
|
69
|
+
* - X: "unknown" change type (most probably a bug, please report it)
|
|
70
|
+
*/
|
|
71
|
+
const status = statusWithScore[0]
|
|
72
|
+
|
|
48
73
|
/** "dst" exists when moving files, otherwise it's undefined and only "src" exists */
|
|
49
74
|
const filename = dst ?? src
|
|
50
75
|
|
|
51
|
-
return [
|
|
76
|
+
return [
|
|
77
|
+
{
|
|
78
|
+
filepath: normalizePath(path.resolve(cwd, filename)),
|
|
79
|
+
status,
|
|
80
|
+
},
|
|
81
|
+
]
|
|
52
82
|
})
|
|
53
83
|
} catch {
|
|
54
84
|
return null
|
package/lib/gitWorkflow.js
CHANGED
|
@@ -66,6 +66,10 @@ const handleError = (error, ctx, symbol) => {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export class GitWorkflow {
|
|
69
|
+
/**
|
|
70
|
+
* @param {Object} opts
|
|
71
|
+
* @param {import('./getStagedFiles.js').StagedFile[][]} opts.matchedFileChunks
|
|
72
|
+
*/
|
|
69
73
|
constructor({ allowEmpty, gitConfigDir, topLevelDir, matchedFileChunks, diff, diffFilter }) {
|
|
70
74
|
this.execGit = (args, options = {}) => execGit(args, { ...options, cwd: topLevelDir })
|
|
71
75
|
this.deletedFiles = []
|
|
@@ -74,6 +78,7 @@ export class GitWorkflow {
|
|
|
74
78
|
this.diff = diff
|
|
75
79
|
this.diffFilter = diffFilter
|
|
76
80
|
this.allowEmpty = allowEmpty
|
|
81
|
+
/** @type {import('./getStagedFiles.js').StagedFile[][]} */
|
|
77
82
|
this.matchedFileChunks = matchedFileChunks
|
|
78
83
|
|
|
79
84
|
/**
|
|
@@ -185,7 +190,7 @@ export class GitWorkflow {
|
|
|
185
190
|
const [index, workingTree] = line
|
|
186
191
|
return index !== ' ' && workingTree !== ' ' && index !== '?' && workingTree !== '?'
|
|
187
192
|
})
|
|
188
|
-
.map((line) => line.
|
|
193
|
+
.map((line) => line.slice(3)) // Remove first three letters (index, workingTree, and a whitespace)
|
|
189
194
|
.filter(Boolean) // Filter empty string
|
|
190
195
|
debugLog('Found partially staged files:', partiallyStaged)
|
|
191
196
|
return partiallyStaged.length ? partiallyStaged : null
|
|
@@ -198,13 +203,14 @@ export class GitWorkflow {
|
|
|
198
203
|
try {
|
|
199
204
|
debugLog(task.title)
|
|
200
205
|
|
|
201
|
-
// Get a list of files with
|
|
206
|
+
// Get a list of files with both staged and unstaged changes.
|
|
202
207
|
// Unstaged changes to these files should be hidden before the tasks run.
|
|
203
208
|
this.partiallyStagedFiles = await this.getPartiallyStagedFiles()
|
|
204
209
|
|
|
205
210
|
if (this.partiallyStagedFiles) {
|
|
206
211
|
ctx.hasPartiallyStagedFiles = true
|
|
207
212
|
const unstagedPatch = this.getHiddenFilepath(PATCH_UNSTAGED)
|
|
213
|
+
ctx.unstagedPatch = unstagedPatch
|
|
208
214
|
const files = processRenames(this.partiallyStagedFiles)
|
|
209
215
|
await this.execGit(['diff', ...GIT_DIFF_ARGS, '--output', unstagedPatch, '--', ...files])
|
|
210
216
|
} else {
|
|
@@ -273,7 +279,8 @@ export class GitWorkflow {
|
|
|
273
279
|
// These additions per chunk are run "serially" to prevent race conditions.
|
|
274
280
|
// Git add creates a lockfile in the repo causing concurrent operations to fail.
|
|
275
281
|
for (const files of this.matchedFileChunks) {
|
|
276
|
-
|
|
282
|
+
/** @todo Deleted files cannot be staged because they're... deleted */
|
|
283
|
+
await this.execGit(['add', '--', ...files.map((f) => f.filepath)])
|
|
277
284
|
}
|
|
278
285
|
|
|
279
286
|
debugLog('Done adding task modifications to index!')
|
|
@@ -4,10 +4,17 @@ import debug from 'debug'
|
|
|
4
4
|
|
|
5
5
|
const debugLog = debug('lint-staged:groupFilesByConfig')
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {import('./getStagedFiles.js').StagedFile} StagedFile
|
|
9
|
+
* @type {(args: { config: {[key: string]: { config: any; files: string[] }}; files: StagedFile[]; singleConfigMode?: boolean }) => Promise<{[key: string]: { config: any; files: StagedFile[] } }>
|
|
10
|
+
*/
|
|
7
11
|
export const groupFilesByConfig = async ({ configs, files, singleConfigMode }) => {
|
|
8
12
|
debugLog('Grouping %d files by %d configurations', files.length, Object.keys(configs).length)
|
|
9
13
|
|
|
14
|
+
/** @type {Set<StagedFile>} */
|
|
10
15
|
const filesSet = new Set(files)
|
|
16
|
+
|
|
17
|
+
/** @type {{[key: string]: { config: any; files: StagedFile[] } }} */
|
|
11
18
|
const filesByConfig = {}
|
|
12
19
|
|
|
13
20
|
/** Configs are sorted deepest first by `searchConfigs` */
|
|
@@ -22,7 +29,7 @@ export const groupFilesByConfig = async ({ configs, files, singleConfigMode }) =
|
|
|
22
29
|
|
|
23
30
|
/** Check if file is inside directory of the configuration file */
|
|
24
31
|
const isInsideDir = (file) => {
|
|
25
|
-
const relative = path.relative(dir, file)
|
|
32
|
+
const relative = path.relative(dir, file.filepath)
|
|
26
33
|
return relative && !relative.startsWith('..') && !path.isAbsolute(relative)
|
|
27
34
|
}
|
|
28
35
|
|
package/lib/index.d.ts
CHANGED
|
@@ -66,6 +66,11 @@ export type Options = {
|
|
|
66
66
|
* @default false
|
|
67
67
|
*/
|
|
68
68
|
relative?: boolean
|
|
69
|
+
/**
|
|
70
|
+
* Revert to original state in case of errors
|
|
71
|
+
* @default true
|
|
72
|
+
*/
|
|
73
|
+
revert?: boolean
|
|
69
74
|
/**
|
|
70
75
|
* Enable the backup stash, and revert in case of errors.
|
|
71
76
|
* @warn Disabling this also implies `hidePartiallyStaged: false`.
|
package/lib/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
NO_CONFIGURATION,
|
|
7
7
|
PREVENTED_EMPTY_COMMIT,
|
|
8
8
|
RESTORE_STASH_EXAMPLE,
|
|
9
|
+
UNSTAGED_CHANGES_BACKUP_STASH_LOCATION,
|
|
9
10
|
} from './messages.js'
|
|
10
11
|
import { printTaskOutput } from './printTaskOutput.js'
|
|
11
12
|
import { runAll } from './runAll.js'
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
ConfigNotFoundError,
|
|
16
17
|
GetBackupStashError,
|
|
17
18
|
GitError,
|
|
19
|
+
RestoreUnstagedChangesError,
|
|
18
20
|
} from './symbols.js'
|
|
19
21
|
import { validateOptions } from './validateOptions.js'
|
|
20
22
|
import { getVersion } from './version.js'
|
|
@@ -57,6 +59,7 @@ const getMaxArgLength = () => {
|
|
|
57
59
|
* @param {number} [options.maxArgLength] - Maximum argument string length
|
|
58
60
|
* @param {boolean} [options.quiet] - Disable lint-staged’s own console output
|
|
59
61
|
* @param {boolean} [options.relative] - Pass relative filepaths to tasks
|
|
62
|
+
* @param {boolean} [options.revert] - revert to original state in case of errors
|
|
60
63
|
* @param {boolean} [options.stash] - Enable the backup stash, and revert in case of errors
|
|
61
64
|
* @param {boolean} [options.verbose] - Show task output even when tasks succeed; by default only failed output is shown
|
|
62
65
|
* @param {Logger} [logger]
|
|
@@ -78,7 +81,9 @@ const lintStaged = async (
|
|
|
78
81
|
relative = false,
|
|
79
82
|
// Stashing should be disabled by default when the `diff` option is used
|
|
80
83
|
stash = diff === undefined,
|
|
81
|
-
|
|
84
|
+
// Cannot revert to original state without stash
|
|
85
|
+
revert = stash,
|
|
86
|
+
hidePartiallyStaged = true,
|
|
82
87
|
verbose = false,
|
|
83
88
|
} = {},
|
|
84
89
|
logger = console
|
|
@@ -110,6 +115,7 @@ const lintStaged = async (
|
|
|
110
115
|
maxArgLength,
|
|
111
116
|
quiet,
|
|
112
117
|
relative,
|
|
118
|
+
revert,
|
|
113
119
|
stash,
|
|
114
120
|
hidePartiallyStaged,
|
|
115
121
|
verbose,
|
|
@@ -134,6 +140,9 @@ const lintStaged = async (
|
|
|
134
140
|
logger.error(NO_CONFIGURATION)
|
|
135
141
|
} else if (ctx.errors.has(ApplyEmptyCommitError)) {
|
|
136
142
|
logger.warn(PREVENTED_EMPTY_COMMIT)
|
|
143
|
+
} else if (ctx.errors.has(RestoreUnstagedChangesError)) {
|
|
144
|
+
logger.warn(UNSTAGED_CHANGES_BACKUP_STASH_LOCATION)
|
|
145
|
+
logger.warn(ctx.unstagedPatch)
|
|
137
146
|
} else if (
|
|
138
147
|
(ctx.errors.has(GitError) || cleanupSkipped(ctx)) &&
|
|
139
148
|
!ctx.errors.has(GetBackupStashError)
|
package/lib/messages.js
CHANGED
|
@@ -31,25 +31,15 @@ export const skippingBackup = (hasInitialCommit, diff) => {
|
|
|
31
31
|
const reason =
|
|
32
32
|
diff !== undefined
|
|
33
33
|
? '`--diff` was used'
|
|
34
|
-
: hasInitialCommit
|
|
35
|
-
|
|
36
|
-
: 'there’s no initial commit yet'
|
|
34
|
+
: (hasInitialCommit ? '`--no-stash` was used' : 'there’s no initial commit yet') +
|
|
35
|
+
'. This might result in data loss'
|
|
37
36
|
|
|
38
37
|
return chalk.yellow(`${warning} Skipping backup because ${reason}.\n`)
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
export const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
? '`--diff` was used'
|
|
45
|
-
: !stash
|
|
46
|
-
? '`--no-stash` was used'
|
|
47
|
-
: '`--no-hide-partially-staged` was used'
|
|
48
|
-
|
|
49
|
-
return chalk.yellow(
|
|
50
|
-
`${warning} Skipping hiding unstaged changes from partially staged files because ${reason}.\n`
|
|
51
|
-
)
|
|
52
|
-
}
|
|
40
|
+
export const SKIPPING_HIDE_PARTIALLY_CHANGED = chalk.yellow(
|
|
41
|
+
`${warning} Skipping hiding unstaged changes from partially staged files because \`--no-hide-partially-staged\` was used.\n`
|
|
42
|
+
)
|
|
53
43
|
|
|
54
44
|
export const DEPRECATED_GIT_ADD = chalk.yellow(
|
|
55
45
|
`${warning} Some of your tasks use \`git add\` command. Please remove it from the config since all modifications made by tasks will be automatically added to the git commit index.
|
|
@@ -96,3 +86,5 @@ export const failedToParseConfig = (
|
|
|
96
86
|
${error}
|
|
97
87
|
|
|
98
88
|
See https://github.com/okonet/lint-staged#configuration.`
|
|
89
|
+
|
|
90
|
+
export const UNSTAGED_CHANGES_BACKUP_STASH_LOCATION = `Unstaged changes have been kept back in a patch file:`
|
package/lib/runAll.js
CHANGED
|
@@ -22,8 +22,8 @@ import {
|
|
|
22
22
|
NO_TASKS,
|
|
23
23
|
NOT_GIT_REPO,
|
|
24
24
|
SKIPPED_GIT_ERROR,
|
|
25
|
+
SKIPPING_HIDE_PARTIALLY_CHANGED,
|
|
25
26
|
skippingBackup,
|
|
26
|
-
skippingHidePartiallyStaged,
|
|
27
27
|
} from './messages.js'
|
|
28
28
|
import { normalizePath } from './normalizePath.js'
|
|
29
29
|
import { resolveGitRepo } from './resolveGitRepo.js'
|
|
@@ -42,7 +42,12 @@ import { ConfigNotFoundError, GetStagedFilesError, GitError, GitRepoError } from
|
|
|
42
42
|
|
|
43
43
|
const debugLog = debug('lint-staged:runAll')
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
/**
|
|
46
|
+
* @param {ReturnType<typeof getInitialState>} ctx context
|
|
47
|
+
* @param {unknown} cause error cause
|
|
48
|
+
*/
|
|
49
|
+
const createError = (ctx, cause) =>
|
|
50
|
+
Object.assign(new Error('lint-staged failed', { cause }), { ctx })
|
|
46
51
|
|
|
47
52
|
/**
|
|
48
53
|
* Executes all tasks and either resolves or rejects the promise
|
|
@@ -59,6 +64,7 @@ const createError = (ctx) => Object.assign(new Error('lint-staged failed'), { ct
|
|
|
59
64
|
* @param {number} [options.maxArgLength] - Maximum argument string length
|
|
60
65
|
* @param {boolean} [options.quiet] - Disable lint-staged’s own console output
|
|
61
66
|
* @param {boolean} [options.relative] - Pass relative filepaths to tasks
|
|
67
|
+
* @param {boolean} [options.revert] - revert to original state in case of errors
|
|
62
68
|
* @param {boolean} [options.stash] - Enable the backup stash, and revert in case of errors
|
|
63
69
|
* @param {boolean} [options.verbose] - Show task output even when tasks succeed; by default only failed output is shown
|
|
64
70
|
* @param {Logger} logger
|
|
@@ -79,7 +85,9 @@ export const runAll = async (
|
|
|
79
85
|
relative = false,
|
|
80
86
|
// Stashing should be disabled by default when the `diff` option is used
|
|
81
87
|
stash = diff === undefined,
|
|
82
|
-
|
|
88
|
+
// Cannot revert to original state without stash
|
|
89
|
+
revert = stash,
|
|
90
|
+
hidePartiallyStaged = true,
|
|
83
91
|
verbose = false,
|
|
84
92
|
},
|
|
85
93
|
logger = console
|
|
@@ -91,13 +99,13 @@ export const runAll = async (
|
|
|
91
99
|
cwd = hasExplicitCwd ? path.resolve(cwd) : process.cwd()
|
|
92
100
|
debugLog('Using working directory `%s`', cwd)
|
|
93
101
|
|
|
94
|
-
const ctx = getInitialState({ quiet })
|
|
102
|
+
const ctx = getInitialState({ quiet, revert })
|
|
95
103
|
|
|
96
104
|
const { topLevelDir, gitConfigDir } = await resolveGitRepo(cwd)
|
|
97
105
|
if (!topLevelDir) {
|
|
98
106
|
if (!quiet) ctx.output.push(NOT_GIT_REPO)
|
|
99
107
|
ctx.errors.add(GitRepoError)
|
|
100
|
-
throw createError(ctx)
|
|
108
|
+
throw createError(ctx, GitRepoError)
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
// Test whether we have any commits or not.
|
|
@@ -115,19 +123,19 @@ export const runAll = async (
|
|
|
115
123
|
|
|
116
124
|
ctx.shouldHidePartiallyStaged = hidePartiallyStaged
|
|
117
125
|
if (!ctx.shouldHidePartiallyStaged && !quiet) {
|
|
118
|
-
logger.warn(
|
|
126
|
+
logger.warn(SKIPPING_HIDE_PARTIALLY_CHANGED)
|
|
119
127
|
}
|
|
120
128
|
|
|
121
|
-
const
|
|
122
|
-
if (!
|
|
129
|
+
const stagedFiles = await getStagedFiles({ cwd: topLevelDir, diff, diffFilter })
|
|
130
|
+
if (!stagedFiles) {
|
|
123
131
|
if (!quiet) ctx.output.push(FAILED_GET_STAGED_FILES)
|
|
124
132
|
ctx.errors.add(GetStagedFilesError)
|
|
125
133
|
throw createError(ctx, GetStagedFilesError)
|
|
126
134
|
}
|
|
127
|
-
debugLog('Loaded list of staged files in git:\n%O',
|
|
135
|
+
debugLog('Loaded list of staged files in git:\n%O', stagedFiles)
|
|
128
136
|
|
|
129
137
|
// If there are no files avoid executing any lint-staged logic
|
|
130
|
-
if (
|
|
138
|
+
if (stagedFiles.length === 0) {
|
|
131
139
|
if (!quiet) ctx.output.push(NO_STAGED_FILES)
|
|
132
140
|
return ctx
|
|
133
141
|
}
|
|
@@ -143,7 +151,7 @@ export const runAll = async (
|
|
|
143
151
|
|
|
144
152
|
const filesByConfig = await groupFilesByConfig({
|
|
145
153
|
configs: foundConfigs,
|
|
146
|
-
files,
|
|
154
|
+
files: stagedFiles,
|
|
147
155
|
singleConfigMode: configObject || configPath !== undefined,
|
|
148
156
|
})
|
|
149
157
|
|
|
@@ -171,6 +179,7 @@ export const runAll = async (
|
|
|
171
179
|
const listrTasks = []
|
|
172
180
|
|
|
173
181
|
// Set of all staged files that matched a task glob. Values in a set are unique.
|
|
182
|
+
/** @type {Set<import('./getStagedFiles.js').StagedFile>} */
|
|
174
183
|
const matchedFiles = new Set()
|
|
175
184
|
|
|
176
185
|
for (const [configPath, { config, files }] of Object.entries(filesByConfig)) {
|
|
@@ -192,7 +201,7 @@ export const runAll = async (
|
|
|
192
201
|
const chunkListrTasks = await Promise.all(
|
|
193
202
|
generateTasks({ config, cwd: groupCwd, files, relative }).map((task) =>
|
|
194
203
|
(isFunctionTask(task.commands)
|
|
195
|
-
? getFunctionTask(task.commands,
|
|
204
|
+
? getFunctionTask(task.commands, task.fileList)
|
|
196
205
|
: getSpawnedTasks({
|
|
197
206
|
commands: task.commands,
|
|
198
207
|
cwd: groupCwd,
|
|
@@ -206,9 +215,12 @@ export const runAll = async (
|
|
|
206
215
|
// Make sure relative files are normalized to the
|
|
207
216
|
// group cwd, because other there might be identical
|
|
208
217
|
// relative filenames in the entire set.
|
|
209
|
-
const normalizedFile = path.isAbsolute(file)
|
|
218
|
+
const normalizedFile = path.isAbsolute(file.filepath)
|
|
210
219
|
? file
|
|
211
|
-
:
|
|
220
|
+
: {
|
|
221
|
+
filepath: normalizePath(path.join(groupCwd, file.filepath)),
|
|
222
|
+
status: file.status,
|
|
223
|
+
}
|
|
212
224
|
|
|
213
225
|
matchedFiles.add(normalizedFile)
|
|
214
226
|
})
|
|
@@ -272,6 +284,7 @@ export const runAll = async (
|
|
|
272
284
|
}
|
|
273
285
|
|
|
274
286
|
// Chunk matched files for better Windows compatibility
|
|
287
|
+
/** @type {import('./getStagedFiles.js').StagedFile[][]} */
|
|
275
288
|
const matchedFileChunks = chunkFiles({
|
|
276
289
|
// matched files are relative to `cwd`, not `topLevelDir`, when `relative` is used
|
|
277
290
|
baseDir: cwd,
|
|
@@ -289,6 +302,8 @@ export const runAll = async (
|
|
|
289
302
|
diffFilter,
|
|
290
303
|
})
|
|
291
304
|
|
|
305
|
+
logger.log('shouldHidePartiallyStagedFiles', shouldHidePartiallyStagedFiles(ctx))
|
|
306
|
+
|
|
292
307
|
const runner = new Listr(
|
|
293
308
|
[
|
|
294
309
|
{
|
package/lib/state.js
CHANGED
|
@@ -8,23 +8,25 @@ import {
|
|
|
8
8
|
TaskError,
|
|
9
9
|
} from './symbols.js'
|
|
10
10
|
|
|
11
|
-
export const getInitialState = ({ quiet = false } = {}) => ({
|
|
12
|
-
hasPartiallyStagedFiles: null,
|
|
13
|
-
shouldBackup: null,
|
|
11
|
+
export const getInitialState = ({ quiet = false, revert = true } = {}) => ({
|
|
14
12
|
backupHash: null,
|
|
15
|
-
shouldHidePartiallyStaged: true,
|
|
16
13
|
errors: new Set([]),
|
|
17
14
|
events: new EventEmitter(),
|
|
15
|
+
hasPartiallyStagedFiles: null,
|
|
18
16
|
output: [],
|
|
19
17
|
quiet,
|
|
18
|
+
shouldBackup: null,
|
|
19
|
+
shouldHidePartiallyStaged: true,
|
|
20
|
+
shouldRevert: revert,
|
|
21
|
+
unstagedPatch: null,
|
|
20
22
|
})
|
|
21
23
|
|
|
22
24
|
export const shouldHidePartiallyStagedFiles = (ctx) =>
|
|
23
25
|
ctx.hasPartiallyStagedFiles && ctx.shouldHidePartiallyStaged
|
|
24
26
|
|
|
25
27
|
export const applyModificationsSkipped = (ctx) => {
|
|
26
|
-
// Always apply back unstaged modifications when skipping backup
|
|
27
|
-
if (!ctx.shouldBackup) return false
|
|
28
|
+
// Always apply back unstaged modifications when skipping revert or backup
|
|
29
|
+
if (!ctx.shouldRevert || !ctx.shouldBackup) return false
|
|
28
30
|
// Should be skipped in case of git errors
|
|
29
31
|
if (ctx.errors.has(GitError)) {
|
|
30
32
|
return GIT_ERROR
|
|
@@ -48,7 +50,9 @@ export const restoreUnstagedChangesSkipped = (ctx) => {
|
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
export const restoreOriginalStateEnabled = (ctx) =>
|
|
51
|
-
ctx.
|
|
53
|
+
!!ctx.shouldRevert &&
|
|
54
|
+
!!ctx.shouldBackup &&
|
|
55
|
+
(ctx.errors.has(TaskError) || ctx.errors.has(RestoreUnstagedChangesError))
|
|
52
56
|
|
|
53
57
|
export const restoreOriginalStateSkipped = (ctx) => {
|
|
54
58
|
// Should be skipped in case of unknown git errors
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lint-staged",
|
|
3
|
-
"version": "16.
|
|
3
|
+
"version": "16.1.1",
|
|
4
4
|
"description": "Lint files staged by git",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"url": "https://opencollective.com/lint-staged"
|
|
22
22
|
},
|
|
23
23
|
"engines": {
|
|
24
|
-
"node": ">=20.
|
|
24
|
+
"node": ">=20.17"
|
|
25
25
|
},
|
|
26
26
|
"type": "module",
|
|
27
27
|
"bin": {
|
|
@@ -48,36 +48,36 @@
|
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"chalk": "^5.4.1",
|
|
51
|
-
"commander": "^
|
|
52
|
-
"debug": "^4.4.
|
|
51
|
+
"commander": "^14.0.0",
|
|
52
|
+
"debug": "^4.4.1",
|
|
53
53
|
"lilconfig": "^3.1.3",
|
|
54
54
|
"listr2": "^8.3.3",
|
|
55
55
|
"micromatch": "^4.0.8",
|
|
56
|
-
"nano-spawn": "^1.0.
|
|
56
|
+
"nano-spawn": "^1.0.2",
|
|
57
57
|
"pidtree": "^0.6.0",
|
|
58
58
|
"string-argv": "^0.3.2",
|
|
59
|
-
"yaml": "^2.
|
|
59
|
+
"yaml": "^2.8.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@changesets/changelog-github": "0.5.1",
|
|
63
|
-
"@changesets/cli": "2.29.
|
|
63
|
+
"@changesets/cli": "2.29.4",
|
|
64
64
|
"@commitlint/cli": "19.8.1",
|
|
65
65
|
"@commitlint/config-conventional": "19.8.1",
|
|
66
|
-
"@eslint/js": "9.
|
|
66
|
+
"@eslint/js": "9.29.0",
|
|
67
67
|
"consolemock": "1.1.0",
|
|
68
68
|
"cross-env": "7.0.3",
|
|
69
|
-
"eslint": "9.
|
|
69
|
+
"eslint": "9.29.0",
|
|
70
70
|
"eslint-config-prettier": "10.1.5",
|
|
71
|
-
"eslint-plugin-jest": "28.
|
|
72
|
-
"eslint-plugin-n": "17.
|
|
73
|
-
"eslint-plugin-prettier": "5.4.
|
|
71
|
+
"eslint-plugin-jest": "28.13.5",
|
|
72
|
+
"eslint-plugin-n": "17.20.0",
|
|
73
|
+
"eslint-plugin-prettier": "5.4.1",
|
|
74
74
|
"eslint-plugin-simple-import-sort": "12.1.1",
|
|
75
75
|
"husky": "9.1.7",
|
|
76
|
-
"jest": "
|
|
76
|
+
"jest": "30.0.0",
|
|
77
77
|
"jest-snapshot-serializer-ansi": "2.2.1",
|
|
78
78
|
"mock-stdin": "1.0.0",
|
|
79
79
|
"prettier": "3.5.3",
|
|
80
|
-
"semver": "7.7.
|
|
80
|
+
"semver": "7.7.2",
|
|
81
81
|
"typescript": "5.8.3"
|
|
82
82
|
},
|
|
83
83
|
"keywords": [
|