denoland / deno_lint

Blazing fast linter for JavaScript and TypeScript written in Rust

Home Page:https://lint.deno.land/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Roadmap

bartlomieju opened this issue · comments

Opening this issue for tracking purposes as well as to better communicate what can be expected of deno_lint in the near future.

Here are the issues that current development focuses on (in the order it must be implemented):

  • Scopes analysis #160 - requirement for any "more advanced" rule
  • ESLint recommended rule set #48
  • typescript-eslint recommended rule set #86

Next:

Future:

  • documentation website
  • use deno_lint from Node project #169
  • autofix

Update: recommended set of rules from ESLint and typescript-eslint have been implemented.

We can now proceed to working towards better diagnostics and suggestions for lint rules as well as tentatively working on rudimentary configuration.

commented

I dont think the development team should use issues for tracking reasons, there is projects and readme or other markdown files or such that should be used instead in my opinion.

I'm pretty ignorant on the topic, but would you be able to use deno linter in VSCode for nodejs/webpack projects? :) I tried to look up the answer and so far it looks like it would only work with this plugin and only for deno project.

@JLarky As far as I know, there's no extension that makes it possible for deno_lint to be integrated into VSCode for Node projects. But I would say that technically it could be realized.

Creator of @typescript-eslint here 👋

I stumbled upon this project via a tweet.

I’m just curious, were any experiments undertaken to try and ingest rules as they exist today (in TS) but execute them in rust?

ie replace the ESLint libraries but keep the existing low barrier to entry authoring experience (and 10000s of hours of already invested dev time in existing rules and plugins).

Hey @JamesHenry, thanks for dropping by!

I’m just curious, were any experiments undertaken to try and ingest rules as they exist today (in TS) but execute them in rust?

I'm not sure I understand the question, but let me try to answer anyway. Initially, before the inception of this project we explored the idea of using eslint directly by running it in Deno, however we were unsuccessful in producing something a'la browser build (nor did we find such build, let me know if it exists). From my understanding typescript-eslint is a plugin to eslint that additionally leverages TSC to be able to operate on TS's types (for rules such as no-floating-promises).

Providing similar functionality in Rust would require to have implementation of TSC in Rust, which currently does not exist (although I know @kdy1 is working on it).

We also explored idea of AST parsing in Rust using swc and converting it to a eslint compatible AST. This approach is feasible, however it circles back to the problem of not having browser build of eslint.

deno_lint hasn't received a lot of attention in the last couple months because of major works in deno repo, but we still want to develop it further and I'm more than happy to discuss pooling efforts.

Yeah it was a genuinely open question - I haven't thought about it in any detail and I also don't know that much about rust or deno :)

I do know of interesting experiments involving mixing JS tooling with rust and was genuinely just curious if there are ways to achieve the best of both worlds for linting too.

So yeah nothing more from my side on this but I'll keep thinking about it - I have a good reason to dig into rust more at work now so hopefully that will inform my thinking as well.

Ive juggled with the idea of reusing js rules for a project i am making too and i eventually reached a conclusion of "its too hard and limits things too much" for the following reasons:

  • Most users don't use "esoteric" rules from random plugins beyond popular ones like vue, react, import, and typescript, which i believe should be supported natively by the linter.
  • It limits performance optimizations way too much. Js is single threaded, having to spawn an entirely new vm and its friends for every file you want to lint on a separate thread incurs too much of a memory and performance loss to make it viable.
  • It's not good to rely on the stability of one project from a project in a completely different language with different opinions and an entirely different runtime altogether.
  • It limits further prospects for a different type checker.
  • It forces you to conform to an API you have no control over without being able to change it because of stability concerns in eslint.
  • Js' dynamic nature limits semantic understanding of rules, for example, you can provide a typed json schema for the config if you know what the rule expects for options. This is incredibly easy in rust using typetag + serde.

Also needed is the ability to define a global set of rules, not just per project. Per project rules should override (fully replace) the global rule set. Per file excludes (using // deno-lint-ignore-file ...) add to the the project excludes.

A possible nice enhancement would be to add // deno-lint-include-file to add to the project includes. And if done, // deno-lint-ignore-file should be deprecated for // deno-lint-exclude-file.

Lots of great things happening around this project and it's great to see. I wanted to stop in here and very gently add some feedback into the pool. Since our entire team is coming to Deno from very deep Node experience, and years of experience with ESLint+Prettier, the bar the org is using for whether or not to adopt deno_lint is ESLint; the configurability and ability of ESLint. The closer deno_lint can get to that, I think the easier a switch to it will become for a lot of folks. (We like that deno_lint is opinionated, similar to how Go does things, but the ability to fine tune is something we're all accustomed to)

