Skip to content

Commit

Permalink
New Rule: checkParamExistence
Browse files Browse the repository at this point in the history
This rule reports undocumented parameters when missing @inheritdoc,
@Class or @extends statements.

Closes gh-138
  • Loading branch information
jdlrobson authored and Alexej Yaroshevich committed Sep 6, 2015
1 parent 1d6e20f commit aa40ed5
Show file tree
Hide file tree
Showing 4 changed files with 302 additions and 1 deletion.
44 changes: 43 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,49 @@ function _f() {}
/** @still-invalid */
```

####
### checkParamExistence

Ensures all parameters are documented.

Type: `Boolean`

Values: `true`


#### Example

```js
"checkParamExistence": true
```

##### Valid

```js
/**
* @param {string} message
* @return {string}
*/
function _f ( message ) {
return true;
}

/**
* @inheritdoc
*/
function _f ( message ) {
return true;
}
```

##### Invalid

```js
/**
* @return {string}
*/
function _f ( message ) {
return true;
}

### checkParamNames

Expand Down
40 changes: 40 additions & 0 deletions lib/rules/validate-jsdoc/check-param-existence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module.exports = checkParamExistence;
module.exports.scopes = ['function'];
module.exports.options = {
checkParamExistence: {allowedValues: [true]}
};

