Skip to content

Commit 8b2d143

Browse files
committed
feat(check-param-names): add options disableExtraPropertyReporting to allow extra properties to be documented without error (as long as there are no siblings destructured as for such cases, they will still be expected since the function is not using them)
1 parent 33118ef commit 8b2d143

4 files changed

Lines changed: 276 additions & 18 deletions

File tree

.README/rules/check-param-names.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,20 @@ where instead of destructuring, a whole plain object is supplied as default
6464
value but you wish its keys to be considered as signalling that the properties
6565
are present and can therefore be documented. Defaults to `false`.
6666

67+
##### `disableExtraPropertyReporting`
68+
69+
Whether to check for extra destructured properties. Defaults to `false`. Change
70+
to `true` if you want to be able to document properties which are not actually
71+
destructured. Keep as `false` if you expect properties to be documented in
72+
their own types. Note that extra properties will always be reported if another
73+
item at the same level is destructured as destructuring will prevent other
74+
access and this option is only intended to permit documenting extra properties
75+
that are available and actually used in the function.
76+
6777
|||
6878
|---|---|
6979
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
70-
|Options|`allowExtraTrailingParamDocs`, `checkDestructured`, `checkRestProperty`, `checkTypesPattern`, `useDefaultObjectProperties`|
80+
|Options|`allowExtraTrailingParamDocs`, `checkDestructured`, `checkRestProperty`, `checkTypesPattern`, `useDefaultObjectProperties`, `disableExtraPropertyReporting`|
7181
|Tags|`param`|
7282
|Aliases|`arg`, `argument`|
7383
|Recommended|true|

README.md

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2274,10 +2274,21 @@ where instead of destructuring, a whole plain object is supplied as default
22742274
value but you wish its keys to be considered as signalling that the properties
22752275
are present and can therefore be documented. Defaults to `false`.
22762276

2277+
<a name="eslint-plugin-jsdoc-rules-check-param-names-options-4-disableextrapropertyreporting"></a>
2278+
##### <code>disableExtraPropertyReporting</code>
2279+
2280+
Whether to check for extra destructured properties. Defaults to `false`. Change
2281+
to `true` if you want to be able to document properties which are not actually
2282+
destructured. Keep as `false` if you expect properties to be documented in
2283+
their own types. Note that extra properties will always be reported if another
2284+
item at the same level is destructured as destructuring will prevent other
2285+
access and this option is only intended to permit documenting extra properties
2286+
that are available and actually used in the function.
2287+
22772288
|||
22782289
|---|---|
22792290
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
2280-
|Options|`allowExtraTrailingParamDocs`, `checkDestructured`, `checkRestProperty`, `checkTypesPattern`, `useDefaultObjectProperties`|
2291+
|Options|`allowExtraTrailingParamDocs`, `checkDestructured`, `checkRestProperty`, `checkTypesPattern`, `useDefaultObjectProperties`, `disableExtraPropertyReporting`|
22812292
|Tags|`param`|
22822293
|Aliases|`arg`, `argument`|
22832294
|Recommended|true|
@@ -2685,6 +2696,68 @@ export function testFn1 ({ prop = { a: 1, b: 2 } }) {
26852696
}
26862697
// Options: [{"useDefaultObjectProperties":false}]
26872698
// Message: @param "props.prop.a" does not exist on props
2699+
2700+
/**
2701+
* @param {object} cfg
2702+
* @param {string} cfg.foo
2703+
* @param {string} cfg.bar
2704+
* @param {object} cfg.extra
2705+
*/
2706+
function quux ({foo}) {
2707+
2708+
}
2709+
// Message: @param "cfg.bar" does not exist on cfg
2710+
2711+
/**
2712+
* @param {object} cfg
2713+
* @param {string} cfg.foo
2714+
* @param {string} cfg.bar
2715+
* @param {object} cfg.extra
2716+
*/
2717+
function quux ({foo}) {
2718+
2719+
}
2720+
// Options: [{"disableExtraPropertyReporting":true}]
2721+
// Message: @param "cfg.bar" does not exist on cfg
2722+
2723+
/**
2724+
* @param {object} root
2725+
* @param {object} root.cfg
2726+
* @param {object} root.cfg.a
2727+
* @param {string} root.cfg.a.foo
2728+
* @param {string} root.cfg.a.bar
2729+
* @param {object} root.cfg.a.extra
2730+
*/
2731+
function quux ({cfg: {a: {foo}}}) {
2732+
2733+
}
2734+
// Message: @param "root.cfg.a.bar" does not exist on root
2735+
2736+
/**
2737+
* @param {object} root
2738+
* @param {object} root.cfg
2739+
* @param {object} root.cfg.a
2740+
* @param {string} root.cfg.a.foo
2741+
* @param {string} root.cfg.a.bar
2742+
* @param {object} root.cfg.a.extra
2743+
*/
2744+
function quux ({cfg: {a: {foo}}}) {
2745+
2746+
}
2747+
// Options: [{"disableExtraPropertyReporting":true}]
2748+
// Message: @param "root.cfg.a.bar" does not exist on root
2749+
2750+
/**
2751+
* @param {object} root
2752+
* @param {object} root.cfg
2753+
* @param {string} root.cfg.foo
2754+
* @param {string} root.cfg.bar
2755+
* @param {object} root.cfg.extra
2756+
*/
2757+
function quux ({cfg}) {
2758+
2759+
}
2760+
// Message: @param "root.cfg.foo" does not exist on root
26882761
````
26892762

