Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0f0ae8f

Browse files
committed
Add a flag to document all exported bindings
This adds a boolean flag called `document-exported` (defaults to false) that effectively adds an empty comment to all exported bindings that do not already have a JSDoc comment. It also does the same for the members of exported classes and objects. ```js export class C { method() {} } ``` Both `C` and `C#method` are now part of the generated documentation. Related to #424
1 parent b506893 commit 0f0ae8f

14 files changed

+853
-62
lines changed

docs/USAGE.md

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,37 +19,41 @@ Commands:
1919
readme inject documentation into your README.md
2020

2121
Options:
22-
--help Show help [boolean]
23-
--version Show version number [boolean]
24-
--shallow shallow mode turns off dependency resolution, only
25-
processing the specified files (or the main script
26-
specified in package.json) [boolean] [default: false]
27-
--config, -c configuration file. an array defining explicit sort order
28-
--external a string / glob match pattern that defines which external
29-
modules will be whitelisted and included in the generated
30-
documentation. [default: null]
31-
--extension, -e only input source files matching this extension will be
32-
parsed, this option can be used multiple times.
33-
--polyglot polyglot mode turns off dependency resolution and enables
34-
multi-language support. use this to document c++ [boolean]
35-
--private, -p generate documentation tagged as private
22+
--help Show help [boolean]
23+
--version Show version number [boolean]
24+
--shallow shallow mode turns off dependency resolution, only
25+
processing the specified files (or the main script
26+
specified in package.json) [boolean] [default: false]
27+
--config, -c configuration file. an array defining explicit sort order
28+
--external a string / glob match pattern that defines which external
29+
modules will be whitelisted and included in the generated
30+
documentation. [default: null]
31+
--extension, -e only input source files matching this extension will be
32+
parsed, this option can be used multiple times.
33+
--polyglot polyglot mode turns off dependency resolution and enables
34+
multi-language support. use this to document c++[boolean]
35+
--private, -p generate documentation tagged as private
3636
[boolean] [default: false]
37-
--access, -a Include only comments with a given access level, out of
38-
private, protected, public, undefined. By default, public,
39-
protected, and undefined access levels are included
37+
--access, -a Include only comments with a given access level, out of
38+
private, protected, public, undefined. By default,
39+
public, protected, and undefined access levels are
40+
included
4041
[choices: "public", "private", "protected", "undefined"]
41-
--github, -g infer links to github in documentation [boolean]
42-
--infer-private Infer private access based on the name. This is a regular
43-
expression that is used to match the name [string]
44-
--theme, -t specify a theme: this must be a valid theme module
45-
--name project name. by default, inferred from package.json
46-
--watch, -w watch input files and rebuild documentation when they
47-
change [boolean]
48-
--project-version project version. by default, inferred from package.json
49-
--output, -o output location. omit for stdout, otherwise is a filename
50-
for single-file outputs and a directory name for multi-file
51-
outputs like html [default: "stdout"]
52-
--format, -f [choices: "json", "md", "html"] [default: "json"]
42+
--github, -g infer links to github in documentation [boolean]
43+
--infer-private Infer private access based on the name. This is a regular
44+
expression that is used to match the name [string]
45+
--document-exported Generate documentation for all exported bindings and
46+
members even if there is no JSDoc for them
47+
[boolean] [default: false]
48+
--theme, -t specify a theme: this must be a valid theme module
49+
--name project name. by default, inferred from package.json
50+
--watch, -w watch input files and rebuild documentation when they
51+
change [boolean]
52+
--project-version project version. by default, inferred from package.json
53+
--output, -o output location. omit for stdout, otherwise is a filename
54+
for single-file outputs and a directory name for
55+
multi-file outputs like html [default: "stdout"]
56+
--format, -f [choices: "json", "md", "remark", "html"] [default: "json"]
5357

5458
Examples:
5559
documentation build foo.js -f md > parse documentation in a file and

