Skip to content

Commit cc0add6

Browse files
author
Alexej Yaroshevich
committed
final steps
1 parent 74a08e9 commit cc0add6

File tree

2 files changed

+137
-8
lines changed

2 files changed

+137
-8
lines changed

lib/rules/validate-jsdoc/check-annotations.js

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,20 @@ validateAnnotations.configure = function(options) {
1919

2020
if (typeof o === 'string') {
2121
o = {preset: o};
22+
} else if (typeof o === 'object') {
23+
var oKeys = Object.keys(o);
24+
oKeys.forEach(function(key) {
25+
if (key === 'preset') {
26+
assert(typeof o.preset === 'string', 'jsDoc.checkAnnotation.preset should be preset name');
27+
} else if (key === 'extra') {
28+
assert(typeof o[key] === 'object', 'jsDoc.checkAnnotation.preset should be `tag: fulfill` map');
29+
} else {
30+
throw new Error('jsDoc.checkAnnotation.' + key + ' is unsupported field');
31+
}
32+
});
2233
}
2334

24-
tags = {};
35+
tags = Object.create ? Object.create(null) : {};
2536

2637
if (o === true) {
2738
Object.keys(availablePresets).forEach(function(preset) {
@@ -33,15 +44,18 @@ validateAnnotations.configure = function(options) {
3344

3445
} else if (typeof o === 'object') {
3546
if (o.preset) {
36-
assert(typeof o.preset === 'string', 'jsDoc.checkAnnotation.preset should be preset name');
3747
assert(availablePresets[o.preset], 'Unknown tag preset ' + o.preset);
3848
Object.keys(availablePresets[o.preset]).forEach(function(tag) {
3949
tags[tag] = tags[tag] || availablePresets[o.preset][tag];
4050
});
4151
}
4252
if (o.extra) {
4353
Object.keys(o.extra).forEach(function(tag) {
44-
tags[tag] = o.extra[tag];
54+
if (o.extra[tag] === null) {
55+
delete tags[tag];
56+
} else {
57+
tags[tag] = o.extra[tag];
58+
}
4559
});
4660
}
4761
}
@@ -53,6 +67,7 @@ validateAnnotations.configure = function(options) {
5367
* @param {JSCS.Errors} errors
5468
*/
5569
function validateAnnotations(file, errors) {
70+
var checkFulfill = true; //this._options.checkAnnotations.checkFulfill;
5671
var comments = file.getComments();
5772
comments.forEach(function(commentNode) {
5873
if (commentNode.type !== 'Block' || commentNode.value[0] !== '*') {
@@ -66,11 +81,19 @@ function validateAnnotations(file, errors) {
6681
}
6782

6883
node.iterate(function(tag) {
69-
if (!tags.hasOwnProperty[tag.id]) {
84+
if (!(tag.id in tags)) {
7085
errors.add('unavailable tag ' + tag.id, tag.loc);
7186
}
72-
else if (tags[tag.id] && (!tag.name || !tag.type)) {
73-
errors.add('incomplete tag ' + tag.id + ' data', tag.loc);
87+
if (!checkFulfill) {
88+
return;
89+
}
90+
91+
// checking tag fullfill
92+
var isFilled = tag.name || tag.type || tag.description;
93+
if (tags[tag.id] === false && isFilled) {
94+
errors.add('unexpected data in tag ' + tag.id, tag.loc);
95+
} else if (tags[tag.id] === true && !isFilled) {
96+
errors.add('incomplete data in tag ' + tag.id, tag.loc);
7497
}
7598
});
7699
});

test/lib/rules/validate-jsdoc/check-annotations.js

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
describe('lib/rules/validate-jsdoc/check-annotations', function () {
1+
describe('lib/rules/validate-jsdoc/check-annotations', function() {
22
var checker = global.checker({
33
additionalRules: ['lib/rules/validate-jsdoc.js']
44
});
55

6-
describe('with true', function () {
6+
describe('with true', function() {
77
checker.rules({checkAnnotations: true});
88

99
checker.cases([
@@ -16,10 +16,116 @@ describe('lib/rules/validate-jsdoc/check-annotations', function () {
1616
* @ppublic
1717
*/
1818
}
19+
},
20+
{
21+
it: 'should not report valid tags',
22+
code: function() {
23+
/** @const FOO */
24+
var FOO = 'bar';
25+
26+
/**
27+
* @chainable
28+
* @abstract
29+
* @accessor
30+
* @param {string} message
31+
* @return {string}
32+
*/
33+
function _f() {}
34+
}
35+
},
36+
{
37+
it: 'should throw @access without data',
38+
errors: {message: 'incomplete data in tag access'},
39+
code: function() {
40+
/** @access */
41+
}
42+
}
43+
/* jshint ignore:end */
44+
]);
45+
});
46+
47+
describe('with "jsduck5"', function() {
48+
checker.rules({checkAnnotations: 'jsduck5'});
49+
50+
checker.cases([
51+
/* jshint ignore:start */
52+
{
53+
it: 'should not throw @alternateClassName',
54+
code: function() {
55+
/** @alternateClassName Vasya */
56+
}
57+
},
58+
{
59+
it: 'should throw unavailable @arg',
60+
errors: {message: 'unavailable tag arg'},
61+
code: function() {
62+
/**
63+
* @arg
64+
*/
65+
}
66+
}
67+
/* jshint ignore:end */
68+
]);
69+
});
70+
71+
describe('with "jsdoc3" and extra tags', function() {
72+
checker.rules({checkAnnotations: {
73+
'preset': 'jsdoc3',
74+
'extra': {
75+
'empty': false,
76+
'fulfilled': true
77+
}
78+
}});
79+
80+
checker.cases([
81+
/* jshint ignore:start */
82+
{
83+
it: 'should not throw @boomer/@argument',
84+
code: function() {
85+
/**
86+
* @empty
87+
* @fulfilled tag
88+
* @argument {String} jsdoc3 specific tag
89+
*/
90+
}
91+
}, {
92+
it: 'should throw invalid tags',
93+
errors: 3,
94+
code: function() {
95+
/**
96+
* @empty with value
97+
* @fulfilled
98+
* @alternateClassName {string}
99+
*/
100+
}
19101
}
20102
/* jshint ignore:end */
21103
]);
104+
});
105+
106+
describe('with "jsdoc3" and disabled @arg, @argument tags', function() {
107+
checker.rules({checkAnnotations: {
108+
'preset': 'jsdoc3',
109+
'extra': {
110+
'arg': null,
111+
'argument': null
112+
}
113+
}});
22114

115+
checker.cases([
116+
/* jshint ignore:start */
117+
{
118+
it: 'should throw',
119+
errors: 2,
120+
code: function() {
121+
/**
122+
* @arg {string}
123+
* @argument {string}
124+
*/
125+
}
126+
}
127+
/* jshint ignore:end */
128+
]);
23129
});
24130

25131
});

0 commit comments

Comments
 (0)