Lots of great things happening around this project and it's great to see. I wanted to stop in here and very gently add some feedback into the pool. Since our entire team is coming to Deno from very deep Node experience, and years of experience with ESLint+Prettier, the bar the org is using for whether or not to adopt deno_lint is ESLint; the configurability and ability of ESLint. The closer deno_lint can get to that, I think the easier a switch to it will become for a lot of folks. (We like that deno_lint is opinionated, similar to how Go does things, but the ability to fine tune is something we're all accustomed to)

Thanks for feedback, could you give some more concrete examples of what you want to fine tune?

there just doesn't seem to be enough optional rules (from what i can find) effectively replace eslint fully.

some example we're using and quite love, based on airbnb-base w/ eslint:

  • quotes
  • no-useless-concat
  • max-len

i'm trying to migrate [a lot] of code from node to deno (project w/ 30,000+ lines JS)
and trying to make lines be node/eslint or deno agnostic with line-by-line comments like:
/* eslint-disable-next-line no-empty */ // deno-lint-ignore no-empty

which works nicely. but i'm finding there are many rules we use/rely on w/ our team that dont seem to have deno complements (again, best i can tell). The above was just a few of them.

@traceypooh thanks for the feedback. I'm interested in helping you out with the migration, could you please open a new issue listing which rules you use that are missing so we could evaluate and look into implementing them?

thanks @bartlomieju

so keeping in mind these are just from one-off lines, where doing the trick like:
/* eslint-disable-next-line no-empty */ // deno-lint-ignore no-empty

caused them to get flagged by deno lint as an unknown rule, etc.
(So point being, there could be some other rules that, say, the airbnb-base has that deno lint doesnt have... yet! :) )

guard-for-in
import/no-extraneous-dependencies
import/no-named-as-default
import/no-named-as-default-member
import/no-unresolved
import/prefer-default-export
max-len
new-cap
no-alert
no-cond-assign
no-console
no-continue
no-multi-assign
no-nested-ternary
no-param-reassign
no-plusplus
no-return-assign
no-return-await
no-shadow
no-tabs
no-underscore-dangle
no-use-before-define
no-unused-expressions
no-useless-concat
no-useless-escape
prefer-destructuring
prefer-rest-params
quotes

Is autofix near future or distant future?

Is autofix near future or distant future?

At this point in time, there are no plans for when "autofix" feature could be delivered (or if it will be delivered at all).

I'd encourage you all to at least begin planning, talking about it. If the recommendation is going to be to use the platform/builtins and not a litany of secondary community tooling, this is a must-have.

Thanks for suggestion @shellscape but there's a lot of projects planned for Q1 and Q2 in Deno and we don't have bandwidth to squeeze autofix there, especially since we're planning to provide ESLint compatbility.

Doesn't ESLint contain --fix support? Or is autofix talking about something else?

Doesn't ESLint contain --fix support? Or is autofix talking about something else?

It does, but I'm talking about compatibility with existing ESLint plugins.

@bartlomieju Thanks for the work on this project 🚀 . We're looking at replacing ESLint/TypeScript ESLint with deno lint, mainly due to the first-party TypeScript support and performance benefits, along with less configuration to maintain.

Did you have an updated Roadmap for 2023? I know there was talk about ESLint compatibility. Just interested in the direction this project is taking.

Hey @teriu. We are still discussing internally whether we should continue to work on improvements to deno_lint like custom plugin system (that wouldn't be compatible with ESLint's plugin system) or should we instead embed eslint (and probably typescript-eslint) and work on performance improvements to make it faster (we are in contact with ESLint maintainers and looking for ways how Deno team can help ESLint team, see https://github.com/bartlomieju/eslint_binary for some experimentation on that front).

That said, currently we have limited bandwidth to work on deno_lint and we plan to revisit this topic at a later date (think Q2/Q3).

It would be helpful if folks could leave feedback here with information what are your expectations for improvements and use cases.

I believe I've already mentioned this before. But if the Deno team does decide to improve deno lint over embedding eslint, then support for JavaScript/TypeScript plugins would be a requirement for me to start using it. Otherwise I'd likely keep using ESLint, because I don't see myself writing ffi/rust plugins for small rules I want to add.

That said I'd prefer the ESLint embedding, I'm already using a lot of the built in rules as well as eslint-plugin-jsdoc for both linting and formatting. Because deno fmt is a bit too opinionated for my liking :)