index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ function buildSync(indexes, options) {
171171
return index;
172172
}).filter(filterJS(options.extension, options.polyglot))
173173
.reduce(function (memo, file) {
174-
return memo.concat(parseFn(file));
174+
return memo.concat(parseFn(file, options));
175175
}, [])
176176
.map(pipeline(
177177
inferName(),
@@ -226,7 +226,7 @@ function lint(indexes, options, callback) {
226226
inputs
227227
.filter(filterJS(options.extension, options.polyglot))
228228
.reduce(function (memo, file) {
229-
return memo.concat(parseFn(file));
229+
return memo.concat(parseFn(file, options));
230230
}, [])
231231
.map(pipeline(
232232
lintComments,

lib/commands/shared_options.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ function sharedInputOptions(parser) {
5353
type: 'string',
5454
describe: 'Infer private access based on the name. This is a regular expression that ' +
5555
'is used to match the name'
56+
})
57+
.option('document-exported', {
58+
type: 'boolean',
59+
describe: 'Generate documentation for all exported bindings and members ' +
60+
'even if there is no JSDoc for them',
61+
default: false
5662
});
5763
}
5864

lib/parsers/javascript.js

Lines changed: 80 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ function leftPad(str, width) {
2727
* reads the file, parses the JavaScript, and parses the JSDoc.
2828
*
2929
* @param {Object} data a chunk of data provided by module-deps
30+
* @param {Object} options options
3031
* @return {Array<Object>} an array of parsed comments
3132
*/
32-
function parseJavaScript(data) {
33+
function parseJavaScript(data, options) {
34+
options = options || {};
3335
var results = [];
3436
var ast = babylon.parse(data.source, {
3537
allowImportExportEverywhere: true,
@@ -80,31 +82,7 @@ function parseJavaScript(data) {
8082
* @return {undefined} this emits data
8183
*/
8284
function parseComment(comment) {
83-
var context = {
84-
loc: extend({}, JSON.parse(JSON.stringify(path.node.loc))),
85-
file: data.file,
86-
sortKey: data.sortKey + ' ' + leftPad(path.node.loc.start.line, 8)
87-
};
88-
// Avoid visiting the same comment twice as a leading
89-
// and trailing node
90-
var key = JSON.stringify(comment.loc);
91-
if (!visited[key]) {
92-
visited[key] = true;
93-
if (includeContext) {
94-
// This is non-enumerable so that it doesn't get stringified in
95-
// output; e.g. by the documentation binary.
96-
Object.defineProperty(context, 'ast', {
97-
enumerable: false,
98-
value: path
99-
});
100-
101-
if (path.parentPath && path.parentPath.node) {
102-
context.code = data.source.substring
103-
.apply(data.source, path.parentPath.node.range);
104-
}
105-
}
106-
results.push(parse(comment.value, comment.loc, context));
107-
}
85+
addComment(comment.value, comment.loc, path, path.node.loc, includeContext);
10886
}
10987

11088
(path.node[type] || [])
@@ -114,10 +92,86 @@ function parseJavaScript(data) {
11492
});
11593
}
11694

95+
function addComment(commentValue, commentLoc, path, nodeLoc, includeContext) {
96+
var context = {
97+
loc: extend({}, JSON.parse(JSON.stringify(nodeLoc))),
98+
file: data.file,
99+
sortKey: data.sortKey + ' ' + leftPad(nodeLoc.start.line, 8)
100+
};
101+
// Avoid visiting the same comment twice as a leading
102+
// and trailing node
103+
var key = JSON.stringify(commentLoc);
104+
if (!visited[key]) {
105+
visited[key] = true;
106+
if (includeContext) {
107+
// This is non-enumerable so that it doesn't get stringified in
108+
// output; e.g. by the documentation binary.
109+
Object.defineProperty(context, 'ast', {
110+
enumerable: false,
111+
value: path
112+
});
113+
114+
if (path.parentPath && path.parentPath.node) {
115+
context.code = data.source.substring
116+
.apply(data.source, path.parentPath.node.range);
117+
}
118+
}
119+
results.push(parse(commentValue, commentLoc, context));
120+
}
121+
}
122+
123+
function addBlankComment(path, node) {
124+
addComment('', node.loc, path, node.loc, true);
125+
}
126+
127+
function walkExported(ast) {
128+
traverse(ast, {
129+
enter: function (path) {
130+
if (path.isExportDeclaration()) {
131+
if (!hasJSDocComment(path)) {
132+
if (!path.node.declaration) {
133+
return;
134+
}
135+
const node = path.node.declaration;
136+
addBlankComment(path, node);
137+
}
138+
} else if ((path.isClassProperty() || path.isClassMethod()) &&
139+
!hasJSDocComment(path) && inExportedClass(path)) {
140+
addBlankComment(path, path.node);
141+
} else if ((path.isObjectProperty() || path.isObjectMethod()) &&
142+
!hasJSDocComment(path) && inExportedObject(path)) {
143+
addBlankComment(path, path.node);
144+
}
145+
}
146+
});
147+
}
148+
149+
function hasJSDocComment(path) {
150+
return path.node.leadingComments && path.node.leadingComments.some(isJSDocComment);
151+
}
152+
153+
function inExportedClass(path) {
154+
var c = path.parentPath.parentPath;
155+
return c.isClass() && c.parentPath.isExportDeclaration();
156+
}
157+
158+
function inExportedObject(path) {
159+
// ObjectExpression -> VariableDeclarator -> VariableDeclaration -> ExportNamedDeclaration
160+
var p = path.parentPath.parentPath;
161+
if (!p.isVariableDeclarator()) {
162+
return false;
163+
}
164+
return p.parentPath.parentPath.isExportDeclaration();
165+
}
166+
117167
walkComments(ast, 'leadingComments', true);
118168
walkComments(ast, 'innerComments', false);
119169
walkComments(ast, 'trailingComments', false);
120170

171+
if (options.documentExported) {
172+
walkExported(ast);
173+
}
174+
121175
return results;
122176
}
123177

test/bin.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,18 @@ test('fatal error', function (t) {
341341
t.end();
342342
}, false);
343343
}, options);
344+
345+
test('build --document-exported', function (t) {
346+
documentation(['build fixture/document-exported.input.js --document-exported -f md'], {}, function (err, data) {
347+
t.error(err);
348+
349+
var outputfile = path.join(__dirname, 'fixture', 'document-exported.output.enabled.md');
350+
if (process.env.UPDATE) {
351+
fs.writeFileSync(outputfile, data, 'utf8');
352+
}
353+
354+
var expect = fs.readFileSync(outputfile, 'utf-8');
355+
t.equal(data, expect);
356+
t.end();
357+
}, false);
358+
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
export class Class {
2+
classMethod() {}
3+
get classGetter() {}
4+
set classSetter(v) {}
5+
static staticMethod() {}
6+
static get staticGetter() {}
7+
static set staticSetter(v) {}
8+
}
9+
10+
export var object = {
11+
method() {},
12+
get getter() {},
13+
set setter(v) {},
14+
prop: 42,
15+
func: function() {},
16+
};
17+
18+
class NotExportedClass {
19+
classMethod() {}
20+
get classGetter() {}
21+
set classSetter(v) {}
22+
static staticMethod() {}
23+
static get staticGetter() {}
24+
static set staticSetter(v) {}
25+
}
26+
27+
var notExportedObject = {
28+
method() {},
29+
get getter() {},
30+
set setter(v) {},
31+
prop: 42,
32+
func: function() {},
33+
};

0 commit comments

Comments
 (0)