/**
* validator for check-param-existence
*
* @param {(FunctionDeclaration|FunctionExpression)} node
* @param {Function} err
*/
function checkParamExistence(node, err) {
if (!node.jsdoc) {
return;
}

var totalParams = 0;
var excludable;
var documentedParams = {};
node.jsdoc.iterateByType(['param', 'arg', 'argument', 'inheritdoc', 'class', 'extends'],
function(tag) {
totalParams += 1;
if (['inheritdoc', 'class', 'extends'].indexOf(tag.id) > -1) {
excludable = true;
}
// set first instance at place where documentation is missing.
if (['arg', 'argument', 'param'].indexOf(tag.id) > -1 && tag.name) {
documentedParams[tag.name.value] = true;
}
});
if (totalParams !== node.params.length && !excludable) {
node.params.forEach(function(param) {
if (!documentedParams[param.name]) {
err('Function is missing documentation for parameter `' + param.name + '`.',
node.loc.start);
}
});
}
}
1 change: 1 addition & 0 deletions lib/rules/validate-jsdoc/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var assert = require('assert');
var validatorsByName = module.exports = {
checkTypes: require('./check-types'),

checkParamExistence: require('./check-param-existence'),
checkParamNames: require('./check-param-names'),
checkRedundantParams: require('./check-redundant-params'),
requireParamTypes: require('./require-param-types'),
Expand Down
218 changes: 218 additions & 0 deletions test/lib/rules/validate-jsdoc/check-param-existence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
describe('lib/rules/validate-jsdoc/check-param-existence', function() {
var checker = global.checker({
plugins: ['./lib/index']
});

describe('not configured', function() {

it('should report with undefined', function() {
global.expect(function() {
checker.configure({checkParamExistence: undefined});
}).to.throws(/accepted value/i);
});

it('should report with an object', function() {
global.expect(function() {
checker.configure({checkParamExistence: {}});
}).to.throws(/accepted value/i);
});

});

describe('checkParams compatability', function() {
checker.rules({checkParamExistence: true, checkParamNames: true});

checker.cases([
/* jshint ignore:start */
/* jscs:disable */
{
it: 'should report when a parameter is omitted',
code: function () {
Cls.prototype = {
/**
* @param xxx
*/
run: function(xxx, zzz) {
}
};
},
errors: [
{message: 'Function is missing documentation for parameter `zzz`.',
line: 5, column: 9, filename: 'input', fixed: undefined, rule: 'jsDoc' }
]
},
{
it: 'should report when the documentation of a parameter is skipped as well as complain about order.',
code: function () {
Cls.prototype = {
/**
* @param {Object} xxx
* @param {String} aaa
*/
run: function(xxx, zzz, aaa) {
}
};
},
errors: [
{message: 'Parameter aaa is out of order',
line: 4, column: 23, filename: 'input', fixed: undefined, rule: 'jsDoc' },
{message: 'Function is missing documentation for parameter `zzz`.',
line: 6, column: 9, filename: 'input', fixed: undefined, rule: 'jsDoc' }
]
},
{
it: 'should report when the documentation of a parameter is forgotten.',
code: function () {
Cls.prototype = {
/**
* @param {Object} xxx
* @param {String} zzz
*/
run: function(xxx, zzz, aaa) {
}
};
},
errors: [
{message: 'Function is missing documentation for parameter `aaa`.',
line: 6, column: 9, filename: 'input', fixed: undefined, rule: 'jsDoc' }
]
}
// jscs:enable
/* jshint ignore:end */
]);
});

describe('with true', function() {
checker.rules({checkParamExistence: true});

checker.cases([
/* jshint ignore:start */
/* jscs:disable */
{
it: 'should report when a parameter is omitted',
code: function () {
Cls.prototype = {
/**
* @param xxx
*/
run: function(xxx, zzz) {
}
};
},
errors: [
{message: 'Function is missing documentation for parameter `zzz`.',
line: 5, column: 9, filename: 'input', fixed: undefined, rule: 'jsDoc' }
]
},
{
it: 'should report when an argument is omitted',
code: function () {
Cls.prototype = {
/**
* @argument xxx
*/
run: function(xxx, zzz) {
}
};
},
errors: [
{message: 'Function is missing documentation for parameter `zzz`.',
line: 5, column: 9, filename: 'input', fixed: undefined, rule: 'jsDoc' }
]
},
{
it: 'should report when an arg is omitted',
code: function () {
Cls.prototype = {
/**
* @arg xxx
*/
run: function(xxx, zzz) {
}
};
},
errors: [
{message: 'Function is missing documentation for parameter `zzz`.',
line: 5, column: 9, filename: 'input', fixed: undefined, rule: 'jsDoc' }
]
},
{
it: 'should report when the documentation of a parameter is skipped.',
code: function () {
Cls.prototype = {
/**
* @param {Object} xxx
* @param {String} aaa
*/
run: function(xxx, zzz, aaa) {
}
};
},
errors: [
{message: 'Function is missing documentation for parameter `zzz`.',
line: 6, column: 9, filename: 'input', fixed: undefined, rule: 'jsDoc' }
]
},
{
it: 'should complain twice when more than one parameter missed.',
code: function () {
Cls.prototype = {
/**
* @param {Object} xxx
* @param {String} aaa
* @param {String} fff
*/
run: function(xxx, zzz, aaa, ggg, fff) {
}
};
},
errors: [
{message: 'Function is missing documentation for parameter `zzz`.',
line: 7, column: 9, filename: 'input', fixed: undefined, rule: 'jsDoc' },
{message: 'Function is missing documentation for parameter `ggg`.',
line: 7, column: 9, filename: 'input', fixed: undefined, rule: 'jsDoc' }
]
},
{
it: 'should not complain at all when an inheritdoc is present even if a parameter is documented.',
code: function () {
Cls.prototype = {
/**
* @inheritdoc
* @param {String} xxx
*/
run: function(xxx, zzz, aaa, ggg, fff) {
}
};
},
errors: []
},
{
it: 'should not complain at all when an inheritdoc is present.',
code: function () {
Cls.prototype = {
/**
* @inheritdoc
*/
run: function(xxx, zzz, aaa, ggg, fff) {
}
};
},
errors: []
},
{
it: 'should not complain on classes.',
code: function () {
/**
* @class Foo
*/
function Cls( foo, bar ) {
}
},
errors: []
}
// jscs:enable
/* jshint ignore:end */
]);
});
});

0 comments on commit aa40ed5

Please sign in to comment.