Skip to content

Commit

Permalink
fix(require-param, check-param-names): add option `useDefaultObje…
Browse files Browse the repository at this point in the history
…ctProperties for expecting documentation or avoiding reporting of documented; addresses gajus#676
  • Loading branch information
brettz9 committed Jan 22, 2021
1 parent c6dbf0c commit 9ef72c1
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 9 deletions.
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2661,6 +2661,19 @@ function quux ({ foo: { bar } }) {}
*/
function foo({ foo: { bar: { baz } }}) {}
// Message: Missing @param "options.foo.bar.baz"

/**
* Returns a number.
* @param {Object} props Props.
* @param {Object} props.prop Prop.
* @param {string} props.prop.a String.
* @param {string} props.prop.b String.
* @return {number} A number.
*/
export function testFn1 ({ prop = { a: 1, b: 2 } }) {
}
// Options: [{"useDefaultObjectProperties":false}]
// Message: @param "props.prop.a" does not exist on props
````

The following patterns are not considered problems:
Expand Down Expand Up @@ -2992,6 +3005,18 @@ function Item({
defaulting: [quux, xyz] = []
}) {
}

/**
* Returns a number.
* @param {Object} props Props.
* @param {Object} props.prop Prop.
* @param {string} props.prop.a String.
* @param {string} props.prop.b String.
* @return {number} A number.
*/
export function testFn1 ({ prop = { a: 1, b: 2 } }) {
}
// Options: [{"useDefaultObjectProperties":true}]
````


Expand Down Expand Up @@ -12562,6 +12587,17 @@ function quux ({ foo: { bar } }) {}
*/
function foo({ foo: { bar: { baz } }}) {}
// Message: Missing JSDoc @param "options.foo.bar.baz" declaration.

/**
* Returns a number.
* @param {Object} props Props.
* @param {Object} props.prop Prop.
* @return {number} A number.
*/
export function testFn1 ({ prop = { a: 1, b: 2 } }) {
}
// Options: [{"useDefaultObjectProperties":true}]
// Message: Missing JSDoc @param "props.prop.a" declaration.
````

The following patterns are not considered problems:
Expand Down Expand Up @@ -13175,6 +13211,16 @@ function Item({
defaulting: [quux, xyz] = []
}) {
}

/**
* Returns a number.
* @param {Object} props Props.
* @param {Object} props.prop Prop.
* @return {number} A number.
*/
export function testFn1 ({ prop = { a: 1, b: 2 } }) {
}
// Options: [{"useDefaultObjectProperties":false}]
````


Expand Down
4 changes: 2 additions & 2 deletions src/iterateJsdoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,8 @@ const getUtils = (
return jsdocUtils.flattenRoots(params);
};

utils.getFunctionParameterNames = () => {
return jsdocUtils.getFunctionParameterNames(node);
utils.getFunctionParameterNames = (useDefaultObjectProperties) => {
return jsdocUtils.getFunctionParameterNames(node, useDefaultObjectProperties);
};

utils.hasParams = () => {
Expand Down
18 changes: 14 additions & 4 deletions src/jsdocUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ const getPropertiesFromPropertySignature = (propSignature): T => {
return propSignature.key.name;
};

const getFunctionParameterNames = (functionNode : Object) : Array<T> => {
const getFunctionParameterNames = (
functionNode : Object, checkDefaultObjects: Boolean,
) : Array<T> => {
// eslint-disable-next-line complexity
const getParamName = (param, isProperty) => {
if (_.has(param, 'typeAnnotation') || _.has(param, 'left.typeAnnotation')) {
Expand Down Expand Up @@ -149,12 +151,20 @@ const getFunctionParameterNames = (functionNode : Object) : Array<T> => {
})];
}
if (param.value.type === 'AssignmentPattern') {
if (param.value.left.type === 'ObjectPattern') {
switch (param.value.left.type) {
case 'Identifier':
// Default parameter
if (checkDefaultObjects && param.value.right.type === 'ObjectExpression') {
return [param.key.name, param.value.right.properties.map((prop) => {
return getParamName(prop, isProperty);
})];
}
break;
case 'ObjectPattern':
return [param.key.name, param.value.left.properties.map((prop) => {
return getParamName(prop, isProperty);
})];
}
if (param.value.left.type === 'ArrayPattern') {
case 'ArrayPattern':
return [param.key.name, param.value.left.elements.map((prop, idx) => {
return {
name: idx,
Expand Down
10 changes: 8 additions & 2 deletions src/rules/checkParamNames.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ const validateParameterNames = (
if (!hasPropertyRest || checkRestProperty) {
actualNames.forEach((name, idx) => {
const match = name.startsWith(tag.name.trim() + '.');
if (match && !expectedNames.some(utils.comparePaths(name)) && !utils.comparePaths(name)(tag.name)) {
if (match && !expectedNames.some(
utils.comparePaths(name),
) && !utils.comparePaths(name)(tag.name)) {
extraProperties.push([name, paramTags[idx][1]]);
}
});
Expand Down Expand Up @@ -219,6 +221,7 @@ export default iterateJsdoc(({
checkRestProperty = false,
checkTypesPattern = '/^(?:[oO]bject|[aA]rray|PlainObject|Generic(?:Object|Array))$/',
enableFixer = false,
useDefaultObjectProperties = false,
} = context.options[0] || {};

const lastSlashPos = checkTypesPattern.lastIndexOf('/');
Expand All @@ -230,7 +233,7 @@ export default iterateJsdoc(({
if (!jsdocParameterNamesDeep.length) {
return;
}
const functionParameterNames = utils.getFunctionParameterNames();
const functionParameterNames = utils.getFunctionParameterNames(useDefaultObjectProperties);
const targetTagName = utils.getPreferredTagName({tagName: 'param'});
const isError = validateParameterNames(
targetTagName,
Expand Down Expand Up @@ -278,6 +281,9 @@ export default iterateJsdoc(({
enableFixer: {
type: 'boolean',
},
useDefaultObjectProperties: {
type: 'boolean',
},
},
type: 'object',
},
Expand Down
6 changes: 5 additions & 1 deletion src/rules/requireParam.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export default iterateJsdoc(({
utils,
context,
}) => {
const functionParameterNames = utils.getFunctionParameterNames();
const preferredTagName = utils.getPreferredTagName({tagName: 'param'});
if (!preferredTagName) {
return;
Expand Down Expand Up @@ -57,6 +56,7 @@ export default iterateJsdoc(({
enableRootFixer = true,
enableRestElementFixer = true,
unnamedRootBase = ['root'],
useDefaultObjectProperties = false,
} = context.options[0] || {};

const lastSlashPos = checkTypesPattern.lastIndexOf('/');
Expand All @@ -65,6 +65,7 @@ export default iterateJsdoc(({
new RegExp(checkTypesPattern.slice(1, lastSlashPos), checkTypesPattern.slice(lastSlashPos + 1));

const missingTags = [];
const functionParameterNames = utils.getFunctionParameterNames(useDefaultObjectProperties);
const flattenedRoots = utils.flattenRoots(functionParameterNames).names;

const paramIndex = {};
Expand Down Expand Up @@ -372,6 +373,9 @@ export default iterateJsdoc(({
},
type: 'array',
},
useDefaultObjectProperties: {
type: 'boolean',
},
},
type: 'object',
},
Expand Down
48 changes: 48 additions & 0 deletions test/rules/assertions/checkParamNames.js
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,34 @@ export default {
},
],
},
{
code: `
/**
* Returns a number.
* @param {Object} props Props.
* @param {Object} props.prop Prop.
* @param {string} props.prop.a String.
* @param {string} props.prop.b String.
* @return {number} A number.
*/
export function testFn1 ({ prop = { a: 1, b: 2 } }) {
}
`,
errors: [
{
message: '@param "props.prop.a" does not exist on props',
},
{
message: '@param "props.prop.b" does not exist on props',
},
],
options: [{
useDefaultObjectProperties: false,
}],
parserOptions: {
sourceType: 'module',
},
},
],
valid: [
{
Expand Down Expand Up @@ -1423,5 +1451,25 @@ export default {
}
`,
},
{
code: `
/**
* Returns a number.
* @param {Object} props Props.
* @param {Object} props.prop Prop.
* @param {string} props.prop.a String.
* @param {string} props.prop.b String.
* @return {number} A number.
*/
export function testFn1 ({ prop = { a: 1, b: 2 } }) {
}
`,
options: [{
useDefaultObjectProperties: true,
}],
parserOptions: {
sourceType: 'module',
},
},
],
};
56 changes: 56 additions & 0 deletions test/rules/assertions/requireParam.js
Original file line number Diff line number Diff line change
Expand Up @@ -2118,6 +2118,44 @@ export default {
function foo({ foo: { bar: { baz } }}) {}
`,
},
{
code: `
/**
* Returns a number.
* @param {Object} props Props.
* @param {Object} props.prop Prop.
* @return {number} A number.
*/
export function testFn1 ({ prop = { a: 1, b: 2 } }) {
}
`,
errors: [
{
message: 'Missing JSDoc @param "props.prop.a" declaration.',
},
{
message: 'Missing JSDoc @param "props.prop.b" declaration.',
},
],
options: [{
useDefaultObjectProperties: true,
}],
output: `
/**
* Returns a number.
* @param {Object} props Props.
* @param {Object} props.prop Prop.
* @param props.prop.a
* @param props.prop.b
* @return {number} A number.
*/
export function testFn1 ({ prop = { a: 1, b: 2 } }) {
}
`,
parserOptions: {
sourceType: 'module',
},
},
],
valid: [
{
Expand Down Expand Up @@ -3044,5 +3082,23 @@ export default {
}
`,
},
{
code: `
/**
* Returns a number.
* @param {Object} props Props.
* @param {Object} props.prop Prop.
* @return {number} A number.
*/
export function testFn1 ({ prop = { a: 1, b: 2 } }) {
}
`,
options: [{
useDefaultObjectProperties: false,
}],
parserOptions: {
sourceType: 'module',
},
},
],
};

0 comments on commit 9ef72c1

Please sign in to comment.