diff --git a/crates/oxc_linter/src/generated/rule_runner_impls.rs b/crates/oxc_linter/src/generated/rule_runner_impls.rs index 8e9028adc624c..1df3cfb017e09 100644 --- a/crates/oxc_linter/src/generated/rule_runner_impls.rs +++ b/crates/oxc_linter/src/generated/rule_runner_impls.rs @@ -3194,7 +3194,7 @@ impl RuleRunner for crate::rules::unicorn::prefer_classlist_toggle::PreferClassl impl RuleRunner for crate::rules::unicorn::prefer_code_point::PreferCodePoint { const NODE_TYPES: Option<&AstTypesBitset> = - Some(&AstTypesBitset::from_types(&[AstType::CallExpression])); + Some(&AstTypesBitset::from_types(&[AstType::StaticMemberExpression])); const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run; } diff --git a/crates/oxc_linter/src/rules/unicorn/prefer_code_point.rs b/crates/oxc_linter/src/rules/unicorn/prefer_code_point.rs index b67af752f662c..ae4a8ef152767 100644 --- a/crates/oxc_linter/src/rules/unicorn/prefer_code_point.rs +++ b/crates/oxc_linter/src/rules/unicorn/prefer_code_point.rs @@ -47,21 +47,31 @@ declare_oxc_lint!( impl Rule for PreferCodePoint { fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { - let AstKind::CallExpression(call_expr) = node.kind() else { + let AstKind::StaticMemberExpression(member_expr) = node.kind() else { return; }; - let Some(memb_expr) = call_expr.callee.as_member_expression() else { - return; - }; - - if memb_expr.is_computed() || memb_expr.optional() || call_expr.optional { - return; - } - - let (current, replacement, span) = match memb_expr.static_property_info() { - Some((span, "charCodeAt")) => ("charCodeAt", "codePointAt", span), - Some((span, "fromCharCode")) => ("fromCharCode", "fromCodePoint", span), + let (span, property_name) = member_expr.static_property_info(); + let (current, replacement) = match property_name { + "fromCharCode" => { + if !member_expr.object.is_specific_id("String") { + return; + } + ("fromCharCode", "fromCodePoint") + } + "charCodeAt" => { + let AstKind::CallExpression(call_expr) = ctx.nodes().parent_kind(node.id()) else { + return; + }; + if call_expr.optional + || call_expr.callee.as_member_expression().and_then(|callee| { + callee.static_property_info().map(|(_, property_name)| property_name) + }) != Some("charCodeAt") + { + return; + } + ("charCodeAt", "codePointAt") + } _ => return, }; @@ -82,12 +92,12 @@ fn test() { "new foo.charCodeAt", "charCodeAt(0)", "foo.charCodeAt?.(0)", - "foo?.charCodeAt(0)", "foo[charCodeAt](0)", r#"foo["charCodeAt"](0)"#, "foo.notCharCodeAt(0)", "String.fromCodePoint(0x1f984)", "String.fromCodePoint", + "NotString.fromCharCode(foo)", "new String.fromCodePoint", "fromCodePoint(foo)", "String.fromCodePoint?.(foo)", @@ -101,9 +111,12 @@ fn test() { let fail = vec![ "string.charCodeAt(index)", + "string?.charCodeAt(index)", "(( (( string )).charCodeAt( ((index)), )))", "String.fromCharCode( code )", "(( (( String )).fromCharCode( ((code)), ) ))", + "String.fromCharCode.bind(String)", + "const x = String.fromCharCode", ]; let fix = vec![ @@ -112,6 +125,8 @@ fn test() { "(( (( String )).fromCharCode( ((code)), ) ))", "(( (( String )).fromCodePoint( ((code)), ) ))", ), + ("String.fromCharCode.bind(String)", "String.fromCodePoint.bind(String)"), + ("const x = String.fromCharCode", "const x = String.fromCodePoint"), (r#""๐Ÿฆ„".charCodeAt(0)"#, r#""๐Ÿฆ„".codePointAt(0)"#), ("String.fromCharCode(0x1f984);", "String.fromCodePoint(0x1f984);"), ]; diff --git a/crates/oxc_linter/src/snapshots/unicorn_prefer_code_point.snap b/crates/oxc_linter/src/snapshots/unicorn_prefer_code_point.snap index 592f08f420483..07a91c0f16f55 100644 --- a/crates/oxc_linter/src/snapshots/unicorn_prefer_code_point.snap +++ b/crates/oxc_linter/src/snapshots/unicorn_prefer_code_point.snap @@ -9,6 +9,13 @@ source: crates/oxc_linter/src/tester.rs โ•ฐโ”€โ”€โ”€โ”€ help: Unicode is better supported in `codePointAt` than `charCodeAt` + โš  eslint-plugin-unicorn(prefer-code-point): Prefer `codePointAt` over `charCodeAt` + โ•ญโ”€[prefer_code_point.tsx:1:9] + 1 โ”‚ string?.charCodeAt(index) + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Unicode is better supported in `codePointAt` than `charCodeAt` + โš  eslint-plugin-unicorn(prefer-code-point): Prefer `codePointAt` over `charCodeAt` โ•ญโ”€[prefer_code_point.tsx:1:17] 1 โ”‚ (( (( string )).charCodeAt( ((index)), ))) @@ -29,3 +36,17 @@ source: crates/oxc_linter/src/tester.rs ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ•ฐโ”€โ”€โ”€โ”€ help: Unicode is better supported in `fromCodePoint` than `fromCharCode` + + โš  eslint-plugin-unicorn(prefer-code-point): Prefer `fromCodePoint` over `fromCharCode` + โ•ญโ”€[prefer_code_point.tsx:1:8] + 1 โ”‚ String.fromCharCode.bind(String) + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Unicode is better supported in `fromCodePoint` than `fromCharCode` + + โš  eslint-plugin-unicorn(prefer-code-point): Prefer `fromCodePoint` over `fromCharCode` + โ•ญโ”€[prefer_code_point.tsx:1:18] + 1 โ”‚ const x = String.fromCharCode + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Unicode is better supported in `fromCodePoint` than `fromCharCode`