Skip to content

Commit 674852d

Browse files
committed
feat(linter): add rule no-undefined
related to #479
1 parent 02ea19a commit 674852d

File tree

3 files changed

+395
-0
lines changed

3 files changed

+395
-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;
@@ -494,6 +495,7 @@ oxc_macros::declare_all_lint_rules! {
494495
eslint::no_shadow_restricted_names,
495496
eslint::no_sparse_arrays,
496497
eslint::no_undef,
498+
eslint::no_undefined,
497499
eslint::no_unreachable,
498500
eslint::no_unsafe_finally,
499501
eslint::no_unsafe_negation,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
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: String, 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.to_string(), ident.span, ctx);
73+
}
74+
AstKind::BindingIdentifier(ident) => {
75+
diagnostic_undefined_keyword(ident.name.to_string(), 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+
"ndefined",
94+
"a.undefined",
95+
"this.undefined",
96+
"global['undefined']",
97+
"({ undefined: bar })",
98+
"({ undefined: bar } = foo)",
99+
"({ undefined() {} })",
100+
"class Foo { undefined() {} }",
101+
"(class { undefined() {} })",
102+
"import { undefined as a } from 'foo'", // ES6_MODULE,
103+
"export { undefined } from 'foo'", // ES6_MODULE,
104+
"export { undefined as a } from 'foo'", // ES6_MODULE,
105+
"export { a as undefined } from 'foo'", // ES6_MODULE
106+
];
107+
108+
let fail = vec![
109+
"undefined",
110+
"undefined.a",
111+
"a[undefined]",
112+
"undefined[0]",
113+
"f(undefined)",
114+
"function f(undefined) {}",
115+
"function f() { var undefined; }",
116+
"function f() { undefined = true; }",
117+
"var undefined;",
118+
"try {} catch(undefined) {}",
119+
"function undefined() {}",
120+
"(function undefined(){}())",
121+
"var foo = function undefined() {}",
122+
"foo = function undefined() {}",
123+
"undefined = true",
124+
"var undefined = true",
125+
"({ undefined })",
126+
"({ [undefined]: foo })",
127+
"({ bar: undefined })",
128+
"({ bar: undefined } = foo)",
129+
"var { undefined } = foo",
130+
"var { bar: undefined } = foo",
131+
"({ undefined: function undefined() {} })",
132+
"({ foo: function undefined() {} })",
133+
"class Foo { [undefined]() {} }",
134+
"(class { [undefined]() {} })",
135+
"var undefined = true; undefined = false;",
136+
"import undefined from 'foo'", // ES6_MODULE,
137+
"import * as undefined from 'foo'", // ES6_MODULE,
138+
"import { undefined } from 'foo'", // ES6_MODULE,
139+
"import { a as undefined } from 'foo'", // ES6_MODULE,
140+
"let a = [b, ...undefined]",
141+
"[a, ...undefined] = b",
142+
"[a = undefined] = b",
143+
];
144+
145+
Tester::new(NoUndefined::NAME, pass, fail).test_and_snapshot();
146+
}

0 commit comments

Comments
 (0)