lint-staged 11.3.0-beta.2 β 12.0.3
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 +10 -5
- package/bin/lint-staged.js +31 -45
- package/lib/chunkFiles.js +10 -9
- package/lib/execGit.js +7 -9
- package/lib/figures.js +6 -8
- package/lib/file.js +53 -0
- package/lib/generateTasks.js +8 -10
- package/lib/getRenderer.js +1 -5
- package/lib/getStagedFiles.js +2 -4
- package/lib/gitWorkflow.js +156 -72
- package/lib/index.js +28 -20
- package/lib/makeCmdTasks.js +7 -9
- package/lib/messages.js +27 -45
- package/lib/printTaskOutput.js +1 -5
- package/lib/resolveGitRepo.js +12 -18
- package/lib/resolveTaskFn.js +13 -13
- package/lib/runAll.js +34 -37
- package/lib/state.js +25 -40
- package/lib/symbols.js +23 -25
- package/lib/validateBraces.js +3 -7
- package/lib/validateConfig.js +9 -11
- package/lib/validateOptions.js +9 -13
- package/package.json +22 -33
- package/lib/unlink.js +0 -22
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# π«π© lint-staged  [ [](https://badge.fury.io/js/lint-staged) [](https://codecov.io/gh/okonet/lint-staged)
|
|
2
2
|
|
|
3
3
|
Run linters against staged git files and don't let :poop: slip into your code base!
|
|
4
4
|
|
|
@@ -42,6 +42,10 @@ See [Releases](https://github.com/okonet/lint-staged/releases).
|
|
|
42
42
|
|
|
43
43
|
### Migration
|
|
44
44
|
|
|
45
|
+
#### v12
|
|
46
|
+
|
|
47
|
+
- Since `v12.0.0` _lint-staged_ is a pure ESM module, so make sure your Node.js version is at least `12.20.0`, `14.13.1`, or `16.0.0`. Read more about ESM modules from the official [Node.js Documentation site here](https://nodejs.org/api/esm.html#introduction).
|
|
48
|
+
|
|
45
49
|
#### v10
|
|
46
50
|
|
|
47
51
|
- From `v10.0.0` onwards any new modifications to originally staged files will be automatically added to the commit.
|
|
@@ -65,7 +69,8 @@ Options:
|
|
|
65
69
|
(default: false)
|
|
66
70
|
-c, --config [path] path to configuration file, or - to read from stdin
|
|
67
71
|
-d, --debug print additional debug information (default: false)
|
|
68
|
-
--no-
|
|
72
|
+
--no-stash disable the backup stash, and do not revert in case of
|
|
73
|
+
errors
|
|
69
74
|
-p, --concurrent <parallel tasks> the number of tasks to run concurrently, or false to run
|
|
70
75
|
tasks serially (default: true)
|
|
71
76
|
-q, --quiet disable lint-stagedβs own console output (default: false)
|
|
@@ -86,7 +91,7 @@ Options:
|
|
|
86
91
|
- `false`: Run all tasks serially
|
|
87
92
|
- `true` (default) : _Infinite_ concurrency. Runs as many tasks in parallel as possible.
|
|
88
93
|
- `{number}`: Run the specified number of tasks in parallel, where `1` is equivalent to `false`.
|
|
89
|
-
- **`--no-
|
|
94
|
+
- **`--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.
|
|
90
95
|
- **`--quiet`**: Supress all CLI output, except from tasks.
|
|
91
96
|
- **`--relative`**: Pass filepaths relative to `process.cwd()` (where `lint-staged` runs) to tasks. Default is `false`.
|
|
92
97
|
- **`--shell`**: By default linter commands will be parsed for speed and security. This has the side-effect that regular shell scripts might not work as expected. You can skip parsing of commands with this option. To use a specific shell, use a path like `--shell "/bin/bash"`.
|
|
@@ -564,8 +569,8 @@ const success = await lintStaged({
|
|
|
564
569
|
maxArgLength: null,
|
|
565
570
|
quiet: false,
|
|
566
571
|
relative: false,
|
|
567
|
-
reset: true,
|
|
568
572
|
shell: false
|
|
573
|
+
stash: true,
|
|
569
574
|
verbose: false
|
|
570
575
|
})
|
|
571
576
|
```
|
|
@@ -582,8 +587,8 @@ const success = await lintStaged({
|
|
|
582
587
|
maxArgLength: null,
|
|
583
588
|
quiet: false,
|
|
584
589
|
relative: false,
|
|
585
|
-
reset: true,
|
|
586
590
|
shell: false,
|
|
591
|
+
stash: true,
|
|
587
592
|
verbose: false,
|
|
588
593
|
})
|
|
589
594
|
```
|
package/bin/lint-staged.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import fs from 'fs'
|
|
4
|
+
import path from 'path'
|
|
5
|
+
import { fileURLToPath } from 'url'
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
import cmdline from 'commander'
|
|
8
|
+
import debug from 'debug'
|
|
9
|
+
import supportsColor from 'supports-color'
|
|
10
|
+
|
|
11
|
+
import lintStaged from '../lib/index.js'
|
|
12
|
+
import { CONFIG_STDIN_ERROR } from '../lib/messages.js'
|
|
6
13
|
|
|
7
14
|
// Force colors for packages that depend on https://www.npmjs.com/package/supports-color
|
|
8
|
-
const supportsColor = require('supports-color')
|
|
9
15
|
if (supportsColor.stdout) {
|
|
10
16
|
process.env.FORCE_COLOR = supportsColor.stdout.level.toString()
|
|
11
17
|
}
|
|
@@ -13,31 +19,16 @@ if (supportsColor.stdout) {
|
|
|
13
19
|
// Do not terminate main Listr process on SIGINT
|
|
14
20
|
process.on('SIGINT', () => {})
|
|
15
21
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
engines: {
|
|
20
|
-
node: '>=12.13.0', // First LTS release of 'Erbium'
|
|
21
|
-
},
|
|
22
|
-
})
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
const { Command, Option } = require('commander')
|
|
26
|
-
const debugLib = require('debug')
|
|
27
|
-
const lintStaged = require('../lib')
|
|
28
|
-
const { CONFIG_STDIN_ERROR } = require('../lib/messages')
|
|
29
|
-
|
|
30
|
-
const debug = debugLib('lint-staged:bin')
|
|
31
|
-
|
|
32
|
-
const program = new Command('lint-staged')
|
|
22
|
+
const packageJsonPath = path.join(fileURLToPath(import.meta.url), '../../package.json')
|
|
23
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath))
|
|
24
|
+
const version = packageJson.version
|
|
33
25
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
program
|
|
26
|
+
cmdline
|
|
27
|
+
.version(version)
|
|
37
28
|
.option('--allow-empty', 'allow empty commits when tasks revert all staged changes', false)
|
|
38
29
|
.option('-c, --config [path]', 'path to configuration file, or - to read from stdin')
|
|
39
30
|
.option('-d, --debug', 'print additional debug information', false)
|
|
40
|
-
.option('--no-
|
|
31
|
+
.option('--no-stash', 'disable the backup stash, and do not revert in case of errors', false)
|
|
41
32
|
.option(
|
|
42
33
|
'-p, --concurrent <parallel tasks>',
|
|
43
34
|
'the number of tasks to run concurrently, or false to run tasks serially',
|
|
@@ -51,17 +42,13 @@ program
|
|
|
51
42
|
'show task output even when tasks succeed; by default only failed output is shown',
|
|
52
43
|
false
|
|
53
44
|
)
|
|
45
|
+
.parse(process.argv)
|
|
54
46
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
program.parse(process.argv)
|
|
59
|
-
|
|
60
|
-
if (program.debug) {
|
|
61
|
-
debugLib.enable('lint-staged*')
|
|
47
|
+
const debugLog = debug('lint-staged:bin')
|
|
48
|
+
if (cmdline.debug) {
|
|
49
|
+
debug.enable('lint-staged*')
|
|
62
50
|
}
|
|
63
|
-
|
|
64
|
-
debug('Running `lint-staged@%s`', pkg.version)
|
|
51
|
+
debugLog('Running `lint-staged@%s`', version)
|
|
65
52
|
|
|
66
53
|
/**
|
|
67
54
|
* Get the maximum length of a command-line argument string based on current platform
|
|
@@ -81,23 +68,22 @@ const getMaxArgLength = () => {
|
|
|
81
68
|
}
|
|
82
69
|
}
|
|
83
70
|
|
|
84
|
-
const
|
|
71
|
+
const cmdlineOptions = cmdline.opts()
|
|
85
72
|
|
|
86
73
|
const options = {
|
|
87
|
-
allowEmpty: !!
|
|
88
|
-
concurrent: JSON.parse(
|
|
89
|
-
configPath:
|
|
90
|
-
debug: !!
|
|
74
|
+
allowEmpty: !!cmdlineOptions.allowEmpty,
|
|
75
|
+
concurrent: JSON.parse(cmdlineOptions.concurrent),
|
|
76
|
+
configPath: cmdlineOptions.config,
|
|
77
|
+
debug: !!cmdlineOptions.debug,
|
|
91
78
|
maxArgLength: getMaxArgLength() / 2,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
shell:
|
|
96
|
-
|
|
97
|
-
verbose: !!programOpts.verbose,
|
|
79
|
+
stash: !!cmdlineOptions.stash, // commander inverts `no-<x>` flags to `!x`
|
|
80
|
+
quiet: !!cmdlineOptions.quiet,
|
|
81
|
+
relative: !!cmdlineOptions.relative,
|
|
82
|
+
shell: cmdlineOptions.shell /* Either a boolean or a string pointing to the shell */,
|
|
83
|
+
verbose: !!cmdlineOptions.verbose,
|
|
98
84
|
}
|
|
99
85
|
|
|
100
|
-
|
|
86
|
+
debugLog('Options parsed from command-line:', options)
|
|
101
87
|
|
|
102
88
|
if (options.configPath === '-') {
|
|
103
89
|
delete options.configPath
|
package/lib/chunkFiles.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import path from 'path'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import debug from 'debug'
|
|
4
|
+
import normalize from 'normalize-path'
|
|
5
|
+
|
|
6
|
+
const debugLog = debug('lint-staged:chunkFiles')
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Chunk array into sub-arrays
|
|
@@ -10,7 +11,7 @@ const path = require('path')
|
|
|
10
11
|
* @param {Number} chunkCount
|
|
11
12
|
* @retuns {Array<Array>}
|
|
12
13
|
*/
|
|
13
|
-
|
|
14
|
+
const chunkArray = (arr, chunkCount) => {
|
|
14
15
|
if (chunkCount === 1) return [arr]
|
|
15
16
|
const chunked = []
|
|
16
17
|
let position = 0
|
|
@@ -32,21 +33,21 @@ function chunkArray(arr, chunkCount) {
|
|
|
32
33
|
* @param {Boolean} [opts.relative] whether files are relative to `gitDir` or should be resolved as absolute
|
|
33
34
|
* @returns {Array<Array<String>>}
|
|
34
35
|
*/
|
|
35
|
-
|
|
36
|
+
export const chunkFiles = ({ files, baseDir, maxArgLength = null, relative = false }) => {
|
|
36
37
|
const normalizedFiles = files.map((file) =>
|
|
37
38
|
normalize(relative || !baseDir ? file : path.resolve(baseDir, file))
|
|
38
39
|
)
|
|
39
40
|
|
|
40
41
|
if (!maxArgLength) {
|
|
41
|
-
|
|
42
|
+
debugLog('Skip chunking files because of undefined maxArgLength')
|
|
42
43
|
return [normalizedFiles] // wrap in an array to return a single chunk
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
const fileListLength = normalizedFiles.join(' ').length
|
|
46
|
-
|
|
47
|
+
debugLog(
|
|
47
48
|
`Resolved an argument string length of ${fileListLength} characters from ${normalizedFiles.length} files`
|
|
48
49
|
)
|
|
49
50
|
const chunkCount = Math.min(Math.ceil(fileListLength / maxArgLength), normalizedFiles.length)
|
|
50
|
-
|
|
51
|
+
debugLog(`Creating ${chunkCount} chunks for maxArgLength of ${maxArgLength}`)
|
|
51
52
|
return chunkArray(normalizedFiles, chunkCount)
|
|
52
53
|
}
|
package/lib/execGit.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import debug from 'debug'
|
|
2
|
+
import execa from 'execa'
|
|
2
3
|
|
|
3
|
-
const
|
|
4
|
-
const execa = require('execa')
|
|
4
|
+
const debugLog = debug('lint-staged:execGit')
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Explicitly never recurse commands into submodules, overriding local/global configuration.
|
|
@@ -9,10 +9,11 @@ const execa = require('execa')
|
|
|
9
9
|
*/
|
|
10
10
|
const NO_SUBMODULE_RECURSE = ['-c', 'submodule.recurse=false']
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
// exported for tests
|
|
13
|
+
export const GIT_GLOBAL_OPTIONS = [...NO_SUBMODULE_RECURSE]
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
export const execGit = async (cmd, options = {}) => {
|
|
16
|
+
debugLog('Running git command', cmd)
|
|
16
17
|
try {
|
|
17
18
|
const { stdout } = await execa('git', GIT_GLOBAL_OPTIONS.concat(cmd), {
|
|
18
19
|
...options,
|
|
@@ -24,6 +25,3 @@ module.exports = async function execGit(cmd, options = {}) {
|
|
|
24
25
|
throw new Error(all)
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
|
-
|
|
28
|
-
// exported for tests
|
|
29
|
-
module.exports.GIT_GLOBAL_OPTIONS = GIT_GLOBAL_OPTIONS
|
package/lib/figures.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { blue, redBright, yellow } from 'colorette'
|
|
2
|
+
import { figures } from 'listr2'
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
export const info = blue(figures.arrowRight)
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
warning: yellow(warning),
|
|
10
|
-
}
|
|
6
|
+
export const error = redBright(figures.cross)
|
|
7
|
+
|
|
8
|
+
export const warning = yellow(figures.warning)
|
package/lib/file.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { promises as fs } from 'fs'
|
|
2
|
+
|
|
3
|
+
import debug from 'debug'
|
|
4
|
+
|
|
5
|
+
const debugLog = debug('lint-staged:file')
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Read contents of a file to buffer
|
|
9
|
+
* @param {String} filename
|
|
10
|
+
* @param {Boolean} [ignoreENOENT=true] β Whether to throw if the file doesn't exist
|
|
11
|
+
* @returns {Promise<Buffer>}
|
|
12
|
+
*/
|
|
13
|
+
export const readFile = async (filename, ignoreENOENT = true) => {
|
|
14
|
+
debugLog('Reading file `%s`', filename)
|
|
15
|
+
try {
|
|
16
|
+
return await fs.readFile(filename)
|
|
17
|
+
} catch (error) {
|
|
18
|
+
if (ignoreENOENT && error.code === 'ENOENT') {
|
|
19
|
+
debugLog("File `%s` doesn't exist, ignoring...", filename)
|
|
20
|
+
return null // no-op file doesn't exist
|
|
21
|
+
} else {
|
|
22
|
+
throw error
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Remove a file
|
|
29
|
+
* @param {String} filename
|
|
30
|
+
* @param {Boolean} [ignoreENOENT=true] β Whether to throw if the file doesn't exist
|
|
31
|
+
*/
|
|
32
|
+
export const unlink = async (filename, ignoreENOENT = true) => {
|
|
33
|
+
debugLog('Removing file `%s`', filename)
|
|
34
|
+
try {
|
|
35
|
+
await fs.unlink(filename)
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if (ignoreENOENT && error.code === 'ENOENT') {
|
|
38
|
+
debugLog("File `%s` doesn't exist, ignoring...", filename)
|
|
39
|
+
} else {
|
|
40
|
+
throw error
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Write buffer to file
|
|
47
|
+
* @param {String} filename
|
|
48
|
+
* @param {Buffer} buffer
|
|
49
|
+
*/
|
|
50
|
+
export const writeFile = async (filename, buffer) => {
|
|
51
|
+
debugLog('Writing file `%s`', filename)
|
|
52
|
+
await fs.writeFile(filename, buffer)
|
|
53
|
+
}
|
package/lib/generateTasks.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import path from 'path'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import debug from 'debug'
|
|
4
|
+
import micromatch from 'micromatch'
|
|
5
|
+
import normalize from 'normalize-path'
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const debugLog = debug('lint-staged:generateTasks')
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Generates all task commands, and filelist
|
|
@@ -16,8 +16,8 @@ const debug = require('debug')('lint-staged:gen-tasks')
|
|
|
16
16
|
* @param {boolean} [options.files] - Staged filepaths
|
|
17
17
|
* @param {boolean} [options.relative] - Whether filepaths to should be relative to gitDir
|
|
18
18
|
*/
|
|
19
|
-
const generateTasks = ({ config, cwd = process.cwd(), gitDir, files, relative = false }) => {
|
|
20
|
-
|
|
19
|
+
export const generateTasks = ({ config, cwd = process.cwd(), gitDir, files, relative = false }) => {
|
|
20
|
+
debugLog('Generating linter tasks')
|
|
21
21
|
|
|
22
22
|
const absoluteFiles = files.map((file) => normalize(path.resolve(gitDir, file)))
|
|
23
23
|
const relativeFiles = absoluteFiles.map((file) => normalize(path.relative(cwd, file)))
|
|
@@ -47,10 +47,8 @@ const generateTasks = ({ config, cwd = process.cwd(), gitDir, files, relative =
|
|
|
47
47
|
const fileList = matches.map((file) => normalize(relative ? file : path.resolve(cwd, file)))
|
|
48
48
|
|
|
49
49
|
const task = { pattern, commands, fileList }
|
|
50
|
-
|
|
50
|
+
debugLog('Generated task: \n%O', task)
|
|
51
51
|
|
|
52
52
|
return task
|
|
53
53
|
})
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
module.exports = generateTasks
|
package/lib/getRenderer.js
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const getRenderer = ({ debug, quiet }, env = process.env) => {
|
|
1
|
+
export const getRenderer = ({ debug, quiet }, env = process.env) => {
|
|
4
2
|
if (quiet) return { renderer: 'silent' }
|
|
5
3
|
// Better support for dumb terminals: https://en.wikipedia.org/wiki/Computer_terminal#Dumb_terminals
|
|
6
4
|
const isDumbTerminal = env.TERM === 'dumb'
|
|
7
5
|
if (debug || isDumbTerminal || env.NODE_ENV === 'test') return { renderer: 'verbose' }
|
|
8
6
|
return { renderer: 'update', rendererOptions: { dateFormat: false } }
|
|
9
7
|
}
|
|
10
|
-
|
|
11
|
-
module.exports = getRenderer
|
package/lib/getStagedFiles.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { execGit } from './execGit.js'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
module.exports = async function getStagedFiles(options) {
|
|
3
|
+
export const getStagedFiles = async (options) => {
|
|
6
4
|
try {
|
|
7
5
|
// Docs for --diff-filter option: https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---diff-filterACDMRTUXB82308203
|
|
8
6
|
// Docs for -z option: https://git-scm.com/docs/git-diff#Documentation/git-diff.txt--z
|