Lint eslint Found Some Errors Please Fix Them and Try Committing Again
🚫 💩 lint-staged
Run linters against staged git files and don't permit
Why
Linting makes more sense when run before committing your code. By doing so you can ensure no errors get into the repository and enforce code fashion. Merely running a lint process on a whole project is slow, and linting results can be irrelevant. Ultimately you merely desire to lint files that will exist committed.
This project contains a script that will run capricious beat out tasks with a listing of staged files as an argument, filtered by a specified glob pattern.
Related blog posts and talks
- Introductory Medium mail - Andrey Okonetchnikov, 2016
- Running Jest Tests Earlier Each Git Commit - Ben McCormick, 2017
- AgentConf presentation - Andrey Okonetchnikov, 2018
- SurviveJS interview - Juho Vepsäläinen and Andrey Okonetchnikov, 2018
- Prettier your CSharp with
dotnet-format
andlint-staged
If you lot've written 1, please submit a PR with the link to it!
Installation and setup
The fastest mode to start using lint-staged is to run the following command in your terminal:
This command will install and configure husky and lint-staged depending on the lawmaking quality tools from your project's package.json
dependencies, then please make sure yous install (npm install --save-dev
) and configure all lawmaking quality tools like Prettier and ESLint prior to that.
Don't forget to commit changes to package.json
and .husky
to share this setup with your team!
At present change a few files, git add
or git add together --patch
some of them to your commit, and endeavor to git commit
them.
See examples and configuration for more data.
Changelog
Meet Releases.
Migration
v10
- From
v10.0.0
onwards any new modifications to originally staged files will be automatically added to the commit. If your task previously independent agit add
pace, please remove this. The automatic behaviour ensures at that place are less race-atmospheric condition, since trying to run multiple git operations at the same time usually results in an fault. - From
v10.0.0
onwards, lint-staged uses git stashes to improve speed and provide backups while running. Since git stashes require at least an initial commit, you shouldn't run lint-staged in an empty repo. - From
v10.0.0
onwards, lint-staged requires Node.js version ten.xiii.0 or afterward. - From
v10.0.0
onwards, lint-staged will abort the commit if linter tasks disengage all staged changes. To allow creating an empty commit, please use the--permit-empty
choice.
Control line flags
❯ npx lint-staged --aid Usage: lint-staged [options] Options: -Five, --version output the version number --allow-empty allow empty commits when tasks revert all staged changes (default: faux) -c, --config [path] path to configuration file, or - to read from stdin -d, --debug print additional debug data (default: fake) --no-reset practice not reset changes in case of errors -p, --concurrent <parallel tasks> the number of tasks to run concurrently, or false to run tasks serially (default: true) -q, --quiet disable lint-staged's own console output (default: false) -r, --relative pass relative filepaths to tasks (default: fake) -x, --shell [path] skip parsing of tasks for better shell support (default: false) -five, --verbose prove task output even when tasks succeed; by default only failed output is shown (default: imitation) -h, --aid brandish help for command
-
--allow-empty
: By default, when linter tasks undo all staged changes, lint-staged will exit with an error and abort the commit. Utilise this flag to allow creating empty git commits. -
--config [path]
: Manually specify a path to a config file or npm package proper noun. Note: when used, lint-staged won't perform the config file search and volition impress an error if the specified file cannot be found. If '-' is provided as the filename then the config will exist read from stdin, allowing piping in the config similarcat my-config.json | npx lint-staged --config -
. -
--debug
: Run in debug manner. When set, it does the post-obit:- uses debug internally to log boosted information nearly staged files, commands existence executed, location of binaries, etc. Debug logs, which are automatically enabled by passing the flag, can also be enabled by setting the environment variable
$DEBUG
tolint-staged*
. - uses
verbose
renderer forlistr
; this causes serial, uncoloured output to the final, instead of the default (beautified, dynamic) output.
- uses debug internally to log boosted information nearly staged files, commands existence executed, location of binaries, etc. Debug logs, which are automatically enabled by passing the flag, can also be enabled by setting the environment variable
-
--concurrent [number | (true/false)]
: Controls the concurrency of tasks being run by lint-staged. NOTE: This does Not affect the concurrency of subtasks (they will always be run sequentially). Possible values are:-
false
: Run all tasks serially -
true
(default) : Infinite concurrency. Runs as many tasks in parallel as possible. -
{number}
: Run the specified number of tasks in parallel, where1
is equivalent tofalse
.
-
-
--no-reset
: By default a backup stash volition be created before running the tasks, and all task modifications volition be reverted in case of an fault. This pick will disable creating the stash, and instead leave all modifications in the alphabetize when aborting the commit. -
--placidity
: Supress all CLI output, except from tasks. -
--relative
: Pass filepaths relative toprocess.cwd()
(wherelint-staged
runs) to tasks. Default issimulated
. -
--crush
: By default linter commands volition exist parsed for speed and security. This has the side-effect that regular shell scripts might not work as expected. Yous can skip parsing of commands with this choice. To use a specific shell, employ a path like--shell "/bin/bash"
. -
--verbose
: Bear witness chore output even when tasks succeed. By default merely failed output is shown.
Configuration
Starting with v3.i you can now use different ways of configuring lint-staged:
-
lint-staged
object in yourpacket.json
-
.lintstagedrc
file in JSON or YML format, or yous tin can exist explicit with the file extension:-
.lintstagedrc.json
-
.lintstagedrc.yaml
-
.lintstagedrc.yml
-
-
lint-staged.config.js
,.lintstagedrc.js
, or.lintstagedrc.cjs
file in JS format - Pass a configuration file using the
--config
or-c
flag
Encounter cosmiconfig for more details on what formats are supported.
Configuration should be an object where each value is a command to run and its central is a glob blueprint to apply for this control. This package uses micromatch for glob patterns.
package.json
example:
{ "lint-staged" : { "*" : "your-cmd" } }
.lintstagedrc
example
This config will execute your-cmd
with the list of currently staged files passed every bit arguments.
So, considering yous did git add file1.ext file2.ext
, lint-staged volition run the following control:
your-cmd file1.ext file2.ext
Filtering files
Linter commands work on a subset of all staged files, defined by a glob pattern. lint-staged uses micromatch for matching files with the post-obit rules:
- If the glob design contains no slashes (
/
), micromatch'smatchBase
option will enabled, so globs match a file'south basename regardless of directory:-
"*.js"
will lucifer all JS files, like/test.js
and/foo/bar/test.js
-
"!(*test).js"
. will match all JS files, except those ending intest.js
, sofoo.js
simply notfoo.test.js
-
- If the glob pattern does contain a slash (
/
), it volition match for paths too:-
"./*.js"
will lucifer all JS files in the git repo root, so/test.js
but not/foo/bar/test.js
-
"foo/**/\*.js"
will match all JS files inside the/foo
directory, so/foo/bar/test.js
merely not/test.js
-
When matching, lint-staged volition do the post-obit
- Resolve the git root automatically, no configuration needed.
- Pick the staged files which are nowadays inside the project directory.
- Filter them using the specified glob patterns.
- Pass absolute paths to the linters as arguments.
Note: lint-staged
will pass accented paths to the linters to avoid any defoliation in case they're executed in a different working directory (i.e. when your .git
directory isn't the same as your package.json
directory).
Also encounter How to utilize lint-staged
in a multi-package monorepo?
Ignoring files
The concept of lint-staged
is to run configured linter tasks (or other tasks) on files that are staged in git. lint-staged
volition always pass a listing of all staged files to the job, and ignoring whatsoever files should be configured in the task itself.
Consider a project that uses prettier
to continue code format consistent across all files. The projection likewise stores minified 3rd-party vendor libraries in the vendor/
directory. To keep prettier
from throwing errors on these files, the vendor directory should exist added to prettier's ignore configuration, the .prettierignore
file. Running npx prettier .
will ignore the unabridged vendor directory, throwing no errors. When lint-staged
is added to the project and configured to run prettier, all modified and staged files in the vendor directory will exist ignored by prettier, even though it receives them as input.
In advanced scenarios, where it is impossible to configure the linter job itself to ignore files, but some staged files should still be ignored by lint-staged
, information technology is possible to filter filepaths before passing them to tasks past using the part syntax. See Example: Ignore files from lucifer.
What commands are supported?
Supported are any executables installed locally or globally via npm
likewise every bit any executable from your $PATH.
Using globally installed scripts is discouraged, since lint-staged may not work for someone who doesn't have it installed.
lint-staged
uses execa to locate locally installed scripts. Then in your .lintstagedrc
you can write:
{ "*.js" : "eslint --set up" }
Pass arguments to your commands separated by space as yous would do in the shell. Meet examples below.
Running multiple commands in a sequence
You tin run multiple commands in a sequence on every glob. To do so, pass an array of commands instead of a unmarried one. This is useful for running autoformatting tools like eslint --fix
or stylefmt
just can be used for any arbitrary sequences.
For example:
{ "*.js" : [ "eslint" , "prettier --write" ] }
going to execute eslint
and if it exits with 0
code, it will execute prettier --write
on all staged *.js
files.
Using JS configuration file
Writing the configuration file in JavaScript is the most powerful way to configure lint-staged (lint-staged.config.js
, like, or passed via --config
). From the configuration file, you can export either a single function or an object.
If the exports
value is a part, it will receive an array of all staged filenames. You can then build your own matchers for the files and return a command string or an array of command strings. These strings are considered consummate and should include the filename arguments, if wanted.
If the exports
value is an object, its keys should be glob matches (like in the normal non-js config format). The values tin can either be similar in the normal config or individual functions like described above. Instead of receiving all matched files, the functions in the exported object will merely receive the staged files matching the respective glob key.
Office signature
The role can also exist async:
( filenames: string [ ] ) => string | string [ ] | Promise < string | string [ ] >
Example: Export a part to build your ain matchers
Click to aggrandize
// lint-staged.config.js const micromatch = require ( 'micromatch' ) module . exports = ( allStagedFiles ) => { const shFiles = micromatch ( allStagedFiles , [ '**/src/**/*.sh' ] ) if ( shFiles . length ) { return `printf '%southward\north' "Script files aren't allowed in src directory" >&2` } const codeFiles = micromatch ( allStagedFiles , [ '**/*.js' , '**/*.ts' ] ) const docFiles = micromatch ( allStagedFiles , [ '**/*.doctor' ] ) return [ `eslint ${ codeFiles . join ( ' ' ) } ` , `mdl ${ docFiles . join ( ' ' ) } ` ] }
Instance: Wrap filenames in single quotes and run once per file
Click to expand
// .lintstagedrc.js module . exports = { '**/*.js?(ten)': ( filenames ) => filenames . map ( ( filename ) => `prettier --write ' ${ filename } '` ) , }
Instance: Run tsc
on changes to TypeScript files, only practice not pass any filename arguments
Click to aggrandize
// lint-staged.config.js module . exports = { '**/*.ts?(x)': ( ) => 'tsc -p tsconfig.json --noEmit' , }
Example: Run ESLint on unabridged repo if more than 10 staged files
Click to expand
// .lintstagedrc.js module . exports = { '**/*.js?(x)': ( filenames ) => filenames . length > 10 ? 'eslint .' : `eslint ${ filenames . join ( ' ' ) } ` , }
Instance: Employ your own globs
Click to expand
It's better to use the part-based configuration (seen above), if your employ case is this.
// lint-staged.config.js const micromatch = require ( 'micromatch' ) module . exports = { '*': ( allFiles ) => { const codeFiles = micromatch ( allFiles , [ '**/*.js' , '**/*.ts' ] ) const docFiles = micromatch ( allFiles , [ '**/*.md' ] ) return [ `eslint ${ codeFiles . join ( ' ' ) } ` , `mdl ${ docFiles . bring together ( ' ' ) } ` ] } , }
Example: Ignore files from friction match
Click to expand
If for some reason y'all want to ignore files from the glob friction match, you can employ micromatch.not()
:
// lint-staged.config.js const micromatch = crave ( 'micromatch' ) module . exports = { '*.js': ( files ) => { // from `files` filter those _NOT_ matching `*test.js` const match = micromatch . non ( files , '*examination.js' ) return `eslint ${ friction match . join ( ' ' ) } ` } , }
Delight note that for most cases, globs tin achieve the same effect. For the above example, a matching glob would be !(*test).js
.
Example: Use relative paths for commands
Click to aggrandize
const path = require ( 'path' ) module . exports = { '*.ts': ( absolutePaths ) => { const cwd = process . cwd ( ) const relativePaths = absolutePaths . map ( ( file ) => path . relative ( cwd , file ) ) return `ng lint myProjectName --files ${ relativePaths . join ( ' ' ) } ` } , }
Reformatting the code
Tools like Prettier, ESLint/TSLint, or stylelint tin can reformat your code according to an appropriate config by running prettier --write
/eslint --set
/tslint --fix
/stylelint --fix
. Lint-staged will automatically add together any modifications to the commit as long as there are no errors.
{ "*.js" : "prettier --write" }
Prior to version 10, tasks had to manually include git add
as the last step. This behavior has been integrated into lint-staged itself in social club to forbid race conditions with multiple tasks editing the same files. If lint-staged detects git add together
in task configurations, it will bear witness a warning in the console. Delight remove git add
from your configuration later on upgrading.
Examples
All examples assume you've already prepare lint-staged in the package.json
file and husky in its own config file.
{ "proper noun" : "My projection" , "version" : "0.one.0" , "scripts" : { "my-custom-script" : "linter --arg1 --arg2" }, "lint-staged" : {} }
In .husky/pre-commit
#!/usr/bin/env sh . " $(dirname " $0 " ) /_/husky.sh" npx lint-staged
Notation: we don't pass a path as an argument for the runners. This is important since lint-staged will do this for you.
ESLint with default parameters for *.js
and *.jsx
running as a pre-commit claw
Click to expand
{ "*.{js,jsx}" : "eslint" }
Automatically fix code style with --set up
and add to commit
Click to expand
{ "*.js" : "eslint --prepare" }
This volition run eslint --ready
and automatically add changes to the commit.
Reuse npm script
Click to aggrandize
If you wish to reuse a npm script defined in your parcel.json:
{ "*.js" : "npm run my-custom-script --" }
The following is equivalent:
{ "*.js" : "linter --arg1 --arg2" }
Use environment variables with linting commands
Click to expand
Linting commands do not support the beat out convention of expanding surround variables. To enable the convention yourself, use a tool like cross-env
.
For example, here is jest
running on all .js
files with the NODE_ENV
variable being set to "test"
:
{ "*.js" : [ "cantankerous-env NODE_ENV=test jest --bail --findRelatedTests" ] }
Automatically prepare code style with prettier
for whatsoever format Prettier supports
Click to expand
{ "*" : "prettier --ignore-unknown --write" }
Automatically fix code style with prettier
for JavaScript, TypeScript, Markdown, HTML, or CSS
Click to aggrandize
{ "*.{js,jsx,ts,tsx,doc,html,css}" : "prettier --write" }
Stylelint for CSS with defaults and for SCSS with SCSS syntax
Click to aggrandize
{ "*.css" : "stylelint" , "*.scss" : "stylelint --syntax=scss" }
Run PostCSS sorting and Stylelint to check
Click to expand
{ "*.scss" : [ "postcss --config path/to/your/config --replace" , "stylelint" ] }
Minify the images
Click to expand
{ "*.{png,jpeg,jpg,gif,svg}" : "imagemin-lint-staged" }
More near imagemin-lint-staged
imagemin-lint-staged is a CLI tool designed for lint-staged usage with sensible defaults.
Run into more on this blog mail for benefits of this approach.
Typecheck your staged files with flow
Click to expand
{ "*.{js,jsx}" : "menstruum focus-check" }
Frequently Asked Questions
Can I use lint-staged
via node?
Click to expand
Yes!
const lintStaged = require ( 'lint-staged' ) effort { const success = wait lintStaged ( ) panel . log ( success ? 'Linting was successful!' : 'Linting failed!' ) } catch ( east ) { // Failed to load configuration console . error ( due east ) }
Parameters to lintStaged
are equivalent to their CLI counterparts:
const success = expect lintStaged ( { allowEmpty: faux , concurrent: truthful , configPath: './path/to/configuration/file' , cwd: process . cwd ( ) , debug: false , maxArgLength: null , quiet: false , relative: false , reset: true , shell: false verbose: false } )
Yous tin can too pass config direct with config
option:
const success = await lintStaged ( { allowEmpty: false , concurrent: true , config: { '*.js': 'eslint --fix' } , cwd: procedure . cwd ( ) , debug: false , maxArgLength: null , quiet: imitation , relative: faux , reset: true , beat: false , verbose: false , } )
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 cord when there are many staged files. This choice is set automatically from the cli, simply not via the Node.js API past default.
Using with JetBrains IDEs (WebStorm, PyCharm, IntelliJ Idea, RubyMine, etc.)
Click to expand
Update : The latest version of JetBrains IDEs now support running hooks as you would expect.
When using the IDE'southward GUI to commit changes with the precommit
hook, you might see inconsistencies in the IDE and control line. This is known effect at JetBrains so if you desire this fixed, please vote for it on YouTrack.
Until the issue is resolved in the IDE, you can employ the following config to work around it:
husky v1.ten
{ "husky" : { "hooks" : { "pre-commit" : "lint-staged" , "mail-commit" : "git update-index --again" } } }
croaking v0.x
{ "scripts" : { "precommit" : "lint-staged" , "postcommit" : "git update-index --once again" } }
Thanks to this comment for the set!
How to use lint-staged
in a multi-package monorepo?
Click to aggrandize
Starting with v5.0, lint-staged
automatically resolves the git root without any boosted configuration. Yous configure lint-staged
as you lot normally would if your project root and git root were the aforementioned directory.
If you wish to use lint-staged
in a multi bundle monorepo, information technology is recommended to install croaking
in the root package.json. lerna
tin be used to execute the precommit
script in all sub-packages.
Case repo: sudo-suhas/lint-staged-multi-pkg.
Tin can I lint files exterior of the electric current project folder?
Click to aggrandize
tl;dr: Yes, but the design should kickoff with ../
.
By default, lint-staged
executes linters only on the files present within the project folder(where lint-staged
is installed and run from). And so this question is relevant only when the projection folder is a child folder inside the git repo. In certain project setups, it might be desirable to bypass this restriction. See #425, #487 for more context.
lint-staged
provides an escape hatch for the same(>= v7.3.0
). For patterns that starting time with ../
, all the staged files are allowed to match against the blueprint. Note that patterns like *.js
, **/*.js
will still only match the project files and not any of the files in parent or sibling directories.
Case repo: sudo-suhas/lint-staged-django-react-demo.
How tin can I ignore files from .eslintignore
?
Click to expand
ESLint throws out warning File ignored considering of a matching ignore pattern. Utilize "--no-ignore" to override
warnings that breaks the linting process ( if you lot used --max-warnings=0
which is recommended ).
ESLint < vii
Click to aggrandize
Based on the give-and-take from this upshot, it was decided that using the outlined script is the best route to fix this.
So you lot tin can setup a .lintstagedrc.js
config file to do this:
const { CLIEngine } = require ( 'eslint' ) const cli = new CLIEngine ( { } ) module . exports = { '*.js': ( files ) => 'eslint --max-warnings=0 ' + files . filter ( ( file ) => ! cli . isPathIgnored ( file ) ) . join ( ' ' ) , }
ESLint >= 7
Click to expand
In versions of ESLint > seven, isPathIgnored is an async part and now returns a promise. The code below tin can exist used to reinstate the higher up functionality.
Since 10.v.3, any errors due to a bad ESLint config will come up through to the console.
const { ESLint } = require ( 'eslint' ) const removeIgnoredFiles = async ( files ) => { const eslint = new ESLint ( ) const isIgnored = wait Promise . all ( files . map ( ( file ) => { return eslint . isPathIgnored ( file ) } ) ) const filteredFiles = files . filter ( ( _ , i ) => ! isIgnored [ i ] ) render filteredFiles . join ( ' ' ) } module . exports = { '**/*.{ts,tsx,js,jsx}': async ( files ) => { const filesToLint = look removeIgnoredFiles ( files ) return [ `eslint --max-warnings=0 ${ filesToLint } ` ] } , }
Source: https://www.npmjs.com/package/lint-staged/v/11.2.0-beta.1
0 Response to "Lint eslint Found Some Errors Please Fix Them and Try Committing Again"
Post a Comment