Skip to content

Commit 986be00

Browse files
committed
feat(bin): Support globs on windows and use smarter recursion
This brings logic from eslint over to documentation: instead of readdirSync, we're using the glob module. This also, I hope, will let us support globs on Windows without changing OSX/Linux behavior. Fixes #607
1 parent 7a66b3f commit 986be00

15 files changed

+294
-122
lines changed

LICENSE

+25
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,28 @@ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16+
17+
--------------------------------------------------------------------------------
18+
19+
Contains sections of eslint
20+
21+
ESLint
22+
Copyright JS Foundation and other contributors, https://js.foundation
23+
24+
Permission is hereby granted, free of charge, to any person obtaining a copy
25+
of this software and associated documentation files (the "Software"), to deal
26+
in the Software without restriction, including without limitation the rights
27+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28+
copies of the Software, and to permit persons to whom the Software is
29+
furnished to do so, subject to the following conditions:
30+
31+
The above copyright notice and this permission notice shall be included in
32+
all copies or substantial portions of the Software.
33+
34+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
40+
THE SOFTWARE.

docs/POLYGLOT.md

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# About documentation.js, polyglot mode, and file extensions
2+
3+
Base assumptions:
4+
5+
* documentation.js subsists on a combination of _source comments_ and
6+
_smart inferences from source code_.
7+
* The default mode of documentation.js is parsing JavaScript, but it has another
8+
mode, called `--polyglot` mode, that doesn't include any inference at all
9+
and lets you document other kinds of source code.
10+
* The default settings for everything should work for most projects, but
11+
this is a guide for if you have a particular setup.
12+
13+
## File extensions
14+
15+
Let's talk about file extensions. We have two different flags for controlling
16+
file extensions: `requireExtension` and `parseExtension`.
17+
18+
* requireExtension adds additional filetypes to the node.js `require()` method.
19+
By default, you can call, for instance, `require('foo')`, and the require algorithm
20+
will look for `foo.js`, `foo` the module, and `foo.json`. Adding another
21+
extension in requireExtension lets it look for `foo.otherextension`.
22+
* parseExtension adds additional filetypes to the list of filetypes documentation.js
23+
thinks it can parse, and it also adds those additional filetypes to the default
24+
files it looks for when you specify a directory or glob as input.
25+
26+
## Polyglot
27+
28+
Polyglot mode switches documentation.js from running on babylon and [babel](https://babeljs.io/)
29+
as a JavaScript parser, to using [get-comments](https://github.com/tunnckocore/get-comments).
30+
This lets it grab comments formatted in the `/** Comment */` style from source
31+
code that _isn't_ JavaScript, like C++ or CSS code.
32+
33+
Since documentation.js doesn't _parse_ C++ and lots of other languages (parsing JavaScript is complicated enough!),
34+
it can't make any of its smart inferences about their source code: it just
35+
takes documentation comments and shows them as-is.
36+
37+
You _can_ use polyglot mode to turn off inference across the board, but I don't recommend
38+
it. See the 'too much inference' topic in [TROUBLESHOOTING.md](TROUBLESHOOTING.md)
39+
for detail about that.

index.js

+4-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ var fs = require('fs'),
55
sort = require('./lib/sort'),
66
nest = require('./lib/nest'),
77
filterAccess = require('./lib/filter_access'),
8-
filterJS = require('./lib/filter_js'),
98
dependency = require('./lib/input/dependency'),
109
shallow = require('./lib/input/shallow'),
1110
parseJavaScript = require('./lib/parsers/javascript'),
@@ -27,6 +26,8 @@ var fs = require('fs'),
2726
markdownAST = require('./lib/output/markdown_ast'),
2827
loadConfig = require('./lib/load_config');
2928

29+
var parseExtensions = ['js', 'jsx', 'es5', 'es6'];
30+
3031
/**
3132
* Build a pipeline of comment handlers.
3233
* @param {...Function|null} args - Pipeline elements. Each is a function that accepts
@@ -62,6 +63,8 @@ function expandInputs(indexes, options, callback) {
6263
} else {
6364
inputFn = dependency;
6465
}
66+
options.parseExtensions = parseExtensions
67+
.concat(options.parseExtension || []);
6568
inputFn(indexes, options, callback);
6669
}
6770

@@ -214,8 +217,6 @@ function buildSync(indexes, options) {
214217
options.github && github,
215218
garbageCollect);
216219

217-
var jsFilterer = filterJS(options.extension, options.polyglot);
218-
219220
return filterAccess(options.access,
220221
hierarchy(
221222
sort(
@@ -231,10 +232,6 @@ function buildSync(indexes, options) {
231232
indexObject = index;
232233
}
233234

234-
if (!jsFilterer(indexObject)) {
235-
return [];
236-
}
237-
238235
return parseFn(indexObject, options).map(buildPipeline);
239236
})
240237
.filter(Boolean), options)));
@@ -309,7 +306,6 @@ function lint(indexes, options, callback) {
309306
callback(null,
310307
formatLint(hierarchy(
311308
inputs
312-
.filter(filterJS(options.extension, options.polyglot))
313309
.reduce(function (memo, file) {
314310
return memo.concat(parseFn(file, options).map(lintPipeline));
315311
}, [])

lib/commands/shared_options.js

+16-4
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,22 @@ module.exports.sharedInputOptions = {
2424
'modules will be whitelisted and included in the generated documentation.',
2525
default: null
2626
},
27-
'extension': {
28-
describe: 'only input source files matching this extension will be parsed, ' +
29-
'this option can be used multiple times.',
30-
alias: 'e'
27+
'requireExtension': {
28+
describe: 'additional extensions to include in require() and import\'s search algorithm.' +
29+
'For instance, adding .es5 would allow require("adder") to find "adder.es5"',
30+
coerce: function (value) {
31+
// Ensure that the value is an array
32+
return [].concat(value);
33+
},
34+
alias: 're'
35+
},
36+
'parseExtension': {
37+
describe: 'additional extensions to parse as source code.',
38+
coerce: function (value) {
39+
// Ensure that the value is an array
40+
return [].concat(value);
41+
},
42+
alias: 'pe'
3143
},
3244
'polyglot': {
3345
type: 'boolean',

lib/filter_js.js

-34
This file was deleted.

lib/input/dependency.js

+28-20
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
'use strict';
22

3-
var mdeps = require('module-deps-sortable'),
4-
fs = require('fs'),
5-
path = require('path'),
6-
babelify = require('babelify'),
7-
filterJS = require('../filter_js'),
8-
concat = require('concat-stream'),
9-
moduleFilters = require('../../lib/module_filters'),
10-
expandDirectories = require('./expand_directories');
3+
var mdeps = require('module-deps-sortable');
4+
var fs = require('fs');
5+
var path = require('path');
6+
var babelify = require('babelify');
7+
var concat = require('concat-stream');
8+
var moduleFilters = require('../../lib/module_filters');
9+
var smartGlob = require('../smart_glob.js');
1110

1211
/**
1312
* Returns a readable stream of dependencies, given an array of entry
@@ -22,8 +21,6 @@ var mdeps = require('module-deps-sortable'),
2221
* @returns {undefined} calls callback
2322
*/
2423
function dependencyStream(indexes, options, callback) {
25-
var filterer = filterJS(options.extension, options.polyglot);
26-
2724
var md = mdeps({
2825
/**
2926
* Determine whether a module should be included in documentation
@@ -33,11 +30,11 @@ function dependencyStream(indexes, options, callback) {
3330
filter: function (id) {
3431
return !!options.external || moduleFilters.internalOnly(id);
3532
},
36-
extensions: [].concat(options.extension || [])
37-
.concat(['js', 'es6', 'jsx', 'json'])
33+
extensions: [].concat(options.requireExtension || [])
3834
.map(function (ext) {
39-
return '.' + ext;
40-
}),
35+
return '.' + ext.replace(/^\./, '');
36+
})
37+
.concat(['.js', '.json', '.es6', '.jsx']),
4138
transform: [babelify.configure({
4239
sourceMap: false,
4340
compact: false,
@@ -55,19 +52,30 @@ function dependencyStream(indexes, options, callback) {
5552
})],
5653
postFilter: moduleFilters.externals(indexes, options)
5754
});
58-
expandDirectories(indexes, filterer).forEach(function (index) {
55+
smartGlob(indexes, options.parseExtensions).forEach(function (index) {
5956
md.write(path.resolve(index));
6057
});
6158
md.end();
6259
md.once('error', function (error) {
6360
return callback(error);
6461
});
6562
md.pipe(concat(function (inputs) {
66-
callback(null, inputs.map(function (input) {
67-
// un-transform babelify transformed source
68-
input.source = fs.readFileSync(input.file, 'utf8');
69-
return input;
70-
}));
63+
callback(null, inputs
64+
.filter(function (input) {
65+
// At this point, we may have allowed a JSON file to be caught by
66+
// module-deps, or anything else allowed by requireExtension.
67+
// otherwise module-deps would complain about
68+
// it not being found. But Babel can't parse JSON, so we filter non-JavaScript
69+
// files away.
70+
return options.parseExtensions.indexOf(
71+
path.extname(input.file).replace(/^\./, '')
72+
) > -1;
73+
})
74+
.map(function (input) {
75+
// un-transform babelify transformed source
76+
input.source = fs.readFileSync(input.file, 'utf8');
77+
return input;
78+
}));
7179
}));
7280
}
7381

lib/input/expand_directories.js

-40
This file was deleted.

lib/input/shallow.js

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict';
22

3-
var filterJS = require('../filter_js');
4-
var expandDirectories = require('./expand_directories');
3+
var smartGlob = require('../smart_glob.js');
54

65
/**
76
* A readable source for content that doesn't do dependency resolution, but
@@ -21,6 +20,16 @@ var expandDirectories = require('./expand_directories');
2120
* @return {undefined} calls callback
2221
*/
2322
module.exports = function (indexes, options, callback) {
24-
var filterer = filterJS(options.extension, options.polyglot);
25-
return callback(null, expandDirectories(indexes, filterer));
23+
var objects = [];
24+
var strings = [];
25+
indexes.forEach(function (index) {
26+
if (typeof index === 'string') {
27+
strings.push(index);
28+
} else if (typeof index === 'object') {
29+
objects.push(index);
30+
} else {
31+
throw new Error('Indexes should be either strings or objects');
32+
}
33+
});
34+
return callback(null, objects.concat(smartGlob(strings, options.parseExtensions)));
2635
};

0 commit comments

Comments
 (0)