Skip to content

Commit dc6bf05

Browse files
author
Alexej Yaroshevich
committed
add dev docs with internal api for happy contributing
Fixes #53
1 parent 4ba9648 commit dc6bf05

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed

CONTRIBUTION.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@ Features
2929
It you've got an idea about a new feature, it's most likely that you'll have to implement it on your own.
3030
If you cannot implement the feature, but it is very important, you can create an issue at GitHub,
3131
but expect it to be declined by the maintainer.
32+
33+
Feel free to add your own rules. We really need to know your guide styles to write js documentation.
34+
35+
Please read [maintainers guide](./MAINTAIN.md) with inner API and some other things.

MAINTAIN.md

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# README for contributors
2+
3+
## Naming convention
4+
5+
Rules should be placed as they are in configuration. Their names should be hyphenized (as well as in jscs).
6+
7+
Tests for them should be placed in the same manner in `./test` directory. For one rule file should be maked one test file with the same name.
8+
9+
## Rule formats
10+
11+
There are 3 rule formats atm to simplify developing:
12+
13+
- Classic (used in `jscs`) - function with JSFile and JSErrors objects
14+
- Scope based - function with specified scope and 2 params: esprima node object and err callback
15+
- Tag based - function with specified tags and 3 params: DocTag, esprima node object (if exists) and err callback
16+
17+
Scopes and tags are pretty fine for structurizing rules for jsdocs (at some pov) but also there are iterators in file and jsdoc blocks.
18+
19+
### Classic
20+
21+
Some times you need to have full data of file to check it. You can take a look at [checkTypes rule](https://github.com/jscs-dev/jscs-jsdoc/blob/master/lib/rules/validate-jsdoc/check-types.js)
22+
23+
```js
24+
// passing a function
25+
module.exports = ruleChecker;
26+
// define a scope 'file'
27+
module.exports.scopes = ['file'];
28+
// define allowed options
29+
module.exports.options = {
30+
rule: {allowedValues: [true]}
31+
};
32+
33+
/**
34+
* @param {JSCS.JSFile} file
35+
* @param {JSCS.Errors} errors
36+
*/
37+
function ruleChecker(file, errors) {
38+
var comments = file.getComments();
39+
comments.forEach(function(commentNode) {
40+
if (commentNode.type !== 'Block' || commentNode.value[0] !== '*') {
41+
return;
42+
}
43+
44+
// trying to create DocComment object
45+
var node = jsdoc.createDocCommentByCommentNode(commentNode);
46+
if (!node.valid) {
47+
errors.add('invalid doc comment block', node.loc.start);
48+
}
49+
50+
node.iterate(function(tag) {
51+
// test tags here
52+
)}
53+
});
54+
}
55+
```
56+
57+
### Scope based
58+
59+
For now it's only function scope. But it could be a variable, or some other important places. (need to know about it actually)
60+
61+
```js
62+
module.exports = ruleChecker;
63+
module.exports.scopes = ['function'];
64+
module.exports.options = {
65+
rule: {allowedValues: [true]}
66+
};
67+
68+
/**
69+
* @param {(FunctionDeclaration|FunctionExpression)} node
70+
* @param {function(string,DocLocation|number,?number)} err
71+
*/
72+
function ruleChecker(node, err) {
73+
if (!node.jsdoc) {
74+
return;
75+
}
76+
77+
// will check only `@nohugshere` tags in function jsdocs
78+
node.jsdoc.iterateByType(['nohugshere'],
79+
function (tag, i) {
80+
if (tag.value.indexOf('hug')) {
81+
err('hug found in tag ' + tag.id, tag.loc);
82+
}
83+
});
84+
}
85+
```
86+
87+
### Tag based
88+
89+
```js
90+
module.exports = ruleChecker;
91+
module.exports.tags = ['foo', 'bar', 'baz'];
92+
module.exports.scopes = ['function'];
93+
module.exports.options = {
94+
rule: {allowedValues: [true]}
95+
};
96+
97+
/**
98+
* @param {(FunctionDeclaration|FunctionExpression)} node
99+
* @param {DocTag} tag
100+
* @param {Function} err
101+
*/
102+
function ruleChecker(node, tag, err) {
103+
// etc.
104+
}
105+
```
106+
107+
## Tests
108+
109+
The root name of each test should be full path name of rule without `.js` suffix (to simplify debugging process).
110+
111+
Each section in test file could be splitted to several sections: allowed params tests, functional tests, and location tests.
112+
113+
Also there're [some helpers](./test/init.js) to simplify test development. Most important of them are global.checker, and chai's `.deep.similar` assertion.
114+
115+
### Tests checker
116+
117+
This object provides few methods to make tests much easier:
118+
- __construct(opts) - makes checker wrapper object
119+
- configure(opts) - to configure checker instantly
120+
- check - to check case instantly
121+
- rules - to configure checker before each case
122+
- cases - to describe what cases it should check
123+
124+
```js
125+
describe('lib/rules/validate-jsdoc/some-rule', function () {
126+
var checker = global.checker({
127+
additionalRules: ['lib/rules/validate-jsdoc.js']
128+
});
129+
130+
checker.rules({commonRule: true});
131+
checker.cases([
132+
/* jshint ignore:start */
133+
{
134+
it: 'should not report',
135+
code: function() {
136+
// some code here
137+
}
138+
}, {
139+
it: 'should report something',
140+
errors: 1,
141+
code: function () {}
142+
}, {
143+
it: 'should report something concrete',
144+
errors: {loc: {line: 5, column:10}},
145+
code: function () {}
146+
}, {
147+
it: 'should be called with additional rules',
148+
rules: {additionalRule: 'orAnother'},
149+
errors: {loc: {line: 5, column:10}},
150+
code: function () {}
151+
}
152+
/* jshint ignore:end */
153+
]);
154+
});
155+
```
156+
157+
## Another helpful things
158+
159+
There're pretty simple `Doc*` objects so please take a look at [their code](./lib/jsdoc.js).
160+
161+
Also we have some helpers in the [root rule file](./lib/rules/validate-jsdoc.js).

0 commit comments

Comments
 (0)