Husky/lint-staged is it possible to exclude/ignore file? - husky

Is it possible to exclude/ignore a file when using Husky/lint-staged hooks?
Looking through the docs atm but not having any luck finding anything on this.
Was hoping there was something like an
/*ignore*/
tag that I could add.
To make lint-staged ignore certain files that were causing formatting issues.
Any thought on this greatly appreciated :)

Ended up adding
.prettierignore
file.
Not ideal but seems to do the job ok.

I finally found out how to do this (at least as of lint-staged v11.1.2)
In package.json:
"lint-staged": {
"!(path/to/excluded/dir/**/*)*.ts": [
"eslint --fix",
"prettier --write"
]
}
Note the globstar pattern is within the negation pattern and not outside it. This ensures that subdirectories are also excluded.

While configuring lint-staged in package.json or If you're using any other IDE, in order to ignore/exclude files by lint-Staged and husky hooks, you can add an "ignore" key in the lint-staged object to make it ignore whatever packages or files you want to ignore. Use the following extensible syntax:
{
"lint-staged": {
"linters": {
"src/**/*.js": ["formatter --write", "git add"],
},
"ignore": ["node_modules", "dist", "package-lock.json"] }
}
Just add the target pattern to 'linters' object and all the ignored files which you might be adding previously to .prettierignore to "ignore" key of lint-Staged object. And there you go!

If anyone still looking, take a look at this https://github.com/okonet/lint-staged#filtering-files It has good examples.
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 following rules:
If the glob pattern contains no slashes (/), micromatch's matchBase option will enabled, so globs match a file's basename regardless of directory:
"*.js" will match all JS files, like /test.js and /foo/bar/test.js
"!(*test).js". will match all JS files, except those ending in test.js, so foo.js but not foo.test.js
If the glob pattern does contain a slash (/), it will match for paths as well:
"./*.js" will match 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/foodirectory, so/foo/bar/test.jsbut not/test.js

So I've been trying to find an answer for this for an entire day and looking at all the forums suggested that they use minimatch for glob check which might have been correct for older versions but they use micromatch for new version and to solve this issue we can use their pattern to exclude certain directories
So in your .lintstagedrc you can add the following pattern to avoid certain folders
{
"*.{json,md,html,scss}": ["prettier --write", "git add"],
["**/!(folder1|folder2)/*.ts"]: ["tslint --project tsconfig.json -c tslint.commit.json --fix", "prettier --write", "git add"]
}
So the glob here is an actual array and make sure not to pass this array within a string else it won't recognize the patterns also do not include **/*.ts the reason being lint-staged automatically converts this into a matchBase comparision if it finds / in the pattern so including this will also match against your folder1|folder2 files.

can fix in three ways:
.lintstagedrc.js
.prettierignore
lint-staged.config.js
more info : https://github.com/okonet/lint-staged/issues/797

Related

Can't target test directory with jest testMatch glob pattern