26902763
The following patterns are not considered problems:
@@ -3028,6 +3101,18 @@ function Item({
30283101
export function testFn1 ({ prop = { a: 1, b: 2 } }) {
30293102
}
30303103
// Options: [{"useDefaultObjectProperties":true}]
3104+
3105+
/**
3106+
* @param {object} root
3107+
* @param {object} root.cfg
3108+
* @param {string} root.cfg.foo
3109+
* @param {string} root.cfg.bar
3110+
* @param {object} root.cfg.extra
3111+
*/
3112+
function quux ({cfg}) {
3113+
3114+
}
3115+
// Options: [{"disableExtraPropertyReporting":true}]
30313116
````
30323117

30333118

src/rules/checkParamNames.js

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const validateParameterNames = (
66
checkDestructured : boolean,
77
checkRestProperty : boolean,
88
checkTypesRegex : RegExp,
9+
disableExtraPropertyReporting,
910
enableFixer: boolean,
1011
functionParameterNames : Array<string>, jsdoc, _jsdocNode, utils, report,
1112
) => {
@@ -104,31 +105,35 @@ const validateParameterNames = (
104105
}
105106
});
106107

107-
const extraProperties = [];
108-
if (!hasPropertyRest || checkRestProperty) {
109-
actualNames.forEach((name, idx) => {
110-
const match = name.startsWith(tag.name.trim() + '.');
111-
if (match && !expectedNames.some(
112-
utils.comparePaths(name),
113-
) && !utils.comparePaths(name)(tag.name)) {
114-
extraProperties.push([name, paramTags[idx][1]]);
115-
}
116-
});
117-
}
118-
119108
const hasMissing = missingProperties.length;
120109
if (hasMissing) {
121110
missingProperties.forEach((missingProperty) => {
122111
report(`Missing @${targetTagName} "${missingProperty}"`, null, tag);
123112
});
124113
}
125114

126-
if (extraProperties.length) {
127-
extraProperties.forEach(([extraProperty, tg]) => {
128-
report(`@${targetTagName} "${extraProperty}" does not exist on ${tag.name}`, null, tg);
115+
if (!hasPropertyRest || checkRestProperty) {
116+
const extraProperties = [];
117+
actualNames.forEach((name, idx) => {
118+
const match = name.startsWith(tag.name.trim() + '.');
119+
if (
120+
match && !expectedNames.some(
121+
utils.comparePaths(name),
122+
) && !utils.comparePaths(name)(tag.name) &&
123+
(!disableExtraPropertyReporting || properties.some((prop) => {
124+
return prop.split('.').length >= name.split('.').length - 1;
125+
}))
126+
) {
127+
extraProperties.push([name, paramTags[idx][1]]);
128+
}
129129
});
130+
if (extraProperties.length) {
131+
extraProperties.forEach(([extraProperty, tg]) => {
132+
report(`@${targetTagName} "${extraProperty}" does not exist on ${tag.name}`, null, tg);
133+
});
130134

131-
return true;
135+
return true;
136+
}
132137
}
133138

134139
return hasMissing;
@@ -222,6 +227,7 @@ export default iterateJsdoc(({
222227
checkTypesPattern = '/^(?:[oO]bject|[aA]rray|PlainObject|Generic(?:Object|Array))$/',
223228
enableFixer = false,
224229
useDefaultObjectProperties = false,
230+
disableExtraPropertyReporting = false,
225231
} = context.options[0] || {};
226232

227233
const lastSlashPos = checkTypesPattern.lastIndexOf('/');
@@ -241,6 +247,7 @@ export default iterateJsdoc(({
241247
checkDestructured,
242248
checkRestProperty,
243249
checkTypesRegex,
250+
disableExtraPropertyReporting,
244251
enableFixer,
245252
functionParameterNames,
246253
jsdoc, jsdocNode, utils, report,
@@ -278,6 +285,9 @@ export default iterateJsdoc(({
278285
checkTypesPattern: {
279286
type: 'string',
280287
},
288+
disableExtraPropertyReporting: {
289+
type: 'boolean',
290+
},
281291
enableFixer: {
282292
type: 'boolean',
283293
},

test/rules/assertions/checkParamNames.js

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,140 @@ export default {
971971
sourceType: 'module',
972972
},
973973
},
974+
{
975+
code: `
976+
/**
977+
* @param {object} cfg
978+
* @param {string} cfg.foo
979+
* @param {string} cfg.bar
980+
* @param {object} cfg.extra
981+
*/
982+
function quux ({foo}) {
983+
984+
}
985+
`,
986+
errors: [
987+
{
988+
line: 5,
989+
message: '@param "cfg.bar" does not exist on cfg',
990+
},
991+
{
992+
line: 6,
993+
message: '@param "cfg.extra" does not exist on cfg',
994+
},
995+
],
996+
},
997+
{
998+
code: `
999+
/**
1000+
* @param {object} cfg
1001+
* @param {string} cfg.foo
1002+
* @param {string} cfg.bar
1003+
* @param {object} cfg.extra
1004+
*/
1005+
function quux ({foo}) {
1006+
1007+
}
1008+
`,
1009+
errors: [
1010+
{
1011+
line: 5,
1012+
message: '@param "cfg.bar" does not exist on cfg',
1013+
},
1014+
{
1015+
line: 6,
1016+
message: '@param "cfg.extra" does not exist on cfg',
1017+
},
1018+
],
1019+
options: [
1020+
{
1021+
disableExtraPropertyReporting: true,
1022+
},
1023+
],
1024+
},
1025+
{
1026+
code: `
1027+
/**
1028+
* @param {object} root
1029+
* @param {object} root.cfg
1030+
* @param {object} root.cfg.a
1031+
* @param {string} root.cfg.a.foo
1032+
* @param {string} root.cfg.a.bar
1033+
* @param {object} root.cfg.a.extra
1034+
*/
1035+
function quux ({cfg: {a: {foo}}}) {
1036+
1037+
}
1038+
`,
1039+
errors: [
1040+
{
1041+
line: 7,
1042+
message: '@param "root.cfg.a.bar" does not exist on root',
1043+
},
1044+
{
1045+
line: 8,
1046+
message: '@param "root.cfg.a.extra" does not exist on root',
1047+
},
1048+
],
1049+
},
1050+
{
1051+
code: `
1052+
/**
1053+
* @param {object} root
1054+
* @param {object} root.cfg
1055+
* @param {object} root.cfg.a
1056+
* @param {string} root.cfg.a.foo
1057+
* @param {string} root.cfg.a.bar
1058+
* @param {object} root.cfg.a.extra
1059+
*/
1060+
function quux ({cfg: {a: {foo}}}) {
1061+
1062+
}
1063+
`,
1064+
errors: [
1065+
{
1066+
line: 7,
1067+
message: '@param "root.cfg.a.bar" does not exist on root',
1068+
},
1069+
{
1070+
line: 8,
1071+
message: '@param "root.cfg.a.extra" does not exist on root',
1072+
},
1073+
],
1074+
options: [
1075+
{
1076+
disableExtraPropertyReporting: true,
1077+
},
1078+
],
1079+
},
1080+
{
1081+
code: `
1082+
/**
1083+
* @param {object} root
1084+
* @param {object} root.cfg
1085+
* @param {string} root.cfg.foo
1086+
* @param {string} root.cfg.bar
1087+
* @param {object} root.cfg.extra
1088+
*/
1089+
function quux ({cfg}) {
1090+
1091+
}
1092+
`,
1093+
errors: [
1094+
{
1095+
line: 5,
1096+
message: '@param "root.cfg.foo" does not exist on root',
1097+
},
1098+
{
1099+
line: 6,
1100+
message: '@param "root.cfg.bar" does not exist on root',
1101+
},
1102+
{
1103+
line: 7,
1104+
message: '@param "root.cfg.extra" does not exist on root',
1105+
},
1106+
],
1107+
},
9741108
],
9751109
valid: [
9761110
{
@@ -1471,5 +1605,24 @@ export default {
14711605
sourceType: 'module',
14721606
},
14731607
},
1608+
{
1609+
code: `
1610+
/**
1611+
* @param {object} root
1612+
* @param {object} root.cfg
1613+
* @param {string} root.cfg.foo
1614+
* @param {string} root.cfg.bar
1615+
* @param {object} root.cfg.extra
1616+
*/
1617+
function quux ({cfg}) {
1618+
1619+
}
1620+
`,
1621+
options: [
1622+
{
1623+
disableExtraPropertyReporting: true,
1624+
},
1625+
],
1626+
},
14741627
],
14751628
};

0 commit comments

Comments
 (0)