Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ arguments: -c .oxlintrc.json
working directory: fixtures/issue_11644
----------
Found 0 warnings and 0 errors.
Finished in <variable>ms on 1 file with 166 rules using 1 threads.
Finished in <variable>ms on 1 file with 167 rules using 1 threads.
----------
CLI result: LintSucceeded
----------
38 changes: 38 additions & 0 deletions crates/oxc_linter/src/config/settings/react.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,17 @@ impl ReactVersion {
pub fn patch(&self) -> u32 {
self.patch
}

/// Checks if the React version supports `UNSAFE_` prefixed lifecycle methods.
///
/// React 16.3 introduced the `UNSAFE_` prefixed lifecycle methods
/// (`UNSAFE_componentWillMount`, `UNSAFE_componentWillReceiveProps`, `UNSAFE_componentWillUpdate`).
///
/// Returns `true` if this version is >= 16.3.
#[inline]
pub fn supports_unsafe_lifecycle_prefix(&self) -> bool {
self.major > 16 || (self.major == 16 && self.minor >= 3)
}
}

impl fmt::Display for ReactVersion {
Expand Down Expand Up @@ -281,6 +292,33 @@ mod test {
assert!(serde_json::from_str::<ReactVersion>(r#""18. 2.0""#).is_err());
}

#[test]
fn test_supports_unsafe_lifecycle_prefix() {
// Version 16.3.0 - should support UNSAFE_ prefix
let v16_3: ReactVersion = serde_json::from_str(r#""16.3.0""#).unwrap();
assert!(v16_3.supports_unsafe_lifecycle_prefix());

// Version 16.4.0 - should support UNSAFE_ prefix
let v16_4: ReactVersion = serde_json::from_str(r#""16.4.0""#).unwrap();
assert!(v16_4.supports_unsafe_lifecycle_prefix());

// Version 17.0.0 - should support UNSAFE_ prefix
let v17: ReactVersion = serde_json::from_str(r#""17.0.0""#).unwrap();
assert!(v17.supports_unsafe_lifecycle_prefix());

// Version 16.2.0 - should NOT support UNSAFE_ prefix
let v16_2: ReactVersion = serde_json::from_str(r#""16.2.0""#).unwrap();
assert!(!v16_2.supports_unsafe_lifecycle_prefix());

// Version 16.0.0 - should NOT support UNSAFE_ prefix
let v16_0: ReactVersion = serde_json::from_str(r#""16.0.0""#).unwrap();
assert!(!v16_0.supports_unsafe_lifecycle_prefix());

// Version 15.0.0 - should NOT support UNSAFE_ prefix
let v15: ReactVersion = serde_json::from_str(r#""15.0.0""#).unwrap();
assert!(!v15.supports_unsafe_lifecycle_prefix());
}

#[test]
fn test_version_regex() {
let re = &*REACT_VERSION_REGEX;
Expand Down
6 changes: 6 additions & 0 deletions crates/oxc_linter/src/generated/rule_runner_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2504,6 +2504,12 @@ impl RuleRunner for crate::rules::react::no_unsafe::NoUnsafe {
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
}

impl RuleRunner for crate::rules::react::no_will_update_set_state::NoWillUpdateSetState {
const NODE_TYPES: Option<&AstTypesBitset> =
Some(&AstTypesBitset::from_types(&[AstType::CallExpression]));
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
}

impl RuleRunner for crate::rules::react::only_export_components::OnlyExportComponents {
const NODE_TYPES: Option<&AstTypesBitset> = None;
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::RunOnce;
Expand Down
2 changes: 2 additions & 0 deletions crates/oxc_linter/src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ pub(crate) mod react {
pub mod no_unescaped_entities;
pub mod no_unknown_property;
pub mod no_unsafe;
pub mod no_will_update_set_state;
pub mod only_export_components;
pub mod prefer_es6_class;
pub mod react_in_jsx_scope;
Expand Down Expand Up @@ -1103,6 +1104,7 @@ oxc_macros::declare_all_lint_rules! {
react::no_unescaped_entities,
react::no_unknown_property,
react::no_unsafe,
react::no_will_update_set_state,
react::only_export_components,
react::prefer_es6_class,
react::react_in_jsx_scope,
Expand Down
19 changes: 9 additions & 10 deletions crates/oxc_linter/src/rules/react/no_unsafe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,20 +99,16 @@ impl Rule for NoUnsafe {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
match node.kind() {
AstKind::MethodDefinition(method_def) => {
let react_version = ctx.settings().react.version.as_ref();

if let Some(name) = method_def.key.static_name()
&& is_unsafe_method(name.as_ref(), self.0.check_aliases, react_version)
&& is_unsafe_method(name.as_ref(), self.0.check_aliases, ctx)
&& get_parent_component(node, ctx).is_some()
{
ctx.diagnostic(no_unsafe_diagnostic(name.as_ref(), method_def.key.span()));
}
}
AstKind::ObjectProperty(obj_prop) => {
let react_version = ctx.settings().react.version.as_ref();

if let Some(name) = obj_prop.key.static_name()
&& is_unsafe_method(name.as_ref(), self.0.check_aliases, react_version)
&& is_unsafe_method(name.as_ref(), self.0.check_aliases, ctx)
{
for ancestor in ctx.nodes().ancestors(node.id()) {
if is_es5_component(ancestor) {
Expand All @@ -135,10 +131,13 @@ impl Rule for NoUnsafe {
}

/// Check if a method name is an unsafe lifecycle method
fn is_unsafe_method(name: &str, check_aliases: bool, react_version: Option<&ReactVersion>) -> bool {
// React 16.3 introduced the UNSAFE_ prefixed lifecycle methods
let check_unsafe_prefix =
react_version.is_none_or(|v| v.major() > 16 || (v.major() == 16 && v.minor() >= 3));
fn is_unsafe_method(name: &str, check_aliases: bool, ctx: &LintContext) -> bool {
let check_unsafe_prefix = ctx
.settings()
.react
.version
.as_ref()
.is_none_or(ReactVersion::supports_unsafe_lifecycle_prefix);

match name {
"UNSAFE_componentWillMount"
Expand Down
Loading
Loading