Skip to content

Commit a3bb85e

Browse files
authored
feat(require-param): add interfaceExemptsParamsCheck option; fixes #1511 (#1521)
1 parent ae4e95d commit a3bb85e

File tree

5 files changed

+201
-2
lines changed

5 files changed

+201
-2
lines changed

.README/rules/require-param.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,15 @@ supplied as default values. Defaults to `false`.
374374
Set to `true` to ignore reporting when all params are missing. Defaults to
375375
`false`.
376376

377+
### `interfaceExemptsParamsCheck`
378+
379+
Set if you wish TypeScript interfaces to exempt checks for the existence of
380+
`@param`'s.
381+
382+
Will check for a type defining the function itself (on a variable
383+
declaration) or if there is a single destructured object with a type.
384+
Defaults to `false`.
385+
377386
## Context and settings
378387

379388
| | |
@@ -382,7 +391,7 @@ Set to `true` to ignore reporting when all params are missing. Defaults to
382391
| Tags | `param` |
383392
| Aliases | `arg`, `argument` |
384393
|Recommended | true|
385-
| Options |`autoIncrementBase`, `checkConstructors`, `checkDestructured`, `checkDestructuredRoots`, `checkGetters`, `checkRestProperty`, `checkSetters`, `checkTypesPattern`, `contexts`, `enableFixer`, `enableRestElementFixer`, `enableRootFixer`, `exemptedBy`, `ignoreWhenAllParamsMissing`, `unnamedRootBase`, `useDefaultObjectProperties`|
394+
| Options |`autoIncrementBase`, `checkConstructors`, `checkDestructured`, `checkDestructuredRoots`, `checkGetters`, `checkRestProperty`, `checkSetters`, `checkTypesPattern`, `contexts`, `enableFixer`, `enableRestElementFixer`, `enableRootFixer`, `exemptedBy`, `ignoreWhenAllParamsMissing`, `interfaceExemptsParamsCheck`, `unnamedRootBase`, `useDefaultObjectProperties`|
386395
| Settings | `ignoreReplacesDocs`, `overrideReplacesDocs`, `augmentsExtendsReplacesDocs`, `implementsReplacesDocs`|
387396

388397
## Failing examples