Let's say that I have a project structure like below:
src/index.js
src/test/foo.js
test/integration/src/index.test.js
test/unit/src/index.test.js
jest.config.json
In jest.config.json I have my testMatch
{
"testMatch": [
"test/**"
]
}
When I run jest with --config jest.config.json it matches with 0 file.
testMatch: test/** - 0 matches
testPathIgnorePatterns: /node_modules/ - 5 matches
testRegex: - 0 matches
Pattern: - 0 matches
I thought it might be related with some incorrect rootDir since testMatch is relative to that. I run jest in debug mode to see my root and it seems it's correct. It shows my project directory. (where jest.config.json exists)
When I change my testMatch to **/test/** it can detect my tests in test/ directory but that's not what I want because then it also matches with src/test/ directory.
Why it cannot detect my tests in test/ directory? Is my glob pattern incorrect?
Why it cannot detect my tests in test/ directory? Is my glob pattern incorrect?
Jest's glob implementation has been going through some issues as of late. Under the hood Jest uses micromatch, but why it is getting hung up on relative path globs is unclear.
There are a couple things you can try in your Jest config:
Include the <rootDir> string token directly in your testMatch glob like testMatch: ['<rootDir>/test/**'].
Follow the globstar example more closely from the Jest testMatch documentation, paying attention to the note about glob order:
Note: Each glob pattern is applied in the order they are specified in the config. (For example ["!/fixtures/", "/tests//.js"] will not exclude fixtures because the negation is overwritten with the second pattern. In order to make the negated glob work in this example it has to come after /tests//.js.)
testMatch: [
'**/test/**',
'!**/src/**'
]

eslint for storybook mdx

I am setting up storybook for a project using .mdx format and I would like to set up eslint so that I can check for things like spaces, alphabetical ordering and other things.
I have tried to set up this https://github.com/mdx-js/eslint-mdx and it seems that I have, but when I run eslint . --ext mdx, I get the following errors in one of my stories.mdx files:
Could someone please point me to a good resource to solving this or tell me what I am doing wrong?
Cheers
I found this issue on their github page that fixed the issue for me. Basically we use "overrides" in .eslintrc to assign the correct parser to mdx files, like so:
{
...,
overrides: [
{
files: '*.mdx',
extends: 'plugin:mdx/recommended',
},
],
}

How to disable autofix for specific rules in eslint using CLI?

I want to be able to disable the rules that --fix fixes when running eslint in a console for a repo. The reason for this is because --fix leads to undesirable behavior for our jsdoc eslint rules. It creates invalid or sometimes empty jsdoc in our project- which typically leads to even more eslint rules (due to our configuration) and leads to tons of manual fixing or removal.
I want to just run --fix without it touching any jsdoc rules so that I can complete jsdoc manually- while eslint fixes all the rest of the rules.
I came across this SO question- but package mentioned in the answer does not support non-core plugins.
ESLint autofix ignore rule
Is there anything I can do short of modifying my eslintrc file every time I run the linter or using vscode for linting and modifying the config for the web editor instead? Its not a big deal for newer files- but linting legacy files is a chore when there's hundreds of spacing errors that I can't automatically fix easily.
Using an .eslintrc.js file you can do something like this:
const isFixMode = process.argv.includes('--fix');
const config = {
rules: {
'no-console': 'error',
...(isFixMode && {
'no-console': 'warn',
}),
},
};
module.exports = config;
Technically, that already exists, right? If a user wants to avoid auto-fixing a particular rule, they can use:
eslint somedir --fix --rule "somerule: 0"
Or, if they want to whitelist a set of rules, they can use &nbps --no-eslintrc and specify rules directly or use --config and point to a particular config that they want to use for fixes.
Ok here’s another idea. Convert you .eslinrc file into .eslintrc.js. This will allow you to programmatically set eslint config.
Then you could use the commander library to detect the —fix flag and set a Boolean to determine which eslint rules you would like to disable.
What worked best for me was setting the rule to warn and afterwards run.
eslint . --fix --quiet
It is not an error anymore, but better than getting my code broken by a erroneous fixer.

ESLint ignore specific rule for a specific directory

Is it possible with ESLint to ignore one specific rule for an entire directory?
In my case, I would like to ignore import/prefer-default-export for a directory named commonComponents
ESLint configuration (.eslintrc) files are hierarchical:
ESLint will automatically look for them in the directory of the file to be linted, and in successive parent directories all the way up to the root directory of the filesystem. This option is useful when you want different configurations for different parts of a project or when you want others to be able to use ESLint directly without needing to remember to pass in the configuration file.
You can disable the import/prefer-default-export rule for the commonComponents directory by creating a .eslintrc file with the following content in that directory:
{
"rules": {
"import/prefer-default-export": "off"
}
}
You can also use the "overrides" key to declare rules for different glob patterns.
Have a read of Configuration Based on Glob Patterns
Sometimes a more fine-controlled configuration is necessary, for example if the configuration for files within the same directory has to be different. Therefore you can provide configurations under the overrides key that will only apply to files that match specific glob patterns, using the same format you would pass on the command line (e.g., app/**/*.test.js).
I use this to remove the no-unused-expressions rule from my test files like so;
"overrides": [{
"files": [ "*.spec.js" ],
"rules": {
"no-unused-expressions": 0
}
}]
If there are multiple directories that you want to apply your rules to, then you can create different configs for different purposes. For example:
.eslintrc.json for common config
.eslintrc-main.json for main linting and run eslint -c .eslintrc-main src test
.eslintrc-comp.json for components and run eslint -c .eslintrc-comp commonComponents fooBarComponent
YAML version :
rules:
no-unused-expressions: true
overrides:
- files: *-tests.js
rules:
no-unused-expressions: false
cretae .eslintignore file and put inside it your exluded folders. example :
node_modules/
functions/
dist/

how to silence warnings about ignored files in eslint

