UNPKG

3.1 kBJavaScriptView Raw
1const streamArray = require('stream-array');
2const sharedOptions = require('./shared_options');
3const path = require('path');
4const fs = require('fs');
5const vfs = require('vinyl-fs');
6const chokidar = require('chokidar');
7const documentation = require('../');
8const _ = require('lodash');
9
10module.exports.command = 'build [input..]';
11module.exports.describe = 'build documentation';
12
13/**
14 * Add yargs parsing for the build command
15 * @param {Object} yargs module instance
16 * @returns {Object} yargs with options
17 * @private
18 */
19module.exports.builder = Object.assign(
20 {},
21 sharedOptions.sharedOutputOptions,
22 sharedOptions.sharedInputOptions,
23 {
24 output: {
25 describe:
26 'output location. omit for stdout, otherwise is a filename ' +
27 'for single-file outputs and a directory name for multi-file outputs like html',
28 default: 'stdout',
29 alias: 'o'
30 }
31 }
32);
33
34/*
35 * The `build` command. Requires either `--output` or the `callback` argument.
36 * If the callback is provided, it is called with (error, formattedResult);
37 * otherwise, formatted results are outputted based on the value of `--output`.
38 *
39 * The former case, with the callback, is used by the `serve` command, which is
40 * just a thin wrapper around this one.
41 */
42module.exports.handler = function build(argv) {
43 let watcher;
44 argv._handled = true;
45
46 if (!argv.input.length) {
47 try {
48 argv.input = [
49 JSON.parse(fs.readFileSync(path.resolve('package.json'), 'utf8'))
50 .main || 'index.js'
51 ];
52 } catch (e) {
53 throw new Error(
54 'documentation was given no files and was not run in a module directory'
55 );
56 }
57 }
58
59 if (argv.f === 'html' && argv.o === 'stdout') {
60 throw new Error(
61 'The HTML output mode requires a destination directory set with -o'
62 );
63 }
64
65 function generator() {
66 return documentation
67 .build(argv.input, argv)
68 .then(comments =>
69 documentation.formats[argv.format](comments, argv).then(onFormatted)
70 )
71 .catch(err => {
72 /* eslint no-console: 0 */
73 if (err instanceof Error) {
74 console.error(err.stack);
75 } else {
76 console.error(err);
77 }
78 process.exit(1);
79 });
80 }
81
82 function onFormatted(output) {
83 if (argv.watch) {
84 updateWatcher();
85 }
86
87 if (argv.output === 'stdout') {
88 if (argv.watch) {
89 // In watch mode, clear the screen first to make updated outputs
90 // obvious.
91 process.stdout.write('\u001b[2J');
92 }
93 process.stdout.write(output);
94 } else if (Array.isArray(output)) {
95 streamArray(output).pipe(vfs.dest(argv.output));
96 } else {
97 fs.writeFileSync(argv.output, output);
98 }
99 }
100
101 function updateWatcher() {
102 if (!watcher) {
103 watcher = chokidar.watch(argv.input);
104 watcher.on('all', _.debounce(generator, 300));
105 }
106 documentation
107 .expandInputs(argv.input, argv)
108 .then(files =>
109 watcher.add(
110 files.map(data => (typeof data === 'string' ? data : data.file))
111 )
112 );
113 }
114
115 return generator();
116};