Skip to content

feat(linter/jsdoc): Added missing options to jsdoc/require-param rule#23364

Merged
camc314 merged 8 commits into
oxc-project:mainfrom
kapobajza:feat/jsdoc-require-param-add-missing-options
Jul 2, 2026
Merged

feat(linter/jsdoc): Added missing options to jsdoc/require-param rule#23364
camc314 merged 8 commits into
oxc-project:mainfrom
kapobajza:feat/jsdoc-require-param-add-missing-options

Conversation

@kapobajza

@kapobajza kapobajza commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Partially addresses #23356

AI usage disclosure

I used Claude Code to generate the test cases from upstream, to verify my solutions, to help me find TS-related AST kinds, and to generate this PR description.

Summary

Adds three previously-missing options to the jsdoc/require-param rule, bringing it closer to parity with the upstream eslint-plugin-jsdoc rule:

  • ignoreWhenAllParamsMissing (default false) — when enabled, skips reporting if a function has no documented @param tags at all. Partially-documented functions are still checked.
  • interfaceExemptsParamsCheck (default false) — when enabled, exempts parameter checks when TypeScript type information is present: either the function is assigned to a variable with a type annotation (e.g. const quux: FunctionInterface = function (foo) {}), or its first parameter has a named type annotation (e.g. function quux({ abc }: FunctionInterface) {}).
  • useDefaultObjectProperties (default false) — when enabled, requires documentation for the properties of an object used as a default value for a destructured parameter, e.g. function fn({ prop = { a: 1, b: 2 } }) expects @param props.prop.a and @param props.prop.b.

This leaves autoIncrementBase and unnamedRootBase from #23356 for a follow-up.

Notes

  • The interfaceExemptsParamsCheck exemption logic was folded into the existing match node.kind() dispatch so that cargo lintgen still derives NODE_TYPES = [Function, ArrowFunctionExpression] (avoiding a perf regression from the rule running on every node).
  • useDefaultObjectProperties is threaded through collect_params / get_param_name in utils/jsdoc.rs; the sibling rules require-param-type and require-param-description pass false since the option is specific to require-param.

@kapobajza
kapobajza requested a review from camc314 as a code owner June 13, 2026 02:30
@codspeed-hq

codspeed-hq Bot commented Jun 13, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 5 untouched benchmarks
⏩ 66 skipped benchmarks1


Comparing kapobajza:feat/jsdoc-require-param-add-missing-options (3bb6041) with main (911c106)

Open in CodSpeed

Footnotes

  1. 66 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@kapobajza kapobajza changed the title feat(jsdoc): Added missing options to jsdoc/require-param rule feat(linter/jsdoc): Added missing options to jsdoc/require-param rule Jun 13, 2026
@xiaokhkh

Copy link
Copy Markdown
Contributor

One correctness detail on interfaceExemptsParamsCheck: is_first_fn_param_typed currently returns true for any first parameter whose type annotation is a TSTypeReference, so it can exempt normal typed parameters too, not just the typed destructured-object case described in the PR.

For example, if this is added as a failing case for jsdoc/require-param, the current branch passes it without reporting missing params:

/**
 *
 */
const quux = (foo: FunctionInterface, bar) => {
};

with:

[{ "interfaceExemptsParamsCheck": true }]

The test output is 1 test case expected to fail, but passed. I think is_first_fn_param_typed needs to also check that the first parameter is a destructured object pattern, and probably that it is the single parameter, before applying the exemption.

@camc314 camc314 added the A-linter Area - Linter label Jun 13, 2026
@camc314 camc314 self-assigned this Jun 13, 2026
@kapobajza

Copy link
Copy Markdown
Contributor Author

@xiaokhkh Hello. Thanks for the observations. Here's my response to it:

returns true for any first parameter whose type annotation is a TSTypeReference, so it can exempt normal typed parameters too, not just the typed destructured-object case described in the PR.

That's what I also thought, that I should only take into consideration destructured objects, because the description of the upstream rule states it:

Will check for a type defining the function itself (on a variable declaration) or if there is a single destructured object with a type. Defaults to false.

But then in the test cases of the upstream rule I found this test case. Additionally, the implementation only checks if the param has a type annotation. That's the reason why I also did it like that.

and probably that it is the single parameter

This actually also makes sense to me, because the description of the option, again, states it:

Will check for a type defining the function itself (on a variable declaration) or if there is a single destructured object with a type. Defaults to false.

But the implementation in the code is different, as far as I've seen there's no check anywhere if there's a single param.

