Skip to content

Start --watch integration #236

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 24, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
## 4.0.0

**Revitalized documentation.js command line interface!**

The `documentation` utility now takes commands:

* `documentation build` extracts and formats documentation
* `documentation serve` provides an auto-reloading server
* `documentation lint` reviews files for inconsistencies

This functionality was previously included in `dev-documentation` and has
been folded into `documentation` proper.

## 3.0.4

* Allow parameter types to be mixed into explicit parameter documentation. (#239 and #232)
Expand Down
81 changes: 60 additions & 21 deletions bin/documentation.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,80 @@
'use strict';

var documentation = require('../'),
chokidar = require('chokidar'),
debounce = require('debounce'),
streamArray = require('stream-array'),
fs = require('fs'),
vfs = require('vinyl-fs'),
lint = require('../lib/lint'),
args = require('../lib/args.js');
errorPage = require('../lib/error_page'),
Server = require('../lib/server'),
args = require('../lib/args');

var parsedArgs = args(process.argv.slice(2)),
formatterOptions = parsedArgs.formatterOptions,
outputLocation = parsedArgs.output,
formatter = documentation.formats[parsedArgs.formatter];
var parsedArgs = args(process.argv.slice(2));

documentation(parsedArgs.inputs, parsedArgs.options, function (err, comments) {
var generator = documentation.bind(null,
parsedArgs.inputs, parsedArgs.options, onDocumented.bind(null, parsedArgs));

var server = new Server();
server.on('listening', function () {
process.stdout.write('documentation.js serving on port 4001\n');
});

function onDocumented(parsedArgs, err, comments) {
if (err) {
if (parsedArgs.command === 'serve') {
return server.setFiles([errorPage(err)]).start();
}
throw err;
}

if (parsedArgs.options.lint) {
var lintOutput = lint.format(comments);
documentation.formats[parsedArgs.formatter](
comments, parsedArgs.formatterOptions,
onFormatted.bind(null, parsedArgs));
}

function onFormatted(parsedArgs, err, output) {
if (parsedArgs.watch) {
updateWatcher();
}

if (parsedArgs.command === 'serve') {
server.setFiles(output).start();
} else if (parsedArgs.output === 'stdout') {
process.stdout.write(output);
} else if (Array.isArray(output)) {
streamArray(output).pipe(vfs.dest(parsedArgs.output));
} else {
fs.writeFileSync(parsedArgs.output, output);
}
}

if (parsedArgs.command === 'lint') {
documentation.lint(parsedArgs.inputs, parsedArgs.options, function (err, lintOutput) {
if (err) {
throw err;
}
if (lintOutput) {
console.log(lintOutput);
process.exit(1);
} else {
process.exit(0);
}
});
} else {
generator();
if (parsedArgs.watch) {
var watcher = chokidar.watch(parsedArgs.inputs);
watcher.on('all', debounce(generator, 300));
}
}

formatter(comments, formatterOptions, function (err, output) {
if (outputLocation !== 'stdout') {
if (parsedArgs.formatter === 'html') {
streamArray(output).pipe(vfs.dest(outputLocation));
} else {
fs.writeFileSync(outputLocation, output);
}
} else {
process.stdout.write(output);
}
});
});
function updateWatcher() {
documentation.expandInputs(parsedArgs.inputs, parsedArgs.options, addNewFiles);
}

function addNewFiles(err, files) {
watcher.add(files.map(function (data) {
return data.file;
}));
}
79 changes: 74 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ var sort = require('./lib/sort'),
inferProperties = require('./lib/infer/properties'),
inferMembership = require('./lib/infer/membership'),
inferReturn = require('./lib/infer/return'),
lint = require('./lib/lint');
formatLint = require('./lib/lint').formatLint,
lintComments = require('./lib/lint').lintComments;

/**
* Build a pipeline of comment handlers.
Expand Down Expand Up @@ -45,6 +46,20 @@ function noop(comment) {
return comment;
}

/**
* Given an array of indexes and options for whether to resolve shallow
* or deep dependencies, resolve dependencies.
*
* @param {Array<string>|string} indexes files to process
* @param {Object} options options
* @param {Function} callback called with results
* @returns {undefined}
*/
function expandInputs(indexes, options, callback) {
var inputFn = (options.polyglot || options.shallow) ? shallow : dependency;
inputFn(indexes, options, callback);
}

/**
* Generate JavaScript documentation as a list of parsed JSDoc
* comments, given a root file as a path.
Expand Down Expand Up @@ -75,25 +90,23 @@ module.exports = function (indexes, options, callback) {
indexes = [indexes];
}

var inputFn = (options.polyglot || options.shallow) ? shallow : dependency;
var parseFn = (options.polyglot) ? polyglot : parseJavaScript;

return inputFn(indexes, options, function (error, inputs) {
return expandInputs(indexes, options, function (error, inputs) {
if (error) {
return callback(error);
}
try {
callback(null,
filterAccess(
(options.private || options.lint) ? [] : undefined,
options.private ? [] : undefined,
hierarchy(
inputs
.filter(filterJS)
.reduce(function (memo, file) {
return memo.concat(parseFn(file));
}, [])
.map(pipeline(
lint.lint,
inferName(),
inferKind(),
inferParams(),
Expand All @@ -111,6 +124,62 @@ module.exports = function (indexes, options, callback) {
});
};

/**
* Lint files for non-standard or incorrect documentation
* information, returning a potentially-empty string
* of lint information intended for human-readable output.
*
* @param {Array<string>|string} indexes files to process
* @param {Object} options options
* @param {Array<string>} options.external a string regex / glob match pattern
* that defines what external modules will be whitelisted and included in the
* generated documentation.
* @param {Array<string>} options.transform source transforms given as strings
* passed to [the module-deps transform option](https://github.com/substack/module-deps)
* @param {boolean} [options.polyglot=false] parse comments with a regex rather than
* a proper parser. This enables support of non-JavaScript languages but
* reduces documentation's ability to infer structure of code.
* @param {boolean} [options.shallow=false] whether to avoid dependency parsing
* even in JavaScript code. With the polyglot option set, this has no effect.
* @param {Function} callback to be called when the documentation generation
* is complete, with (err, result) argumentsj
* @returns {undefined} calls callback
*/
module.exports.lint = function lint(indexes, options, callback) {
options = options || {};

if (typeof indexes === 'string') {
indexes = [indexes];
}

var parseFn = (options.polyglot) ? polyglot : parseJavaScript;

return expandInputs(indexes, options, function (error, inputs) {
if (error) {
return callback(error);
}
callback(null,
formatLint(hierarchy(
inputs
.filter(filterJS)
.reduce(function (memo, file) {
return memo.concat(parseFn(file));
}, [])
.map(pipeline(
lintComments,
inferName(),
inferKind(),
inferParams(),
inferProperties(),
inferReturn(),
inferMembership(),
nest))
.filter(Boolean))));
});
};

module.exports.expandInputs = expandInputs;

module.exports.formats = {
html: require('./lib/output/html'),
md: require('./lib/output/markdown'),
Expand Down
Loading