Skip to content

Commit 7ff8584

Browse files
committed
Infer parameters
This uses the AST to add (untyped) params where they aren't explicitly specified. Would love to infer types here as well, but espree doesn't support them yet. cc @anandthakker / @jfirebaugh for the review
1 parent c058a0d commit 7ff8584

10 files changed

+354
-1
lines changed

index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ var sort = require('./lib/sort'),
1313
hierarchy = require('./lib/hierarchy'),
1414
inferName = require('./lib/infer/name'),
1515
inferKind = require('./lib/infer/kind'),
16+
inferParams = require('./lib/infer/params'),
1617
inferMembership = require('./lib/infer/membership'),
1718
lint = require('./lib/lint');
1819

@@ -59,7 +60,12 @@ module.exports = function (indexes, options, callback) {
5960
}, [])
6061
.map(function (comment) {
6162
// compose nesting & membership to avoid intermediate arrays
62-
comment = nestParams(inferMembership(inferKind(inferName(lint(comment)))));
63+
comment = nestParams(
64+
inferMembership(
65+
inferParams(
66+
inferKind(
67+
inferName(
68+
lint(comment))))));
6369
if (options.github) {
6470
comment = github(comment);
6571
}

lib/infer/params.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
'use strict';
2+
3+
var types = require('ast-types');
4+
5+
/**
6+
* Infers param tags by reading function parameter names
7+
*
8+
* @name inferParams
9+
* @param {Object} comment parsed comment
10+
* @returns {Object} comment with parameters
11+
*/
12+
module.exports = function inferParams(comment) {
13+
14+
types.visit(comment.context.ast, {
15+
visitFunction: function (path) {
16+
17+
// Ensure that explicitly specified parameters are not overridden
18+
// by inferred parameters
19+
var existingParams = comment.tags.filter(function (tag) {
20+
return tag.title === 'param';
21+
}).reduce(function (memo, param) {
22+
memo[param.name] = param;
23+
return memo;
24+
}, {});
25+
26+
var paramOrder = [];
27+
28+
path.value.params.forEach(function (param) {
29+
if (existingParams[param.name] === undefined) {
30+
comment.tags.push({
31+
title: 'param',
32+
name: param.name,
33+
lineNumber: param.loc.start.line
34+
});
35+
}
36+
paramOrder.push(param.name);
37+
});
38+
39+
// Ensure that if params are specified partially or in
40+
// the wrong order, they'll be output in the order
41+
// they actually appear in code
42+
comment.tags.sort(function (a, b) {
43+
if (a.title === 'param' && b.title === 'param') {
44+
return paramOrder.indexOf(a.name) -
45+
paramOrder.indexOf(b.name);
46+
}
47+
return 0;
48+
});
49+
50+
this.abort();
51+
}
52+
});
53+
54+
return comment;
55+
};

test/fixture/es6.output.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@
1010
"type": "NameExpression",
1111
"name": "Number"
1212
}
13+
},
14+
{
15+
"title": "param",
16+
"name": "a",
17+
"lineNumber": 5
18+
},
19+
{
20+
"title": "param",
21+
"name": "b",
22+
"lineNumber": 5
1323
}
1424
],
1525
"loc": {

test/fixture/factory.output.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@
6767
"lineNumber": 1,
6868
"type": null,
6969
"name": "area"
70+
},
71+
{
72+
"title": "param",
73+
"name": "selection",
74+
"lineNumber": 10
7075
}
7176
],
7277
"loc": {
@@ -115,6 +120,11 @@
115120
"description": null,
116121
"lineNumber": 2,
117122
"name": null
123+
},
124+
{
125+
"title": "param",
126+
"name": "_",
127+
"lineNumber": 17
118128
}
119129
],
120130
"loc": {

test/fixture/infer-params.input.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/* eslint valid-jsdoc: 0 */
2+
3+
/**
4+
* This function returns the number one.
5+
* @param {number} b the second param
6+
*/
7+
function addThem(a, b, c) {
8+
return a + b + c;
9+
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# addThem
2+
3+
This function returns the number one.
4+
5+
6+
**Parameters**
7+
8+
- `b` **number** the second param
9+
10+
11+

test/fixture/infer-params.output.json

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
[
2+
{
3+
"description": "This function returns the number one.",
4+
"tags": [
5+
{
6+
"title": "param",
7+
"name": "a",
8+
"lineNumber": 7
9+
},
10+
{
11+
"title": "param",
12+
"description": "the second param",
13+
"lineNumber": 2,
14+
"type": {
15+
"type": "NameExpression",
16+
"name": "number"
17+
},
18+
"name": "b"
19+
},
20+
{
21+
"title": "param",
22+
"name": "c",
23+
"lineNumber": 7
24+
}
25+
],
26+
"loc": {
27+
"start": {
28+
"line": 3,
29+
"column": 0
30+
},
31+
"end": {
32+
"line": 6,
33+
"column": 3
34+
}
35+
},
36+
"context": {
37+
"loc": {
38+
"start": {
39+
"line": 7,
40+
"column": 0
41+
},
42+
"end": {
43+
"line": 9,
44+
"column": 1
45+
}
46+
},
47+
"code": "function addThem(a, b, c) {\n return a + b + c;\n};"
48+
},
49+
"errors": [],
50+
"params": [
51+
{
52+
"title": "param",
53+
"description": "the second param",
54+
"lineNumber": 2,
55+
"type": {
56+
"type": "NameExpression",
57+
"name": "number"
58+
},
59+
"name": "b"
60+
}
61+
],
62+
"name": "addThem",
63+
"kind": "function",
64+
"members": {
65+
"instance": [],
66+
"static": []
67+
},
68+
"events": [],
69+
"path": [
70+
"addThem"
71+
]
72+
}
73+
]

test/fixture/infer-params.output.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# addThem
2+
3+
This function returns the number one.
4+
5+
6+
**Parameters**
7+
8+
- `b` **number** the second param
9+
10+
11+
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
{
2+
"type": "root",
3+
"children": [
4+
{
5+
"type": "root",
6+
"children": [
7+
{
8+
"depth": 1,
9+
"type": "heading",
10+
"children": [
11+
{
12+
"type": "text",
13+
"value": "addThem"
14+
}
15+
]
16+
},
17+
{
18+
"type": "root",
19+
"children": [
20+
{
21+
"type": "paragraph",
22+
"children": [
23+
{
24+
"type": "text",
25+
"value": "This function returns the number one.",
26+
"position": {
27+
"start": {
28+
"line": 1,
29+
"column": 1
30+
},
31+
"end": {
32+
"line": 1,
33+
"column": 38
34+
},
35+
"indent": []
36+
}
37+
}
38+
],
39+
"position": {
40+
"start": {
41+
"line": 1,
42+
"column": 1
43+
},
44+
"end": {
45+
"line": 1,
46+
"column": 38
47+
},
48+
"indent": []
49+
}
50+
}
51+
],
52+
"position": {
53+
"start": {
54+
"line": 1,
55+
"column": 1
56+
},
57+
"end": {
58+
"line": 1,
59+
"column": 38
60+
}
61+
}
62+
},
63+
{
64+
"type": "root",
65+
"children": [
66+
{
67+
"type": "strong",
68+
"children": [
69+
{
70+
"type": "text",
71+
"value": "Parameters"
72+
}
73+
]
74+
},
75+
{
76+
"ordered": false,
77+
"type": "list",
78+
"children": [
79+
{
80+
"type": "listItem",
81+
"children": [
82+
{
83+
"type": "paragraph",
84+
"children": [
85+
{
86+
"type": "inlineCode",
87+
"value": "b"
88+
},
89+
{
90+
"type": "text",
91+
"value": " "
92+
},
93+
{
94+
"type": "strong",
95+
"children": [
96+
{
97+
"type": "text",
98+
"value": "number"
99+
}
100+
]
101+
},
102+
{
103+
"type": "text",
104+
"value": " "
105+
},
106+
{
107+
"type": "root",
108+
"children": [
109+
{
110+
"type": "paragraph",
111+
"children": [
112+
{
113+
"type": "text",
114+
"value": "the second param",
115+
"position": {
116+
"start": {
117+
"line": 1,
118+
"column": 1
119+
},
120+
"end": {
121+
"line": 1,
122+
"column": 17
123+
},
124+
"indent": []
125+
}
126+
}
127+
],
128+
"position": {
129+
"start": {
130+
"line": 1,
131+
"column": 1
132+
},
133+
"end": {
134+
"line": 1,
135+
"column": 17
136+
},
137+
"indent": []
138+
}
139+
}
140+
],
141+
"position": {
142+
"start": {
143+
"line": 1,
144+
"column": 1
145+
},
146+
"end": {
147+
"line": 1,
148+
"column": 17
149+
}
150+
}
151+
}
152+
]
153+
}
154+
]
155+
}
156+
]
157+
}
158+
]
159+
}
160+
]
161+
}
162+
]
163+
}

0 commit comments

Comments
 (0)