Skip to content

Commit 428174d

Browse files
authored
fix(require-param, check-param-names): check deeply destructured parameters (fixes #569) (#630)
* test: add test case * fix: destructuring false errors of require-param rule. * test: fix test case * docs: update README * refactor: resolve conflict with another rule * test: add invalid test case * docs: update README * refactor: fix to improve performence * test: add detailed case for added code * test: add nested test case * fix(`check-param-name`): fix up destructuring false errors The error mentioned in issue #569 also occurred in `check-param-name` rule. So I fixed.
1 parent dd4a985 commit 428174d

File tree

5 files changed

+376
-1
lines changed

5 files changed

+376
-1
lines changed

README.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2132,6 +2132,31 @@ function quux ({foo, bar}, baz) {
21322132
}
21332133
// Options: [{"checkDestructured":false}]
21342134
// Message: Expected @param names to be "root, baz". Got "root, foo".
2135+
2136+
/**
2137+
* Description.
2138+
* @param {Object} options
2139+
* @param {FooBar} foo
2140+
*/
2141+
function quux ({ foo: { bar } }) {}
2142+
// Message: Missing @param "options.foo"
2143+
2144+
/**
2145+
* Description.
2146+
* @param {Object} options
2147+
* @param options.foo
2148+
*/
2149+
function quux ({ foo: { bar } }) {}
2150+
// Message: Missing @param "options.foo.bar"
2151+
2152+
/**
2153+
* Description.
2154+
* @param {object} options Options.
2155+
* @param {object} options.foo A description.
2156+
* @param {object} options.foo.bar
2157+
*/
2158+
function foo({ foo: { bar: { baz } }}) {}
2159+
// Message: Missing @param "options.foo.bar.baz"
21352160
````
21362161

21372162
The following patterns are not considered problems:
@@ -2408,6 +2433,29 @@ class A {
24082433
{
24092434
}
24102435
}
2436+
2437+
/**
2438+
* Description.
2439+
* @param {Object} options Options.
2440+
* @param {FooBar} options.foo foo description.
2441+
*/
2442+
function quux ({ foo: { bar }}) {}
2443+
2444+
/**
2445+
* Description.
2446+
* @param {FooBar} options
2447+
* @param {Object} options.foo
2448+
*/
2449+
function quux ({ foo: { bar } }) {}
2450+
// Options: [{"checkTypesPattern":"FooBar"}]
2451+
2452+
/**
2453+
* Description.
2454+
* @param {Object} options
2455+
* @param {FooBar} options.foo
2456+
* @param {FooBar} options.baz
2457+
*/
2458+
function quux ({ foo: { bar }, baz: { cfg } }) {}
24112459
````
24122460

24132461

@@ -11595,6 +11643,48 @@ module.exports = class GraphQL {
1159511643
}
1159611644
})();
1159711645
// Message: Missing JSDoc @param "param" declaration.
11646+
11647+
/**
11648+
* Description.
11649+
* @param {Object} options
11650+
* @param {Object} options.foo
11651+
*/
11652+
function quux ({ foo: { bar } }) {}
11653+
// Message: Missing JSDoc @param "options.foo.bar" declaration.
11654+
11655+
/**
11656+
* Description.
11657+
* @param {FooBar} options
11658+
* @param {FooBar} options.foo
11659+
*/
11660+
function quux ({ foo: { bar } }) {}
11661+
// Options: [{"checkTypesPattern":"FooBar"}]
11662+
// Message: Missing JSDoc @param "options.foo.bar" declaration.
11663+
11664+
/**
11665+
* Description.
11666+
* @param {Object} options
11667+
* @param {FooBar} foo
11668+
*/
11669+
function quux ({ foo: { bar } }) {}
11670+
// Message: Missing JSDoc @param "options.foo" declaration.
11671+
11672+
/**
11673+
* Description.
11674+
* @param {Object} options
11675+
* @param options.foo
11676+
*/
11677+
function quux ({ foo: { bar } }) {}
11678+
// Message: Missing JSDoc @param "options.foo.bar" declaration.
11679+
11680+
/**
11681+
* Description.
11682+
* @param {object} options Options.
11683+
* @param {object} options.foo A description.
11684+
* @param {object} options.foo.bar
11685+
*/
11686+
function foo({ foo: { bar: { baz } }}) {}
11687+
// Message: Missing JSDoc @param "options.foo.bar.baz" declaration.
1159811688
````
1159911689

