@depup/lint-staged 16.4.0-depup.1 → 17.1.0-depup.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/MIGRATION.md +20 -0
- package/README.md +3 -12
- package/bin/lint-staged.js +20 -139
- package/changes.json +3 -20
- package/lib/assertGitVersion.js +48 -0
- package/lib/cli.js +251 -0
- package/lib/colors.js +18 -95
- package/lib/debug.js +4 -6
- package/lib/execGit.js +4 -18
- package/lib/figures.js +9 -5
- package/lib/getFunctionTask.js +13 -4
- package/lib/getSpawnedTask.js +10 -11
- package/lib/getSpawnedTasks.js +3 -6
- package/lib/gitWorkflow.js +229 -119
- package/lib/index.d.ts +5 -0
- package/lib/index.js +23 -13
- package/lib/messages.js +45 -32
- package/lib/parseGitZOutput.js +1 -1
- package/lib/printTaskOutput.js +2 -2
- package/lib/runAll.js +116 -107
- package/lib/runParallelTasks.js +112 -0
- package/lib/state.js +47 -26
- package/lib/validateOptions.js +9 -0
- package/package.json +30 -52
- package/lib/getRenderer.js +0 -63
package/MIGRATION.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## v17
|
|
2
|
+
|
|
3
|
+
#### Node.js v20 is no longer supported.
|
|
4
|
+
|
|
5
|
+
The oldest supported Node.js version is now 22.22.1, which is the latest active v22 LTS version at the time of release. You can — of course — update to v24 or v25, or later.
|
|
6
|
+
|
|
7
|
+
#### The `yaml` dependency is now optional
|
|
8
|
+
|
|
9
|
+
The dependency `yaml` is now marked as optional and probably won't be installed by default. If you're using a YAML configuration file you should install the package separately:
|
|
10
|
+
|
|
11
|
+
```shell
|
|
12
|
+
npm install --development yaml
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
If you're using `.lintstagedrc` as the config file name (without a file extension), it will be treated as a YAML file. If the content is JSON, consider renaming it to `.lintstagedrc.json` to avoid needing to install `yaml`.
|
|
16
|
+
|
|
17
|
+
#### Git version needs to be at least 2.32.0
|
|
18
|
+
|
|
19
|
+
_Lint-staged_ now tries to verify the installed Git version is at least `2.32.0`, released in 2021. If you're using an even older Git version, you need to [upgrade](https://git-scm.com/install/mac) it before running _lint-staged_!
|
|
20
|
+
|
|
1
21
|
## v16
|
|
2
22
|
|
|
3
23
|
#### Updated Node.js version requirement
|
package/README.md
CHANGED
|
@@ -13,19 +13,10 @@ npm install @depup/lint-staged
|
|
|
13
13
|
|
|
14
14
|
| Field | Value |
|
|
15
15
|
|-------|-------|
|
|
16
|
-
| Original | [lint-staged](https://www.npmjs.com/package/lint-staged) @
|
|
17
|
-
| Processed | 2026-
|
|
16
|
+
| Original | [lint-staged](https://www.npmjs.com/package/lint-staged) @ 17.1.0 |
|
|
17
|
+
| Processed | 2026-07-21 |
|
|
18
18
|
| Smoke test | passed |
|
|
19
|
-
| Deps updated |
|
|
20
|
-
|
|
21
|
-
## Dependency Changes
|
|
22
|
-
|
|
23
|
-
| Dependency | From | To |
|
|
24
|
-
|------------|------|-----|
|
|
25
|
-
| listr2 | ^9.0.5 | ^10.2.1 |
|
|
26
|
-
| picomatch | ^4.0.3 | ^4.0.4 |
|
|
27
|
-
| tinyexec | ^1.0.4 | ^1.1.1 |
|
|
28
|
-
| yaml | ^2.8.2 | ^2.8.3 |
|
|
19
|
+
| Deps updated | 0 |
|
|
29
20
|
|
|
30
21
|
---
|
|
31
22
|
|
package/bin/lint-staged.js
CHANGED
|
@@ -2,152 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
import { userInfo } from 'node:os'
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import { getVersionNumber, parseCliOptions, printHelpText } from '../lib/cli.js'
|
|
6
|
+
import { enableColors } from '../lib/colors.js'
|
|
7
7
|
import { createDebug, enableDebug } from '../lib/debug.js'
|
|
8
8
|
import lintStaged from '../lib/index.js'
|
|
9
|
-
import { CONFIG_STDIN_ERROR, restoreStashExample } from '../lib/messages.js'
|
|
10
9
|
import { readStdin } from '../lib/readStdin.js'
|
|
11
|
-
import { getVersion } from '../lib/version.js'
|
|
12
10
|
|
|
11
|
+
enableColors(!!process.stdout.hasColors?.())
|
|
13
12
|
const debugLog = createDebug('lint-staged:bin')
|
|
14
13
|
|
|
15
|
-
//
|
|
14
|
+
// SIGINT handled by an AbortController
|
|
16
15
|
process.on('SIGINT', () => {})
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
.version(await getVersion())
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* This shouldn't be necessary for lint-staged, but add migration step just in case
|
|
23
|
-
* to preserve old behavior of "commander".
|
|
24
|
-
*
|
|
25
|
-
* @todo remove this in the major version
|
|
26
|
-
* @see https://github.com/tj/commander.js/releases/tag/v13.0.0
|
|
27
|
-
* */
|
|
28
|
-
.allowExcessArguments()
|
|
29
|
-
|
|
30
|
-
.addOption(
|
|
31
|
-
new Option('--allow-empty', 'allow empty commits when tasks revert all staged changes').default(
|
|
32
|
-
false
|
|
33
|
-
)
|
|
34
|
-
)
|
|
35
|
-
.addOption(
|
|
36
|
-
new Option(
|
|
37
|
-
'-p, --concurrent <number|boolean>',
|
|
38
|
-
'the number of tasks to run concurrently, or false for serial'
|
|
39
|
-
).default(true)
|
|
40
|
-
)
|
|
41
|
-
.addOption(
|
|
42
|
-
new Option('-c, --config [path]', 'path to configuration file, or - to read from stdin')
|
|
43
|
-
)
|
|
44
|
-
.addOption(
|
|
45
|
-
new Option('--cwd [path]', 'run all tasks in specific directory, instead of the current')
|
|
46
|
-
)
|
|
47
|
-
.addOption(new Option('-d, --debug', 'print additional debug information').default(false))
|
|
48
|
-
.addOption(
|
|
49
|
-
new Option(
|
|
50
|
-
'--diff [string]',
|
|
51
|
-
'override the default "--staged" flag of "git diff" to get list of files. Implies "--no-stash".'
|
|
52
|
-
).implies({ stash: false })
|
|
53
|
-
)
|
|
54
|
-
.addOption(
|
|
55
|
-
new Option(
|
|
56
|
-
'--diff-filter [string]',
|
|
57
|
-
'override the default "--diff-filter=ACMR" flag of "git diff" to get list of files'
|
|
58
|
-
)
|
|
59
|
-
)
|
|
60
|
-
.addOption(
|
|
61
|
-
new Option('--continue-on-error', 'run all tasks to completion even if one fails').default(
|
|
62
|
-
false
|
|
63
|
-
)
|
|
64
|
-
)
|
|
65
|
-
.addOption(
|
|
66
|
-
new Option('--fail-on-changes', 'fail with exit code 1 when tasks modify tracked files')
|
|
67
|
-
.default(false)
|
|
68
|
-
.implies({ revert: false })
|
|
69
|
-
)
|
|
70
|
-
.addOption(
|
|
71
|
-
new Option(
|
|
72
|
-
'--max-arg-length [number]',
|
|
73
|
-
'maximum length of the command-line argument string'
|
|
74
|
-
).default(0)
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* We don't want to show the `--revert` flag because it's on by default, and only show the
|
|
79
|
-
* negatable flag `--no-rever` instead. There seems to be a bug in Commander.js where
|
|
80
|
-
* configuring only the latter won't actually set the default value.
|
|
81
|
-
*/
|
|
82
|
-
.addOption(
|
|
83
|
-
new Option('--revert', 'revert to original state in case of errors').default(true).hideHelp()
|
|
84
|
-
)
|
|
85
|
-
.addOption(
|
|
86
|
-
new Option('--no-revert', 'do not revert to original state in case of errors.').default(false)
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
.addOption(new Option('--stash', 'enable the backup stash').default(true).hideHelp())
|
|
90
|
-
.addOption(
|
|
91
|
-
new Option('--no-stash', 'disable the backup stash. Implies "--no-revert".')
|
|
92
|
-
.default(false)
|
|
93
|
-
.implies({ revert: false })
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
.addOption(
|
|
97
|
-
new Option('--hide-partially-staged', 'hide unstaged changes from partially staged files')
|
|
98
|
-
.default(true)
|
|
99
|
-
.hideHelp()
|
|
100
|
-
)
|
|
101
|
-
.addOption(
|
|
102
|
-
new Option(
|
|
103
|
-
'--no-hide-partially-staged',
|
|
104
|
-
'disable hiding unstaged changes from partially staged files'
|
|
105
|
-
).default(false)
|
|
106
|
-
)
|
|
17
|
+
const cliOptions = parseCliOptions(process.argv)
|
|
107
18
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
.addOption(new Option('-q, --quiet', 'disable lint-staged’s own console output').default(false))
|
|
115
|
-
.addOption(new Option('-r, --relative', 'pass relative filepaths to tasks').default(false))
|
|
116
|
-
.addOption(
|
|
117
|
-
new Option(
|
|
118
|
-
'-v, --verbose',
|
|
119
|
-
'show task output even when tasks succeed; by default only failed output is shown'
|
|
120
|
-
).default(false)
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
.addHelpText('afterAll', '\n' + restoreStashExample())
|
|
19
|
+
if (cliOptions.version) {
|
|
20
|
+
console.log(await getVersionNumber())
|
|
21
|
+
process.exit(0)
|
|
22
|
+
}
|
|
124
23
|
|
|
125
|
-
|
|
24
|
+
if (cliOptions.help) {
|
|
25
|
+
console.log(await printHelpText())
|
|
26
|
+
process.exit(0)
|
|
27
|
+
}
|
|
126
28
|
|
|
127
29
|
if (cliOptions.debug) {
|
|
128
30
|
enableDebug()
|
|
129
31
|
}
|
|
130
32
|
|
|
131
|
-
const options = {
|
|
132
|
-
allowEmpty: !!cliOptions.allowEmpty,
|
|
133
|
-
concurrent: JSON.parse(cliOptions.concurrent),
|
|
134
|
-
configPath: cliOptions.config,
|
|
135
|
-
continueOnError: !!cliOptions.continueOnError,
|
|
136
|
-
cwd: cliOptions.cwd,
|
|
137
|
-
debug: !!cliOptions.debug,
|
|
138
|
-
diff: cliOptions.diff,
|
|
139
|
-
diffFilter: cliOptions.diffFilter,
|
|
140
|
-
failOnChanges: !!cliOptions.failOnChanges,
|
|
141
|
-
hidePartiallyStaged: !!cliOptions.hidePartiallyStaged, // commander inverts `no-<x>` flags to `!x`
|
|
142
|
-
hideUnstaged: !!cliOptions.hideUnstaged,
|
|
143
|
-
maxArgLength: cliOptions.maxArgLength || undefined,
|
|
144
|
-
quiet: !!cliOptions.quiet,
|
|
145
|
-
relative: !!cliOptions.relative,
|
|
146
|
-
revert: !!cliOptions.revert, // commander inverts `no-<x>` flags to `!x`
|
|
147
|
-
stash: !!cliOptions.stash, // commander inverts `no-<x>` flags to `!x`
|
|
148
|
-
verbose: !!cliOptions.verbose,
|
|
149
|
-
}
|
|
150
|
-
|
|
151
33
|
try {
|
|
152
34
|
const { shell } = userInfo()
|
|
153
35
|
debugLog('Using shell: %s', shell)
|
|
@@ -155,21 +37,20 @@ try {
|
|
|
155
37
|
debugLog('Could not determine current shell')
|
|
156
38
|
}
|
|
157
39
|
|
|
158
|
-
debugLog('Options parsed from command-line: %o',
|
|
40
|
+
debugLog('Options parsed from command-line: %o', cliOptions)
|
|
159
41
|
|
|
160
|
-
if (
|
|
161
|
-
delete
|
|
42
|
+
if (cliOptions.configPath === '-') {
|
|
43
|
+
delete cliOptions.configPath
|
|
162
44
|
try {
|
|
163
45
|
debugLog('Reading config from stdin')
|
|
164
|
-
|
|
46
|
+
cliOptions.config = JSON.parse(await readStdin())
|
|
165
47
|
} catch (error) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
process.exit(1)
|
|
48
|
+
console.error('Failed to read config from stdin!')
|
|
49
|
+
throw error
|
|
169
50
|
}
|
|
170
51
|
}
|
|
171
52
|
|
|
172
|
-
const passed = await lintStaged(
|
|
53
|
+
const passed = await lintStaged(cliOptions)
|
|
173
54
|
if (!passed) {
|
|
174
55
|
process.exitCode = 1
|
|
175
56
|
}
|
package/changes.json
CHANGED
|
@@ -1,22 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"bumped": {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
"to": "^10.2.1"
|
|
6
|
-
},
|
|
7
|
-
"picomatch": {
|
|
8
|
-
"from": "^4.0.3",
|
|
9
|
-
"to": "^4.0.4"
|
|
10
|
-
},
|
|
11
|
-
"tinyexec": {
|
|
12
|
-
"from": "^1.0.4",
|
|
13
|
-
"to": "^1.1.1"
|
|
14
|
-
},
|
|
15
|
-
"yaml": {
|
|
16
|
-
"from": "^2.8.2",
|
|
17
|
-
"to": "^2.8.3"
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
"timestamp": "2026-04-07T16:32:54.966Z",
|
|
21
|
-
"totalUpdated": 4
|
|
2
|
+
"bumped": {},
|
|
3
|
+
"timestamp": "2026-07-21T17:26:54.382Z",
|
|
4
|
+
"totalUpdated": 0
|
|
22
5
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** @see {@link https://github.com/git/git/blob/master/Documentation/RelNotes/2.32.0.adoc} */
|
|
2
|
+
export const MIN_GIT_VERSION = '2.32.0'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} gitVersionOutput the Git version command output
|
|
6
|
+
* @returns {string} the Git version number in format `<major>.<minor>.<patch>`
|
|
7
|
+
*/
|
|
8
|
+
const extractGitVersionNumber = (gitVersionOutput) => {
|
|
9
|
+
const match = gitVersionOutput.match(/git version\s+(\d+\.\d+\.\d+)/i)
|
|
10
|
+
return match?.[1]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} version the version number in format `<major>.<minor>.<patch>`
|
|
15
|
+
* @returns {[string, string, string]} the version number parsed as integers `[major, minor, patch]`
|
|
16
|
+
*/
|
|
17
|
+
const parseSemver = (version) => {
|
|
18
|
+
const match = /(\d+)\.(\d+)\.(\d+)/.exec(version)
|
|
19
|
+
return match?.slice(1, 4).map(Number)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* @param {string} actual the actual version number in format `<major>.<minor>.<patch>`
|
|
25
|
+
* @param {string} expected the expected version number in format `<major>.<minor>.<patch>`
|
|
26
|
+
* @returns {boolean} `true` when the actual version number is at least the expected version number
|
|
27
|
+
*/
|
|
28
|
+
export const satisfiesVersion = (actual, expected) => {
|
|
29
|
+
const a = parseSemver(actual)
|
|
30
|
+
const e = parseSemver(expected)
|
|
31
|
+
if (a[0] !== e[0]) return a[0] > e[0]
|
|
32
|
+
if (a[1] !== e[1]) return a[1] > e[1]
|
|
33
|
+
return a[2] >= e[2]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
* @param {string} gitVersionOutput the Git version command output
|
|
39
|
+
* @returns {boolean} `true` when the Git version number is supported
|
|
40
|
+
*/
|
|
41
|
+
export const assertGitVersion = (gitVersionOutput) => {
|
|
42
|
+
try {
|
|
43
|
+
const version = extractGitVersionNumber(gitVersionOutput)
|
|
44
|
+
return satisfiesVersion(version, MIN_GIT_VERSION)
|
|
45
|
+
} catch {
|
|
46
|
+
return false
|
|
47
|
+
}
|
|
48
|
+
}
|
package/lib/cli.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { parseArgs } from 'node:util'
|
|
5
|
+
|
|
6
|
+
import { restoreStashExample } from './messages.js'
|
|
7
|
+
|
|
8
|
+
const CLI_OPTIONS = [
|
|
9
|
+
{
|
|
10
|
+
short: 'h',
|
|
11
|
+
flag: 'help',
|
|
12
|
+
type: 'boolean',
|
|
13
|
+
description: 'display this help message',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
short: 'V',
|
|
17
|
+
flag: 'version',
|
|
18
|
+
type: 'boolean',
|
|
19
|
+
description: 'display the current version number',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
flag: 'allow-empty',
|
|
23
|
+
type: 'boolean',
|
|
24
|
+
description: 'allow empty commits when tasks revert all staged changes (default: false)',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
short: 'p',
|
|
28
|
+
flag: 'concurrent',
|
|
29
|
+
positional: '<number|boolean>',
|
|
30
|
+
type: 'string',
|
|
31
|
+
description: 'the number of tasks to run concurrently, or false for serial (default: true)',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
short: 'c',
|
|
35
|
+
flag: 'config',
|
|
36
|
+
positional: '[path]',
|
|
37
|
+
type: 'string',
|
|
38
|
+
description: 'path to configuration file, or - to read from stdin',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
flag: 'continue-on-error',
|
|
42
|
+
type: 'boolean',
|
|
43
|
+
description: 'run all tasks to completion even if one fails (default: false)',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
flag: 'cwd',
|
|
47
|
+
positional: '[path]',
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: 'run all tasks in specific directory, instead of the current',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
short: 'd',
|
|
53
|
+
flag: 'debug',
|
|
54
|
+
type: 'boolean',
|
|
55
|
+
description: 'print additional debug information (default: false)',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
flag: 'diff',
|
|
59
|
+
positional: '[string]',
|
|
60
|
+
type: 'string',
|
|
61
|
+
description:
|
|
62
|
+
'override the default "--staged" flag of "git diff" to get list of files. Implies "--no-stash".',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
flag: 'diff-filter',
|
|
66
|
+
positional: '[string]',
|
|
67
|
+
type: 'string',
|
|
68
|
+
description:
|
|
69
|
+
'override the default "--diff-filter=ACMR" flag of "git diff" to get list of files',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
flag: 'fail-on-changes',
|
|
73
|
+
type: 'boolean',
|
|
74
|
+
description: 'fail with exit code 1 when tasks modify tracked files (default: false)',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
negative: true,
|
|
78
|
+
flag: 'hide-partially-staged',
|
|
79
|
+
type: 'boolean',
|
|
80
|
+
description: 'hide unstaged changes from partially staged files (default: true)',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
flag: 'hide-unstaged',
|
|
84
|
+
type: 'boolean',
|
|
85
|
+
description: 'hide all unstaged changes, instead of just partially staged (default: false)',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
flag: 'hide-all',
|
|
89
|
+
type: 'boolean',
|
|
90
|
+
description: 'hide all unstaged changes and untracked files (default: false)',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
flag: 'max-arg-length',
|
|
94
|
+
type: 'string', // Parsed with `parseInt()` below
|
|
95
|
+
positional: '[number]',
|
|
96
|
+
description: 'maximum length of the command-line argument string (default: 0)',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
short: 'q',
|
|
100
|
+
flag: 'quiet',
|
|
101
|
+
type: 'boolean',
|
|
102
|
+
description: "disable lint-staged's own console output (default: false)",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
short: 'r',
|
|
106
|
+
flag: 'relative',
|
|
107
|
+
type: 'boolean',
|
|
108
|
+
description: 'pass relative filepaths to tasks (default: false)',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
negative: true,
|
|
112
|
+
flag: 'revert',
|
|
113
|
+
type: 'boolean',
|
|
114
|
+
description: 'revert to original state in case of errors (default: true)',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
negative: true,
|
|
118
|
+
flag: 'stash',
|
|
119
|
+
type: 'boolean',
|
|
120
|
+
description: 'enable the backup stash (default: true)',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
short: 'v',
|
|
124
|
+
flag: 'verbose',
|
|
125
|
+
type: 'boolean',
|
|
126
|
+
description:
|
|
127
|
+
'show task output even when tasks succeed; by default only failed output is shown (default: false)',
|
|
128
|
+
},
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
/** @param {string[]} argv */
|
|
132
|
+
export const parseCliOptions = (argv) => {
|
|
133
|
+
const options = CLI_OPTIONS.reduce((acc, current) => {
|
|
134
|
+
acc[current.flag] = { type: current.type }
|
|
135
|
+
if (current.short) acc[current.flag].short = current.short
|
|
136
|
+
return acc
|
|
137
|
+
}, {})
|
|
138
|
+
|
|
139
|
+
const { values } = parseArgs({
|
|
140
|
+
args: argv,
|
|
141
|
+
allowNegative: true,
|
|
142
|
+
allowPositionals: true,
|
|
143
|
+
options,
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
if (values.diff !== undefined && values.stash === undefined) {
|
|
147
|
+
/** Disable stashing by default when diffing specific value */
|
|
148
|
+
values.stash = false
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (values['fail-on-changes'] && values.revert === undefined) {
|
|
152
|
+
/** When using --fail-on-changes, default to not reverting on errors */
|
|
153
|
+
values.revert = false
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (values.stash === false && values.revert === undefined) {
|
|
157
|
+
/** Can't revert when using --no-stash */
|
|
158
|
+
values.revert = false
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (values['hide-unstaged'] === true) {
|
|
162
|
+
values['hide-partially-staged'] = false // becomes redundant
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (values['hide-all'] === true) {
|
|
166
|
+
values['hide-partially-staged'] = false // becomes redundant
|
|
167
|
+
values['hide-unstaged'] = false // becomes redundant
|
|
168
|
+
}
|
|
169
|
+
|
|
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
|
+
return {
|
|
180
|
+
allowEmpty: values['allow-empty'] ?? false,
|
|
181
|
+
concurrent: values.concurrent === undefined ? true : JSON.parse(values.concurrent),
|
|
182
|
+
configPath: values.config,
|
|
183
|
+
continueOnError: !!values['continue-on-error'],
|
|
184
|
+
cwd: values.cwd,
|
|
185
|
+
debug: !!values.debug,
|
|
186
|
+
diff: values.diff,
|
|
187
|
+
diffFilter: values['diff-filter'],
|
|
188
|
+
failOnChanges: !!values['fail-on-changes'],
|
|
189
|
+
help: !!values.help,
|
|
190
|
+
hidePartiallyStaged: values['hide-partially-staged'] ?? true,
|
|
191
|
+
hideUnstaged: !!values['hide-unstaged'],
|
|
192
|
+
hideAll: !!values['hide-all'],
|
|
193
|
+
maxArgLength,
|
|
194
|
+
quiet: !!values.quiet,
|
|
195
|
+
relative: !!values.relative,
|
|
196
|
+
revert: values.revert ?? true,
|
|
197
|
+
stash: values.stash ?? true,
|
|
198
|
+
verbose: !!values.verbose,
|
|
199
|
+
version: !!values.version,
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export const getVersionNumber = async () => {
|
|
204
|
+
const dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
205
|
+
const packageJsonFile = await readFile(path.join(dirname, '../package.json'), 'utf-8')
|
|
206
|
+
/** @type {import('../package.json')} */
|
|
207
|
+
const packageJson = JSON.parse(packageJsonFile)
|
|
208
|
+
|
|
209
|
+
return packageJson.version
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const helpOptions = CLI_OPTIONS.map((option) => {
|
|
213
|
+
if (option.negative) {
|
|
214
|
+
/** @example `--no-stash` */
|
|
215
|
+
return [`--no-${option.flag}`, option.description]
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @example `-V, --version
|
|
220
|
+
* or
|
|
221
|
+
* @example `--allow-empty`
|
|
222
|
+
*/
|
|
223
|
+
let arg = option.short ? `-${option.short}, --${option.flag}` : `--${option.flag}`
|
|
224
|
+
|
|
225
|
+
/** @example `--cwd [path]` */
|
|
226
|
+
if (option.positional) arg += ` ${option.positional}`
|
|
227
|
+
|
|
228
|
+
return [arg, option.description]
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
const createWrap = (width) => {
|
|
232
|
+
const regExp = new RegExp(`.{1,${width}}(\\s|$)`, 'g')
|
|
233
|
+
return (text) => text.match(regExp)?.map((s) => s.trimEnd())
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export const printHelpText = async (width = process.stdout.columns ?? 80) => {
|
|
237
|
+
const output = ['Usage: lint-staged [options]', '']
|
|
238
|
+
|
|
239
|
+
const col1Width = Math.max(...helpOptions.map(([arg]) => arg.length)) + 2
|
|
240
|
+
const wrap = createWrap(width - col1Width)
|
|
241
|
+
|
|
242
|
+
for (const [arg, description] of helpOptions) {
|
|
243
|
+
const lines = wrap(description)
|
|
244
|
+
const pad = ' '.repeat(col1Width)
|
|
245
|
+
output.push(arg.padEnd(col1Width) + lines[0], ...lines.slice(1).map((line) => pad + line))
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
output.push('', restoreStashExample())
|
|
249
|
+
|
|
250
|
+
return output.join('\n')
|
|
251
|
+
}
|
package/lib/colors.js
CHANGED
|
@@ -1,106 +1,29 @@
|
|
|
1
|
-
import
|
|
1
|
+
import util from 'node:util'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
* @example NO_COLOR
|
|
5
|
-
* @example NO_COLOR=1
|
|
6
|
-
* @example NO_COLOR=true
|
|
7
|
-
*/
|
|
8
|
-
const TRUTHRY_ENV_VAR_VALUES = ['', '1', 'true']
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @example FORCE_COLOR=0
|
|
12
|
-
* @example FORCE_COLOR=false
|
|
13
|
-
*/
|
|
14
|
-
const FALSY_ENV_VAR_VALUES = ['0', 'false']
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @returns `true` if ANSI colors are supported
|
|
18
|
-
*
|
|
19
|
-
* @param {NodeJS.Process} [p]
|
|
20
|
-
* @param {boolean} [isTty]
|
|
21
|
-
*/
|
|
22
|
-
export const supportsAnsiColors = (p = process, isTty = nodeTty.isatty(1)) => {
|
|
23
|
-
const noColor = p?.env?.NO_COLOR?.toLowerCase()
|
|
24
|
-
if (TRUTHRY_ENV_VAR_VALUES.includes(noColor)) {
|
|
25
|
-
return false
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const forceColor = p?.env?.FORCE_COLOR?.toLowerCase()
|
|
29
|
-
if (TRUTHRY_ENV_VAR_VALUES.includes(forceColor)) {
|
|
30
|
-
return true
|
|
31
|
-
} else if (FALSY_ENV_VAR_VALUES.includes(forceColor)) {
|
|
32
|
-
return false
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const forceTty = p?.env?.FORCE_TTY
|
|
36
|
-
if (TRUTHRY_ENV_VAR_VALUES.includes(forceTty)) {
|
|
37
|
-
return true
|
|
38
|
-
} else if (FALSY_ENV_VAR_VALUES.includes(forceTty)) {
|
|
39
|
-
return false
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (isTty) {
|
|
43
|
-
return true
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Assume CI supports color
|
|
48
|
-
* @see {@link https://github.com/alexeyraspopov/picocolors/blob/0e7c4af2de299dd7bc5916f2bddd151fa2f66740/picocolors.js#L4}
|
|
49
|
-
* @see {@link https://github.com/tinylibs/tinyrainbow/blob/071034bf2eafa28d91ef0ba48a3837420d81a40a/src/index.ts#L91}
|
|
50
|
-
*/
|
|
51
|
-
if (TRUTHRY_ENV_VAR_VALUES.includes(p?.env?.CI)) {
|
|
52
|
-
return true
|
|
53
|
-
}
|
|
3
|
+
export let COLORS_ENABLED = false
|
|
54
4
|
|
|
55
|
-
|
|
56
|
-
|
|
5
|
+
/** @param {boolean} [enabled] */
|
|
6
|
+
export const enableColors = (enabled) => {
|
|
7
|
+
if (enabled) {
|
|
8
|
+
COLORS_ENABLED = true
|
|
57
9
|
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Assume Windows supports color
|
|
61
|
-
* @see {@link https://github.com/alexeyraspopov/picocolors/blob/0e7c4af2de299dd7bc5916f2bddd151fa2f66740/picocolors.js#L4}
|
|
62
|
-
* @see {@link https://github.com/tinylibs/tinyrainbow/blob/071034bf2eafa28d91ef0ba48a3837420d81a40a/src/index.ts#L89}
|
|
63
|
-
*/
|
|
64
|
-
if (p?.platform === 'win32') {
|
|
65
|
-
return true
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return false
|
|
69
10
|
}
|
|
70
11
|
|
|
71
12
|
/**
|
|
72
|
-
* @
|
|
73
|
-
* @
|
|
13
|
+
* @param {util.InspectColor | readonly util.InspectColor[]} format
|
|
14
|
+
* @returns {(text: string) => string}
|
|
74
15
|
*/
|
|
75
|
-
|
|
16
|
+
const styleText = (format) => (text) =>
|
|
17
|
+
COLORS_ENABLED ? util.styleText(format, text, { validateStream: false }) : text
|
|
76
18
|
|
|
77
|
-
const
|
|
19
|
+
export const green = styleText('green')
|
|
78
20
|
|
|
79
|
-
|
|
80
|
-
* @callback WrapAnsi
|
|
81
|
-
* @param {string} text
|
|
82
|
-
* @returns {string}
|
|
83
|
-
*/
|
|
84
|
-
/**
|
|
85
|
-
* @deprecated replace this with Node.js builtin after minimum supported version is >=20.18.0
|
|
86
|
-
* @example (format) => (text) => util.styleText(format, text)
|
|
87
|
-
*
|
|
88
|
-
* @param {string} code
|
|
89
|
-
* @param {boolean} [supported]
|
|
90
|
-
* @returns {WrapAnsi}
|
|
91
|
-
*
|
|
92
|
-
*/
|
|
93
|
-
export const wrapAnsiColor = (code, supported = SUPPORTS_COLOR) => {
|
|
94
|
-
if (supported) {
|
|
95
|
-
return (text) => code + text + ANSI_RESET
|
|
96
|
-
}
|
|
21
|
+
export const red = styleText('red')
|
|
97
22
|
|
|
98
|
-
|
|
99
|
-
|
|
23
|
+
export const yellow = styleText('yellow')
|
|
24
|
+
|
|
25
|
+
export const blue = styleText('blue')
|
|
26
|
+
|
|
27
|
+
export const dim = styleText('dim')
|
|
100
28
|
|
|
101
|
-
export const
|
|
102
|
-
export const green = wrapAnsiColor('\u001B[0;32m')
|
|
103
|
-
export const yellow = wrapAnsiColor('\u001B[0;33m')
|
|
104
|
-
export const blue = wrapAnsiColor('\u001B[0;34m')
|
|
105
|
-
export const blackBright = wrapAnsiColor('\u001B[0;90m')
|
|
106
|
-
export const bold = wrapAnsiColor('\u001b[1m')
|
|
29
|
+
export const bold = styleText('bold')
|