UNPKG

docma

Version:

A powerful dev-tool to easily generate beautiful HTML documentation from Javascript (JSDoc), Markdown and HTML files.

310 lines (281 loc) 10.4 kB
#!/usr/bin/env node /* eslint prefer-template:0 */ // -------------------------- // DOCMA CLI // -------------------------- 'use strict'; // core modules const path = require('path'); // dep modules const yargs = require('yargs'); const _ = require('lodash'); const fs = require('fs-extra'); const chalk = require('chalk'); // own modules const Docma = require('../lib/Docma'); const serve = require('./commands/serve'); const doctor = require('./commands/template.doctor'); const init = require('./commands/template.init'); const pkg = require('../package.json'); const utils = require('../lib/utils'); // -------------------------- // CLI SETUP // -------------------------- const examples = 'Examples:\n' + '\n * Build documentation with a Docma configuration (JSON) file:\n' + chalk.white(' docma -c path/to/docma.json') + '\n * If a docma.json exists in the current directory, simply:\n' + chalk.white(' docma') + '\n * Output to a different directory:\n' + chalk.white(' docma -c path/to/docma.json -d path/to/docs') + '\n * Re-define source files (ignore the ones defined in the config file):\n' + chalk.white(' docma -c path/to/docma.json -s path/to/lib-1.js -s path/to/lib-2.js') + '\n * Define name-grouped source files:\n' + chalk.white(' docma -c path/to/docma.json -s mylib:path/to/lib-1.js -s mylib:path/to/lib-2.js') + '\n' + '\n * See help for `serve` command:\n' + chalk.white(' docma serve --help') + '\n * See help for `template` command:\n' + chalk.white(' docma template --help'); const serveExamples = 'Examples:\n' + '\n * Serve generated SPA at the default port(9000):\n' + chalk.white(' docma serve path/to/docs') + '\n * Serve current working directory:\n' + chalk.white(' cd path/to/docs && docma serve') + '\n * Serve configured destination directory (looks for a docma.json):\n' + chalk.white(' cd path/to/project && docma serve') + '\n * Configure a custom port and serve:\n' + chalk.white(' docma serve path/to/docs -p 8080') + '\n * Serve without request logs\n' + chalk.white(' docma serve path/to/docs -q'); const templateDoctorExamples = 'Examples:\n' + '\n * Diagnose a Docma template module:\n' + chalk.white(' docma template doctor path/to/project') + '\n * Diagnose a template in current working directory:\n' + chalk.white(' cd path/to/project && docma template doctor'); const info = '\n\n' + chalk.yellow('Docma Repo ') + '@ ' + chalk.blue('https://github.com/onury/docma') + '\n' + chalk.yellow('Docma Docs ') + '@ ' + chalk.blue('https://onury.io/docma') + '\n' + chalk.yellow('Docma CLI ') + ' @ ' + chalk.blue('https://onury.io/docma/cli'); console.log(); const argv = yargs .usage('docma [command] [options]\n\nBuild documentation from Javascript, Markdown and HTML files.') // 'Usage: $0 <cmd> [options]' .help('h', 'Show this help').alias('h', 'help') .version('v', 'Output Docma version', pkg.version).alias('v', 'version') .option('c', { alias: 'config', type: 'string', description: 'Docma JSON configuration file path. You can define all build options within this file. Any option (below) set via CLI will overwrite the value defined in this file.', global: false, normalize: true // apply path.normalize }) .option('s', { alias: 'src', type: 'array', description: '<[name:]path> Source file path. To define multiple source files, this option can be used more than once. To group/name source files, prefix each path with "name:" e.g. -s a.js -s mylib:b.js -s mylib:c.js -s other:d.js', global: false, normalize: true }) .option('d', { alias: 'dest', type: 'string', description: '<path> Destination output directory path.', global: false, normalize: true }) .option('clean', { type: 'boolean', description: 'Whether to empty destination directory before building.', global: false }) .option('web-logs', { type: 'boolean', description: '(Debug) Enable logs in the browser console, for the generated SPA.', global: false }) .option('V', { alias: 'verbose', type: 'boolean', description: '(Debug) Output verbose logs to consoles.', global: false }) .option('nomin', { type: 'boolean', description: '(Debug) Disable minification for the generated SPA assets. (e.g. js, css files)', global: false }) .option('jd-out', { type: 'boolean', description: '(Debug) Output one or more [name.]jsdoc.json files for each (name-grouped) javascript source.', global: false }) .option('debug', { type: 'boolean', description: 'Enable all debugging options. Equivalent to: --web-logs -v --nomin --jd-out', global: false }) .option('q', { alias: 'quiet', type: 'boolean', description: '(Debug) Disable build logs for the Node console.', global: false }) .command('serve [path]', 'Start a static server for the generated SPA.', yargs => { yargs .options({ p: { alias: 'port', describe: 'Port number to bind the mock-server on.', type: 'number', default: 9000, global: false }, b: { alias: 'base', describe: 'Base path for the application.', type: 'string', default: null, global: false }, q: { alias: 'quiet', type: 'boolean', description: 'Disable request logs for the Node console.', global: false } }) .epilog(serveExamples + info); }) .command('template <cmd>', 'Execute template related commands.', yargs => { yargs .command('init [path]', 'Initialize a new Docma template module.', () => { // yargs.options(); }) .command('doctor [path]', 'Diagnose a Docma template.', yargs => { yargs .options({ // v: { alias: 'verbose', default: true }, first: { describe: 'Whether to stop on first fault when diagnosing the template.', default: false, global: false } }) .epilog(templateDoctorExamples + info); }); }) .wrap(80) // .locale('en') .epilog(examples + info) .showHelpOnFail(false, 'Run with --help for available options.') .argv; // -------------------------- // PROGRAM HELPERS // -------------------------- function updateConfig(config) { config = config || {}; if (argv.src && argv.src.length) { config.src = []; let s, p; const named = {}; _.each(argv.src, item => { s = item.split(':'); if (s.length > 1) { p = s[0]; named[p] = named[p] || []; named[p].push(s.slice(1)); } else { config.src.push(item); } }); if (_.keys(named).length) config.src.push(named); } if (argv.dest) config.dest = argv.dest; if (argv.clean) config.clean = Boolean(argv.clean); // DEBUG OPTIONS let debug = 0; if (argv.debug) { debug |= 31; } else { if (argv['web-logs']) debug |= 2; if (argv.verbose) debug |= 4; if (argv.nomin) debug |= 8; if (argv['jd-out']) debug |= 16; } if (debug > 0) { config.debug = debug; } else { config.debug = typeof config.debug === 'boolean' ? (config.debug ? 31 : 1) : (typeof config.debug === 'number' ? config.debug : 1); } if (argv.quiet) { config.debug &= ~1; // unset node logs } else { if (config.debug & 1 === 0) config.debug = 1; } return config; } function getConfigFileSync() { if (argv.config) { if (fs.pathExistsSync(argv.config)) return path.resolve(argv.config); // throw only if -c option is set initially and file does not exist console.error(chalk.red(`Error: Config file "${argv.config}" does not exist.`)); process.exit(1); } // otherwise, try other default config file names. const conf = utils._findDocmaConfigFileSync(); if (conf) { console.log(chalk.blue(`Using configuration file: ${conf}`)); return conf; } // if `docma` is run with no options/commands, // we'll display help. if (!process.argv.slice(2).length) { console.log(chalk.yellow('No source or destination is specified.\n')); yargs.showHelp(); process.exit(0); } // otherwise we'll use empty config console.log(chalk.blue('No configuration file specified. Using default configuration.')); return null; } // -------------------------- // PROGRAM ROUTINE // -------------------------- // console.log(argv); const cmds = argv._ || []; // checking for `serve` command if (cmds.indexOf('serve') >= 0) { serve(argv.path, { port: argv.port, base: argv.base, quiet: argv.quiet }); } else if (cmds.indexOf('template') >= 0) { if (cmds.indexOf('init') >= 0) { init(argv.path); } else if (cmds.indexOf('doctor') >= 0) { doctor(argv.path, { quiet: argv.quiet, stopOnFirstFailure: argv.first }); } } else { const configFile = getConfigFileSync(); Promise.resolve() .then(() => { return configFile ? utils.json.read(configFile) : {}; // use empty config }) .then(config => { config = updateConfig(config); return Docma.create().build(config); }) .catch(error => { console.error(chalk.red(error.stack || error)); }); }