Skip to content

Commit 6876490

Browse files
authored
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
1 parent bf04dee commit 6876490

File tree

3 files changed

+394
-0
lines changed

3 files changed

+394
-0
lines changed

crates/oxc_linter/src/rules.rs

+2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ mod eslint {
9696
pub mod no_ternary;
9797
pub mod no_this_before_super;
9898
pub mod no_undef;
99+
pub mod no_undefined;
99100
pub mod no_unreachable;
100101
pub mod no_unsafe_finally;
101102
pub mod no_unsafe_negation;
@@ -495,6 +496,7 @@ oxc_macros::declare_all_lint_rules! {
495496
eslint::no_shadow_restricted_names,
496497
eslint::no_sparse_arrays,
497498
eslint::no_undef,
499+
eslint::no_undefined,
498500
eslint::no_unreachable,
499501
eslint::no_unsafe_finally,
500502
eslint::no_unsafe_negation,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
use oxc_ast::AstKind;
2+
use oxc_diagnostics::OxcDiagnostic;
3+
use oxc_macros::declare_oxc_lint;
4+
use oxc_span::Span;
5+
6+
use crate::{context::LintContext, rule::Rule, AstNode};
7+
8+
#[derive(Debug, Default, Clone)]
9+
pub struct NoUndefined;
10+
11+
fn no_undefined_diagnostic(span0: Span) -> OxcDiagnostic {
12+
OxcDiagnostic::warn("eslint(no-undefined): Disallow the use of `undefined` as an identifier")
13+
.with_help("Unexpected use of undefined.")
14+
.with_label(span0)
15+
}
16+
17+
declare_oxc_lint!(
18+
/// ### What it does
19+
/// Disallow the use of `undefined` as an identifier
20+
///
21+
/// ### Why is this bad?
22+
///
23+
///
24+
/// ### Example of bad code
25+
/// ```javascript
26+
///
27+
/// var foo = undefined;
28+
///
29+
/// var undefined = "foo";
30+
///
31+
/// if (foo === undefined) {
32+
/// ...
33+
/// }
34+
///
35+
/// function baz(undefined) {
36+
/// ...
37+
/// }
38+
///
39+
/// bar(undefined, "lorem");
40+
///
41+
/// ```
42+
///
43+
/// ### Example of good code
44+
/// ```javascript
45+
/// var foo = void 0;
46+
///
47+
/// var Undefined = "foo";
48+
///
49+
/// if (typeof foo === "undefined") {
50+
/// ...
51+
/// }
52+
///
53+
/// global.undefined = "foo";
54+
///
55+
/// bar(void 0, "lorem");
56+
/// ```
57+
///
58+
NoUndefined,
59+
restriction,
60+
);
61+
62+
fn diagnostic_undefined_keyword(name: &str, span0: Span, ctx: &LintContext) {
63+
if name == "undefined" {
64+
ctx.diagnostic(no_undefined_diagnostic(span0));
65+
}
66+
}
67+
68+
impl Rule for NoUndefined {
69+
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
70+
match node.kind() {
71+
AstKind::IdentifierReference(ident) => {
72+
diagnostic_undefined_keyword(ident.name.as_str(), ident.span, ctx);
73+
}
74+
AstKind::BindingIdentifier(ident) => {
75+
diagnostic_undefined_keyword(ident.name.as_str(), ident.span, ctx);
76+
}
77+
_ => {}
78+
}
79+
}
80+
}
81+
82+
#[test]
83+
fn test() {
84+
use crate::tester::Tester;
85+
86+
let pass = vec![
87+
"void 0",
88+
"void!0",
89+
"void-0",
90+
"void+0",
91+
"null",
92+
"undefine",
93+
"a.undefined",
94+
"this.undefined",
95+
"global['undefined']",
96+
"({ undefined: bar })",
97+
"({ undefined: bar } = foo)",
98+
"({ undefined() {} })",
99+
"class Foo { undefined() {} }",
100+
"(class { undefined() {} })",
101+
"import { undefined as a } from 'foo'", // ES6_MODULE,
102+
"export { undefined } from 'foo'", // ES6_MODULE,
103+
"export { undefined as a } from 'foo'", // ES6_MODULE,
104+
"export { a as undefined } from 'foo'", // ES6_MODULE
105+
];
106+
107+
let fail = vec![
108+
"undefined",
109+
"undefined.a",
110+
"a[undefined]",
111+
"undefined[0]",
112+
"f(undefined)",
113+
"function f(undefined) {}",
114+
"function f() { var undefined; }",
115+
"function f() { undefined = true; }",
116+
"var undefined;",
117+
"try {} catch(undefined) {}",
118+
"function undefined() {}",
119+
"(function undefined(){}())",
120+
"var foo = function undefined() {}",
121+
"foo = function undefined() {}",
122+
"undefined = true",
123+
"var undefined = true",
124+
"({ undefined })",
125+
"({ [undefined]: foo })",
126+
"({ bar: undefined })",
127+
"({ bar: undefined } = foo)",
128+
"var { undefined } = foo",
129+
"var { bar: undefined } = foo",
130+
"({ undefined: function undefined() {} })",
131+
"({ foo: function undefined() {} })",
132+
"class Foo { [undefined]() {} }",
133+
"(class { [undefined]() {} })",
134+
"var undefined = true; undefined = false;",
135+
"import undefined from 'foo'", // ES6_MODULE,
136+
"import * as undefined from 'foo'", // ES6_MODULE,
137+
"import { undefined } from 'foo'", // ES6_MODULE,
138+
"import { a as undefined } from 'foo'", // ES6_MODULE,
139+
"let a = [b, ...undefined]",
140+
"[a, ...undefined] = b",
141+
"[a = undefined] = b",
142+
];
143+
144+
Tester::new(NoUndefined::NAME, pass, fail).test_and_snapshot();
145+
}

0 commit comments

Comments
 (0)