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-formatandlint-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.0onwards any new modifications to originally staged files will be automatically added to the commit. If your task previously independent agit addpace, 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.0onwards, 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.0onwards, lint-staged requires Node.js version ten.xiii.0 or afterward. - From
v10.0.0onwards, lint-staged will abort the commit if linter tasks disengage all staged changes. To allow creating an empty commit, please use the--permit-emptychoice.
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
$DEBUGtolint-staged*. - uses
verboserenderer 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, where1is 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-stagedruns) 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-stagedobject in yourpacket.json -
.lintstagedrcfile 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.cjsfile in JS format - Pass a configuration file using the
--configor-cflag
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'smatchBaseoption will enabled, so globs match a file'south basename regardless of directory:-
"*.js"will lucifer all JS files, like/test.jsand/foo/bar/test.js -
"!(*test).js". will match all JS files, except those ending intest.js, sofoo.jssimply 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.jsbut not/foo/bar/test.js -
"foo/**/\*.js"will match all JS files inside the/foodirectory, so/foo/bar/test.jsmerely 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