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 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
- ```js
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.5",
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.2",
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.26.10"
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
+ }
@@ -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
 
@@ -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
- const resolveGitDir = require('./resolveGitDir')
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 && options.cwd ? options.cwd : resolveGitDir()
35
+ const { cwd } = options
55
36
  const files = await gStatus({ cwd })
56
37
  const partiallyStaged = files.filter(
57
38
  file =>
@@ -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 => ({
@@ -1,7 +1,16 @@
1
1
  'use strict'
2
2
 
3
- const findParentDir = require('find-parent-dir')
3
+ const execGit = require('./execGit')
4
+ const path = require('path')
4
5
 
5
- module.exports = function resolveGitDir() {
6
- return findParentDir.sync(process.cwd(), '.git')
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
- const tasks = generateTasks(config, filenames).map(task => ({
37
- title: `Running tasks for ${task.pattern}`,
38
- task: () =>
39
- new Listr(
40
- makeCmdTasks(task.commands, task.fileList, {
41
- chunkSize,
42
- subTaskConcurrency
43
- }),
44
- {
45
- // In sub-tasks we don't want to run concurrently
46
- // and we want to abort on errors
47
- dateFormat: false,
48
- concurrent: false,
49
- exitOnError: true
50
- }
51
- ),
52
- skip: () => {
53
- if (task.fileList.length === 0) {
54
- return `No staged files match ${task.pattern}`
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
- return false
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
- // If all of the configured "linters" should be skipped
66
- // avoid executing any lint-staged logic
67
- if (tasks.every(task => task.skip())) {
68
- console.log('No staged files match any of provided globs.')
69
- return 'No tasks to run.'
70
- }
66
+ const listrBaseOptions = {
67
+ dateFormat: false,
68
+ renderer
69
+ }
71
70
 
72
- // Do not terminate main Listr process on SIGINT
73
- process.on('SIGINT', () => {})
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
- return new Listr(
76
- [
77
- {
78
- title: 'Stashing changes...',
79
- skip: async () => {
80
- const hasPSF = await git.hasPartiallyStagedFiles()
81
- if (!hasPSF) {
82
- return 'No partially staged files found...'
83
- }
84
- return false
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
- title: 'Running linters...',
93
- task: () =>
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
- listrBaseOptions
113
- ).run()
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
  }