lint-staged 8.1.5 → 8.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -3
- package/package.json +4 -5
- package/src/execGit.js +23 -0
- package/src/generateTasks.js +1 -3
- package/src/gitWorkflow.js +3 -22
- package/src/makeCmdTasks.js +2 -3
- package/src/resolveGitDir.js +12 -3
- package/src/runAll.js +81 -76
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ The fastest way to start using lint-staged is to run following command in your t
|
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
27
|
npx mrm lint-staged
|
|
28
|
-
```
|
|
28
|
+
```
|
|
29
29
|
|
|
30
30
|
It will install and configure [husky](https://github.com/typicode/husky) and lint-staged depending on code quality tools from `package.json` dependencies so please make sure you install (`npm install --save-dev`) and configure all code quality tools like [Prettier](https://prettier.io), [ESlint](https://eslint.org) prior that.
|
|
31
31
|
|
|
@@ -140,7 +140,7 @@ It is possible to run linters for certain paths only by using glob patterns. [mi
|
|
|
140
140
|
|
|
141
141
|
```js
|
|
142
142
|
{
|
|
143
|
-
// .js files anywhere in the project
|
|
143
|
+
// .js files anywhere in the root directory of the project
|
|
144
144
|
"*.js": "eslint",
|
|
145
145
|
// .js files anywhere in the project
|
|
146
146
|
"**/*.js": "eslint",
|
|
@@ -345,7 +345,22 @@ When using the IDE's GUI to commit changes with the `precommit` hook, you might
|
|
|
345
345
|
|
|
346
346
|
Until the issue is resolved in the IDE, you can use the following config to work around it:
|
|
347
347
|
|
|
348
|
-
|
|
348
|
+
husky v1.x
|
|
349
|
+
|
|
350
|
+
```json
|
|
351
|
+
{
|
|
352
|
+
"husky": {
|
|
353
|
+
"hooks": {
|
|
354
|
+
"pre-commit": "lint-staged",
|
|
355
|
+
"post-commit": "git update-index --again"
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
husky v0.x
|
|
362
|
+
|
|
363
|
+
```json
|
|
349
364
|
{
|
|
350
365
|
"scripts": {
|
|
351
366
|
"precommit": "lint-staged",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lint-staged",
|
|
3
|
-
"version": "8.1
|
|
3
|
+
"version": "8.2.1",
|
|
4
4
|
"description": "Lint files staged by git",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "https://github.com/okonet/lint-staged",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"cz": "git-cz",
|
|
19
19
|
"lint:base": "eslint --rule \"prettier/prettier: 2\"",
|
|
20
20
|
"lint": "npm run lint:base -- .",
|
|
21
|
-
"lint:fix": "npm run lint --fix",
|
|
21
|
+
"lint:fix": "npm run lint -- --fix",
|
|
22
22
|
"pretest": "npm run lint",
|
|
23
23
|
"test": "jest --coverage",
|
|
24
24
|
"test:watch": "jest --watch"
|
|
@@ -31,12 +31,11 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"chalk": "^2.3.1",
|
|
33
33
|
"commander": "^2.14.1",
|
|
34
|
-
"cosmiconfig": "^5.0
|
|
34
|
+
"cosmiconfig": "^5.2.0",
|
|
35
35
|
"debug": "^3.1.0",
|
|
36
36
|
"dedent": "^0.7.0",
|
|
37
37
|
"del": "^3.0.0",
|
|
38
38
|
"execa": "^1.0.0",
|
|
39
|
-
"find-parent-dir": "^0.3.0",
|
|
40
39
|
"g-status": "^2.0.2",
|
|
41
40
|
"is-glob": "^4.0.0",
|
|
42
41
|
"is-windows": "^1.0.2",
|
|
@@ -53,7 +52,7 @@
|
|
|
53
52
|
"staged-git-files": "1.1.2",
|
|
54
53
|
"string-argv": "^0.0.2",
|
|
55
54
|
"stringify-object": "^3.2.2",
|
|
56
|
-
"yup": "^0.
|
|
55
|
+
"yup": "^0.27.0"
|
|
57
56
|
},
|
|
58
57
|
"devDependencies": {
|
|
59
58
|
"babel-core": "^6.26.3",
|
package/src/execGit.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const debug = require('debug')('lint-staged:git')
|
|
4
|
+
const execa = require('execa')
|
|
5
|
+
const path = require('path')
|
|
6
|
+
|
|
7
|
+
function getAbsolutePath(dir) {
|
|
8
|
+
return path.isAbsolute(dir) ? dir : path.resolve(dir)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = async function execGit(cmd, options = {}) {
|
|
12
|
+
const cwd = options.cwd || process.cwd()
|
|
13
|
+
debug('Running git command', cmd)
|
|
14
|
+
try {
|
|
15
|
+
const { stdout } = await execa('git', [].concat(cmd), {
|
|
16
|
+
...options,
|
|
17
|
+
cwd: getAbsolutePath(cwd)
|
|
18
|
+
})
|
|
19
|
+
return stdout
|
|
20
|
+
} catch (err) {
|
|
21
|
+
throw new Error(err)
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/generateTasks.js
CHANGED
|
@@ -4,17 +4,15 @@ const path = require('path')
|
|
|
4
4
|
const micromatch = require('micromatch')
|
|
5
5
|
const pathIsInside = require('path-is-inside')
|
|
6
6
|
const { getConfig } = require('./getConfig')
|
|
7
|
-
const resolveGitDir = require('./resolveGitDir')
|
|
8
7
|
|
|
9
8
|
const debug = require('debug')('lint-staged:gen-tasks')
|
|
10
9
|
|
|
11
|
-
module.exports = function generateTasks(config, stagedRelFiles) {
|
|
10
|
+
module.exports = async function generateTasks(config, gitDir, stagedRelFiles) {
|
|
12
11
|
debug('Generating linter tasks')
|
|
13
12
|
|
|
14
13
|
const normalizedConfig = getConfig(config) // Ensure we have a normalized config
|
|
15
14
|
const { linters, globOptions, ignore } = normalizedConfig
|
|
16
15
|
|
|
17
|
-
const gitDir = resolveGitDir()
|
|
18
16
|
const cwd = process.cwd()
|
|
19
17
|
const stagedFiles = stagedRelFiles.map(file => path.resolve(gitDir, file))
|
|
20
18
|
|
package/src/gitWorkflow.js
CHANGED
|
@@ -1,34 +1,15 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const path = require('path')
|
|
4
|
-
const execa = require('execa')
|
|
5
3
|
const gStatus = require('g-status')
|
|
6
4
|
const del = require('del')
|
|
7
5
|
const debug = require('debug')('lint-staged:git')
|
|
8
|
-
|
|
6
|
+
|
|
7
|
+
const execGit = require('./execGit')
|
|
9
8
|
|
|
10
9
|
let workingCopyTree = null
|
|
11
10
|
let indexTree = null
|
|
12
11
|
let formattedIndexTree = null
|
|
13
12
|
|
|
14
|
-
function getAbsolutePath(dir) {
|
|
15
|
-
return path.isAbsolute(dir) ? dir : path.resolve(dir)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async function execGit(cmd, options) {
|
|
19
|
-
const cwd = options && options.cwd ? options.cwd : resolveGitDir()
|
|
20
|
-
debug('Running git command', cmd)
|
|
21
|
-
try {
|
|
22
|
-
const { stdout } = await execa('git', [].concat(cmd), {
|
|
23
|
-
...options,
|
|
24
|
-
cwd: getAbsolutePath(cwd)
|
|
25
|
-
})
|
|
26
|
-
return stdout
|
|
27
|
-
} catch (err) {
|
|
28
|
-
throw new Error(err)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
13
|
async function writeTree(options) {
|
|
33
14
|
return execGit(['write-tree'], options)
|
|
34
15
|
}
|
|
@@ -51,7 +32,7 @@ async function getDiffForTrees(tree1, tree2, options) {
|
|
|
51
32
|
}
|
|
52
33
|
|
|
53
34
|
async function hasPartiallyStagedFiles(options) {
|
|
54
|
-
const cwd = options
|
|
35
|
+
const { cwd } = options
|
|
55
36
|
const files = await gStatus({ cwd })
|
|
56
37
|
const partiallyStaged = files.filter(
|
|
57
38
|
file =>
|
package/src/makeCmdTasks.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const resolveTaskFn = require('./resolveTaskFn')
|
|
4
|
-
const resolveGitDir = require('./resolveGitDir')
|
|
5
4
|
|
|
6
5
|
const debug = require('debug')('lint-staged:make-cmd-tasks')
|
|
7
6
|
|
|
@@ -14,14 +13,14 @@ const debug = require('debug')('lint-staged:make-cmd-tasks')
|
|
|
14
13
|
* @param {number} options.chunkSize
|
|
15
14
|
* @param {number} options.subTaskConcurrency
|
|
16
15
|
*/
|
|
17
|
-
module.exports = function makeCmdTasks(
|
|
16
|
+
module.exports = async function makeCmdTasks(
|
|
18
17
|
commands,
|
|
18
|
+
gitDir,
|
|
19
19
|
pathsToLint,
|
|
20
20
|
{ chunkSize = Number.MAX_SAFE_INTEGER, subTaskConcurrency = 1 } = {}
|
|
21
21
|
) {
|
|
22
22
|
debug('Creating listr tasks for commands %o', commands)
|
|
23
23
|
|
|
24
|
-
const gitDir = resolveGitDir()
|
|
25
24
|
const lintersArray = Array.isArray(commands) ? commands : [commands]
|
|
26
25
|
|
|
27
26
|
return lintersArray.map(linter => ({
|
package/src/resolveGitDir.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const execGit = require('./execGit')
|
|
4
|
+
const path = require('path')
|
|
4
5
|
|
|
5
|
-
module.exports = function resolveGitDir() {
|
|
6
|
-
|
|
6
|
+
module.exports = async function resolveGitDir(options) {
|
|
7
|
+
try {
|
|
8
|
+
// git cli uses GIT_DIR to fast track its response however it might be set to a different path
|
|
9
|
+
// depending on where the caller initiated this from, hence clear GIT_DIR
|
|
10
|
+
delete process.env.GIT_DIR
|
|
11
|
+
const gitDir = await execGit(['rev-parse', '--show-toplevel'], options)
|
|
12
|
+
return path.normalize(gitDir)
|
|
13
|
+
} catch (error) {
|
|
14
|
+
return null
|
|
15
|
+
}
|
|
7
16
|
}
|
package/src/runAll.js
CHANGED
|
@@ -16,7 +16,7 @@ const debug = require('debug')('lint-staged:run')
|
|
|
16
16
|
* @param config {Object}
|
|
17
17
|
* @returns {Promise}
|
|
18
18
|
*/
|
|
19
|
-
module.exports = function runAll(config) {
|
|
19
|
+
module.exports = async function runAll(config) {
|
|
20
20
|
debug('Running all linter scripts')
|
|
21
21
|
// Config validation
|
|
22
22
|
if (!config || !has(config, 'concurrent') || !has(config, 'renderer')) {
|
|
@@ -24,92 +24,97 @@ module.exports = function runAll(config) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const { concurrent, renderer, chunkSize, subTaskConcurrency } = config
|
|
27
|
-
const gitDir = resolveGitDir()
|
|
27
|
+
const gitDir = await resolveGitDir(config)
|
|
28
|
+
|
|
29
|
+
if (!gitDir) {
|
|
30
|
+
throw new Error('Current directory is not a git directory!')
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
debug('Resolved git directory to be `%s`', gitDir)
|
|
29
34
|
|
|
30
35
|
sgf.cwd = gitDir
|
|
31
|
-
return pify(sgf)('ACM').then(files => {
|
|
32
|
-
/* files is an Object{ filename: String, status: String } */
|
|
33
|
-
const filenames = files.map(file => file.filename)
|
|
34
|
-
debug('Loaded list of staged files in git:\n%O', filenames)
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
37
|
+
/* files is an Object{ filename: String, status: String } */
|
|
38
|
+
const files = await pify(sgf)('ACM')
|
|
39
|
+
const filenames = files.map(file => file.filename)
|
|
40
|
+
debug('Loaded list of staged files in git:\n%O', filenames)
|
|
41
|
+
|
|
42
|
+
const tasks = (await generateTasks(config, gitDir, filenames)).map(task => ({
|
|
43
|
+
title: `Running tasks for ${task.pattern}`,
|
|
44
|
+
task: async () =>
|
|
45
|
+
new Listr(
|
|
46
|
+
await makeCmdTasks(task.commands, gitDir, task.fileList, {
|
|
47
|
+
chunkSize,
|
|
48
|
+
subTaskConcurrency
|
|
49
|
+
}),
|
|
50
|
+
{
|
|
51
|
+
// In sub-tasks we don't want to run concurrently
|
|
52
|
+
// and we want to abort on errors
|
|
53
|
+
dateFormat: false,
|
|
54
|
+
concurrent: false,
|
|
55
|
+
exitOnError: true
|
|
55
56
|
}
|
|
56
|
-
|
|
57
|
+
),
|
|
58
|
+
skip: () => {
|
|
59
|
+
if (task.fileList.length === 0) {
|
|
60
|
+
return `No staged files match ${task.pattern}`
|
|
57
61
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const listrBaseOptions = {
|
|
61
|
-
dateFormat: false,
|
|
62
|
-
renderer
|
|
62
|
+
return false
|
|
63
63
|
}
|
|
64
|
+
}))
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return 'No tasks to run.'
|
|
70
|
-
}
|
|
66
|
+
const listrBaseOptions = {
|
|
67
|
+
dateFormat: false,
|
|
68
|
+
renderer
|
|
69
|
+
}
|
|
71
70
|
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
// If all of the configured "linters" should be skipped
|
|
72
|
+
// avoid executing any lint-staged logic
|
|
73
|
+
if (tasks.every(task => task.skip())) {
|
|
74
|
+
console.log('No staged files match any of provided globs.')
|
|
75
|
+
return 'No tasks to run.'
|
|
76
|
+
}
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
task: ctx => {
|
|
87
|
-
ctx.hasStash = true
|
|
88
|
-
return git.gitStashSave()
|
|
78
|
+
// Do not terminate main Listr process on SIGINT
|
|
79
|
+
process.on('SIGINT', () => {})
|
|
80
|
+
|
|
81
|
+
return new Listr(
|
|
82
|
+
[
|
|
83
|
+
{
|
|
84
|
+
title: 'Stashing changes...',
|
|
85
|
+
skip: async () => {
|
|
86
|
+
const hasPSF = await git.hasPartiallyStagedFiles({ cwd: gitDir })
|
|
87
|
+
if (!hasPSF) {
|
|
88
|
+
return 'No partially staged files found...'
|
|
89
89
|
}
|
|
90
|
+
return false
|
|
90
91
|
},
|
|
91
|
-
{
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
new Listr(tasks, {
|
|
95
|
-
...listrBaseOptions,
|
|
96
|
-
concurrent,
|
|
97
|
-
exitOnError: !concurrent // Wait for all errors when running concurrently
|
|
98
|
-
})
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
title: 'Updating stash...',
|
|
102
|
-
enabled: ctx => ctx.hasStash,
|
|
103
|
-
skip: ctx => ctx.hasErrors && 'Skipping stash update since some tasks exited with errors',
|
|
104
|
-
task: () => git.updateStash()
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
title: 'Restoring local changes...',
|
|
108
|
-
enabled: ctx => ctx.hasStash,
|
|
109
|
-
task: () => git.gitStashPop()
|
|
92
|
+
task: ctx => {
|
|
93
|
+
ctx.hasStash = true
|
|
94
|
+
return git.gitStashSave({ cwd: gitDir })
|
|
110
95
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
title: 'Running linters...',
|
|
99
|
+
task: () =>
|
|
100
|
+
new Listr(tasks, {
|
|
101
|
+
...listrBaseOptions,
|
|
102
|
+
concurrent,
|
|
103
|
+
exitOnError: !concurrent // Wait for all errors when running concurrently
|
|
104
|
+
})
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
title: 'Updating stash...',
|
|
108
|
+
enabled: ctx => ctx.hasStash,
|
|
109
|
+
skip: ctx => ctx.hasErrors && 'Skipping stash update since some tasks exited with errors',
|
|
110
|
+
task: () => git.updateStash({ cwd: gitDir })
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
title: 'Restoring local changes...',
|
|
114
|
+
enabled: ctx => ctx.hasStash,
|
|
115
|
+
task: () => git.gitStashPop({ cwd: gitDir })
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
listrBaseOptions
|
|
119
|
+
).run()
|
|
115
120
|
}
|