I am not sure if my approach is the correct one, your points are also totally valid. I suggest that we wait and see what the maintainers say about it.

@camc314 camc314 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you!

@Sysix

Sysix commented Jun 18, 2026

Copy link
Copy Markdown
Member

@camc314 not sure why you committed b522b50, it broke the PR. I re-added them back in a67c083 + for other rule.
The upstream rules are sharing a iterateJsdoc helper https://github.com/gajus/eslint-plugin-jsdoc/blob/main/src/rules/requireParamDescription.js, so it should be safe for the second rule too 🤞

@Sysix
Sysix requested a review from camc314 June 18, 2026 17:35
@camc314

camc314 commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

@camc314 not sure why you committed b522b50, it broke the PR.

oops, wasn't deliberate - thanks for fixing

@camc314
camc314 merged commit 439c344 into oxc-project:main Jul 2, 2026
28 checks passed
camc314 added a commit that referenced this pull request Jul 3, 2026
…le (#23364)

Partially addresses #23356
### AI usage disclosure

I used Claude Code to generate the test cases from upstream, to verify
my solutions, to help me find TS-related AST kinds, and to generate this
PR description.

### Summary

Adds three previously-missing options to the `jsdoc/require-param` rule,
bringing it closer to parity with the upstream
[`eslint-plugin-jsdoc`](https://github.com/gajus/eslint-plugin-jsdoc)
rule:

- **`ignoreWhenAllParamsMissing`** (default `false`) — when enabled,
skips reporting if a function has no documented `@param` tags at all.
Partially-documented functions are still checked.
- **`interfaceExemptsParamsCheck`** (default `false`) — when enabled,
exempts parameter checks when TypeScript type information is present:
either the function is assigned to a variable with a type annotation
(e.g. `const quux: FunctionInterface = function (foo) {}`), or its first
parameter has a named type annotation (e.g. `function quux({ abc }:
FunctionInterface) {}`).
- **`useDefaultObjectProperties`** (default `false`) — when enabled,
requires documentation for the properties of an object used as a default
value for a destructured parameter, e.g. `function fn({ prop = { a: 1,
b: 2 } })` expects `@param props.prop.a` and `@param props.prop.b`.

This leaves `autoIncrementBase` and `unnamedRootBase` from #23356 for a
follow-up.

### Notes

- The `interfaceExemptsParamsCheck` exemption logic was folded into the
existing `match node.kind()` dispatch so that `cargo lintgen` still
derives `NODE_TYPES = [Function, ArrowFunctionExpression]` (avoiding a
perf regression from the rule running on every node).
- `useDefaultObjectProperties` is threaded through `collect_params` /
`get_param_name` in `utils/jsdoc.rs`; the sibling rules
`require-param-type` and `require-param-description` pass `false` since
the option is specific to `require-param`.

---------

Co-authored-by: Kapobajza <kapobajza@gmail.com>
Co-authored-by: Cameron Clark <cameron.clark@hey.com>
Co-authored-by: Sysix <sysix@sysix-coding.de>
camc314 added a commit that referenced this pull request Jul 3, 2026
…le (#23364)

Partially addresses #23356
### AI usage disclosure

I used Claude Code to generate the test cases from upstream, to verify
my solutions, to help me find TS-related AST kinds, and to generate this
PR description.

### Summary

Adds three previously-missing options to the `jsdoc/require-param` rule,
bringing it closer to parity with the upstream
[`eslint-plugin-jsdoc`](https://github.com/gajus/eslint-plugin-jsdoc)
rule:

- **`ignoreWhenAllParamsMissing`** (default `false`) — when enabled,
skips reporting if a function has no documented `@param` tags at all.
Partially-documented functions are still checked.
- **`interfaceExemptsParamsCheck`** (default `false`) — when enabled,
exempts parameter checks when TypeScript type information is present:
either the function is assigned to a variable with a type annotation
(e.g. `const quux: FunctionInterface = function (foo) {}`), or its first
parameter has a named type annotation (e.g. `function quux({ abc }:
FunctionInterface) {}`).
- **`useDefaultObjectProperties`** (default `false`) — when enabled,
requires documentation for the properties of an object used as a default
value for a destructured parameter, e.g. `function fn({ prop = { a: 1,
b: 2 } })` expects `@param props.prop.a` and `@param props.prop.b`.

This leaves `autoIncrementBase` and `unnamedRootBase` from #23356 for a
follow-up.

### Notes

- The `interfaceExemptsParamsCheck` exemption logic was folded into the
existing `match node.kind()` dispatch so that `cargo lintgen` still
derives `NODE_TYPES = [Function, ArrowFunctionExpression]` (avoiding a
perf regression from the rule running on every node).
- `useDefaultObjectProperties` is threaded through `collect_params` /
`get_param_name` in `utils/jsdoc.rs`; the sibling rules
`require-param-type` and `require-param-description` pass `false` since
the option is specific to `require-param`.

---------

Co-authored-by: Kapobajza <kapobajza@gmail.com>
Co-authored-by: Cameron Clark <cameron.clark@hey.com>
Co-authored-by: Sysix <sysix@sysix-coding.de>
Boshen added a commit that referenced this pull request Jul 6, 2026
# Oxlint
### 🚀 Features

- 7db7a29 allocator: Add `ReplaceWith` trait (#24012) (overlookmotel)
- a2c97f3 linter/unicorn: Implement `explicit-timer-delay` rule (#23612)
(Mikhail Baev)
- 85735cb linter/unicorn: Implement `no-confusing-array-with` rule
(#23638) (Shekhu☺️)
- cb4fbb9 linter/eslint: Implement no-unreachable-loop rule (#23975)
(Todor Andonov)
- dc32112 linter/eslint/no-constant-binary-expression: Check relational
comparisons (#24088) (camc314)
- 439c344 linter/jsdoc: Added missing options to `jsdoc/require-param`
rule (#23364) (kapobajza)
- 62af717 linter/unicorn/filename-case: Add `lowercase` and
`screamingSnakeCase` (#24045) (Boshen)
- d963967 linter/unicorn/no-array-sort: Add `allowAfterSpread` option
(#24043) (Boshen)
- 0a75682 linter: Add per-rule timings for type-aware linting (#22488)
(camchenry)
- 743e222 linter/react: Add `disallowedValues` option for
`forbid-dom-props` rule (#23970) (Mikhail Baev)

### 🐛 Bug Fixes

- 7b80010 linter: Use direct binding symbol ids (#24216) (camc314)
- 8f94b49 linter/import/no-duplicates: Don't flag a type-only import
beside a side-effect import (#24030) (Boshen)
- d8c3fee linter/react/rules-of-hooks: Flag `useEffectEvent` escapes
(#23764) (Rayan Salhab)
- 0a7312b linter/no-deprecated-functions: Map `require.requireActual` to
`jest.requireActual` (#23627) (Jerry Zhao)
- d9e3ab3 linter/eslint/no-useless-return: Handle switch case
continuation (#23984) (camc314)
- 0b25582 ast: Type binding node `typeAnnotation` as `TSTypeAnnotation |
null` (#23113) (Boshen)
- 122d112 linter/eslint/no-restricted-imports: Flag dynamic import()
expressions (#24029) (Boshen)
- 59b6b83 linter: Avoid `OnceLock` re-entry on cyclic `export *`
re-exports (#23632) (Jerry Zhao)
- dd09af0 linter/import/namespace: Avoid panic on destructuring of an
unresolvable namespace re-export (#23626) (Jerry Zhao)
- bdb51c7 linter/jest/prefer-ending-with-an-expect: Validate config
patterns (#24122) (camc314)
- e383843 linter/unicorn/prefer-modern-dom-apis: Skip fixer for non
identifier arguments (#23630) (Jerry Zhao)
- 0ac4c83 linter: Detect circular config extends (#24115) (camc314)
- bae1edf linter/import/namespace: Check namespace imports after named
imports (#24094) (camc314)
- cd8fdfe linter/eslint/no-eval: Recognize Array.from family thisArg
(#24091) (camc314)
- 851ee43 linter/eslint/no-eval: Resolve this binding for functions
returned from an IIFE (#23643) (Jerry Zhao)
- 002ab35 linter/unicorn: Avoid prefer-array-find rest destructuring
false positive (#23654) (ColemanDunn)
- 01c8775 linter/unicorn/filename-case: Keep digits attached in
screamingSnakeCase (#24056) (Boshen)
- f256941 linter: Recognize `@effect/vitest` as a vitest import source
(#24025) (Boshen)
- 73eeb1d linter/import/extensions: Honor per-extension `never` for
explicit extensions (#24031) (Boshen)
- d4ebe1f linter: Reject non-object oxlint config files (#24026)
(Boshen)
- 45d607d linter/react/forbid-component-props: Make allow/disallow lists
optional in schema (#24024) (Boshen)
- 54076ad linter/unicorn/no-array-for-each: Suggest entries loop for
index callbacks (#24004) (camc314)
- d057736 linter/jsdoc: Avoid param root underflow (#23945) (camc314)
- 29c76bf linter/unicorn/prefer-at: Skip object numeric-key access
(#23909) (Gaurav Dubey)

### ⚡ Performance

- 657a8fc linter/oxc/bad-array-method-on-arguments: Only run on member
expressions instead of all identifiers (#24164) (camchenry)
- 073d9e7 linter/eslint/prefer-rest-params: Run on functions instead of
all identifiers (#24163) (camchenry)
- e5a4162 linter/jest/no-confusing-set-timeout: Early exit fast path
(#24092) (camc314)
- bca7ce5 linter: Only run react-perf rules on JSX attribute nodes
(#24083) (camchenry)
- 6881bf6 linter: Compute `apply_overrides` rule set lazily (#23648)
(Jerry Zhao)
- 911c106 linter/eslint/no-obj-calls: Use resolved reference instead of
scope walk (#23895) (Marius Schulz)
- dc8fd9a linter/unicorn/prefer-dom-node-text-content: Change dispatch
to run only on less common node types (#23897) (Connor Shea)
- fdbd34d linter/eslint/no-useless-call: Fast-path static callees
(#24077) (camc314)
- b1be114 linter/import/extensions: Skip empty config and borrow
extensions (#24075) (camc314)
- 4781b2d linter/eslint/no-obj-calls: Use direct global matches (#24076)
(camc314)
- e6cee89 linter: Avoid node-chain allocation for non-Jest calls
(#23907) (Yagiz Nizipli)
- 30dc517 linter/typescript/no-restricted-types: O(1) banned-type
lookups (#23827) (Yagiz Nizipli)

### 📚 Documentation

- 6ca9125 linter/typescript: Clarify consistent-type-imports behavior
(#23972) (camc314)
# Oxfmt
### 🚀 Features

- 4f4313e formatter_css: Update oxc-css-parser 0.0.5 (#24120) (leaysgur)
- 0ccd8a1 formatter_graphql: Update oxc-graphql-parser 0.0.5 (#24106)
(leaysgur)
- 89ec3d9 formatter_core: Add literal line and root indention primitives
(#24051) (leaysgur)
- 213a96b formatter_core: Add no-expand-parent for multiline text
(#24050) (leaysgur)
- 0e5bcc9 formatter_graphql: Update oxc-graphql-parser 0.0.4 (#24039)
(leaysgur)
- e0b35a1 formatter_css: Update `oxc-css-parser@0.0.3` (#23974)
(leaysgur)

### 🐛 Bug Fixes

- 1fe6546 formatter: Omit unneeded `;` for type members with `no-semi`
(#24212) (leaysgur)
- 0ad7316 formatter: Print space for `ForStatement`.`update` only if
exists (#24211) (leaysgur)
- 3abbed5 formatter: Print `;` before jsdoc type-cast parens with
no-semi (#24208) (leaysgur)
- 9af3833 formatter_css: Make scss formatter consistent (#24207)
(leaysgur)
- 46d7194 formatter_css: Use fill IR for `@forward` members (#24206)
(leaysgur)
- e31038f formatter_css: Keep comment inside sass config list (#24205)
(leaysgur)
- d3b9591 formatter: Add parens around `await/yield` with `<T>` (#24202)
(leaysgur)
- 2121a55 oxfmt: Reuse tinypool process during the same LSP process
(#24197) (leaysgur)
- 9bf4b4a formatter_css: Align CSS output to Prettier 3.9.1 (#24100)
(leaysgur)
- cd2452e formatter_css: Align SCSS output to Prettier 3.9.1 (#24097)
(leaysgur)
- 4ee8745 formatter_css: Keep selector value contain line-break without
breaking line (#24055) (leaysgur)
- e1ece97 formatter_graphql: Break `implements` list by print-width
(#23997) (leaysgur)
- 0a6b16c formatter_json: Preserve key and literal value for
json-stringify (#23996) (leaysgur)
- 903ab6e formatter_css: Preserve newlines in css-in-js selector list
(#23992) (leaysgur)
- ea5d095 oxfmt: Update `--migrate prettier` (#23963) (leaysgur)

### ⚡ Performance

- 468e1e3 formatter_core: Make printer queues cursor-based (#24098)
(Boshen)
- c59f2fe rust: Return impl ExactSizeIterator from slice-backed
accessors (#24144) (Boshen)
- c292fb2 formatter: Inline fits element dispatcher (#23982) (camc314)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-linter Area - Linter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants