diff --git a/apps/oxlint/fixtures/tsgolint_rule_options/.oxlintrc.json b/apps/oxlint/fixtures/tsgolint_rule_options/.oxlintrc.json index aa88ce0ee55a0..dd3f1f0b04f53 100644 --- a/apps/oxlint/fixtures/tsgolint_rule_options/.oxlintrc.json +++ b/apps/oxlint/fixtures/tsgolint_rule_options/.oxlintrc.json @@ -36,6 +36,12 @@ { "checkLiteralConstAssertions": false } + ], + "typescript/no-unsafe-member-access": [ + "error", + { + "allowOptionalChaining": true + } ] } } diff --git a/apps/oxlint/fixtures/tsgolint_rule_options/test.ts b/apps/oxlint/fixtures/tsgolint_rule_options/test.ts index f506fe56ec0e3..2efd9c4bdcd28 100644 --- a/apps/oxlint/fixtures/tsgolint_rule_options/test.ts +++ b/apps/oxlint/fixtures/tsgolint_rule_options/test.ts @@ -50,4 +50,11 @@ const notAllowedSpread = { ...notAllowedFunc }; // When checkLiteralConstAssertions is true, this SHOULD error const literalConst = 'hello' as const; -export { result, customStr, allowedSpread, notAllowedSpread, literalConst }; +// Test no-unsafe-member-access with allowOptionalChaining option +declare const anyValue: any; +// This should NOT error because allowOptionalChaining is true and we use ?. +const optionalAccess = anyValue?.foo; +// This SHOULD error because it's not using optional chaining +const unsafeAccess = anyValue.bar; + +export { result, customStr, allowedSpread, notAllowedSpread, literalConst, optionalAccess, unsafeAccess }; diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_rule_options_--type-aware@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_rule_options_--type-aware@oxlint.snap index 2b714c554fae7..795556a3dc830 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_rule_options_--type-aware@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_rule_options_--type-aware@oxlint.snap @@ -22,7 +22,15 @@ working directory: fixtures/tsgolint_rule_options 48 | `---- -Found 0 warnings and 2 errors. + x typescript-eslint(no-unsafe-member-access): Unsafe member access .bar on an `any` value. + ,-[test.ts:58:31] + 57 | // This SHOULD error because it's not using optional chaining + 58 | const unsafeAccess = anyValue.bar; + : ^^^ + 59 | + `---- + +Found 0 warnings and 3 errors. Finished in ms on 1 file using 1 threads. ---------- CLI result: LintFoundErrors diff --git a/crates/oxc_linter/src/rules/typescript/no_unsafe_member_access.rs b/crates/oxc_linter/src/rules/typescript/no_unsafe_member_access.rs index dd2b3d7a3f7a6..0b23b3f0b9056 100644 --- a/crates/oxc_linter/src/rules/typescript/no_unsafe_member_access.rs +++ b/crates/oxc_linter/src/rules/typescript/no_unsafe_member_access.rs @@ -1,9 +1,20 @@ use oxc_macros::declare_oxc_lint; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; -use crate::rule::Rule; +use crate::rule::{DefaultRuleConfig, Rule}; -#[derive(Debug, Default, Clone)] -pub struct NoUnsafeMemberAccess; +#[derive(Debug, Default, Clone, Deserialize)] +pub struct NoUnsafeMemberAccess(Box); + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)] +#[serde(rename_all = "camelCase", default)] +pub struct NoUnsafeMemberAccessConfig { + /// Whether to allow `?.` optional chains on `any` values. + /// When `true`, optional chaining on `any` values will not be flagged. + /// Default is `false`. + pub allow_optional_chaining: bool, +} declare_oxc_lint!( /// ### What it does @@ -52,6 +63,17 @@ declare_oxc_lint!( typescript, pedantic, pending, + config = NoUnsafeMemberAccessConfig, ); -impl Rule for NoUnsafeMemberAccess {} +impl Rule for NoUnsafeMemberAccess { + fn from_configuration(value: serde_json::Value) -> Self { + serde_json::from_value::>(value) + .unwrap_or_default() + .into_inner() + } + + fn to_configuration(&self) -> Option> { + Some(serde_json::to_value(&*self.0)) + } +}