docs/rules/require-param.md

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* [`checkDestructuredRoots`](#user-content-require-param-options-checkdestructuredroots)
2525
* [`useDefaultObjectProperties`](#user-content-require-param-options-usedefaultobjectproperties)
2626
* [`ignoreWhenAllParamsMissing`](#user-content-require-param-options-ignorewhenallparamsmissing)
27+
* [`interfaceExemptsParamsCheck`](#user-content-require-param-options-interfaceexemptsparamscheck)
2728
* [Context and settings](#user-content-require-param-context-and-settings)
2829
* [Failing examples](#user-content-require-param-failing-examples)
2930
* [Passing examples](#user-content-require-param-passing-examples)
@@ -445,6 +446,17 @@ supplied as default values. Defaults to `false`.
445446
Set to `true` to ignore reporting when all params are missing. Defaults to
446447
`false`.
447448

449+
<a name="user-content-require-param-options-interfaceexemptsparamscheck"></a>
450+
<a name="require-param-options-interfaceexemptsparamscheck"></a>
451+
### <code>interfaceExemptsParamsCheck</code>
452+
453+
Set if you wish TypeScript interfaces to exempt checks for the existence of
454+
`@param`'s.
455+
456+
Will check for a type defining the function itself (on a variable
457+
declaration) or if there is a single destructured object with a type.
458+
Defaults to `false`.
459+
448460
<a name="user-content-require-param-context-and-settings"></a>
449461
<a name="require-param-context-and-settings"></a>
450462
## Context and settings
@@ -455,7 +467,7 @@ Set to `true` to ignore reporting when all params are missing. Defaults to
455467
| Tags | `param` |
456468
| Aliases | `arg`, `argument` |
457469
|Recommended | true|
458-
| Options |`autoIncrementBase`, `checkConstructors`, `checkDestructured`, `checkDestructuredRoots`, `checkGetters`, `checkRestProperty`, `checkSetters`, `checkTypesPattern`, `contexts`, `enableFixer`, `enableRestElementFixer`, `enableRootFixer`, `exemptedBy`, `ignoreWhenAllParamsMissing`, `unnamedRootBase`, `useDefaultObjectProperties`|
470+
| Options |`autoIncrementBase`, `checkConstructors`, `checkDestructured`, `checkDestructuredRoots`, `checkGetters`, `checkRestProperty`, `checkSetters`, `checkTypesPattern`, `contexts`, `enableFixer`, `enableRestElementFixer`, `enableRootFixer`, `exemptedBy`, `ignoreWhenAllParamsMissing`, `interfaceExemptsParamsCheck`, `unnamedRootBase`, `useDefaultObjectProperties`|
459471
| Settings | `ignoreReplacesDocs`, `overrideReplacesDocs`, `augmentsExtendsReplacesDocs`, `implementsReplacesDocs`|
460472

461473
<a name="user-content-require-param-failing-examples"></a>
@@ -1185,6 +1197,25 @@ function quux (a, b) {}
11851197
export type Test = (foo: number) => string;
11861198
// "jsdoc/require-param": ["error"|"warn", {"contexts":["TSFunctionType"]}]
11871199
// Message: Missing JSDoc @param "foo" declaration.
1200+
1201+
/**
1202+
*
1203+
*/
1204+
const quux = function quux (foo) {
1205+
};
1206+
// "jsdoc/require-param": ["error"|"warn", {"interfaceExemptsParamsCheck":true}]
1207+
// Message: Missing JSDoc @param "foo" declaration.
1208+
1209+
/**
1210+
*
1211+
*/
1212+
function quux ({
1213+
abc,
1214+
def
1215+
}) {
1216+
}
1217+
// "jsdoc/require-param": ["error"|"warn", {"interfaceExemptsParamsCheck":true}]
1218+
// Message: Missing JSDoc @param "root0" declaration.
11881219
````
11891220

11901221

@@ -1853,5 +1884,22 @@ function myFunction(foo: string): void;
18531884
*/
18541885
function myFunction(): void;
18551886
function myFunction(foo?: string) {}
1887+
1888+
/**
1889+
*
1890+
*/
1891+
const quux: FunctionInterface = function quux (foo) {
1892+
};
1893+
// "jsdoc/require-param": ["error"|"warn", {"interfaceExemptsParamsCheck":true}]
1894+
1895+
/**
1896+
*
1897+
*/
1898+
function quux ({
1899+
abc,
1900+
def
1901+
}: FunctionInterface) {
1902+
}
1903+
// "jsdoc/require-param": ["error"|"warn", {"interfaceExemptsParamsCheck":true}]
18561904
````
18571905

src/rules.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,7 @@ export interface Rules {
591591
enableRootFixer?: boolean;
592592
exemptedBy?: string[];
593593
ignoreWhenAllParamsMissing?: boolean;
594+
interfaceExemptsParamsCheck?: boolean;
594595
unnamedRootBase?: string[];
595596
useDefaultObjectProperties?: boolean;
596597
}

src/rules/requireParam.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const rootNamer = (desiredRoots, currentIndex) => {
3535
export default iterateJsdoc(({
3636
context,
3737
jsdoc,
38+
node,
3839
utils,
3940
}) => {
4041
/* eslint-enable complexity -- Temporary */
@@ -57,12 +58,28 @@ export default iterateJsdoc(({
5758
enableRestElementFixer = true,
5859
enableRootFixer = true,
5960
ignoreWhenAllParamsMissing = false,
61+
interfaceExemptsParamsCheck = false,
6062
unnamedRootBase = [
6163
'root',
6264
],
6365
useDefaultObjectProperties = false,
6466
} = context.options[0] || {};
6567

68+
if (interfaceExemptsParamsCheck) {
69+
if (node && 'params' in node && node.params.length === 1 &&
70+
node.params?.[0] && typeof node.params[0] === 'object' &&
71+
node.params[0].type === 'ObjectPattern' &&
72+
'typeAnnotation' in node.params[0] && node.params[0].typeAnnotation
73+
) {
74+
return;
75+
}
76+
77+
if (node && node.parent.type === 'VariableDeclarator' &&
78+
'typeAnnotation' in node.parent.id && node.parent.id.typeAnnotation) {
79+
return;
80+
}
81+
}
82+
6683
const preferredTagName = /** @type {string} */ (utils.getPreferredTagName({
6784
tagName: 'param',
6885
}));
@@ -579,6 +596,9 @@ export default iterateJsdoc(({
579596
ignoreWhenAllParamsMissing: {
580597
type: 'boolean',
581598
},
599+
interfaceExemptsParamsCheck: {
600+
type: 'boolean',
601+
},
582602
unnamedRootBase: {
583603
items: {
584604
type: 'string',

test/rules/assertions/requireParam.js

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2587,6 +2587,87 @@ export default /** @type {import('../index.js').TestCases} */ ({
25872587
export type Test = (foo: number) => string;
25882588
`,
25892589
},
2590+
{
2591+
code: `
2592+
/**
2593+
*
2594+
*/
2595+
const quux = function quux (foo) {
2596+
};
2597+
`,
2598+
errors: [
2599+
{
2600+
line: 2,
2601+
message: 'Missing JSDoc @param "foo" declaration.',
2602+
},
2603+
],
2604+
languageOptions: {
2605+
parser: typescriptEslintParser,
2606+
sourceType: 'module',
2607+
},
2608+
options: [
2609+
{
2610+
interfaceExemptsParamsCheck: true,
2611+
},
2612+
],
2613+
output: `
2614+
/**
2615+
*
2616+
* @param foo
2617+
*/
2618+
const quux = function quux (foo) {
2619+
};
2620+
`,
2621+
},
2622+
2623+
{
2624+
code: `
2625+
/**
2626+
*
2627+
*/
2628+
function quux ({
2629+
abc,
2630+
def
2631+
}) {
2632+
}
2633+
`,
2634+
errors: [
2635+
{
2636+
line: 2,
2637+
message: 'Missing JSDoc @param "root0" declaration.',
2638+
},
2639+
{
2640+
line: 2,
2641+
message: 'Missing JSDoc @param "root0.abc" declaration.',
2642+
},
2643+
{
2644+
line: 2,
2645+
message: 'Missing JSDoc @param "root0.def" declaration.',
2646+
},
2647+
],
2648+
languageOptions: {
2649+
parser: typescriptEslintParser,
2650+
sourceType: 'module',
2651+
},
2652+
options: [
2653+
{
2654+
interfaceExemptsParamsCheck: true,
2655+
},
2656+
],
2657+
output: `
2658+
/**
2659+
*
2660+
* @param root0
2661+
* @param root0.abc
2662+
* @param root0.def
2663+
*/
2664+
function quux ({
2665+
abc,
2666+
def
2667+
}) {
2668+
}
2669+
`,
2670+
},
25902671
],
25912672
valid: [
25922673
{
@@ -3695,5 +3776,45 @@ export default /** @type {import('../index.js').TestCases} */ ({
36953776
sourceType: 'module',
36963777
},
36973778
},
3779+
{
3780+
code: `
3781+
/**
3782+
*
3783+
*/
3784+
const quux: FunctionInterface = function quux (foo) {
3785+
};
3786+
`,
3787+
languageOptions: {
3788+
parser: typescriptEslintParser,
3789+
sourceType: 'module',
3790+
},
3791+
options: [
3792+
{
3793+
interfaceExemptsParamsCheck: true,
3794+
},
3795+
],
3796+
},
3797+
3798+
{
3799+
code: `
3800+
/**
3801+
*
3802+
*/
3803+
function quux ({
3804+
abc,
3805+
def
3806+
}: FunctionInterface) {
3807+
}
3808+
`,
3809+
languageOptions: {
3810+
parser: typescriptEslintParser,
3811+
sourceType: 'module',
3812+
},
3813+
options: [
3814+
{
3815+
interfaceExemptsParamsCheck: true,
3816+
},
3817+
],
3818+
},
36983819
],
36993820
});

0 commit comments

Comments
 (0)