Tom MacWright 631c6925d4 feat(core): Switch to Promises everywhere. Adopt Node v4 ES6 (#648)
* feat(core): Switch to Promises everywhere. Adopt Node v4 ES6

Big changes:

* Uses template strings where appropriate
* Config and argument parsing is unified and there is no such thing
  as formatterOptions anymore. All user-passed options go through
  mergeConfig.
* The node API surface changed (again): `buildSync` is removed,
  building operations return Promises.
* Now using Flow for internal type annotations.

More changes:

* Remove buildSync command
* feat(inference): Partially implement object shorthand support
* Refs #649
* Use Flow annotations to  enforce types
* Keep flow but switch to comment syntax
* Clarify types
* More flow improvements
* Turn server into class
* LinkerStack becomes class too
* Fix comment description type
* Run flow on lint
* Many more flow fixes
* More intense flow refactoring
* Simplify inference steps
* Update inference tests, flow errors down to 1
* Continue refining types
* Fix more flow issues
* Use 'use strict' everywhere
* Make 'ast' property configurable
* Fix many tests
* Fix more tests
* Fix more tests
* Fix augments
* Test Markdown meta support
* Improve test coverage
* Switch back from for of to for for speed
2017-01-27 16:14:19 -05:00
..

/* @flow */
'use strict';


var fs = require('fs');
var remark = require('remark');
var path = require('path');
var documentation = require('../../');
var inject = require('mdast-util-inject');
var chalk = require('chalk');
var disparity = require('disparity');

module.exports.command = 'readme [input..]';
module.exports.description = 'inject documentation into your README.md';
/**
 * Add yargs parsing for the readme command
 * @param {Object} yargs module instance
 * @returns {Object} yargs with options
 * @private
 */
module.exports.builder = {
  usage: 'Usage: documentation readme [--readme-file=README.md] --section "API"' +
    ' [--compare-only] [other documentationjs options]',
  example: 'documentation readme index.js -s "API Docs" --github',
  'readme-file': {
    describe: 'The markdown file into which to inject documentation',
    default: 'README.md'
  },
  'section': {
    alias: 's',
    describe: 'The section heading after which to inject generated documentation',
    required: true
  },
  'diff-only': {
    alias: 'd',
    describe: 'Instead of updating the given README with the generated documentation,' +
      ' just check if its contents match, exiting nonzero if not.',
    default: false
  },
  'quiet': {
    alias: 'q',
    describe: 'Quiet mode: do not print messages or README diff to stdout.',
    default: false
  }
};

function noop() {}

/**
 * Insert API documentation into a Markdown readme
 * @private
 * @param {Object} argv args from the CLI option parser
 * @return {undefined} has the side-effect of writing a file or printing to stdout
 */
module.exports.handler = function readme(argv/*: Object*/) {
  argv._handled = true;

  if (!argv.input.length) {
    try {
      argv.input = [JSON.parse(fs.readFileSync(path.resolve('package.json'), 'utf8')).main || 'index.js'];
    } catch (e) {
      throw new Error('documentation was given no files and was not run in a module directory');
    }
  }

  argv.format = 'remark';
  /* eslint no-console: 0 */
  var log = argv.q ? noop : console.log.bind(console, '[documentation-readme] ');

  var readmeContent = fs.readFileSync(argv.readmeFile, 'utf8');

  documentation.build(argv.input, argv)
    .then(comments =>
      documentation.formats.remark(comments, argv))
   .then(docsAst => remark().use(plugin, {
     section: argv.section,
     toInject: JSON.parse(docsAst)
   }).process(readmeContent))
   .then(file => {
     var diffOutput = disparity.unified(readmeContent, file.contents, {
       paths: [argv.readmeFile, argv.readmeFile]
     });
     if (!diffOutput.length) {
       log(`${argv.readmeFile} is up to date.`);
       process.exit(0);
     }

     if (argv.d) {
       log(chalk.bold(`${argv.readmeFile} needs the following updates:`), `\n${diffOutput}`);
       process.exit(1);
     } else {
       log(chalk.bold(`Updating ${argv.readmeFile}`), `\n${diffOutput}`);
     }

     fs.writeFileSync(argv.readmeFile, file.contents);
   })
   .catch(err => {
     console.error(err);
     process.exit(1);
   });
};

// wrap the inject utility as an remark plugin
function plugin(remark, options) {
  return function transform(targetAst, file, next) {
    if (!inject(options.section, targetAst, options.toInject)) {
      return next(new Error(`Heading ${options.section} not found.`));
    }
    next();
  };
}