After setting up eslint and adding some files in the ignore list, every time that eslint is run it produces warnings about files that are ignored:
/path/to/file/name.min.js
0:0 warning File ignored because of a matching ignore pattern. Use "--no-ignore" to override
How can this warning be silenced?
One workaround I know at the moment is --quiet option, which suppresses all warnings. Of course that doesn't make sense if you have "warn" rules in your config.
Another way not to show that warning is to use dir names: eslint src instead of globbing patterns: eslint src/*.
Check if you're running eslint with an unquoted glob argument.
If so, put the glob in quotes.
eslint src/** ❌ Bad (no quotes = OS will expand into many args)
eslint "src/**" ✔️ Good (quotes = a single string argument)
Why?
If you call eslint using a cli glob pattern not in quotes, e.g. eslint src/**, that glob gets expanded into all matching files and passed to eslint as a gigantic list of cli arguments. e.g. eslint path/to/file/name.min.js src/foo.js src/bar.js src/manymore.js .....
So when eslint ignores a file due to your ignore pattern, yet that file was explicitly passed as a command line argument, eslint is warning us
eslint speaking:
"Um, I ignored /path/to/file/name.min.js because of an ignore pattern, but you explicitly passed it to me to lint, so this must not be what you wanted, right?"
But when you pass the glob in quotes, e.g. eslint "src/**", the glob is not expanded to many arguments; rather, it's just a single string argument, and eslint is the one who knows it's a glob but since it takes care of figuring out which files to match it can do so while respecting eslintignore. So there's nothing weird going on that eslint thinks it should warn you about.
You can't and they don't plan on fixing it since they don't consider it a bug. So if you pass in a file that's being ignored them it will tell you it didn't process linting rules because it's ignored: https://github.com/eslint/eslint/issues/5623
We run pre-commit hooks to lint code before committing, so ended up needing to write some additional code to differentiate between actual Warnings and File ignored warnings and only fail linting if an actual warning or error is thrown.
The solution for Lint Staged & Husky errors
// lint-staged.config.js
const { ESLint } = require("eslint");
const removeIgnoredFiles = async (files) => {
const eslint = new ESLint();
const ignoredFiles = await Promise.all(files.map((file) => eslint.isPathIgnored(file)));
const filteredFiles = files.filter((_, i) => !ignoredFiles[i]);
return filteredFiles.join(" ");
};
module.exports = {
"*.{js,ts}": async (files) => {
const filesToLint = await removeIgnoredFiles(files);
return [`eslint --max-warnings=0 ${filesToLint}`];
},
};
If the file is ignored by ESLint (i.e. in .eslintignore), this snippet filters the file and does not pass it through the ESLint CLI.
ref: Testing Library - Aug 2022
I found the REAL answer here:
https://github.com/eslint/eslint/issues/5623
The problem in my case was in the way I called eslint. I used eslint src/* but it should be eslint src/. (Or in your case it might be eslint . instead of eslint *)
The reason why you get the warning is that by using the star, you are telling the eslint that you want to lint EVERY single file which does not make sense if you ignore some files. So by omiting the star you are making the eslint to decide what to lint and it will skip the ignored files without any warning.
Eslint throws this warning on telling it to lint a file, at the same time as having the file ignored. src/* is actually passing every file single file uniquely, while only passing src would let eslint ignore the files without warnings
If you are using lint-staged, it will pass every single staged file that matches the lint-staged regex. If matching, and you put it inside ignore, eslint gets confused and outputs a warning
"lint-staged": {
"*.{ts,tsx,js}": [ // <-- this regex needs to be changed to not match your files
"eslint --fix --max-warnings 0 --ignore-path '.eslintignore' --plugin tsc --rule 'tsc/config: [2, {configFile: \"./tsconfig.json\"}]'",
"prettier --ignore-path .eslintignore --write"
],
"*.js": "eslint --cache --fix",
"*.{js,css,md}": "prettier --write"
},
For me, I just wanted to exclude some js files, so I just removed the js matching inside "*.{ts,tsx,js}"
try with --ext. In my case, I replaced matching from:
eslint modules/**/*{js,vue}
to:
eslint --ext .js,.vue .
Warnings with File ignored because... are gone, but others warnings remain.
My solution for Next.js next lint and a .lintstagedrc.js file. This removes the files that have that warning from the final string of files to lint.
// .lintstagedrc.js
const path = require("path");
const ignorePaths = ["types/global.d.ts", ".lintstagedrc.js"];
const buildEslintCommand = (filenames) => {
return `next lint --fix --max-warnings=0 --file ${filenames
.reduce((files, file) => {
const pathToFile = path.relative(process.cwd(), file);
if (!ignorePaths.includes(pathToFile)) files.push(pathToFile);
return files;
}, [])
.join(" --file ")}`;
};
module.exports = {
"*.{ts,tsx,js,jsx}": [buildEslintCommand],
"*.{ts,tsx,js,jsx,css,scss,md}": "prettier --write",
};

Resources