because I don't see myself writing ffi/rust plugins for small rules I want to add

The plugins would have a JavaScript/TypeScript API

gentle reminder that deno still fails to run eslint: denoland/deno#17448 😇

@bartlomieju Interesting. I've been reading through the proposed ESLint rewrite on the Github Issue. It's an interesting thread, although I'm not sure what the end result will look like for a codebase with predominantly TypeScript code. In our current codebase, we run the following ESLint configuration: airbnb-base + airbnb-typescript/base, along with typescript-eslint/recommended + type checking, unicorn/recommended and prettier/recommended (formatting related).

The state of play seems to be (and correct me if I'm wrong here 😀):

  • ESLint + TypeScript ESLint. ESLint doesn't support TypeScript parsing/rules out of the box, so in order to use Lint rules that require Type checking, you need to use a combination of ESLint & TypeScript ESLint. Quite a bit of complexity, and the current solution isn't necessarily performant, especially in a TypeScript monorepo (project references).
  • Rome. Written in Rust. Unfortunately, looks like funding is an issue, and development has slowed considerably (?). An "all-in-one" solution, rather than just purely handling linting/formatting. Native TypeScript support, impressive performance benchmarks.
  • deno lint. Written in Rust. Native TypeScript support, impressive performance benchmarks.

The main issue with Rome & deno lint seems to stem from limited compatibility with existing ESLint rule sets. Having a way to create certain rules using a JavaScript/TypeScript API might suffice, instead of trying to support all existing eslint- plugins. The performance advantages of using deno lint over other tools would make it worth the investment in plugins/rules. There is likely some rules which just don't need to exist anymore (ESLint is ~10 years old now), and TypeScript contains some checks (strict mode) that we use in place of Lint rules.

I would happily switch to deno-lint if it supported a plugin system, preferably one that maintains the most performance while making plugins writable in TS/JS. Eslint plugin compatibility isn't a concern for me, and it seems like it would go in the opposite direction of performance (AST conversions required) and in general cause more headaches than it's worth. Ability to create auto-fix rules certainly seems like it should be a higher priority than Eslint compat. I suspect even if Eslint compat was available users would be unlikely to switch anyway if there was no support for auto fix.

counterpoint: we dont particularly care about auto fix (though it's nice. much lower prio).

I switched my team over to npm compatibility mode.

I'm using velociraptor at top of huge project, with a scripts.yml that has these parts:

  lint:
    - vr eslint-setup
    - vr eslint
  eslint-setup:
    - deno cache --unstable --node-modules-dir npm:eslint-config-airbnb-base@14.2.0         && echo>/dev/null
    - deno cache --unstable --node-modules-dir npm:eslint-plugin-compat@^3.3.0              && echo>/dev/null
    - deno cache --unstable --node-modules-dir npm:eslint-plugin-import@^2.22.1             && echo>/dev/null
    - deno cache --unstable --node-modules-dir npm:eslint-plugin-no-floating-promise@^1.0.2 && echo>/dev/null
  eslint:
    # We want to call either `eslint components tests` or `eslint [arg1] <arg2> ..`
    - echo components tests >| .testarg && echo >> .testarg
    # Next, two unusual things going on in..
    # Unfortunately right now running deno like this always exits 0, regardless.
    # Lint warnings/errors write to stdout -- so capture that to a file and check after if empty.
    # Wrap that with `script` command so the invoker will still see the useful colors in the output.
    - script -q .testout sh -c "deno run -A --unstable --node-modules-dir  npm:eslint@^7.32.0
        $(egrep . .testarg |tail -1) 2>/dev/null" &&  echo>/dev/null
    - rm .testarg; echo>/dev/null
    # .testout should be empty -- else a lint failure (remove any docker runtime start/stop logs)
    - egrep -v '^Script (started|done) on ' .testout |tr -d '\r' |egrep . |sort -o .testout && echo>/dev/null
    - test ! -s .testout  &&  echo>/dev/null
    - rm -f .testout && echo>/dev/null

There's obviously some limitations and workarounds. And you have to setup each plugin you are using w/ eslint. It's not ideal, but it was literally the last thing we needed before totally dropping node/npm otherwise for deno.

(Here's our .eslintrc.json in case helpf, too)

{
  // "used by `scripts.yml` for `vr lint`"

  "extends": "airbnb-base",
  "root": true,
  "parserOptions": {
    "sourceType": "module",
    // allow `??`
    "ecmaVersion": 2020
  },
  "plugins": [
    "no-floating-promise",
    "compat"
  ],
  "env": {
    "jest": true,
    "browser": true
  },
  "settings": {
    // Mark these as polyfilled - since we include on every page, @see Nav.inc and search for
    //   https://polyfill.archive.org/
    // We do this so lint testing won't squawk about Promise not being supported in IE 11.
    // Keep this list sync-ed with the URL mentioned in Nav.inc.
    "polyfills": [
      "Array.from",
      "Promise",
      "Object.assign",
      "Object.entries",
      "Object.keys",
      "Object.values",
      "window.customElements"
    ]
  },
  "rules": {
    // this just showed up as necessary w/ `vr lint` on Jun11, 2020
    "no-multiple-empty-lines": [2, {"max": 2}],
    "no-unused-vars": ["error", { "args": "none" }],

    // this just showed up w/ babel + eslint updates to latest versions Sep1,2019
    "operator-linebreak": "off",
    "import/no-cycle": "off", // it's ok to have cycles with ES Modules and import

    // "make sure all used JS compatible with 90%+ of currently used browsers a la caniuse.com"
    "compat/compat": "error",

    // "allow JSX in .js files"
    "react/jsx-filename-extension": "off",

    // "allow snakecase var names if dev desires"
    "camelcase": "off",

    // "allow: x  = 3 (for example lining up multiple lines by column)"
    "no-multi-spaces": "off",

    // "author discretion when using braces around one-liners or same-liners"
    "curly": "off",

    // "allow ++ or -- at the end fo a for() loop (all other uses are banned per airbnb!)"
    "no-plusplus": ["error", {"allowForLoopAfterthoughts": true}],

    // "allow JSON/map definitions to column-align values when multiline"
    "key-spacing": ["error", {"mode": "minimum"}],

    // "allow for (x of array)  and  for (key in obj)  and   for (val in array)"
    "no-restricted-syntax": ["error", "LabeledStatement", "WithStatement"],

    "no-restricted-globals": ["off", "location"],

    "nonblock-statement-body-position": "off",

    "indent": ["error", 2, {"CallExpression": {"arguments": "first"},
                            "ArrayExpression": "first",
                            "FunctionDeclaration": {"parameters": "first"},
                            "FunctionExpression": {"body": 1, "parameters": 2} }],

    "import/no-extraneous-dependencies": ["error", {
      "devDependencies": ["**/webpack.*.js", "**/*.js"]
    }],

    // "Turning these off since they throw errors for devDependencies"
    "import/no-unresolved": ["off"],
    "import/extensions": ["off"],

    "import/prefer-default-export": "off"
  },
  "ignorePatterns": [
    // stopgap until react is gone:
    "/components/ia-bookreader/iaux.min.js",
    // symlink to npm pkg:
    "/components/bookreader/",
    // 3rd party code:
    "/components/npm/",
    "/components/editxml/jquery.json-ui.js",
    "/components/uploader/jquery.sprintf.js",
    "/components/uploader/jquery.wysiwyg.js",
    "/components/uploader/wysiwyg.link.js"
  ]
}

BTW, here's the few issues I've still got, distilled out to a clean/minimal git repo & setup:

https://github.com/traceypooh/eslint-deno

  • import/no-unresolved always unhappy
  • TypeError: cb is not a function (12 times here, more with more files)
  • always exits 0 status

I know at one point one of the main maintainers of eslint was interested in helping if it made sense, towards using with deno.
I wonder if they could help with any of these seemingly last issues?

@traceypooh this seems unrelated to deno lint itself since you're still using eslint. An issue in Deno's main repo is probably a better place for compatibility issues with npm packages like eslint.

You may want to add Type-aware lints (#1138) under Future.

If possible, please add this rule no-implicit-initial-reduce-value, see doc. It will help use to prevent this bug Error: reduce of empty array with no initial value which is one of my production bug on browsers after I update server API.

Any timescale for a fix of this?: #1054
Or a note in the docs at this rule highlighting the issue could be helpful, to save others from confusion (it has been 18 months).