Skip to content

Commit 41f1dbb

Browse files
author
Alexej Yaroshevich
committed
checkAnnotations: add tag checking by presets
Fixes #18
1 parent f454c98 commit 41f1dbb

File tree

5 files changed

+113
-1
lines changed

5 files changed

+113
-1
lines changed

lib/rules/validate-jsdoc.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ module.exports.prototype = {
3030
if (v.options) {
3131
validators.checkOptions(v, options);
3232
}
33+
// configure
34+
if (v.configure) {
35+
v.configure(options);
36+
}
3337
// index rules by tags and scopes
3438
(v.scopes || ['']).forEach(function(scope) {
3539
if (!v.tags) {
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
var assert = require('assert');
2+
3+
var availablePresets = require('../../tags');
4+
var jsdoc = require('../../jsdoc');
5+
6+
module.exports = validateAnnotations;
7+
module.exports.scopes = ['file'];
8+
module.exports.options = {
9+
checkAnnotations: true
10+
};
11+
12+
var tags;
13+
14+
validateAnnotations.configure = function(options) {
15+
var o = options.checkAnnotations;
16+
17+
assert(o === true || typeof o === 'string' || typeof o === 'object',
18+
'jsDoc.checkAnnotation rule was not configured properly');
19+
20+
if (typeof o === 'string') {
21+
o = {preset: o};
22+
}
23+
24+
tags = {};
25+
26+
if (o === true) {
27+
Object.keys(availablePresets).forEach(function(preset) {
28+
var presetTags = availablePresets[preset];
29+
Object.keys(presetTags).forEach(function(tag) {
30+
tags[tag] = tags[tag] || presetTags[tag];
31+
});
32+
});
33+
34+
} else if (typeof o === 'object') {
35+
if (o.preset) {
36+
assert(typeof o.preset === 'string', 'jsDoc.checkAnnotation.preset should be preset name');
37+
assert(availablePresets[o.preset], 'Unknown tag preset ' + o.preset);
38+
Object.keys(availablePresets[o.preset]).forEach(function(tag) {
39+
tags[tag] = tags[tag] || availablePresets[o.preset][tag];
40+
});
41+
}
42+
if (o.extra) {
43+
Object.keys(o.extra).forEach(function(tag) {
44+
tags[tag] = o.extra[tag];
45+
});
46+
}
47+
}
48+
};
49+
50+
/**
51+
* validator for annotations
52+
* @param {JSCS.JSFile} file
53+
* @param {JSCS.Errors} errors
54+
*/
55+
function validateAnnotations(file, errors) {
56+
var comments = file.getComments();
57+
comments.forEach(function(commentNode) {
58+
if (commentNode.type !== 'Block' || commentNode.value[0] !== '*') {
59+
return;
60+
}
61+
62+
// trying to create DocComment object
63+
var node = jsdoc.createDocCommentByCommentNode(commentNode);
64+
if (!node.valid) {
65+
return;
66+
}
67+
68+
node.iterate(function(tag) {
69+
if (!tags.hasOwnProperty[tag.id]) {
70+
errors.add('unavailable tag ' + tag.id, tag.loc);
71+
}
72+
else if (tags[tag.id] && (!tag.name || !tag.type)) {
73+
errors.add('incomplete tag ' + tag.id + ' data', tag.loc);
74+
}
75+
});
76+
});
77+
}

lib/rules/validate-jsdoc/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ var validatorsByName = module.exports = {
1212
requireReturnTypes: require('./require-return-types'),
1313
checkRedundantReturns: require('./check-redundant-returns'),
1414

15-
//returns: require('./returns'),
15+
checkAnnotations: require('./check-annotations'),
16+
1617
checkRedundantAccess: require('./check-redundant-access'),
1718
enforceExistence: require('./enforce-existence'),
1819
leadingUnderscoreAccess: require('./leading-underscore-access')

lib/tags/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
jsdoc3: require('./jsdoc3'),
3+
jsduck5: require('./jsduck5'),
4+
closurecompiler: require('./closurecompiler')
5+
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
describe('lib/rules/validate-jsdoc/check-annotations', function () {
2+
var checker = global.checker({
3+
additionalRules: ['lib/rules/validate-jsdoc.js']
4+
});
5+
6+
describe('with true', function () {
7+
checker.rules({checkAnnotations: true});
8+
9+
checker.cases([
10+
/* jshint ignore:start */
11+
{
12+
it: 'should throw unavailable tag',
13+
errors: {message: 'unavailable tag ppublic'},
14+
code: function() {
15+
/**
16+
* @ppublic
17+
*/
18+
}
19+
}
20+
/* jshint ignore:end */
21+
]);
22+
23+
});
24+
25+
});

0 commit comments

Comments
 (0)