feat(linter): add rule no-undefined (#4041)

Implementing rule https://eslint.org/docs/latest/rules/no-undefined

This is my first time contributing here, I wanted to started with a
simple rule before contributing more.

related to #479
This commit is contained in:
jordan boyer 2024-07-05 05:50:46 +02:00 committed by GitHub
parent bf04dee861
commit 6876490baa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 394 additions and 0 deletions

View file

@ -96,6 +96,7 @@ mod eslint {
pub mod no_ternary;
pub mod no_this_before_super;
pub mod no_undef;
pub mod no_undefined;
pub mod no_unreachable;
pub mod no_unsafe_finally;
pub mod no_unsafe_negation;
@ -495,6 +496,7 @@ oxc_macros::declare_all_lint_rules! {
eslint::no_shadow_restricted_names,
eslint::no_sparse_arrays,
eslint::no_undef,
eslint::no_undefined,
eslint::no_unreachable,
eslint::no_unsafe_finally,
eslint::no_unsafe_negation,

View file

@ -0,0 +1,145 @@
use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use crate::{context::LintContext, rule::Rule, AstNode};
#[derive(Debug, Default, Clone)]
pub struct NoUndefined;
fn no_undefined_diagnostic(span0: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("eslint(no-undefined): Disallow the use of `undefined` as an identifier")
.with_help("Unexpected use of undefined.")
.with_label(span0)
}
declare_oxc_lint!(
/// ### What it does
/// Disallow the use of `undefined` as an identifier
///
/// ### Why is this bad?
///
///
/// ### Example of bad code
/// ```javascript
///
/// var foo = undefined;
///
/// var undefined = "foo";
///
/// if (foo === undefined) {
/// ...
/// }
///
/// function baz(undefined) {
/// ...
/// }
///
/// bar(undefined, "lorem");
///
/// ```
///
/// ### Example of good code
/// ```javascript
/// var foo = void 0;
///
/// var Undefined = "foo";
///
/// if (typeof foo === "undefined") {
/// ...
/// }
///
/// global.undefined = "foo";
///
/// bar(void 0, "lorem");
/// ```
///
NoUndefined,
restriction,
);
fn diagnostic_undefined_keyword(name: &str, span0: Span, ctx: &LintContext) {
if name == "undefined" {
ctx.diagnostic(no_undefined_diagnostic(span0));
}
}
impl Rule for NoUndefined {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
match node.kind() {
AstKind::IdentifierReference(ident) => {
diagnostic_undefined_keyword(ident.name.as_str(), ident.span, ctx);
}
AstKind::BindingIdentifier(ident) => {
diagnostic_undefined_keyword(ident.name.as_str(), ident.span, ctx);
}
_ => {}
}
}
}
#[test]
fn test() {
use crate::tester::Tester;
let pass = vec![
"void 0",
"void!0",
"void-0",
"void+0",
"null",
"undefine",
"a.undefined",
"this.undefined",
"global['undefined']",
"({ undefined: bar })",
"({ undefined: bar } = foo)",
"({ undefined() {} })",
"class Foo { undefined() {} }",
"(class { undefined() {} })",
"import { undefined as a } from 'foo'", // ES6_MODULE,
"export { undefined } from 'foo'", // ES6_MODULE,
"export { undefined as a } from 'foo'", // ES6_MODULE,
"export { a as undefined } from 'foo'", // ES6_MODULE
];
let fail = vec![
"undefined",
"undefined.a",
"a[undefined]",
"undefined[0]",
"f(undefined)",
"function f(undefined) {}",
"function f() { var undefined; }",
"function f() { undefined = true; }",
"var undefined;",
"try {} catch(undefined) {}",
"function undefined() {}",
"(function undefined(){}())",
"var foo = function undefined() {}",
"foo = function undefined() {}",
"undefined = true",
"var undefined = true",
"({ undefined })",
"({ [undefined]: foo })",
"({ bar: undefined })",
"({ bar: undefined } = foo)",
"var { undefined } = foo",
"var { bar: undefined } = foo",
"({ undefined: function undefined() {} })",
"({ foo: function undefined() {} })",
"class Foo { [undefined]() {} }",
"(class { [undefined]() {} })",
"var undefined = true; undefined = false;",
"import undefined from 'foo'", // ES6_MODULE,
"import * as undefined from 'foo'", // ES6_MODULE,
"import { undefined } from 'foo'", // ES6_MODULE,
"import { a as undefined } from 'foo'", // ES6_MODULE,
"let a = [b, ...undefined]",
"[a, ...undefined] = b",
"[a = undefined] = b",
];
Tester::new(NoUndefined::NAME, pass, fail).test_and_snapshot();
}

View file

@ -0,0 +1,247 @@
---
source: crates/oxc_linter/src/tester.rs
---
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:1]
1 │ undefined
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:1]
1 │ undefined.a
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:3]
1 │ a[undefined]
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:1]
1 │ undefined[0]
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:3]
1 │ f(undefined)
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:12]
1 │ function f(undefined) {}
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:20]
1 │ function f() { var undefined; }
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:16]
1 │ function f() { undefined = true; }
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:5]
1 │ var undefined;
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:14]
1 │ try {} catch(undefined) {}
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:10]
1 │ function undefined() {}
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:11]
1 │ (function undefined(){}())
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:20]
1 │ var foo = function undefined() {}
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:16]
1 │ foo = function undefined() {}
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:1]
1 │ undefined = true
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:5]
1 │ var undefined = true
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:4]
1 │ ({ undefined })
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:5]
1 │ ({ [undefined]: foo })
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:9]
1 │ ({ bar: undefined })
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:9]
1 │ ({ bar: undefined } = foo)
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:7]
1 │ var { undefined } = foo
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:12]
1 │ var { bar: undefined } = foo
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:24]
1 │ ({ undefined: function undefined() {} })
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:18]
1 │ ({ foo: function undefined() {} })
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:14]
1 │ class Foo { [undefined]() {} }
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:11]
1 │ (class { [undefined]() {} })
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:5]
1 │ var undefined = true; undefined = false;
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:23]
1 │ var undefined = true; undefined = false;
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:8]
1 │ import undefined from 'foo'
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:13]
1 │ import * as undefined from 'foo'
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:10]
1 │ import { undefined } from 'foo'
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:15]
1 │ import { a as undefined } from 'foo'
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:16]
1 │ let a = [b, ...undefined]
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:8]
1 │ [a, ...undefined] = b
· ─────────
╰────
help: Unexpected use of undefined.
⚠ eslint(no-undefined): Disallow the use of `undefined` as an identifier
╭─[no_undefined.tsx:1:6]
1 │ [a = undefined] = b
· ─────────
╰────
help: Unexpected use of undefined.