Skip to content

Commit 47d34a3

Browse files
feat(linter): add schema for react/jsx-handler-names (#23393)
Adds verified config schema generation for `react/jsx-handler-names`. Refs #22955.
1 parent 173cf31 commit 47d34a3

4 files changed

Lines changed: 136 additions & 6 deletions

File tree

‎apps/oxlint/src-js/package/config.generated.ts‎

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,7 @@ export interface DummyRuleMap {
13001300
"react/jsx-curly-brace-presence"?: DummyRule;
13011301
"react/jsx-filename-extension"?: AllowWarnDeny | [AllowWarnDeny] | [AllowWarnDeny, JsxFilenameExtensionConfig];
13021302
"react/jsx-fragments"?: AllowWarnDeny | [AllowWarnDeny] | [AllowWarnDeny, FragmentMode];
1303-
"react/jsx-handler-names"?: DummyRule;
1303+
"react/jsx-handler-names"?: AllowWarnDeny | [AllowWarnDeny] | [AllowWarnDeny, JsxHandlerNamesConfig];
13041304
"react/jsx-key"?: AllowWarnDeny | [AllowWarnDeny] | [AllowWarnDeny, JsxKeyConfig];
13051305
"react/jsx-max-depth"?: AllowWarnDeny | [AllowWarnDeny] | [AllowWarnDeny, JsxMaxDepthConfig];
13061306
"react/jsx-no-comment-textnodes"?: RuleNoConfig;
@@ -4386,6 +4386,28 @@ export interface JsxFilenameExtensionConfig {
43864386
*/
43874387
ignoreFilesWithoutCode?: boolean;
43884388
}
4389+
export interface JsxHandlerNamesConfig {
4390+
/**
4391+
* Whether to check for inline functions in JSX attributes.
4392+
*/
4393+
checkInlineFunction?: boolean;
4394+
/**
4395+
* Whether to check for local variables in JSX attributes.
4396+
*/
4397+
checkLocalVariables?: boolean;
4398+
/**
4399+
* Event handler prefixes to check against.
4400+
*/
4401+
eventHandlerPrefix?: string | false;
4402+
/**
4403+
* Event handler prop prefixes to check against.
4404+
*/
4405+
eventHandlerPropPrefix?: string | false;
4406+
/**
4407+
* Component names to ignore when checking for event handler prefixes.
4408+
*/
4409+
ignoreComponentNames?: string[];
4410+
}
43894411
export interface JsxKeyConfig {
43904412
/**
43914413
* When true, check fragment shorthand `<>` for keys

‎crates/oxc_linter/src/rules/react/jsx_handler_names.rs‎

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ use oxc_diagnostics::OxcDiagnostic;
1212
use oxc_macros::declare_oxc_lint;
1313
use oxc_span::Span;
1414
use oxc_str::CompactStr;
15-
use schemars::JsonSchema;
15+
use schemars::{
16+
JsonSchema, SchemaGenerator,
17+
schema::{Schema, SchemaObject, SubschemaValidation},
18+
};
1619
use serde_json::Value;
1720

1821
fn bad_handler_name_diagnostic(
@@ -53,24 +56,58 @@ fn bad_handler_prop_name_diagnostic(
5356
pub struct JsxHandlerNames(Box<JsxHandlerNamesConfig>);
5457

5558
#[derive(Debug, Clone, JsonSchema)]
56-
#[serde(rename_all = "camelCase", default)]
59+
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
5760
pub struct JsxHandlerNamesConfig {
5861
/// Whether to check for inline functions in JSX attributes.
62+
#[serde(rename = "checkInlineFunction")]
5963
check_inline_functions: bool,
6064
/// Whether to check for local variables in JSX attributes.
6165
check_local_variables: bool,
6266
/// Event handler prop prefixes to check against.
67+
#[serde(rename = "eventHandlerPropPrefix")]
68+
#[schemars(with = "HandlerPrefix")]
6369
event_handler_prop_prefixes: CompactStr,
6470
/// Event handler prefixes to check against.
71+
#[serde(rename = "eventHandlerPrefix")]
72+
#[schemars(with = "HandlerPrefix")]
6573
event_handler_prefixes: CompactStr,
6674
/// Component names to ignore when checking for event handler prefixes.
6775
ignore_component_names: Vec<CompactStr>,
6876
/// Compiled regex for event handler prefixes.
77+
#[schemars(skip)]
6978
event_handler_regex: Option<Regex>,
7079
/// Compiled regex for event handler prop prefixes.
80+
#[schemars(skip)]
7181
event_handler_prop_regex: Option<Regex>,
7282
}
7383

84+
#[derive(Debug)]
85+
struct HandlerPrefix;
86+
87+
impl JsonSchema for HandlerPrefix {
88+
fn schema_name() -> String {
89+
"HandlerPrefix".to_string()
90+
}
91+
92+
fn json_schema(r#gen: &mut SchemaGenerator) -> Schema {
93+
let mut false_schema = <bool as JsonSchema>::json_schema(r#gen).into_object();
94+
false_schema.const_value = Some(serde_json::Value::Bool(false));
95+
96+
SchemaObject {
97+
subschemas: Some(Box::new(SubschemaValidation {
98+
any_of: Some(vec![<String as JsonSchema>::json_schema(r#gen), false_schema.into()]),
99+
..Default::default()
100+
})),
101+
..Default::default()
102+
}
103+
.into()
104+
}
105+
106+
fn is_referenceable() -> bool {
107+
false
108+
}
109+
}
110+
74111
impl std::ops::Deref for JsxHandlerNames {
75112
type Target = JsxHandlerNamesConfig;
76113

‎crates/oxc_linter/src/utils/schemars.rs‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::rules::RuleEnum;
1313
/// These should return the DummyRule struct/schema instead of the actual rule struct/schema,
1414
/// until we verify that the rule's schema is valid and can be generated by schemars.
1515
#[cfg(feature = "ruledocs")]
16-
const NO_VERIFIED_VALID_SCHEMA: [&str; 19] = [
16+
const NO_VERIFIED_VALID_SCHEMA: [&str; 18] = [
1717
"eslint/func-name-matching", // second config can be on first position like [AllowWarnDeny, Config1, Config2] | [AllowWarnDeny, Config1] | [AllowWarnDeny, Config2]
1818
"eslint/no-restricted-globals", // uses spread syntax like [AllowWarnDeny, ...Config]
1919
"eslint/no-restricted-imports", // uses spread syntax like [AllowWarnDeny, ...Config]
@@ -31,7 +31,6 @@ const NO_VERIFIED_VALID_SCHEMA: [&str; 19] = [
3131
"jsx_a11y/no-noninteractive-element-interactions", // TS Generation generates ts 2411 error
3232
"eslint/prefer-destructuring",
3333
"react/jsx-curly-brace-presence",
34-
"react/jsx-handler-names",
3534
"react/jsx-no-script-url",
3635
];
3736

‎npm/oxlint/configuration_schema.json‎

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6254,7 +6254,24 @@
62546254
]
62556255
},
62566256
"react/jsx-handler-names": {
6257-
"$ref": "#/definitions/DummyRule"
6257+
"anyOf": [
6258+
{
6259+
"$ref": "#/definitions/AllowWarnDeny"
6260+
},
6261+
{
6262+
"type": "array",
6263+
"items": [
6264+
{
6265+
"$ref": "#/definitions/AllowWarnDeny"
6266+
},
6267+
{
6268+
"$ref": "#/definitions/JsxHandlerNamesConfig"
6269+
}
6270+
],
6271+
"maxItems": 2,
6272+
"minItems": 1
6273+
}
6274+
]
62586275
},
62596276
"react/jsx-key": {
62606277
"anyOf": [
@@ -11309,6 +11326,61 @@
1130911326
},
1131011327
"additionalProperties": false
1131111328
},
11329+
"JsxHandlerNamesConfig": {
11330+
"type": "object",
11331+
"properties": {
11332+
"checkInlineFunction": {
11333+
"description": "Whether to check for inline functions in JSX attributes.",
11334+
"default": false,
11335+
"type": "boolean",
11336+
"markdownDescription": "Whether to check for inline functions in JSX attributes."
11337+
},
11338+
"checkLocalVariables": {
11339+
"description": "Whether to check for local variables in JSX attributes.",
11340+
"default": false,
11341+
"type": "boolean",
11342+
"markdownDescription": "Whether to check for local variables in JSX attributes."
11343+
},
11344+
"eventHandlerPrefix": {
11345+
"description": "Event handler prefixes to check against.",
11346+
"default": "handle",
11347+
"anyOf": [
11348+
{
11349+
"type": "string"
11350+
},
11351+
{
11352+
"type": "boolean",
11353+
"const": false
11354+
}
11355+
],
11356+
"markdownDescription": "Event handler prefixes to check against."
11357+
},
11358+
"eventHandlerPropPrefix": {
11359+
"description": "Event handler prop prefixes to check against.",
11360+
"default": "on",
11361+
"anyOf": [
11362+
{
11363+
"type": "string"
11364+
},
11365+
{
11366+
"type": "boolean",
11367+
"const": false
11368+
}
11369+
],
11370+
"markdownDescription": "Event handler prop prefixes to check against."
11371+
},
11372+
"ignoreComponentNames": {
11373+
"description": "Component names to ignore when checking for event handler prefixes.",
11374+
"default": [],
11375+
"type": "array",
11376+
"items": {
11377+
"type": "string"
11378+
},
11379+
"markdownDescription": "Component names to ignore when checking for event handler prefixes."
11380+
}
11381+
},
11382+
"additionalProperties": false
11383+
},
1131211384
"JsxKeyConfig": {
1131311385
"type": "object",
1131411386
"properties": {

0 commit comments

Comments
 (0)