Skip to content

Commit 51910df

Browse files
kapobajzaKapobajzacamc314
authored
feat(linter/jsdoc): Add missing options to require-param-type rule (#23418)
Closes #23371 ### AI usage disclosure I used Claude Code to generate this PR description. ### Summary Adds configuration support and a fixer to the `jsdoc/require-param-type` rule, matching `eslint-plugin-jsdoc`. **New options:** - `setDefaultDestructuredRootType` (default `false`). When `true`, auto-fixes a missing type on a destructured root `@param`. - `defaultDestructuredRootType` (default `"object"`). The type string used by that fix. --------- Co-authored-by: Kapobajza <kapobajza@gmail.com> Co-authored-by: Cameron Clark <cameron.clark@hey.com>
1 parent f592154 commit 51910df

4 files changed

Lines changed: 101 additions & 13 deletions

File tree

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -965,7 +965,7 @@ export interface DummyRuleMap {
965965
"jsdoc/require-param"?: DummyRule;
966966
"jsdoc/require-param-description"?: RuleNoConfig;
967967
"jsdoc/require-param-name"?: RuleNoConfig;
968-
"jsdoc/require-param-type"?: RuleNoConfig;
968+
"jsdoc/require-param-type"?: RuleNoConfig | [AllowWarnDeny, RequireParamTypeConfig];
969969
"jsdoc/require-property"?: RuleNoConfig;
970970
"jsdoc/require-property-description"?: RuleNoConfig;
971971
"jsdoc/require-property-name"?: RuleNoConfig;
@@ -2375,6 +2375,16 @@ export interface NoDefaultsConfig {
23752375
*/
23762376
noOptionalParamNames?: boolean;
23772377
}
2378+
export interface RequireParamTypeConfig {
2379+
/**
2380+
* The type string to set by default for destructured roots. Defaults to "object".
2381+
*/
2382+
defaultDestructuredRootType?: string;
2383+
/**
2384+
* Whether to set a default destructured root type. For example, you may wish to avoid manually having to set the type for a `@param` corresponding to a destructured root object as it is always going to be an object. Uses `defaultDestructuredRootType` for the type string. Defaults to `false`.
2385+
*/
2386+
setDefaultDestructuredRootType?: boolean;
2387+
}
23782388
export interface RequireReturnsConfig {
23792389
/**
23802390
* Whether to check constructor methods.

‎crates/oxc_linter/src/rules/jsdoc/require_param_type.rs‎

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1+
use schemars::JsonSchema;
2+
use serde::Deserialize;
3+
14
use oxc_ast::AstKind;
25
use oxc_diagnostics::OxcDiagnostic;
36
use oxc_macros::declare_oxc_lint;
47
use oxc_span::Span;
8+
use oxc_str::CompactStr;
59

610
use crate::{
711
AstNode,
812
context::LintContext,
9-
rule::Rule,
13+
rule::{DefaultRuleConfig, Rule},
1014
utils::{
1115
ParamKind, collect_params, get_function_nearest_jsdoc_node, should_ignore_as_internal,
1216
should_ignore_as_private,
@@ -19,8 +23,32 @@ fn missing_type_diagnostic(span: Span) -> OxcDiagnostic {
1923
.with_label(span)
2024
}
2125

26+
fn missing_root_type_diagnostic(span: Span, default_type: &CompactStr) -> OxcDiagnostic {
27+
OxcDiagnostic::warn("Missing root type for @param.")
28+
.with_help(format!("Add {{{default_type}}} to `@param` tag."))
29+
.with_label(span)
30+
}
31+
32+
#[derive(Debug, Clone, Deserialize, JsonSchema)]
33+
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
34+
pub struct RequireParamTypeConfig {
35+
/// The type string to set by default for destructured roots. Defaults to "object".
36+
default_destructured_root_type: CompactStr,
37+
/// Whether to set a default destructured root type. For example, you may wish to avoid manually having to set the type for a `@param` corresponding to a destructured root object as it is always going to be an object. Uses `defaultDestructuredRootType` for the type string. Defaults to `false`.
38+
set_default_destructured_root_type: bool,
39+
}
40+
41+
impl Default for RequireParamTypeConfig {
42+
fn default() -> Self {
43+
Self {
44+
default_destructured_root_type: CompactStr::from("object"),
45+
set_default_destructured_root_type: false,
46+
}
47+
}
48+
}
49+
2250
#[derive(Debug, Default, Clone)]
23-
pub struct RequireParamType;
51+
pub struct RequireParamType(Box<RequireParamTypeConfig>);
2452

2553
declare_oxc_lint!(
2654
/// ### What it does
@@ -48,11 +76,17 @@ declare_oxc_lint!(
4876
jsdoc,
4977
pedantic,
5078
pending,
79+
config = RequireParamTypeConfig,
5180
version = "0.4.4",
5281
short_description = "Requires that each `@param` tag has a type value (within curly brackets).",
5382
);
5483

5584
impl Rule for RequireParamType {
85+
fn from_configuration(value: serde_json::Value) -> Result<Self, serde_json::error::Error> {
86+
serde_json::from_value::<DefaultRuleConfig<RequireParamTypeConfig>>(value)
87+
.map(|config| Self(Box::new(config.into_inner())))
88+
}
89+
5690
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
5791
// Collected targets from `FormalParameters`
5892
let params_to_check = match node.kind() {
@@ -100,7 +134,20 @@ impl Rule for RequireParamType {
100134
continue;
101135
}
102136

103-
ctx.diagnostic(missing_type_diagnostic(tag.kind.span));
137+
let is_destructured_root =
138+
matches!(params_to_check.get(root_count - 1), Some(ParamKind::Nested(_)));
139+
140+
if self.0.set_default_destructured_root_type
141+
&& is_destructured_root
142+
&& name_part.is_some()
143+
{
144+
ctx.diagnostic(missing_root_type_diagnostic(
145+
tag.kind.span,
146+
&self.0.default_destructured_root_type,
147+
));
148+
} else {
149+
ctx.diagnostic(missing_type_diagnostic(tag.kind.span));
150+
}
104151
}
105152
}
106153
}
@@ -238,9 +285,7 @@ fn test() {
238285
239286
}
240287
",
241-
// TODO: support configurations for this rule
242-
// Some(serde_json::json!([ { "setDefaultDestructuredRootType": true } ])),
243-
None,
288+
Some(serde_json::json!([ { "setDefaultDestructuredRootType": true } ])),
244289
None,
245290
),
246291
(
@@ -254,9 +299,7 @@ fn test() {
254299
255300
}
256301
",
257-
// TODO: support configurations for this rule
258-
// Some(serde_json::json!([ { "setDefaultDestructuredRootType": false } ])),
259-
None,
302+
Some(serde_json::json!([ { "setDefaultDestructuredRootType": false } ])),
260303
None,
261304
),
262305
];

‎crates/oxc_linter/src/snapshots/jsdoc_require_param_type.snap‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ source: crates/oxc_linter/src/tester.rs
2929
╰────
3030
help: Add {type} to `@param` tag.
3131

32-
⚠ jsdoc(require-param-type): Missing JSDoc `@param` type.
32+
⚠ jsdoc(require-param-type): Missing root type for @param.
3333
╭─[require_param_type.tsx:4:17]
3434
3 │ * @param {number} foo
3535
4 │ * @param root
3636
· ──────
3737
5 │ * @param {boolean} baz
3838
╰────
39-
help: Add {type} to `@param` tag.
39+
help: Add {object} to `@param` tag.
4040

4141
⚠ jsdoc(require-param-type): Missing JSDoc `@param` type.
4242
╭─[require_param_type.tsx:4:17]

‎npm/oxlint/configuration_schema.json‎

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3500,7 +3500,24 @@
35003500
"$ref": "#/definitions/RuleNoConfig"
35013501
},
35023502
"jsdoc/require-param-type": {
3503-
"$ref": "#/definitions/RuleNoConfig"
3503+
"anyOf": [
3504+
{
3505+
"$ref": "#/definitions/RuleNoConfig"
3506+
},
3507+
{
3508+
"type": "array",
3509+
"items": [
3510+
{
3511+
"$ref": "#/definitions/AllowWarnDeny"
3512+
},
3513+
{
3514+
"$ref": "#/definitions/RequireParamTypeConfig"
3515+
}
3516+
],
3517+
"maxItems": 2,
3518+
"minItems": 2
3519+
}
3520+
]
35043521
},
35053522
"jsdoc/require-property": {
35063523
"$ref": "#/definitions/RuleNoConfig"
@@ -16919,6 +16936,24 @@
1691916936
},
1692016937
"additionalProperties": false
1692116938
},
16939+
"RequireParamTypeConfig": {
16940+
"type": "object",
16941+
"properties": {
16942+
"defaultDestructuredRootType": {
16943+
"description": "The type string to set by default for destructured roots. Defaults to \"object\".",
16944+
"default": "object",
16945+
"type": "string",
16946+
"markdownDescription": "The type string to set by default for destructured roots. Defaults to \"object\"."
16947+
},
16948+
"setDefaultDestructuredRootType": {
16949+
"description": "Whether to set a default destructured root type. For example, you may wish to avoid manually having to set the type for a `@param` corresponding to a destructured root object as it is always going to be an object. Uses `defaultDestructuredRootType` for the type string. Defaults to `false`.",
16950+
"default": false,
16951+
"type": "boolean",
16952+
"markdownDescription": "Whether to set a default destructured root type. For example, you may wish to avoid manually having to set the type for a `@param` corresponding to a destructured root object as it is always going to be an object. Uses `defaultDestructuredRootType` for the type string. Defaults to `false`."
16953+
}
16954+
},
16955+
"additionalProperties": false
16956+
},
1692216957
"RequireReturnsConfig": {
1692316958
"type": "object",
1692416959
"properties": {

0 commit comments

Comments
 (0)