diff --git a/crates/oxc_linter/src/rules/eslint/prefer_destructuring.rs b/crates/oxc_linter/src/rules/eslint/prefer_destructuring.rs index 16134be966bf6..208fe128a8c10 100644 --- a/crates/oxc_linter/src/rules/eslint/prefer_destructuring.rs +++ b/crates/oxc_linter/src/rules/eslint/prefer_destructuring.rs @@ -5,6 +5,8 @@ use oxc_ast::{ use oxc_diagnostics::OxcDiagnostic; use oxc_macros::declare_oxc_lint; use oxc_span::{GetSpan, Span}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; use serde_json::Value; use crate::{AstNode, context::LintContext, rule::Rule}; @@ -21,7 +23,8 @@ fn prefer_array_destructuring(span: Span) -> OxcDiagnostic { .with_label(span) } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, JsonSchema, Deserialize, Serialize)] +#[serde(rename_all = "camelCase", default)] struct Config { array: bool, object: bool, @@ -33,10 +36,16 @@ impl Default for Config { } } -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, JsonSchema, Deserialize, Serialize)] +#[serde(rename_all = "camelCase", default)] pub struct PreferDestructuring { + /// Configuration for destructuring in variable declarations, configured for arrays and objects independently. + #[serde(rename = "VariableDeclarator")] variable_declarator: Config, + /// Configuration for destructuring in assignment expressions, configured for arrays and objects independently. + #[serde(rename = "AssignmentExpression")] assignment_expression: Config, + /// Determines whether the object destructuring rule applies to renamed variables. enforce_for_renamed_properties: bool, } @@ -74,45 +83,11 @@ declare_oxc_lint!( /// const { baz } = object; /// const obj = object.bar; /// ``` - /// - /// ### Options - /// - /// This rule takes two arguments, both of which are objects. - /// The first object parameter determines what types of destructuring the rule applies to. - /// In the first object, there are two properties, array and object, - /// that can be used to turn on or off the destructuring requirement for each of those types independently. - /// By default, both are true. - /// - /// ```json - /// { - /// "prefer-destructuring": ["error", { "array": true, "object": true }] - /// } - /// ``` - /// - /// Alternatively, you can use separate configurations for different assignment types. - /// The first argument accepts two other keys instead of array and object. - /// One key is VariableDeclarator and the other is AssignmentExpression, - /// which can be used to control the destructuring requirement for each of those types independently - /// - /// ```json - /// { - /// "prefer-destructuring": ["error", { "VariableDeclarator": { "array": true, "object": true }, "AssignmentExpression": { "array": true, "object": true } }] - /// } - /// ``` - /// - /// #### enforceForRenamedProperties - /// The rule has a second object argument with a single key, - /// enforceForRenamedProperties, which determines whether the object destructuring applies to renamed variables. - /// - /// ```json - /// { - /// "prefer-destructuring": ["error", { "array": true, "object": true }, { "enforceForRenamedProperties": true }] - /// } - /// ``` PreferDestructuring, eslint, style, pending, + config = PreferDestructuring, ); impl Rule for PreferDestructuring { diff --git a/crates/oxc_linter/src/rules/jsx_a11y/mouse_events_have_key_events.rs b/crates/oxc_linter/src/rules/jsx_a11y/mouse_events_have_key_events.rs index 958ea8ec7bb2d..f37ec604cb6af 100644 --- a/crates/oxc_linter/src/rules/jsx_a11y/mouse_events_have_key_events.rs +++ b/crates/oxc_linter/src/rules/jsx_a11y/mouse_events_have_key_events.rs @@ -2,6 +2,7 @@ use oxc_ast::{AstKind, ast::JSXAttributeValue}; use oxc_diagnostics::OxcDiagnostic; use oxc_macros::declare_oxc_lint; use oxc_span::{CompactStr, GetSpan, Span}; +use schemars::JsonSchema; use crate::{ AstNode, @@ -26,9 +27,12 @@ fn miss_on_blur(span: Span, attr_name: &str) -> OxcDiagnostic { #[derive(Debug, Default, Clone)] pub struct MouseEventsHaveKeyEvents(Box); -#[derive(Debug, Clone)] +#[derive(Debug, Clone, JsonSchema)] +#[serde(rename_all = "camelCase", default)] pub struct MouseEventsHaveKeyEventsConfig { + /// List of hover-in mouse event handlers that require corresponding keyboard event handlers. hover_in_handlers: Vec, + /// List of hover-out mouse event handlers that require corresponding keyboard event handlers. hover_out_handlers: Vec, } @@ -44,12 +48,12 @@ impl Default for MouseEventsHaveKeyEventsConfig { declare_oxc_lint!( /// ### What it does /// - /// Enforce onmouseover/onmouseout are accompanied by onfocus/onblur. + /// Enforce onMouseOver/onMouseOut are accompanied by onFocus/onBlur. /// /// ### Why is this bad? /// /// Coding for the keyboard is important for users with physical disabilities who cannot use a mouse, - /// AT compatibility, and screenreader users. + /// AT compatibility, and screen reader users. /// /// ### Examples /// @@ -64,7 +68,8 @@ declare_oxc_lint!( /// ``` MouseEventsHaveKeyEvents, jsx_a11y, - correctness + correctness, + config = MouseEventsHaveKeyEventsConfig, ); impl Rule for MouseEventsHaveKeyEvents { diff --git a/crates/oxc_linter/src/rules/react/jsx_no_target_blank.rs b/crates/oxc_linter/src/rules/react/jsx_no_target_blank.rs index ef6fb2bd9b464..9c216d7882fe9 100644 --- a/crates/oxc_linter/src/rules/react/jsx_no_target_blank.rs +++ b/crates/oxc_linter/src/rules/react/jsx_no_target_blank.rs @@ -10,6 +10,8 @@ use oxc_ast::{ use oxc_diagnostics::OxcDiagnostic; use oxc_macros::declare_oxc_lint; use oxc_span::{CompactStr, GetSpan, Span}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; use crate::{ AstNode, @@ -35,17 +37,25 @@ fn explicit_props_in_spread_attributes(span: Span) -> OxcDiagnostic { .with_label(span) } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, JsonSchema, Deserialize, Serialize)] +#[serde(rename_all = "camelCase", default)] pub struct JsxNoTargetBlank { + /// Whether to enforce dynamic links or enforce static links. enforce_dynamic_links: EnforceDynamicLinksEnum, + /// Whether to warn when spread attributes are used. warn_on_spread_attributes: bool, + /// Whether to allow referrers. allow_referrer: bool, + /// Whether to check link elements. links: bool, + /// Whether to check form elements. forms: bool, } -#[derive(Debug, Clone)] +#[derive(Debug, Default, Clone, JsonSchema, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] enum EnforceDynamicLinksEnum { + #[default] Always, Never, } @@ -129,7 +139,8 @@ declare_oxc_lint!( /// [`noopener` docs]: https://html.spec.whatwg.org/multipage/links.html#link-type-noopener JsxNoTargetBlank, react, - correctness + correctness, + config = JsxNoTargetBlank, ); impl Rule for JsxNoTargetBlank { diff --git a/crates/oxc_linter/src/rules/react/only_export_components.rs b/crates/oxc_linter/src/rules/react/only_export_components.rs index ba337d31e6c2c..3a002a398adb1 100644 --- a/crates/oxc_linter/src/rules/react/only_export_components.rs +++ b/crates/oxc_linter/src/rules/react/only_export_components.rs @@ -4,6 +4,7 @@ use oxc_macros::declare_oxc_lint; use oxc_semantic::NodeId; use oxc_span::{GetSpan, Span}; use rustc_hash::FxHashSet; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use crate::{context::LintContext, rule::Rule}; @@ -67,14 +68,33 @@ pub struct OnlyExportComponentsConfig { check_js: bool, } -#[derive(Debug, Deserialize, Serialize)] +// NOTE: Ensure this is always kept in sync with OnlyExportComponentsConfig +#[derive(Debug, Default, Deserialize, Serialize, JsonSchema)] +#[serde(default)] struct OnlyExportComponentsOptionsJson { + /// Treat specific named exports as HMR-safe (useful for frameworks that hot-replace + /// certain exports). For example, in Remix: + /// `{ "allowExportNames": ["meta", "links", "headers", "loader", "action"] }` #[serde(rename = "allowExportNames")] allow_export_names: Option>, + /// Allow exporting primitive constants (string/number/boolean/template literal) + /// alongside component exports without triggering a violation. Recommended when your + /// bundler’s Fast Refresh integration supports this (enabled by the plugin’s `vite` + /// preset). + /// + /// ```jsx + /// // Allowed when allowConstantExport: true + /// export const VERSION = "3"; + /// export const Foo = () => null; + /// ``` #[serde(rename = "allowConstantExport")] allow_constant_export: Option, + /// If you export components wrapped in custom higher-order components, list their + /// identifiers here to avoid false positives. #[serde(rename = "customHOCs")] custom_hocs: Option>, + /// Check `.js` files that contain JSX (in addition to `.tsx`/`.jsx`). To reduce + /// false positives, only files that import React are checked when this is enabled. #[serde(rename = "checkJS")] check_js: Option, } @@ -153,80 +173,10 @@ declare_oxc_lint!( /// import { App } from "./App"; /// createRoot(document.getElementById("root")).render(); /// ``` - /// - /// ### Options (or not) - /// - /// #### allowExportNames - /// - /// `{ type: string[], default: [] }` - /// - /// Treat specific named exports as HMR-safe (useful for frameworks that hot-replace - /// certain exports). For example, in Remix: - /// - /// ```json - /// { - /// "react/only-export-components": [ - /// "error", - /// { "allowExportNames": ["meta", "links", "headers", "loader", "action"] } - /// ] - /// } - /// ``` - /// - /// #### allowConstantExport - /// - /// `{ type: boolean, default: false }` - /// - /// Allow exporting primitive constants (string/number/boolean/template literal) - /// alongside component exports without triggering a violation. Recommended when your - /// bundler’s Fast Refresh integration supports this (enabled by the plugin’s `vite` - /// preset). - /// - /// ```json - /// { - /// "react/only-export-components": [ - /// "error", - /// { "allowConstantExport": true } - /// ] - /// } - /// ``` - /// - /// ```jsx - /// // Allowed when allowConstantExport: true - /// export const VERSION = "3"; - /// export const Foo = () => null; - /// ``` - /// - /// #### customHOCs - /// - /// `{ type: string[], default: [] }` - /// - /// If you export components wrapped in custom higher-order components, list their - /// identifiers here to avoid false positives: - /// - /// ```json - /// { - /// "react/only-export-components": [ - /// "error", - /// { "customHOCs": ["observer", "withAuth"] } - /// ] - /// } - /// ``` - /// - /// #### checkJS - /// - /// `{ type: boolean, default: false }` - /// - /// Check `.js` files that contain JSX (in addition to `.tsx`/`.jsx`). To reduce - /// false positives, only files that import React are checked when this is enabled. - /// - /// ```json - /// { - /// "react/only-export-components": ["error", { "checkJS": true }] - /// } - /// ``` OnlyExportComponents, react, - restriction + restriction, + config = OnlyExportComponentsOptionsJson, ); static DEFAULT_REACT_HOCS: &[&str] = &["memo", "forwardRef"];