Skip to content

Commit 7bb0121

Browse files
authored
feat(linter): add react/no-namespace (#9404)
This PR adds [react/no-namespace](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-namespace.md) rule issue: #1022
1 parent acb1e2c commit 7bb0121

File tree

3 files changed

+233
-0
lines changed

3 files changed

+233
-0
lines changed

crates/oxc_linter/src/rules.rs

+2
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ mod react {
296296
pub mod no_direct_mutation_state;
297297
pub mod no_find_dom_node;
298298
pub mod no_is_mounted;
299+
pub mod no_namespace;
299300
pub mod no_render_return_value;
300301
pub mod no_set_state;
301302
pub mod no_string_refs;
@@ -882,6 +883,7 @@ oxc_macros::declare_all_lint_rules! {
882883
react::jsx_no_undef,
883884
react::jsx_no_useless_fragment,
884885
react::jsx_props_no_spread_multi,
886+
react::no_namespace,
885887
react::no_array_index_key,
886888
react::no_children_prop,
887889
react::no_danger_with_children,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
use oxc_ast::{
2+
AstKind,
3+
ast::{Argument, JSXElementName},
4+
};
5+
use oxc_diagnostics::OxcDiagnostic;
6+
use oxc_macros::declare_oxc_lint;
7+
use oxc_span::Span;
8+
9+
use crate::{AstNode, context::LintContext, rule::Rule, utils::is_create_element_call};
10+
11+
fn no_namespace_diagnostic(span: Span, component_name: &str) -> OxcDiagnostic {
12+
let message = format!(
13+
r"React component {component_name} must not be in a namespace, as React does not support them."
14+
);
15+
16+
OxcDiagnostic::warn(message).with_label(span)
17+
}
18+
19+
#[derive(Debug, Default, Clone)]
20+
pub struct NoNamespace;
21+
22+
declare_oxc_lint!(
23+
/// ### What it does
24+
/// Enforce that namespaces are not used in React elements.
25+
///
26+
/// ### Why is this bad?
27+
/// Namespaces in React elements, such as svg:circle, are not supported by React.
28+
///
29+
/// ### Examples
30+
///
31+
/// Examples of **incorrect** code for this rule:
32+
/// ```jsx
33+
/// <ns:TestComponent />
34+
/// <Ns:TestComponent />
35+
/// ```
36+
///
37+
/// Examples of **correct** code for this rule:
38+
/// ```jsx
39+
/// <TestComponent />
40+
/// <testComponent />
41+
/// ```
42+
NoNamespace,
43+
react,
44+
suspicious,
45+
);
46+
47+
impl Rule for NoNamespace {
48+
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
49+
match node.kind() {
50+
AstKind::JSXOpeningElement(element) => {
51+
if let JSXElementName::NamespacedName(namespaced_name) = &element.name {
52+
let component_name_with_ns = format!(
53+
"{}:{}",
54+
namespaced_name.namespace.name, namespaced_name.property.name
55+
);
56+
57+
ctx.diagnostic(no_namespace_diagnostic(
58+
namespaced_name.span,
59+
&component_name_with_ns,
60+
));
61+
}
62+
}
63+
AstKind::CallExpression(call_expr) => {
64+
if is_create_element_call(call_expr) {
65+
let Some(Argument::StringLiteral(str_lit)) = call_expr.arguments.first() else {
66+
return;
67+
};
68+
69+
if str_lit.value.contains(':') {
70+
ctx.diagnostic(no_namespace_diagnostic(str_lit.span, &str_lit.value));
71+
}
72+
}
73+
}
74+
_ => {}
75+
}
76+
}
77+
}
78+
79+
#[test]
80+
fn test() {
81+
use crate::tester::Tester;
82+
83+
let pass = vec![
84+
"<testcomponent />",
85+
r#"React.createElement("testcomponent")"#,
86+
"<testComponent />",
87+
r#"React.createElement("testComponent")"#,
88+
"<test_component />",
89+
r#"React.createElement("test_component")"#,
90+
"<TestComponent />",
91+
r#"React.createElement("TestComponent")"#,
92+
"<object.testcomponent />",
93+
r#"React.createElement("object.testcomponent")"#,
94+
"<object.testComponent />",
95+
r#"React.createElement("object.testComponent")"#,
96+
"<object.test_component />",
97+
r#"React.createElement("object.test_component")"#,
98+
"<object.TestComponent />",
99+
r#"React.createElement("object.TestComponent")"#,
100+
"<Object.testcomponent />",
101+
r#"React.createElement("Object.testcomponent")"#,
102+
"<Object.testComponent />",
103+
r#"React.createElement("Object.testComponent")"#,
104+
"<Object.test_component />",
105+
r#"React.createElement("Object.test_component")"#,
106+
"<Object.TestComponent />",
107+
r#"React.createElement("Object.TestComponent")"#,
108+
"React.createElement(null)",
109+
"React.createElement(true)",
110+
"React.createElement({})",
111+
];
112+
113+
let fail = vec![
114+
"<ns:testcomponent />",
115+
r#"React.createElement("ns:testcomponent")"#,
116+
"<ns:testComponent />",
117+
r#"React.createElement("ns:testComponent")"#,
118+
"<ns:test_component />",
119+
r#"React.createElement("ns:test_component")"#,
120+
"<ns:TestComponent />",
121+
r#"React.createElement("ns:TestComponent")"#,
122+
"<Ns:testcomponent />",
123+
r#"React.createElement("Ns:testcomponent")"#,
124+
"<Ns:testComponent />",
125+
r#"React.createElement("Ns:testComponent")"#,
126+
"<Ns:test_component />",
127+
r#"React.createElement("Ns:test_component")"#,
128+
"<Ns:TestComponent />",
129+
r#"React.createElement("Ns:TestComponent")"#,
130+
];
131+
132+
Tester::new(NoNamespace::NAME, NoNamespace::PLUGIN, pass, fail).test_and_snapshot();
133+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
---
2+
source: crates/oxc_linter/src/tester.rs
3+
---
4+
eslint-plugin-react(no-namespace): React component ns:testcomponent must not be in a namespace, as React does not support them.
5+
╭─[no_namespace.tsx:1:2]
6+
1<ns:testcomponent />
7+
· ────────────────
8+
╰────
9+
10+
eslint-plugin-react(no-namespace): React component ns:testcomponent must not be in a namespace, as React does not support them.
11+
╭─[no_namespace.tsx:1:21]
12+
1React.createElement("ns:testcomponent")
13+
· ──────────────────
14+
╰────
15+
16+
eslint-plugin-react(no-namespace): React component ns:testComponent must not be in a namespace, as React does not support them.
17+
╭─[no_namespace.tsx:1:2]
18+
1<ns:testComponent />
19+
· ────────────────
20+
╰────
21+
22+
eslint-plugin-react(no-namespace): React component ns:testComponent must not be in a namespace, as React does not support them.
23+
╭─[no_namespace.tsx:1:21]
24+
1React.createElement("ns:testComponent")
25+
· ──────────────────
26+
╰────
27+
28+
eslint-plugin-react(no-namespace): React component ns:test_component must not be in a namespace, as React does not support them.
29+
╭─[no_namespace.tsx:1:2]
30+
1<ns:test_component />
31+
· ─────────────────
32+
╰────
33+
34+
eslint-plugin-react(no-namespace): React component ns:test_component must not be in a namespace, as React does not support them.
35+
╭─[no_namespace.tsx:1:21]
36+
1React.createElement("ns:test_component")
37+
· ───────────────────
38+
╰────
39+
40+
eslint-plugin-react(no-namespace): React component ns:TestComponent must not be in a namespace, as React does not support them.
41+
╭─[no_namespace.tsx:1:2]
42+
1<ns:TestComponent />
43+
· ────────────────
44+
╰────
45+
46+
eslint-plugin-react(no-namespace): React component ns:TestComponent must not be in a namespace, as React does not support them.
47+
╭─[no_namespace.tsx:1:21]
48+
1React.createElement("ns:TestComponent")
49+
· ──────────────────
50+
╰────
51+
52+
eslint-plugin-react(no-namespace): React component Ns:testcomponent must not be in a namespace, as React does not support them.
53+
╭─[no_namespace.tsx:1:2]
54+
1<Ns:testcomponent />
55+
· ────────────────
56+
╰────
57+
58+
eslint-plugin-react(no-namespace): React component Ns:testcomponent must not be in a namespace, as React does not support them.
59+
╭─[no_namespace.tsx:1:21]
60+
1React.createElement("Ns:testcomponent")
61+
· ──────────────────
62+
╰────
63+
64+
eslint-plugin-react(no-namespace): React component Ns:testComponent must not be in a namespace, as React does not support them.
65+
╭─[no_namespace.tsx:1:2]
66+
1<Ns:testComponent />
67+
· ────────────────
68+
╰────
69+
70+
eslint-plugin-react(no-namespace): React component Ns:testComponent must not be in a namespace, as React does not support them.
71+
╭─[no_namespace.tsx:1:21]
72+
1React.createElement("Ns:testComponent")
73+
· ──────────────────
74+
╰────
75+
76+
eslint-plugin-react(no-namespace): React component Ns:test_component must not be in a namespace, as React does not support them.
77+
╭─[no_namespace.tsx:1:2]
78+
1<Ns:test_component />
79+
· ─────────────────
80+
╰────
81+
82+
eslint-plugin-react(no-namespace): React component Ns:test_component must not be in a namespace, as React does not support them.
83+
╭─[no_namespace.tsx:1:21]
84+
1React.createElement("Ns:test_component")
85+
· ───────────────────
86+
╰────
87+
88+
eslint-plugin-react(no-namespace): React component Ns:TestComponent must not be in a namespace, as React does not support them.
89+
╭─[no_namespace.tsx:1:2]
90+
1<Ns:TestComponent />
91+
· ────────────────
92+
╰────
93+
94+
eslint-plugin-react(no-namespace): React component Ns:TestComponent must not be in a namespace, as React does not support them.
95+
╭─[no_namespace.tsx:1:21]
96+
1React.createElement("Ns:TestComponent")
97+
· ──────────────────
98+
╰────

0 commit comments

Comments
 (0)