A Rust crate for writing fast JavaScript and TypeScript linters.
This crate powers deno lint
, but is
not Deno specific and can be used to write linters for Node as well.
Supports recommended
set of rules from ESLint and @typescript-eslint
out of
the box with no config.
See the roadmap
Visit https://lint.deno.land for the list of available rules.
Blazing fast, see comparison with ESLint:
[
{
"name": "deno_lint",
"totalMs": 105.3750100000002,
"runsCount": 5,
"measuredRunsAvgMs": 21.07500200000004,
"measuredRunsMs": [
24.79783199999997,
19.563640000000078,
20.759051999999883,
19.99068000000011,
20.26380600000016
]
},
{
"name": "eslint",
"totalMs": 11845.073306000002,
"runsCount": 5,
"measuredRunsAvgMs": 2369.0146612000003,
"measuredRunsMs": [
2686.1039550000005,
2281.501061,
2298.6185210000003,
2279.5962849999996,
2299.2534840000008
]
}
]
Benchmarks are run during CI on Ubuntu, using the same set of rules for both
linters. Test subject is oak
server
consisting of about 50 files. See ./benchmarks/
directory for
more info.
If you want to use deno_lint
with Node, please refer to
@node-rs/deno-lint
package
which provides programmatic API as well as Webpack loader for deno_lint
.
examples/dlint/main.rs
provides a minimal standalone binary demonstrating how
deno_lint
can be used as a crate.
# Build standalone binary
$ cargo build --example dlint --features="docs"
$ ./target/debug/examples/dlint --help
dlint
USAGE:
dlint <SUBCOMMAND>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
SUBCOMMANDS:
help Prints this message or the help of the given subcommand(s)
rules
run
$ ./target/debug/examples/dlint run ../deno/std/http/server.ts ../deno/std/http/file_server.ts
(no-empty) Empty block statement
--> ../deno/std/http/server.ts:93:14
|
93 | } catch {}
| ^^
|
(no-empty) Empty block statement
--> ../deno/std/http/server.ts:111:44
|
111 | while ((await body.read(buf)) !== null) {}
| ^^
|
(no-empty) Empty block statement
--> ../deno/std/http/server.ts:120:41
|
120 | constructor(public listener: Listener) {}
| ^^
|
(ban-untagged-todo) TODO should be tagged with (@username) or (#issue)
--> ../deno/std/http/file_server.ts:5:0
|
5 | // TODO Stream responses instead of reading them into memory.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
(ban-untagged-todo) TODO should be tagged with (@username) or (#issue)
--> ../deno/std/http/file_server.ts:6:0
|
6 | // TODO Add tests like these:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
(ban-untagged-todo) TODO should be tagged with (@username) or (#issue)
--> ../deno/std/http/file_server.ts:137:0
|
137 | // TODO: simplify this after deno.stat and deno.readDir are fixed
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
(no-empty) Empty block statement
--> ../deno/std/http/file_server.ts:155:16
|
155 | } catch (e) {}
| ^^
|
Found 7 problems
For more concrete implementation visit
deno
Make sure to have latest stable version of Rust installed (1.56.0).
// check version
$ rustc --version
rustc 1.56.0 (09c42c458 2021-10-18)
// build all targets
$ cargo build --all-targets
// test it
$ cargo test
Prerequisites:
- Install
perf
,stackcollapse-perf
,c++filt
andflamegraph
$ RUSTFLAGS='-g' cargo build --release --all-targets # build target
$ sudo perf record --call-graph dwarf ./target/release/examples/dlint benchmarks/oak/**.ts # create performance profile
$ perf script | stackcollapse-perf | c++filt | flamegraph > flame.svg # generate flamegraph
You can use rust-unmangle or rustfilt instead of c++filt.
These commands can take a few minutes to run.
-
If you are going to work on an issue, mention so in the issue comments before you start working on the issue.
-
Please be professional in the forums. We follow Rust's code of conduct (CoC) Have a problem? Email [email protected].
-
Ask for help in the community chat room.
Before submitting, please make sure the following is done:
- That there is a related issue and it is referenced in the PR text.
- There are tests that cover the changes.
- Ensure
cargo test
passes. - Format your code with
deno run --allow-run tools/format.ts
- Make sure
deno run --allow-run --allow-env tools/lint.ts
passes. - If you've added a new rule:
- Run
cargo build --example dlint --all-features
- Update docs by running the generated binary with these arguments
./target/debug/examples/dlint rules --json > www/static/docs.json
- Run
deno_lint's People
Forkers
nayeemrmn kevinkassimo luca-rand disizali raynos domparfitt rottencandy nikolasmelui bartlomieju utam0k lucacasonato mihinduranasinghe iykekings sdhjhlljn slowpoke69 mihir2901 cptlazy zsomborkaroly pr2018pr jeffd3140 afileunique xanaxcontrol magurotuna lippaitamas1021 bigsee1970 kocsiandras83 zeta1999 rodrigoieh nasafato rambo666999 szekelylaci oflenake balupton lucy-miyuki hugo-paul pista318 peterbanhegyi golya89 marhanum virag94 krishanarya istijam daniellectric ebi2953 swaggerben gcyrlarochelle sikosanita thiagoblima hikaru7719 akshatagarwl piscisaureus kitsonk ardyfeb olenakeqa kdy1 aggmoulik notfilippo zhangaz1 isgasho cknight robbiekruszynski ross-weir tsubasahonda renowncoder henryboisdequin mfunkie icodein mierenmanz mxj4 tjdev7 caspervonb kamchy togami2864 brandly lukasbombach joshua-owens screetbloom kt3k dsherret rkbadatya littledivy richarddeveloper subhakundu satyarohith cdaringe brooooooklyn dmitryromaniuk tanquar bakkot hrishikeshnikam2000 wafuwafu13 lionc ah-yu rivy-t dianpeng chenshuai2144 littletof happysmile12321 crbl69 robertopassanideno_lint's Issues
CI cache not working properly
It seems there is problem with caching in CI - pipeline take about 3-4 minutes and installation of crates can be seen during clippy
stage.
MVP lint rules
Decide on list of lint rules that are required for MVP linter.
Good idea to go through recommended sets and compile a list:
no-empty rule broken
(no-empty) Empty block statement
--> ../deno/std/encoding/toml.ts:13:56
|
13 | constructor(public type: string, public name: string) {}
| ^^
|
Ignore directive should be deno-lint-ignore
The ignore directive should be deno-lint-ignore
. This will match deno-fmt-ignore
denoland/deno#5075. It is the most explicit and least opinionated choice. The current deno:ignore
confuses with lots of other Deno concepts.
[bug] walk_expression is only called for top level expressions.
walk_expression
is not being called for function arguments, if statement tests, variable assignments, switch cases and all other non top level expressions.
The same is true for many other properties.
Publish to crates.io and release binaries
CI pipeline should be updated to publish deno_lint
to crates.io on tag (similar to Deno).
Built binary artifacts should be uploaded to Github and be downloadable from releases page
no-empty-character-class rule broken
(no-empty-character-class) empty character class in RegExp is not allowed
--> ../deno/std/encoding/toml.ts:333:27
|
333 | line.replace(/\[/g, "").replace(/\]/g, ""))
| ^^^^^
|
(no-empty-character-class) empty character class in RegExp is not allowed
--> ../deno/std/encoding/toml.ts:333:46
|
333 | line.replace(/\[/g, "").replace(/\]/g, ""))
| ^^^^^
|
ci: clippy should fail on warnings
It seems CI is passing even if clippy produces warnings.
discussion: plugin support
It would be great if deno_lint had support for plugins that can add rules. Here are my thoughts:
Constraints:
- Plugins should be written in Rust and use the same infrastructure as the rules that are part of this repository.
- Plugins should be loaded at runtime, and should not have to be available at compile time. This means they need to be dynamically executed.
- Plugins should not have to re-parse the source code.
- Plugins should be sandboxed and safe - they should not be able to access the system directly.
Possible solution:
Most likely the best solution that satisfies these constraints is WebAssembly. You can write your rules in Rust, and then compile them to WebAssembly that deno_lint could load and run. WebAssembly is also safe because it is sandboxed and only gets access to resources that deno_lint exposes to it. Here is how I imagine this would work:
deno_lint
should initialise all plugins at startup, by creating a WebAssembly VM for each plugin.deno_lint
parses the source code into a swc AST. This ASTs raw memory is stored in a shared memory area with the WebAssembly plugin.deno_lint
calls a function in WebAssembly to kick off code checking in the plugin. It can now do its analysis and create diagnostics. These diagnostics are stored in a separate section of shared memory between the plugin anddeno_lint
.deno_lint
extracts these diagnostics and augments them with information about plugin origin and returns them to the user.
This approach would allow you to start multiple instances of the same plugin easily, to paralelnize code analysis for large modules.
There are definitely some issues with this. The biggest one I can see right now is how to pass the AST between plugin and deno_lint
. If we only support rust, we might be able to pass the raw backing of the object, but I don't know if this is feasible and how likely it is to break (probably very). Another solution would be to serialise to JSON or protobuf and then deserialise on the plugin side. This is definitely possible, but requires a lot of careful translation of the swc structs into JSON. This might be very complicated and time intensive, and would probably not be great for performance. The third solution would be to have the plugin do the parsing of code itself - this would also slow down the process significantly though.
Prior art:
dprint
also makes use of WebAssembly for its plugin system. To the end user looks like this: https://dprint.dev/plugin-dev/ (very clean)
[deno lint] Uncaught Promise Warning
Would it be possible to somehow warn a user when a Promise is not properly handled? Deno will always crash on uncaught errors. I guarantee there will be many users that will have an issue because their project continues to crash because they forgot to catch a promise. Somewhere in the hundreds, thousands, or millions of lines of code for some project someone is gonna forget a promise and have it crash in production.
Any sort of warning system during compile time to say hey u have an unhandled promise, this could crash your project. Please catch it.
Add deno-lint-ignore-file directive
Deno has // deno-fmt-ignore-file
directive to skip formatting of a file. Linter should have analogous directive: // deno-lint-ignore-file
empty-block too strict
Doesn't allow this valid code:
(no-empty) Empty block statement
constructor(readonly r: BufReader) {}
~~
at /Users/rld/src/deno/cli/../std/textproto/mod.ts:23:37
Show code snippets in report output
Current report is very minimalistic:
$ target/debug/dlint test.ts
error: `any` type is not allowed (noExplicitAny) at ./test.ts:6:14
error: `var` keyword is not allowed (noVar) at ./test.ts:12:0
error: Variables shouldn't be deleted (noDeleteVar) at ./test.ts:14:0
It should be changed to contain a snippet of code that shows where the problem occurs (much like ESLint):
$ target/debug/dlint test.ts
error: `any` type is not allowed (noExplicitAny) at ./test.ts:6:14
1| function foo(a: any) {
| ^
2| //
3| }
@disizali had a PR with colorful output at #26, but I'd rather not introduce new crates for the sake of formatting right now.
Instead we should copy-paste color helpers from deno
and construct diagnostic messages manually.
I expect that Linter
struct will be extended to be able to extract code snippets from from SWC'c source map.
MVP rule ignores
The only way to ignore a lint rule should be inline comment:
// dlint-ignore explicitFunctionReturnType
function fooBar() {
...
}
// dlint-ignore noExplicitAny explicitFunctionReturnType
function fizzBuzz(a: any) {
...
}
remove bin target and move it to examples
deno_lint
library target shouldn't depend on clap
after all. We need to move main.rs
into examples/
Buggy rules
False positives found while linting deno_std
(denoland/deno#6240)
no-misued-new
(no-misused-new) Class cannot have method named `new`.
static create(writer: Writer, size: number = DEFAULT_BUF_SIZE): BufWriter {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
at ./std/io/bufio.ts:451:2
(no-misused-new) Class cannot have method named `new`.
static create(
~~~~~~~~~~~~~~
at ./std/io/bufio.ts:540:2
no-case-declarations
(no-case-declarations) Unexpected declaration in case
case "string":
~~~~~~~~~~~~~~
at ./std/fmt/printf.ts:631:6
(no-case-declarations) Unexpected declaration in case
case OpCode.Close:
~~~~~~~~~~~~~~~~~~
at ./std/ws/mod.ts:265:8
no-empty
(no-empty) Empty block statement
process.on("uncaughtException", (_err: Error) => {});
~~
at ./std/node/process_test.ts:76:57
(no-empty) Empty block statement
const testFunction = (): void => {};
~~
at ./std/node/events_test.ts:134:37
no-empty-function
(no-empty-function) Empty functions are not allowed
function callbackify<Arg1T, Arg2T, Arg3T, ResultT>(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
at ./std/node/_util/_util_callbackify.ts:53:0
(no-empty-function) Empty functions are not allowed
function callbackify<Arg1T, Arg2T, Arg3T, Arg4T, ResultT>(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
at ./std/node/_util/_util_callbackify.ts:56:0
(no-empty-function) Empty functions are not allowed
function callbackify<Arg1T, Arg2T, Arg3T, Arg4T, Arg5T, ResultT>(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
at ./std/node/_util/_util_callbackify.ts:70:0
Ignore directives should be linted
deno-lint-ignore <code...>
allows to ignore diagnostics matching codes originating on the next line.
Each ignore directive should be checked that it was used, otherwise a new diagnostic should be produced to avoid bit rot.
Add descriptions and examples to each lint rule
All lint rules should be updated to contains some kind of method that returns description as well as some examples of valid and invalid. This feature will be used to generate documentation.
- adjacent-overload-signatures
- ban-ts-comment
- ban-types
- ban-untagged-ignore
- ban-untagged-todo
- constructor-super
- default-param-last
- eqeqeq
- explicit-function-return-type
- explicit-module-boundary-types
- for-direction
- getter-return
- no-array-constructor
- no-async-promise-executor
- no-await-in-loop
- no-case-declarations
- no-class-assign
- no-compare-neg-zero
- no-cond-assign
- no-const-assign
- no-constant-condition
- no-control-regex
- no-debugger
- no-delete-var
- no-dupe-args
- no-dupe-class-members
- no-dupe-else-if
- no-dupe-keys
- no-duplicate-case
- no-empty
- no-empty-character-class
- no-empty-interface
- no-empty-pattern
- no-eval
- no-ex-assign
- no-explicit-any
- no-extra-boolean-cast
- no-extra-non-null-assertion
- no-extra-semi
- no-fallthrough
- no-func-assign
- no-global-assign
- no-import-assign
- no-inferrable-types
- no-inner-declarations
- no-invalid-regexp
- no-irregular-whitespace
- no-misused-new
- no-mixed-spaces-and-tabs
- no-namespace
- no-new-symbol
- no-non-null-asserted-optional-chain
- no-non-null-assertion
- no-obj-calls
- no-octal
- no-prototype-builtins
- no-redeclare
- no-regex-spaces
- no-self-assign
- no-setter-return
- no-shadow-restricted-names
- no-sparse-arrays
- no-this-alias
- no-this-before-super
- no-throw-literal
- no-undef
- no-unreachable
- no-unsafe-finally
- no-unsafe-negation
- no-unused-labels
- no-unused-vars
- no-var
- no-with
- prefer-as-const
- prefer-const
- prefer-namespace-keyword
- require-yield
- single-var-declarator
- triple-slash-reference
- use-isnan
- valid-typeof
Out-of-bounds columns when file contains tabs
So built on master a few hours ago and while it works fine on a bunch of modules in cli/js and std/* I found a case that ends with a crash.
$ RUST_BACKTRACE=1 ../deno/target/debug/deno lint --unstable mod.ts
(explicit-function-return-type) Missing return type on function
function errno(err : Error) {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
at mod.ts:231:0
(no-explicit-any) `any` type is not allowed
fds : any[];
~~~
at mod.ts:292:10
(no-explicit-any) `any` type is not allowed
exports: { [key: string]: any };
~~~
at mod.ts:293:30
(explicit-function-return-type) Missing return type on function
view.setUint32(argv_buf_size_out, args.reduce(function(acc, arg) {
~~~~~~~~~~~~~~~~~~~~
at mod.ts:359:62
(explicit-function-return-type) Missing return type on function
view.setUint32(environ_buf_size_out, entries.reduce(function(acc, [key, value]) {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
at mod.ts:390:68
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', cli/fmt_errors.rs:86:8
stack backtrace:
0: backtrace::backtrace::libunwind::trace
at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/libunwind.rs:86
1: backtrace::backtrace::trace_unsynchronized
at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/mod.rs:66
2: std::sys_common::backtrace::_print_fmt
at src/libstd/sys_common/backtrace.rs:78
3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
at src/libstd/sys_common/backtrace.rs:59
4: core::fmt::write
at src/libcore/fmt/mod.rs:1063
5: std::io::Write::write_fmt
at src/libstd/io/mod.rs:1426
6: std::sys_common::backtrace::_print
at src/libstd/sys_common/backtrace.rs:62
7: std::sys_common::backtrace::print
at src/libstd/sys_common/backtrace.rs:49
8: std::panicking::default_hook::{{closure}}
at src/libstd/panicking.rs:204
9: std::panicking::default_hook
at src/libstd/panicking.rs:224
10: std::panicking::rust_panic_with_hook
at src/libstd/panicking.rs:470
11: rust_begin_unwind
at src/libstd/panicking.rs:378
12: std::panicking::begin_panic
13: std::panicking::begin_panic
14: core::str::traits::<impl core::slice::SliceIndex<str> for core::ops::range::RangeFrom<usize>>::index
15: deno::fmt_errors::format_maybe_source_line
at cli/fmt_errors.rs:86
16: deno::fmt_errors::format_stack
at cli/fmt_errors.rs:33
17: deno::lint_command::{{closure}}
at cli/main.rs:359
18: <std::future::GenFuture<T> as core::future::future::Future>::poll
at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:44
19: <rusty_v8::string::WriteOptions as core::ops::bit::BitOr>::bitor
20: tokio::runtime::basic_scheduler::BasicScheduler<P>::block_on::{{closure}}::{{closure}}
at /Users/caspervonb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/basic_scheduler.rs:131
21: tokio::coop::with_budget::{{closure}}
at /Users/caspervonb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/coop.rs:127
22: std::thread::local::LocalKey<T>::try_with
at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/thread/local.rs:262
23: std::thread::local::LocalKey<T>::with
at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/thread/local.rs:239
24: tokio::coop::with_budget
at /Users/caspervonb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/coop.rs:120
25: tokio::coop::budget
at /Users/caspervonb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/coop.rs:96
26: tokio::runtime::basic_scheduler::BasicScheduler<P>::block_on::{{closure}}
at /Users/caspervonb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/basic_scheduler.rs:131
27: tokio::runtime::basic_scheduler::enter::{{closure}}
at /Users/caspervonb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/basic_scheduler.rs:213
28: tokio::macros::scoped_tls::ScopedKey<T>::set
at /Users/caspervonb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/macros/scoped_tls.rs:63
29: tokio::runtime::basic_scheduler::enter
at /Users/caspervonb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/basic_scheduler.rs:213
30: tokio::runtime::basic_scheduler::BasicScheduler<P>::block_on
at /Users/caspervonb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/basic_scheduler.rs:123
31: tokio::runtime::Runtime::block_on::{{closure}}
at /Users/caspervonb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/mod.rs:444
32: tokio::runtime::context::enter
at /Users/caspervonb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/context.rs:72
33: tokio::runtime::handle::Handle::enter
at /Users/caspervonb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/handle.rs:76
34: tokio::runtime::Runtime::block_on
at /Users/caspervonb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/mod.rs:441
35: deno::tokio_util::run_basic
at cli/tokio_util.rs:18
36: deno::main
at cli/main.rs:765
37: std::rt::lang_start::{{closure}}
at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/rt.rs:67
38: std::rt::lang_start_internal::{{closure}}
at src/libstd/rt.rs:52
39: std::panicking::try::do_call
at src/libstd/panicking.rs:303
40: __rust_maybe_catch_panic
at src/libpanic_unwind/lib.rs:86
41: std::panicking::try
at src/libstd/panicking.rs:281
42: std::panic::catch_unwind
at src/libstd/panic.rs:394
43: std::rt::lang_start_internal
at src/libstd/rt.rs:51
44: std::rt::lang_start
at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/rt.rs:67
45: deno::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
See mod.ts
Feature request: Add suggestion(s) to error messages
Error messages should also have suggestions for possible fixes of the error.
Missing documentation on why not eslint
Would it be possible to document why eslint is not used for linting typescript used in deno
?
I would understand the desire to write a linter in rust if eslint
is deemed too slow.
I would also understand that the deno community does not wish to rely on a binary like eslint
that only works with node dist/eslint.js
( That being I said i see eslint
as a third_party module ( https://github.com/denoland/deno_third_party/tree/4a3ade332261afb8fcb8b364e59d3cca7c975d36/node_modules/eslint ) )
eslint
and typescript-eslint
( https://github.com/typescript-eslint/typescript-eslint ) have written a lot of linting rules that can be used to provide linting benefits.
It is possible to "bundle up" eslint into a single standalone CLI linter with no configuration file, for example ( https://github.com/Raynos/tsdocstandard ).
rule suggestion: use arrow syntax for non-top-level functions
There's a lot of code like this in Deno:
Deno.test("foo", function () { /* ... */ });
It would be nice to have a rule to suggest to use arrow syntax for the anonymous function here.
However, for top-level functions, the function syntax should be used.
Lint rule code - camelCase or kebab-case
Currently rule codes are written using camelCase:
noExplicitAny
noEval
getterReturn
In ESLint rule codes are written using kebab-case:
no-explicit-any
no-eval
getter-return
Ignore directives are currently spelled out using kebab-case (deno-lint-ignore
which follows convention from Deno for formatting ignores - deno-fmt-ignore
).
We should make a decision one way or another and unify all codes.
Probably the best to go with kebab-case as it's already established convention in ESLint
Add Deno scripts for formatting and linting Rust code
tools/format.ts
should run:
rustfmt --check examples/dlint/main.rs
rustfmt --check src/lib.rs
deno fmt --check benchmarks/benchmarks.ts
tools/lint.ts
should run:
cargo clippy --all-targets --release --locked -- -D clippy::all
target/release/examples/dlint benchmarks/benchmarks.ts
CI script should be updated to run those scripts
Add CLI parser
It will take a few more months before linter is good enough to be shipped with deno
.
In the meantime we could still use it as a standalone binary for testing purposes. That means we need a CLI parser - we should use clap
(because it's already used in Deno).
For starters CLI should only two situations:
- printing help -
dlint -h
,dlint --help
,dlint help
- running linter on provided list of files -
dlint file.ts
,dlint file2.ts
getter-return does not consider flow analysis
Using the following example:
export class Test {
#internal: string | undefined;
constructor(testStr?: string) {
this.#internal = testStr;
}
get str(): string {
if (this.#internal !== undefined) {
return this.#internal;
} else {
return "empty";
}
}
}
I get the following output:
(getter-return) Getter requires a return
get str(): string {
^
at test.ts:8:20
Found 1 problems
As a side-note, this rule is only useful in JS, as the TypeScript compiler errors with the following if a getter does not return:
A 'get' accessor must return a value. ts(2378)
Is it worth keeping the rule in recommended?
typescript-eslint recommended rules
Tracking issues for recommended rules of typescript-eslint
- adjacent-overload-signatures (easy)
- ban-ts-comment
- ban-types
- explicit-module-boundary-types (easy)
- no-array-constructor
- no-empty-function (needs to be fixed, false positives for constructors)
- no-empty-interface
- no-explicit-any
- no-extra-non-null-assertion
- no-extra-semi (easy)
- no-inferrable-types (easy)
- no-misused-new
- no-namespace
- no-non-null-asserted-optional-chain
- no-non-null-assertion
- no-this-alias
- no-unused-vars (hard, needs scope analysis)
-
no-var-requires - prefer-as-const
- prefer-namespace-keyword
- triple-slash-reference
Thanks for making this :-)
Not really an issue, just a ๐ on the push to a self-contained TypeScript toolchain :) I spend a significant amount of time babysitting TypeScript build for vscode extension for rust-analyzer, and I am looking forward to a (distant) future, where I need only deno
, and don't have a 100k lockfile just to make sure I use ;
consistently.
Add benchmarks
We should have some minimal benchmarks comparing performance with ESlint
.
ESLint benchmarks should use same set of rules that are available in deno_lint
, with configuration producing same results as deno_lint
.
It will require to setup a project with decent number of files.
Finish scope analysis
cargo install deno fails to compile deno_lint v0.1.10 under rustc 1.41.0
Hi & thank you for Deno! I hope I'm not wasting your time with this but here goes.
A few weeks ago, I successfully installed deno with cargo on Fedora 32. Today I was able to use the install-update crate to update deno to v1.1.0 under rustc/cargo 1.44.0. So all good there.
Separately, on another machine, a new Ubuntu Server 20.04 LTS install that thinks rustc 1.41.0 and cargo 1.41.0 are current, I tried cargo install deno
and it failed to cope with some of the new hotness of deno_lint:
Compiling deno_lint v0.1.10
error[E0658]: use of unstable library feature 'matches_macro'
--> /home/nacho/.cargo/registry/src/github.com-1ecc6299db9ec823/deno_lint-0.1.10/src/rules/eqeqeq.rs:37:23
|
37 | Expr::Lit(lit) => matches!(lit, Lit::Null(_)),
| ^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/65721
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.
error: could not compile `deno_lint`.
warning: build failed, waiting for other jobs to finish...
error: failed to compile `deno v1.1.0`, intermediate artifacts can be found at `/tmp/cargo-install4kXDXS`
Maybe there's nothing for you to do here and I should just wait for Ubuntu to offer Rust 1.44.0.
Or I could re-install Rust and Cargo outside of apt and get quicker updates by doing them myself.
Or I could use one of your other recommended install methods for Deno.
All of these are fine with me, but I thought I would report this anyway in case it's more significant than I think, and affects a lot of people.
Also, I noticed cargo install deno
is an install option in the manual at https://deno.land/manual/getting_started/installation but it is not a listed option in the Install instructions linked from the project's README.md at https://github.com/denoland/deno_install
Let me know if I just missed that it's deprecated and I'll use another install method.
.deno-lint configuration file (suggestion)
User can enable / disable rules, but not customize the rules denoland/deno#1880 (comment)
ESLint recommended rules
Tracking issue for rules from eslint:recommended
set.
- constructor-super
- for-direction
- getter-return
- no-async-promise-executor
- no-case-declarations
- no-class-assign (broken, needs scope analysis)
- no-compare-neg-zero
- no-cond-assign
- no-const-assign (broken, needs scope analysis)
- no-constant-condition
- no-control-regex (easy)
- no-debugger
- no-delete-var
- no-dupe-args
- no-dupe-class-members
- no-dupe-else-if
- no-dupe-keys
- no-duplicate-case
- no-empty
- no-empty-character-class
- no-empty-pattern
- no-ex-assign (broken, needs scope analysis)
- no-extra-boolean-cast
- no-extra-semi
- no-fallthrough (hard, needs code path analysis)
- no-func-assign (broken, needs scope analysis)
- no-global-assign (hard, needs scope analysis)
- no-import-assign (hard, needs scope analysis)
- no-inner-declarations
- no-invalid-regexp(
easyhard, need to port additional lib) - no-irregular-whitespace (easy)
- no-misleading-character-class (easy)
- no-mixed-spaces-and-tabs
- no-new-symbol
- no-obj-calls
- no-octal
- no-prototype-builtins
- no-redeclare (hard, needs scope analysis)
- no-regex-spaces
- no-self-assign
- no-setter-return
- no-shadow-restriced-names
- no-sparse-arrays
- no-this-before-super
- no-undef (hard, needs scope analysis)
- no-unexpected-multiline (easy)
- no-unreachable (hard, needs code path analysis)
- no-unsafe-finally
- no-unsafe-negation
- no-unused-labels
- no-unused-vars (hard, needs scope analysis)
-
no-useless-escape (easy)(#48 (comment)) - no-with
- require-yield
- use-isnan
- valid-typeof
eqeqeq is cryptic
[suggestion] remove ban-untagged-ignore and add no-invalid-ignore
two suggestion :
deno-lint-ignore
ignore all rules for the next line ( removeban-untagged-ignore
)deno-lint-ignore no-war
should be reported in a rule likeno-invalid-ignore
fallthrough in switch/case statements
Not essential but I think it would be cool and catch bugs.
I propose that the deno fmt
command would do the following to each case
block in a switch
statement:
- Add a
// fallthrough
comment to the end of the case if there is no unconditionalbreak
statement. - Remove any
// fallthrough
comment otherwise.
Examples
switch foo {
case "bar":
console.log("bar");
break;
// fallthrough
case "baz":
console.log("baz");
case "coconut":
if (jellybean) {
break;
}
}
would be formatted to:
switch foo {
case "bar":
console.log("bar");
break;
case "baz":
console.log("baz");
// fallthrough
case "coconut":
if (jellybean) {
break;
}
// fallthrough
}
Why?
- Makes it clear if the case falls through or not - pretty self-explanatory
- Catches many bugs where you forget to include the
break
keyword. This is because it will add a// fallthrough
comment, and you should notice this. If falling through was not intended you can then ensure you add in thatbreak
statement.
Roadmap
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:
- better rule description and diagnostics #162 #159
- basic configuration - need ability to enable/disable rules for project (denoland/deno#11776, denoland/deno#11686)
- plugin support #175 - mechanism for providing new rule sets
Future:
- documentation website
- use
deno_lint
from Node project #169 - autofix
Refactor testing setup
Writing test cases for lint rules is a cumbersome at the moment.
We should refactor testing setup to be able to write tests easily, here are some things that would be useful:
- create testing fn for lint rule:
assert_lint_ok<T>(lint_rule: T, source_code)
assert_lint_err<T>(lint_rule: T, source_code) -> Vec<Diagnostic>
- compare diagnostics partially - ie. assert that starts on certain column but ignore filename/line
write tests for existing rules
no-octal rule broken
(no-octal) `Octal number` is not allowed
--> ../deno/std/encoding/toml_test.ts:331:13
|
331 | flt3: -0.01,
| ^^^^
|
CC @disizali
deno_lint --version doesn't print version
False negatives in no-explicit-any
(ban-unused-ignore) Ignore for code "no-explicit-any" was not used.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
at ./std/node/module.ts:104:4
static _extensions: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: (module: Module, filename: string) => any;
} = Object.create(null);
(ban-unused-ignore) Ignore for code "no-explicit-any" was not used.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
at ./std/node/module.ts:1048:2
type RequireWrapper = (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
exports: any,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
require: any,
module: Module,
__filename: string,
__dirname: string
) => void;
Interoperate with Existing ESLint Rules and Configs
@axetroy If you say there are too many options, why build out a deno lint
at all? That's only adding more options. We already have a linting tool for linting JavaScript and TypeScript and it is called eslint
. I don't see a value in duplicating all that work again.
Unless a developer only writes backend code, they will still need to touch eslint
.
If a parallel lint tool must be built (are there really not better ways to improve deno?) then it MUST be able to consume existing eslint rules. Otherwise people will waste their time reinventing the wheel, writing duplicate rules for deno and frontend code rather than application code.
Instead deno lint
would be more useful as something like golangci-lint where it aggregates and calls other already written lint rules and linters. It provides a "default lint config" (via url import) with sane default but still extendable.
Originally posted by @brandonkal in denoland/deno#1880 (comment)
Emphasis added.
Integration with Deno CLI
Tracking issue for all things that need to be worked out before linter can be integrated with Deno CLI
- CLI integration (clap)
- source file loading
- error handling
- dependency duplication (
termcolor
) - publish crate with
lib.rs
to crates.io (#83)
Support for React
I love the promise of this project (linting, but fast).
We are using eslint not just for js/ts but also React specific rules (e.g. hooks, etc.).
Is this project eventually planned to support this?
Disable all non `recommended` rules for now
I think while we have no config options we should disable all non recommended
rules because they can give false positives very often (eg eqeqeq
, https://discordapp.com/channels/684898665143206084/684911491035430919/720016434314608710)
โ๏ธ are all rules which are part of eslint:recommended
or typescript-eslint:recommended
๐ฆ are all rules not present in eslint
or typescript-eslint
ban-ts-comment
โ๏ธban-ts-ignore
๐ฆban-untagged-ignore
๐ฆban-untagged-todo
๐ฆconstructor-super
โ๏ธdefault-param-last
eqeqeq
explicit-function-return-type
for-direction
โ๏ธgetter-return
โ๏ธno-array-constructor
no-async-promise-executor
โ๏ธno-case-declarations
โ๏ธno-class-assign
โ๏ธno-compare-neg-zero
โ๏ธno-cond-assign
โ๏ธno-debugger
โ๏ธno-delete-var
โ๏ธno-dupe-args
โ๏ธno-dupe-keys
โ๏ธno-duplicate-case
โ๏ธno-empty
โ๏ธno-empty-character-class
โ๏ธno-empty-function
โ๏ธno-empty-interface
โ๏ธno-empty-pattern
โ๏ธno-eval
no-ex-assign
โ๏ธno-explicit-any
โ๏ธno-func-assign
โ๏ธno-misused-new
โ๏ธno-namespace
โ๏ธno-new-symbol
โ๏ธno-obj-call
โ๏ธno-octal
โ๏ธno-prototype-builtins
โ๏ธno-setter-return
โ๏ธno-sparse-array
โ๏ธno-this-alias
โ๏ธno-throw-literal
no-unsafe-finally
โ๏ธno-unsafe-negation
โ๏ธno-var
no-with
โ๏ธprefer-namespace-keyword
โ๏ธrequire-yield
โ๏ธsingle-var-declarator
๐ฆtriple-slash-reference
โ๏ธuse-isnan
โ๏ธvalid-typeof
โ๏ธ
Add caching to CI
We should set up Github Actions cache to speed up CI builds.
Example set up in Deno repo:
https://github.com/denoland/deno/blob/f366e5e9bb5982376b160bebd35c3edf2c9ff19b/.github/workflows/ci.yml#L106-L121
Remove "no-sparse-array" from recommended rule list
Handle NO_COLOR env variable
Required for #78
Feature Request: Webpack Loader for Deno Lint
I think it would be great if we have a webpack loader for deno lint, and would be configurable to break the build whenever it encounters a lint error
example webpack configuration:
{
test: /\.(ts|js)$/,
enforce: "pre",
loader: "deno-lint-loader",
options: {
emitErrors: true,
failOnHint: true
}
}
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. ๐๐๐
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google โค๏ธ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.