lint-staged 10.5.0 → 10.5.4

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
@@ -12,10 +12,11 @@ This project contains a script that will run arbitrary shell tasks with a list o
12
12
 
13
13
  ## Related blogs posts and talks
14
14
 
15
- - [Make Linting Great Again](https://medium.com/@okonetchnikov/make-linting-great-again-f3890e1ad6b8#.8qepn2b5l)
16
- - [Running Jest Tests Before Each Git Commit](https://benmccormick.org/2017/02/26/running-jest-tests-before-each-git-commit/)
17
- - [AgentConf: Make Linting Great Again](https://www.youtube.com/watch?v=-mhY7e-EsC4)
18
- - [SurviveJS Interview](https://survivejs.com/blog/lint-staged-interview/)
15
+ - [Introductory Medium post - Andrey Okonetchnikov, 2016](https://medium.com/@okonetchnikov/make-linting-great-again-f3890e1ad6b8#.8qepn2b5l)
16
+ - [Running Jest Tests Before Each Git Commit - Ben McCormick, 2017](https://benmccormick.org/2017/02/26/running-jest-tests-before-each-git-commit/)
17
+ - [AgentConf presentation - Andrey Okonetchnikov, 2018](https://www.youtube.com/watch?v=-mhY7e-EsC4)
18
+ - [SurviveJS interview - Juho Vepsäläinen and Andrey Okonetchnikov, 2018](https://survivejs.com/blog/lint-staged-interview/)
19
+ - [Prettier your CSharp with `dotnet-format` and `lint-staged`](https://blog.johnnyreilly.com/2020/12/prettier-your-csharp-with-dotnet-format-and-lint-staged.html)
19
20
 
20
21
  > If you've written one, please submit a PR with the link to it!
21
22
 
@@ -210,51 +211,74 @@ The function can also be async:
210
211
 
211
212
  ### Example: Export a function to build your own matchers
212
213
 
214
+ <details>
215
+ <summary>Click to expand</summary>
216
+
213
217
  ```js
214
218
  // lint-staged.config.js
215
219
  const micromatch = require('micromatch')
216
220
 
217
221
  module.exports = (allStagedFiles) => {
218
- const shFiles = micromatch(allStagedFiles, ['**/src/**/*.sh']);
219
- if (shFiles.length) {
220
- return `printf '%s\n' "Script files aren't allowed in src directory" >&2`
221
- }
222
- const codeFiles = micromatch(allStagedFiles, ['**/*.js', '**/*.ts']);
223
- const docFiles = micromatch(allStagedFiles, ['**/*.md']);
224
- return [`eslint ${codeFiles.join(' ')}`, `mdl ${docFiles.join(' ')}`];
222
+ const shFiles = micromatch(allStagedFiles, ['**/src/**/*.sh'])
223
+ if (shFiles.length) {
224
+ return `printf '%s\n' "Script files aren't allowed in src directory" >&2`
225
225
  }
226
+ const codeFiles = micromatch(allStagedFiles, ['**/*.js', '**/*.ts'])
227
+ const docFiles = micromatch(allStagedFiles, ['**/*.md'])
228
+ return [`eslint ${codeFiles.join(' ')}`, `mdl ${docFiles.join(' ')}`]
229
+ }
226
230
  ```
227
231
 
232
+ </details>
228
233
 
229
234
  ### Example: Wrap filenames in single quotes and run once per file
230
235
 
236
+ <details>
237
+ <summary>Click to expand</summary>
238
+
231
239
  ```js
232
240
  // .lintstagedrc.js
233
241
  module.exports = {
234
- '**/*.js?(x)': (filenames) => filenames.map((filename) => `prettier --write '${filename}'`)
242
+ '**/*.js?(x)': (filenames) => filenames.map((filename) => `prettier --write '${filename}'`),
235
243
  }
236
244
  ```
237
245
 
246
+ </details>
247
+
238
248
  ### Example: Run `tsc` on changes to TypeScript files, but do not pass any filename arguments
239
249
 
250
+ <details>
251
+ <summary>Click to expand</summary>
252
+
240
253
  ```js
241
254
  // lint-staged.config.js
242
255
  module.exports = {
243
- '**/*.ts?(x)': () => 'tsc -p tsconfig.json --noEmit'
256
+ '**/*.ts?(x)': () => 'tsc -p tsconfig.json --noEmit',
244
257
  }
245
258
  ```
246
259
 
260
+ </details>
261
+
247
262
  ### Example: Run eslint on entire repo if more than 10 staged files
248
263
 
264
+ <details>
265
+ <summary>Click to expand</summary>
266
+
249
267
  ```js
250
268
  // .lintstagedrc.js
251
269
  module.exports = {
252
270
  '**/*.js?(x)': (filenames) =>
253
- filenames.length > 10 ? 'eslint .' : `eslint ${filenames.join(' ')}`
271
+ filenames.length > 10 ? 'eslint .' : `eslint ${filenames.join(' ')}`,
254
272
  }
255
273
  ```
256
274
 
275
+ </details>
276
+
257
277
  ### Example: Use your own globs
278
+
279
+ <details>
280
+ <summary>Click to expand</summary>
281
+
258
282
  It's better to use the [function-based configuration (seen above)](https://github.com/okonet/lint-staged/README.md#example-export-a-function-to-build-your-own-matchers), if your use case is this.
259
283
 
260
284
  ```js
@@ -263,15 +287,20 @@ const micromatch = require('micromatch')
263
287
 
264
288
  module.exports = {
265
289
  '*': (allFiles) => {
266
- const codeFiles = micromatch(allFiles, ['**/*.js', '**/*.ts']);
267
- const docFiles = micromatch(allFiles, ['**/*.md']);
268
- return [`eslint ${codeFiles.join(' ')}`, `mdl ${docFiles.join(' ')}`];
269
- }
290
+ const codeFiles = micromatch(allFiles, ['**/*.js', '**/*.ts'])
291
+ const docFiles = micromatch(allFiles, ['**/*.md'])
292
+ return [`eslint ${codeFiles.join(' ')}`, `mdl ${docFiles.join(' ')}`]
293
+ },
270
294
  }
271
295
  ```
272
296
 
297
+ </details>
298
+
273
299
  ### Example: Ignore files from match
274
300
 
301
+ <details>
302
+ <summary>Click to expand</summary>
303
+
275
304
  If for some reason you want to ignore files from the glob match, you can use `micromatch.not()`:
276
305
 
277
306
  ```js
@@ -283,14 +312,19 @@ module.exports = {
283
312
  // from `files` filter those _NOT_ matching `*test.js`
284
313
  const match = micromatch.not(files, '*test.js')
285
314
  return `eslint ${match.join(' ')}`
286
- }
315
+ },
287
316
  }
288
317
  ```
289
318
 
290
319
  Please note that for most cases, globs can achieve the same effect. For the above example, a matching glob would be `!(*test).js`.
291
320
 
321
+ </details>
322
+
292
323
  ### Example: Use relative paths for commands
293
324
 
325
+ <details>
326
+ <summary>Click to expand</summary>
327
+
294
328
  ```js
295
329
  const path = require('path')
296
330
 
@@ -299,10 +333,12 @@ module.exports = {
299
333
  const cwd = process.cwd()
300
334
  const relativePaths = absolutePaths.map((file) => path.relative(cwd, file))
301
335
  return `ng lint myProjectName --files ${relativePaths.join(' ')}`
302
- }
336
+ },
303
337
  }
304
338
  ```
305
339
 
340
+ </details>
341
+
306
342
  ## Reformatting the code
307
343
 
308
344
  Tools like [Prettier](https://prettier.io), ESLint/TSLint, or stylelint can reformat your code according to an appropriate config by running `prettier --write`/`eslint --fix`/`tslint --fix`/`stylelint --fix`. Lint-staged will automatically add any modifications to the commit as long as there are no errors.
@@ -339,14 +375,22 @@ _Note we don’t pass a path as an argument for the runners. This is important s
339
375
 
340
376
  ### ESLint with default parameters for `*.js` and `*.jsx` running as a pre-commit hook
341
377
 
378
+ <details>
379
+ <summary>Click to expand</summary>
380
+
342
381
  ```json
343
382
  {
344
383
  "*.{js,jsx}": "eslint"
345
384
  }
346
385
  ```
347
386
 
387
+ </details>
388
+
348
389
  ### Automatically fix code style with `--fix` and add to commit
349
390
 
391
+ <details>
392
+ <summary>Click to expand</summary>
393
+
350
394
  ```json
351
395
  {
352
396
  "*.js": "eslint --fix"
@@ -355,8 +399,13 @@ _Note we don’t pass a path as an argument for the runners. This is important s
355
399
 
356
400
  This will run `eslint --fix` and automatically add changes to the commit.
357
401
 
402
+ </details>
403
+
358
404
  ### Reuse npm script
359
405
 
406
+ <details>
407
+ <summary>Click to expand</summary>
408
+
360
409
  If you wish to reuse a npm script defined in your package.json:
361
410
 
362
411
  ```json
@@ -373,8 +422,13 @@ The following is equivalent:
373
422
  }
374
423
  ```
375
424
 
425
+ </details>
426
+
376
427
  ### Use environment variables with linting commands
377
428
 
429
+ <details>
430
+ <summary>Click to expand</summary>
431
+
378
432
  Linting commands _do not_ support the shell convention of expanding environment variables. To enable the convention yourself, use a tool like [`cross-env`](https://github.com/kentcdodds/cross-env).
379
433
 
380
434
  For example, here is `jest` running on all `.js` files with the `NODE_ENV` variable being set to `"test"`:
@@ -385,16 +439,59 @@ For example, here is `jest` running on all `.js` files with the `NODE_ENV` varia
385
439
  }
386
440
  ```
387
441
 
442
+ </details>
443
+
444
+ ### Automatically fix code style with `prettier` for any format prettier supports
445
+
446
+ <details>
447
+ <summary>Click to expand</summary>
448
+
449
+ You need to add `micromatch` as a dev dependency.
450
+
451
+ ```sh
452
+ $ npm i --save-dev micromatch
453
+ ```
454
+
455
+ ```js
456
+ // lint-staged.config.js
457
+ const micromatch = require('micromatch')
458
+ const prettier = require('prettier')
459
+
460
+ const prettierSupportedExtensions = prettier
461
+ .getSupportInfo()
462
+ .languages.map(({ extensions }) => extensions)
463
+ .flat()
464
+ const addQuotes = (a) => `"${a}"`
465
+
466
+ module.exports = (allStagedFiles) => {
467
+ const prettierFiles = micromatch(
468
+ allStagedFiles,
469
+ prettierSupportedExtensions.map((extension) => `**/*${extension}`)
470
+ )
471
+ return [`prettier --write ${prettierFiles.map(addQuotes).join(' ')}`]
472
+ }
473
+ ```
474
+
475
+ </details>
476
+
388
477
  ### Automatically fix code style with `prettier` for javascript, typescript, markdown, HTML, or CSS
389
478
 
479
+ <details>
480
+ <summary>Click to expand</summary>
481
+
390
482
  ```json
391
483
  {
392
484
  "*.{js,jsx,ts,tsx,md,html,css}": "prettier --write"
393
485
  }
394
486
  ```
395
487
 
488
+ </details>
489
+
396
490
  ### Stylelint for CSS with defaults and for SCSS with SCSS syntax
397
491
 
492
+ <details>
493
+ <summary>Click to expand</summary>
494
+
398
495
  ```json
399
496
  {
400
497
  "*.css": "stylelint",
@@ -402,16 +499,26 @@ For example, here is `jest` running on all `.js` files with the `NODE_ENV` varia
402
499
  }
403
500
  ```
404
501
 
502
+ </details>
503
+
405
504
  ### Run PostCSS sorting and Stylelint to check
406
505
 
506
+ <details>
507
+ <summary>Click to expand</summary>
508
+
407
509
  ```json
408
510
  {
409
511
  "*.scss": ["postcss --config path/to/your/config --replace", "stylelint"]
410
512
  }
411
513
  ```
412
514
 
515
+ </details>
516
+
413
517
  ### Minify the images
414
518
 
519
+ <details>
520
+ <summary>Click to expand</summary>
521
+
415
522
  ```json
416
523
  {
417
524
  "*.{png,jpeg,jpg,gif,svg}": "imagemin-lint-staged"
@@ -425,20 +532,29 @@ For example, here is `jest` running on all `.js` files with the `NODE_ENV` varia
425
532
 
426
533
  See more on [this blog post](https://medium.com/@tomchentw/imagemin-lint-staged-in-place-minify-the-images-before-adding-to-the-git-repo-5acda0b4c57e) for benefits of this approach.
427
534
 
535
+ </details>
428
536
  </details>
429
537
 
430
538
  ### Typecheck your staged files with flow
431
539
 
540
+ <details>
541
+ <summary>Click to expand</summary>
542
+
432
543
  ```json
433
544
  {
434
545
  "*.{js,jsx}": "flow focus-check"
435
546
  }
436
547
  ```
437
548
 
549
+ </details>
550
+
438
551
  ## Frequently Asked Questions
439
552
 
440
553
  ### Can I use `lint-staged` via node?
441
554
 
555
+ <details>
556
+ <summary>Click to expand</summary>
557
+
442
558
  Yes!
443
559
 
444
560
  ```js
@@ -485,14 +601,19 @@ const success = await lintStaged({
485
601
  relative: false,
486
602
  shell: false,
487
603
  stash: true,
488
- verbose: false
604
+ verbose: false,
489
605
  })
490
606
  ```
491
607
 
492
608
  The `maxArgLength` option configures chunking of tasks into multiple parts that are run one after the other. This is to avoid issues on Windows platforms where the maximum length of the command line argument string is limited to 8192 characters. Lint-staged might generate a very long argument string when there are many staged files. This option is set automatically from the cli, but not via the Node.js API by default.
493
609
 
610
+ </details>
611
+
494
612
  ### Using with JetBrains IDEs _(WebStorm, PyCharm, IntelliJ IDEA, RubyMine, etc.)_
495
613
 
614
+ <details>
615
+ <summary>Click to expand</summary>
616
+
496
617
  _**Update**_: The latest version of JetBrains IDEs now support running hooks as you would expect.
497
618
 
498
619
  When using the IDE's GUI to commit changes with the `precommit` hook, you might see inconsistencies in the IDE and command line. This is [known issue](https://youtrack.jetbrains.com/issue/IDEA-135454) at JetBrains so if you want this fixed, please vote for it on YouTrack.
@@ -525,8 +646,13 @@ husky v0.x
525
646
 
526
647
  _Thanks to [this comment](https://youtrack.jetbrains.com/issue/IDEA-135454#comment=27-2710654) for the fix!_
527
648
 
649
+ </details>
650
+
528
651
  ### How to use `lint-staged` in a multi package monorepo?
529
652
 
653
+ <details>
654
+ <summary>Click to expand</summary>
655
+
530
656
  Starting with v5.0, `lint-staged` automatically resolves the git root **without any** additional configuration. You configure `lint-staged` as you normally would if your project root and git root were the same directory.
531
657
 
532
658
  If you wish to use `lint-staged` in a multi package monorepo, it is recommended to install [`husky`](https://github.com/typicode/husky) in the root package.json.
@@ -534,8 +660,13 @@ If you wish to use `lint-staged` in a multi package monorepo, it is recommended
534
660
 
535
661
  Example repo: [sudo-suhas/lint-staged-multi-pkg](https://github.com/sudo-suhas/lint-staged-multi-pkg).
536
662
 
663
+ </details>
664
+
537
665
  ### Can I lint files outside of the current project folder?
538
666
 
667
+ <details>
668
+ <summary>Click to expand</summary>
669
+
539
670
  tl;dr: Yes, but the pattern should start with `../`.
540
671
 
541
672
  By default, `lint-staged` executes linters only on the files present inside the project folder(where `lint-staged` is installed and run from).
@@ -547,11 +678,23 @@ Note that patterns like `*.js`, `**/*.js` will still only match the project file
547
678
 
548
679
  Example repo: [sudo-suhas/lint-staged-django-react-demo](https://github.com/sudo-suhas/lint-staged-django-react-demo).
549
680
 
681
+ </details>
682
+
550
683
  ### How can i ignore files from `.eslintignore` ?
551
684
 
685
+ <details>
686
+ <summary>Click to expand</summary>
687
+
552
688
  ESLint throws out `warning File ignored because of a matching ignore pattern. Use "--no-ignore" to override` warnings that breaks the linting process ( if you used `--max-warnings=0` which is recommended ).
553
689
 
554
- Based on the discussion from https://github.com/eslint/eslint/issues/9977 , it was decided that using [the outlined script ](https://github.com/eslint/eslint/issues/9977#issuecomment-406420893)is the best route to fix this.
690
+ </details>
691
+
692
+ #### ESLint < 7
693
+
694
+ <details>
695
+ <summary>Click to expand</summary>
696
+
697
+ Based on the discussion from [this issue](https://github.com/eslint/eslint/issues/9977), it was decided that using [the outlined script ](https://github.com/eslint/eslint/issues/9977#issuecomment-406420893)is the best route to fix this.
555
698
 
556
699
  So you can setup a `.lintstagedrc.js` config file to do this:
557
700
 
@@ -562,6 +705,43 @@ const cli = new CLIEngine({})
562
705
 
563
706
  module.exports = {
564
707
  '*.js': (files) =>
565
- 'eslint --max-warnings=0 ' + files.filter((file) => !cli.isPathIgnored(file)).join(' ')
708
+ 'eslint --max-warnings=0 ' + files.filter((file) => !cli.isPathIgnored(file)).join(' '),
566
709
  }
567
710
  ```
711
+
712
+ </details>
713
+
714
+ #### ESlint >= 7
715
+
716
+ <details>
717
+ <summary>Click to expand</summary>
718
+
719
+ In versions of ESlint > 7, [isPathIgnored](https://eslint.org/docs/developer-guide/nodejs-api#-eslintispathignoredfilepath) is an async function and now returns a promise. The code below can be used to reinstate the above functionality.
720
+
721
+ This particular code uses a tiny package, [node-filter-async](https://www.npmjs.com/package/node-filter-async), to filter the files array with an async function. If you prefer to not have an extra dependency, it is quite simple to write a similar function.
722
+
723
+ Since [10.5.3](https://github.com/okonet/lint-staged/releases), any errors due to a bad eslint config will come through to the console.
724
+
725
+ ```js
726
+ const { ESLint } = require('eslint')
727
+ const filterAsync = require('node-filter-async').default
728
+
729
+ const eslintCli = new ESLint()
730
+
731
+ const removeIgnoredFiles = async (files) => {
732
+ const filteredFiles = await filterAsync(files, async (file) => {
733
+ const isIgnored = await eslintCli.isPathIgnored(file)
734
+ return !isIgnored
735
+ })
736
+ return filteredFiles.join(' ')
737
+ }
738
+
739
+ module.exports = {
740
+ '**/*.{ts,tsx,js,jsx}': async (files) => {
741
+ const filesToLint = await removeIgnoredFiles(files)
742
+ return [`eslint --max-warnings=0 ${filesToLint}`]
743
+ },
744
+ }
745
+ ```
746
+
747
+ </details>
@@ -76,7 +76,7 @@ const getMaxArgLength = () => {
76
76
 
77
77
  const options = {
78
78
  allowEmpty: !!cmdline.allowEmpty,
79
- concurrent: cmdline.concurrent,
79
+ concurrent: JSON.parse(cmdline.concurrent),
80
80
  configPath: cmdline.config,
81
81
  debug: !!cmdline.debug,
82
82
  maxArgLength: getMaxArgLength() / 2,
package/lib/index.js CHANGED
@@ -128,19 +128,24 @@ module.exports = async function lintStaged(
128
128
  printTaskOutput(ctx, logger)
129
129
  return true
130
130
  } catch (runAllError) {
131
- const { ctx } = runAllError
132
- if (ctx.errors.has(ApplyEmptyCommitError)) {
133
- logger.warn(PREVENTED_EMPTY_COMMIT)
134
- } else if (ctx.errors.has(GitError) && !ctx.errors.has(GetBackupStashError)) {
135
- logger.error(GIT_ERROR)
136
- if (ctx.shouldBackup) {
137
- // No sense to show this if the backup stash itself is missing.
138
- logger.error(RESTORE_STASH_EXAMPLE)
131
+ if (runAllError && runAllError.ctx && runAllError.ctx.errors) {
132
+ const { ctx } = runAllError
133
+ if (ctx.errors.has(ApplyEmptyCommitError)) {
134
+ logger.warn(PREVENTED_EMPTY_COMMIT)
135
+ } else if (ctx.errors.has(GitError) && !ctx.errors.has(GetBackupStashError)) {
136
+ logger.error(GIT_ERROR)
137
+ if (ctx.shouldBackup) {
138
+ // No sense to show this if the backup stash itself is missing.
139
+ logger.error(RESTORE_STASH_EXAMPLE)
140
+ }
139
141
  }
142
+
143
+ printTaskOutput(ctx, logger)
144
+ return false
140
145
  }
141
146
 
142
- printTaskOutput(ctx, logger)
143
- return false
147
+ // Probably a compilation error in the config js file. Pass it up to the outer error handler for logging.
148
+ throw runAllError
144
149
  }
145
150
  } catch (lintStagedError) {
146
151
  if (lintStagedError === errConfigNotFound) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lint-staged",
3
- "version": "10.5.0",
3
+ "version": "10.5.4",
4
4
  "description": "Lint files staged by git",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/okonet/lint-staged",
@@ -34,13 +34,13 @@
34
34
  "dependencies": {
35
35
  "chalk": "^4.1.0",
36
36
  "cli-truncate": "^2.1.0",
37
- "commander": "^6.0.0",
37
+ "commander": "^6.2.0",
38
38
  "cosmiconfig": "^7.0.0",
39
- "debug": "^4.1.1",
39
+ "debug": "^4.2.0",
40
40
  "dedent": "^0.7.0",
41
41
  "enquirer": "^2.3.6",
42
- "execa": "^4.0.3",
43
- "listr2": "^2.6.0",
42
+ "execa": "^4.1.0",
43
+ "listr2": "^3.2.2",
44
44
  "log-symbols": "^4.0.0",
45
45
  "micromatch": "^4.0.2",
46
46
  "normalize-path": "^3.0.0",
@@ -49,22 +49,22 @@
49
49
  "stringify-object": "^3.3.0"
50
50
  },
51
51
  "devDependencies": {
52
- "@babel/core": "^7.11.4",
53
- "@babel/plugin-proposal-object-rest-spread": "^7.11.0",
54
- "@babel/preset-env": "^7.11.0",
52
+ "@babel/core": "^7.12.3",
53
+ "@babel/plugin-proposal-object-rest-spread": "^7.12.1",
54
+ "@babel/preset-env": "^7.12.1",
55
55
  "babel-eslint": "10.1.0",
56
- "babel-jest": "^26.3.0",
56
+ "babel-jest": "^26.6.1",
57
57
  "consolemock": "^1.1.0",
58
- "eslint": "^7.7.0",
59
- "eslint-config-prettier": "^6.11.0",
60
- "eslint-plugin-import": "^2.22.0",
58
+ "eslint": "^7.12.1",
59
+ "eslint-config-prettier": "^6.15.0",
60
+ "eslint-plugin-import": "^2.22.1",
61
61
  "eslint-plugin-node": "^11.1.0",
62
62
  "eslint-plugin-prettier": "^3.1.4",
63
63
  "fs-extra": "^9.0.1",
64
- "husky": "^4.2.5",
65
- "jest": "^26.4.2",
64
+ "husky": "^4.3.0",
65
+ "jest": "^26.6.1",
66
66
  "jest-snapshot-serializer-ansi": "^1.0.0",
67
- "prettier": "^2.1.0"
67
+ "prettier": "^2.1.2"
68
68
  },
69
69
  "config": {
70
70
  "commitizen": {