Skip to content

Commit

Permalink
feat(linter): add rule no-undefined
Browse files Browse the repository at this point in the history
related to oxc-project#479
  • Loading branch information
jordan-boyer committed Jul 4, 2024
1 parent e32b4bc commit 803ad96
Show file tree
Hide file tree
Showing 3 changed files with 394 additions and 0 deletions.
2 changes: 2 additions & 0 deletions crates/oxc_linter/src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -494,6 +495,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,
Expand Down
145 changes: 145 additions & 0 deletions crates/oxc_linter/src/rules/eslint/no_undefined.rs
Original file line number Diff line number Diff line change
@@ -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();
}
Loading

0 comments on commit 803ad96

Please sign in to comment.