Replies: 46 suggested answers 192 replies
-
What about AST-based autofixing? That's the sole advantage prettier seems to have over eslint. |
Beta Was this translation helpful? Give feedback.
-
@ljharb Oh yes, forgot to include that. |
Beta Was this translation helpful? Give feedback.
-
Very exciting.... One big picture kind of feature I'd like to see as possible would be richer AST traversal too to ensure not only |
Beta Was this translation helpful? Give feedback.
-
Valid preference, but would there be any chance of providing types within ESLint rather than in the separate It could be useful for the large number of TS users if features had their TS declarations added at the same time they are released. Additionally, given the desire to handle types and be type checked (all via typescript) it seems odd to not do the final little bit and simply translate JSDoc typing into TypeScript typing. In my experience I've found TS to be a lot leaner than JSDoc for declaring types, and it's also now the driver behind JSDoc types and inference. |
Beta Was this translation helpful? Give feedback.
-
Providing types in a package is a mistake; it conflates semver of the types with semver of the actual API. |
Beta Was this translation helpful? Give feedback.
-
I would love love love if ESLint is written in Rust. In larger codes, it's noticeable a delay on save and on Intellisense. This is definitively the future. While I love JS/TS and work with it, there is really no performance comparison with Rust. It's more of a matter of time until we have a ready JS/TS linter in Rust, not if it's going to happen. There was https://github.com/rslint/rslint but it looks dead already. Also, I believe it could have a better structure to support formatters to overcome this situation: https://typescript-eslint.io/docs/linting/troubleshooting/formatting. So instead of adding prettier or dprint, we could finally have one proper tool for both linting and formatting. |
Beta Was this translation helpful? Give feedback.
-
@willster277
Yes, that was my intent. I'll update the original text to indicate that. |
Beta Was this translation helpful? Give feedback.
-
@JoshuaKGoldberg @bradzacher If you have time, I'd love to hear what we could change about ESLint to make working with TypeScript easier. |
Beta Was this translation helpful? Give feedback.
-
@ljharb I would say the types and the API are the same thing, if you take statically typed languages, it's usually impossible to separate the concepts simply because of the nature of static typing. Even if no types have changed, and only internal code is different, it's a good idea to maintain parity between the version tacked to the types and the version tacked to the API. "types v1.2.1" to me implies that it doesn't include any new types which may be necessary for "API ^v1.2.2". In JS we can spilt types and API into utterly separate objects, I believe it's a bad idea to do that. |
Beta Was this translation helpful? Give feedback.
-
@willster277 bumping the major version because you renamed a type is correct, but is a very high cost to impose on normal JavaScript consumers who have to read the changelog to discover that they're not actually affected at all. |
Beta Was this translation helpful? Give feedback.
{{title}}
{{editor}}'s edit
{{editor}}'s edit
-
HOOOOO BOY. There's a lot to talk about here. I've got a version of this written up already (typescript-eslint/typescript-eslint#5845 (comment)) but I've copied it here so that I can add more context It's worth noting that a lot of the problems we run into with type-aware linting also apply in some degree to ESLint is currently designed to be a stateless, single-file linter. It and the ecosystem of "API consumers" (tools that build on top of their API - IDEs, CLI tools, etc) assume this to be true and optimise based on the assumption. For most parsers ( Type-aware linting, unfortunately, doesn't fit too well into the ESLint model as it's currently designed - so we've had to implement a number of workarounds to make it fit - we've fit a square peg into a round hole by cutting the edges of the hole. This, as you can imagine, means there are a number of edge-cases where things can get funky. ESLint UsecasesESLint is used by end users in one of three ways:
For a stateless, single-file system - all 3 cases can be treated the same! In that style of system when linting File A you don't ever care if File B changes because the contents of File B have zero impact on the lint results for File A. CachingThese are the caching strategies that we can use for each usecase. Note that each usecase affords a different caching strategy!
APIsTypeScriptTypeScript's consumer API is built around the concept of "Programs". A program is esentially a set of files, their ASTs, and their types. For us a program is derived from a tsconfig (eg the user tells us the configs and we ask TS to create a program from the config). A Program is designed to be immutable - there's no direct way to update it. So to line it up with the aforementioned usecases - we want use the immutable API for (1) and most of (2), and fall back to the builder API when a file is fixed in (2), then (3) always uses the builder API. ESLint's APIESLint implements one unified API for a consumer to perform a lint run on There are no flags or config options that control how this class must be used by consumers. This means that ESLint cannot distinguish between the above usecases. This makes sense from ESLint's POV - why would it care when it's a stateless and single-file system; all the cases are the same to them! This poses a problem for us though because if ESLint can't distinguish the cases, then we can't distinguish the cases and so we're left with the complex problem of "how can we implement different cache strategies without being able to tell which strategy to use?" ProblemsCache Strategy and Codepath SelectionAs mentioned above, we want to use the immutable Program API where possible as it's so much faster. We do this automatically by inferring whether or not you've run ESLint from the CLI by inspecting the environment. It's a hack, but it does work for usecase (1). Unfortunately there's no way for us to differentiate usecase (1) from (2), so we have to have a fallback to switch to the builder Program for usecase (2) so that we can update the Program after a fix is applied. Slow lint runs often occur due to incorrect usecase detection due to the user running things in ways we didn't expect / can't detect (such as custom scripts), or due to cases we haven't handled. Disk WatchersIdeally we'd attach filewatchers to the disk to detect when the relevant files/folders are changed (would solve the "out-of-editor file updates" problem below). There is no lifecycle API built into ESLint so we can't tell when would be a good time to clean up watchers. And because we can't tell the difference between an IDE and a CLI run, we can't make assumptions and attach watchers either. Live File UpdatesThis is only a problem for usecase (3). When you make a change to file A in the IDE, the IDE extension schedules a new lint run with the contents from the editor which we use to update the Program. If you have file B that depends on the types from file A, this means that we've also implicitly recalculated the type for file B. Single-threaded vs Multi-threaded lintingThe implicit update of file B's types based on changes to file A assume that both file A and B are linted in the same thread. If the aren't linted in the same thread, then updates to file A will not be updated in file B's thread, and thus file B will never have the correctly updated types for file A - which leads to incorrect lints!! The only way to fix this would be by restarting the IDE extension (or the IDE itself!) Out-of-editor File UpdatesIn all IDEs it's possible that you can use the "file explorer" to move files around to different folders, or even rename files. This disk change happens outside of the editor window, and thus no IDE extension can or will tell ESLint that such a change occurred. This is a big problem for us because the Program state explicitly depends on the filesystem state! We have some very slow fallback codepaths for this case that attempts to determine if out-of-editor changes occurred on disk, but it's not perfect code and can miss cases. So with all that being said... what would I want to see from a rewritten version of ESLint? Well the biggest problem we have is that we cannot tell what state ESLint is running in, so we have to rely on fuzzy and unsound logic in order to determine cache strategies. So I'd really want ESLint to be able to tell parsers and plugins about the state ESLint is running in so that they can make decisions about how to invalidate or update their data-stores. Worth mentioning this is something I've been thinking about for a long while (eg #13525), but obviously haven't had the time to do any formal design or RFCs. |
Beta Was this translation helpful? Give feedback.
-
If this is intended to be used for any language -either specifically in the web ecosystem or more broadly-, why not rewrite in a more performant language -- e.g. Rust? |
Beta Was this translation helpful? Give feedback.
-
It is recommended to convert this issue to discussion. We need structured comments. |
Beta Was this translation helpful? Give feedback.
-
@JoshuaKGoldberg a major downside of writing any JS tool in "not javascript" is the dramatically decreased pool of potential contributors. |
Beta Was this translation helpful? Give feedback.
-
One potential-maybe problem is linking the concept of type awareness to TypeScript specifically. I worry that the community is starting to enable typescript-eslint's APIs in shared packages so much that we're making extracting ourselves from TypeScript difficult. TypeScript has issues in its control-flow analysis that are only likely to be solved by a native-speed equivalent. We're starting to see early-stage TypeScript competitors pop up, such as Ezno and stc. One path ESLint could go down is:
|
Beta Was this translation helpful? Give feedback.
{{title}}
{{editor}}'s edit
{{editor}}'s edit
-
Introduction
ESLint was first released in 2013, meaning it will be ten years old next year. During that time, the way people write JavaScript has changed dramatically and we have been using the incremental approach to updating ESLint. This has served us well, as we've been able to keep up with changes fairly quickly while building off the same basic core as in 2013. However, I don't believe continually to make incremental changes will get us to where ESLint needs to go if it wants to be around in another ten years.
Even though we are close to rolling out the new config system, which is the first significant rearchitecture we've done, that effort is what led me to believe that it's time for a larger rewrite. We are still stuck on implementing things like async parsers and rules because it's difficult to plot a path forward that doesn't cause a lot of pain for a lot of users. This seems like the right time to stop and take stock of where we are and where we want to go.
Goals
I've been thinking about where I'd like ESLint to go next and have come up with several goals. These are pretty abstract at the moment, but here they are, in no particular order:
tsc
with JSDoc comments to type check the project. This includes publishing type definitions in the packages.@eslint/core
) that is runtime agnostic and then runtime specific packages (@eslint/node
,@eslint/browser
, etc.) that have any additional functionality needed for any given runtime. Yes, that means an officially supported browser version!@eslint/js
? I envision a language implementation being distributed in a plugin that users can then assign to specific file patterns. (This would replace theparserForESLint()
hack.) So ESLint could be used to lint any file format so long as someone as implemented an ESLint language API for it.Linter
class (which started out as alinter
object) and we've continued hacking on this. Right now we have both anESLint
class and aLinter
class, which is confusing and they both do a lot more than just lint. I'd like to completely rethink the public API and provide both high-level APIs suitable for building things like StandardJS and the VSCode plugin and low-level APIs that adhere to the single-responsibility principal to make it possible to do more creative mixing and matching.Maybes
These are some ideas that aren't fully hatched in my mind and I'm not sure how we might go about implementing them or even if they are good ideas, but they are worth exploring.
typescript-eslint
andeslint-plugin-import
both work on more than one file to get a complete picture of the project. Figuring out how this might work in the core seems worthwhile to explore.Approach
For whatever we decide, the overall approach would be to start small and not try to have 100% compatibility with the current ESLint right off the bat. I think we'd added a lot of features that maybe aren't used as much, and so we would focus on getting the core experience right before adding, for example, every existing command line option.
Next steps
This obviously isn't a complete proposal. There would need to be a (massive) RFC taking into account all of the goals and ideas people have for the next generation of ESLint. My intent here is just to start the conversation rolling, solicit feedback from the team and community about what they'd like to see, and then figure out how to move forward from there.
This list is by no means exhaustive. This is the place to add all of your crazy wishlist items for ESLint's future because doing a complete rewrite means taking into account things we can't even consider now.
Beta Was this translation helpful? Give feedback.
All reactions