1160011690
The following patterns are not considered problems:
@@ -12169,6 +12259,21 @@ function quux ({foo: bar}) {
1216912259
module.exports = function a(b) {
1217012260
console.info(b);
1217112261
};
12262+
12263+
/**
12264+
* Description.
12265+
* @param {Object} options Options.
12266+
* @param {FooBar} options.foo foo description.
12267+
*/
12268+
function quux ({ foo: { bar } }) {}
12269+
12270+
/**
12271+
* Description.
12272+
* @param {FooBar} options
12273+
* @param {Object} options.foo
12274+
*/
12275+
function quux ({ foo: { bar } }) {}
12276+
// Options: [{"checkTypesPattern":"FooBar"}]
1217212277
````
1217312278

1217412279

src/rules/checkParamNames.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,29 @@ const validateParameterNames = (
7878
const actualNames = paramTags.map(([, paramTag]) => {
7979
return paramTag.name.trim();
8080
});
81+
const actualTypes = paramTags.map(([, paramTag]) => {
82+
return paramTag.type;
83+
});
8184

8285
const missingProperties = [];
86+
const notCheckingNames = [];
8387

8488
expectedNames.forEach((name, idx) => {
85-
if (!actualNames.some(utils.comparePaths(name))) {
89+
if (notCheckingNames.some((notCheckingName) => {
90+
return name.startsWith(notCheckingName);
91+
})) {
92+
return;
93+
}
94+
const actualNameIdx = actualNames.findIndex((actualName) => {
95+
return utils.comparePaths(name)(actualName);
96+
});
97+
if (actualNameIdx === -1) {
8698
if (!checkRestProperty && rests[idx]) {
8799
return;
88100
}
89101
missingProperties.push(name);
102+
} else if (actualTypes[actualNameIdx].search(checkTypesRegex) === -1 && actualTypes[actualNameIdx] !== '') {
103+
notCheckingNames.push(name);
90104
}
91105
});
92106

src/rules/requireParam.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ export default iterateJsdoc(({
130130
}
131131

132132
const {hasRestElement, hasPropertyRest, rests, names} = functionParameterName[1];
133+
const notCheckingNames = [];
133134
if (!enableRestElementFixer && hasRestElement) {
134135
return;
135136
}
@@ -178,6 +179,20 @@ export default iterateJsdoc(({
178179

179180
const fullParamName = `${rootName}.${paramName}`;
180181

182+
const notCheckingName = jsdocParameterNames.find(({name, type: paramType}) => {
183+
return utils.comparePaths(name)(fullParamName) && paramType.search(checkTypesRegex) === -1 && paramType !== '';
184+
});
185+
186+
if (notCheckingName !== undefined) {
187+
notCheckingNames.push(notCheckingName.name);
188+
}
189+
190+
if (notCheckingNames.find((name) => {
191+
return fullParamName.startsWith(name);
192+
})) {
193+
return;
194+
}
195+
181196
if (jsdocParameterNames && !jsdocParameterNames.find(({name}) => {
182197
return utils.comparePaths(name)(fullParamName);
183198
})) {

test/rules/assertions/checkParamNames.js

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,55 @@ export default {
894894
checkDestructured: false,
895895
}],
896896
},
897+
{
898+
code: `
899+
/**
900+
* Description.
901+
* @param {Object} options
902+
* @param {FooBar} foo
903+
*/
904+
function quux ({ foo: { bar } }) {}
905+
`,
906+
errors: [
907+
{
908+
message: 'Missing @param "options.foo"',
909+
},
910+
{
911+
message: 'Missing @param "options.foo.bar"',
912+
},
913+
],
914+
},
915+
{
916+
code: `
917+
/**
918+
* Description.
919+
* @param {Object} options
920+
* @param options.foo
921+
*/
922+
function quux ({ foo: { bar } }) {}
923+
`,
924+
errors: [
925+
{
926+
message: 'Missing @param "options.foo.bar"',
927+
},
928+
],
929+
},
930+
{
931+
code: `
932+
/**
933+
* Description.
934+
* @param {object} options Options.
935+
* @param {object} options.foo A description.
936+
* @param {object} options.foo.bar
937+
*/
938+
function foo({ foo: { bar: { baz } }}) {}
939+
`,
940+
errors: [
941+
{
942+
message: 'Missing @param "options.foo.bar.baz"',
943+
},
944+
],
945+
},
897946
],
898947
valid: [
899948
{
@@ -1297,5 +1346,41 @@ export default {
12971346
sourceType: 'module',
12981347
},
12991348
},
1349+
{
1350+
code: `
1351+
/**
1352+
* Description.
1353+
* @param {Object} options Options.
1354+
* @param {FooBar} options.foo foo description.
1355+
*/
1356+
function quux ({ foo: { bar }}) {}
1357+
`,
1358+
},
1359+
{
1360+
code: `
1361+
/**
1362+
* Description.
1363+
* @param {FooBar} options
1364+
* @param {Object} options.foo
1365+
*/
1366+
function quux ({ foo: { bar } }) {}
1367+
`,
1368+
options: [
1369+
{
1370+
checkTypesPattern: 'FooBar',
1371+
},
1372+
],
1373+
},
1374+
{
1375+
code: `
1376+
/**
1377+
* Description.
1378+
* @param {Object} options
1379+
* @param {FooBar} options.foo
1380+
* @param {FooBar} options.baz
1381+
*/
1382+
function quux ({ foo: { bar }, baz: { cfg } }) {}
1383+
`,
1384+
},
13001385
],
13011386
};

0 commit comments

Comments
 (0)