New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(eslint-plugin): [no-var-requires, no-require-imports] allow option #7710
feat(eslint-plugin): [no-var-requires, no-require-imports] allow option #7710
Conversation
Thanks for the PR, @Josh-Cena! typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community. The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately. Thanks again! 🙏 Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently on https://opencollective.com/typescript-eslint. |
✅ Deploy Preview for typescript-eslint ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
#5314 asks for |
@@ -28,6 +28,28 @@ import { lib2 } from 'lib2'; | |||
import * as lib3 from 'lib3'; | |||
``` | |||
|
|||
## Options | |||
|
|||
### `allowPackageJson` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've also seen libraries want to import from turbo.json
, project.json
, etc. Maybe this should be the standard format from #6017, with docs showing how to use it for package.json
files? WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm okay with that. What's your proposed API? My thought is something similar to no-restricted-imports
, with an array of paths
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking the exact format from #4436 -> https://typescript-eslint.io/rules/prefer-readonly-parameter-types.
{
"@typescript-eslint/no-var-requires": [
"error",
{
ignore: [
{
name: "package.json",
source: "file",
},
],
},
],
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks couunterintuitive as a user, TBH. This API is for types, but what is "package.json"
as a type? What does source: "file"
even mean? With no-restricted-imports
, the API would look like:
{
"@typescript-eslint/no-var-requires": [
"error",
{
"ignorePaths": [
{
"name": "*.json"
}
]
}
]
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if they want to import from a node module, e.g. import emojis from "emojilib/dist/emoji-en-US.json"
? Should we just have a string[]
as the option to capture all those cases? Feels off to me that we have the big thought-out format and then don't use it... but it is overhead, yes. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ping @Josh-Cena ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I did not forget this 😅 Will try to garner some energy and clear my notifications this afternoon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JoshuaKGoldberg I thought about it. Here are my thoughts:
- The only thing this PR changes is allowing
require
. It doesn't change anything aboutimport
—they can still be used as normal. - Sure, we have a thought-out format for specifying types, but here we are talking about import paths, and this design doesn't come without its precedent either—we are being consistent with
no-restricted-imports
. - About having
string[]
as an option. You mean{ ignorePaths: string[] }
? My initial design is{ ignorePaths: TheOptionsOfNoRestrictedImports }
, i.e. it supports multiple ignore paths, each one with a path, a glob, a custom message, etc. But I now think that's hugely unnecessary for an ignore option. So sure, I can do that. - If you want to differentiate between node modules and local JSON files, you would have to support regex in the ignore path (I think) to be able to tell between
./foo/data.json
andfoo/data.json
. That means the option has to be more granular than astring[]
; it would at minimum need to be{ ignorePaths: { paths: string[] /* globs */, patterns: string[] /* regexes */ }
. Does that make sense? Am I overthinking it?
I'm very curious what your current idea for the option's shape is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intent of #6017 was: "RFC: Common format to specify a type or value as a rule option". I was really hoping it'd be usable for situations exactly like this one. But if we're seeing a practical shortcoming of the format -it being too heavy-handed- then I like this as a motivation to improve it. Or maybe it's just irrelevant here...
Maybe just allow: string[]
or ignore: string[]
, where each of the string elements is a regex for now - and only if users ask we expand to that format? It'd be a little verbose to have to say something like "package\.json$"]
, but not the worst thing in the world IMO.
Thinking on the sticking point of relativity: from what I can think of either:
- the rule gets told a root ESLint path to resolve from (but what about monorepos with config in the root vs per-package?)
- we tell users to either increase regex specificity or allow sibling level
package.json
imports (/[.\\\/]*package.json/
)
I think having two things to think about, like paths
and patterns
from 4., would be a bit much. Is there anything that can only be captured in that system, not the single option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The complicated thing is that sometimes you have tsconfig paths which make things look non-relative. We can't build in any specific assumptions around the path here if we want people to allow local but disallow node_module packages done this way.
So a regex is probably the most flexible option for this so codebases can easily devise some regex that matches their usecase. I'd suspect that most codebases would just want something like you suggested joshg to allow a relative package.json
After #8092 we can finally get rid of this sucky duplication... |
node.arguments[0]?.type === AST_NODE_TYPES.Literal && | ||
typeof node.arguments[0].value === 'string' && | ||
isImportPathAllowed(node.arguments[0].value) | ||
) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does it work with string constants?
const path = 'package.json';
const pkg = require(path);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that needs to make the rule type-aware, or otherwise implement a go-to-definition mechanism, which I'm not sure we have the precedent. I'm also not sure if it happens more than a handful of times IRL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! The template literal support I trust you on 😄 it's not high priority IMO. Otherwise this looks great, thanks!
node.arguments[0]?.type === AST_NODE_TYPES.Literal && | ||
typeof node.arguments[0].value === 'string' && | ||
isImportPathAllowed(node.arguments[0].value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Bug] I think this should use getStaticStringValue
or an equivalent tailored just to strings. Then it would support template literals.
I did a quick search for type === AST_NODE_TYPES.Literal
and found a few files Referencer.ts
, prefer-regexp-exec.ts
, prefer-reduce-type-parameter.ts
, padding-line-between-statements.ts
, no-restricted-imports.ts
...) that do similar "get the value if it's a string literal" logic. Maybe good to make a new utility?
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#8186. I wanted to get this PR merged 😄 and I don't think template literals in require()
calls are pretty rare.
f7b5ca8
into
typescript-eslint:main
PR Checklist
require('../package.json')
#1902, fixes Enhancement: [no-require-imports] Add optionallowJson
#5314Overview