makehtml.cmd.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. var yargs = require('yargs'),
  2. fs = require('fs'),
  3. Messenger = require('./messenger.js'),
  4. showdown = require('../../dist/showdown'),
  5. showdownOptions = showdown.getDefaultOptions(false);
  6. yargs.reset()
  7. .usage('Usage: showdown makehtml [options]')
  8. .example('showdown makehtml -i', 'Reads from stdin and outputs to stdout')
  9. .example('showdown makehtml -i foo.md -o bar.html', 'Reads \'foo.md\' and writes to \'bar.html\'')
  10. .example('showdown makehtml -i --flavor="github"', 'Parses stdin using GFM style')
  11. .version()
  12. .alias('v', 'version')
  13. .config('c')
  14. .alias('c', 'config')
  15. .help('h')
  16. .alias('h', 'help')
  17. .option('i', {
  18. alias : 'input',
  19. describe: 'Input source. Usually a md file. If omitted or empty, reads from stdin',
  20. type: 'string'
  21. })
  22. .option('o', {
  23. alias : 'output',
  24. describe: 'Output target. Usually a html file. If omitted or empty, writes to stdout',
  25. type: 'string',
  26. default: false
  27. })
  28. .option('u', {
  29. alias : 'encoding',
  30. describe: 'Input encoding',
  31. type: 'string'
  32. })
  33. .option('a', {
  34. alias : 'append',
  35. describe: 'Append data to output instead of overwriting',
  36. type: 'string',
  37. default: false
  38. })
  39. .option('e', {
  40. alias : 'extensions',
  41. describe: 'Load the specified extensions. Should be valid paths to node compatible extensions',
  42. type: 'array'
  43. })
  44. .option('p', {
  45. alias : 'flavor',
  46. describe: 'Run with a predetermined flavor of options. Default is vanilla',
  47. type: 'string'
  48. })
  49. .option('q', {
  50. alias: 'quiet',
  51. description: 'Quiet mode. Only print errors',
  52. type: 'boolean',
  53. default: false
  54. })
  55. .option('m', {
  56. alias: 'mute',
  57. description: 'Mute mode. Does not print anything',
  58. type: 'boolean',
  59. default: false
  60. });
  61. // load showdown default options
  62. for (var opt in showdownOptions) {
  63. if (showdownOptions.hasOwnProperty(opt)) {
  64. if (showdownOptions[opt].defaultValue === false) {
  65. showdownOptions[opt].default = null;
  66. } else {
  67. showdownOptions[opt].default = showdownOptions[opt].defaultValue;
  68. }
  69. yargs.option(opt, showdownOptions[opt]);
  70. }
  71. }
  72. function run() {
  73. 'use strict';
  74. var argv = yargs.argv,
  75. readMode = (!argv.i || argv.i === '') ? 'stdin' : 'file',
  76. writeMode = (!argv.o || argv.o === '') ? 'stdout' : 'file',
  77. msgMode = (writeMode === 'file') ? 'stdout' : 'stderr',
  78. /**
  79. * MSG object
  80. * @type {Messenger}
  81. */
  82. messenger = new Messenger(msgMode, argv.q, argv.m),
  83. read = (readMode === 'stdin') ? readFromStdIn : readFromFile,
  84. write = (writeMode === 'stdout') ? writeToStdOut : writeToFile,
  85. enc = argv.encoding || 'utf8',
  86. flavor = argv.p,
  87. append = argv.a || false,
  88. options = parseOptions(flavor),
  89. converter = new showdown.Converter(options),
  90. md, html;
  91. // Load extensions
  92. if (argv.e) {
  93. messenger.printMsg('Loading extensions');
  94. for (var i = 0; i < argv.e.length; ++i) {
  95. try {
  96. var ext = require(argv.e[i]);
  97. converter.addExtension(ext, argv.e[i]);
  98. } catch (e) {
  99. messenger.printError('Could not load extension ' + argv.e[i] + '. Reason:');
  100. messenger.errorExit(e);
  101. }
  102. }
  103. }
  104. messenger.printMsg('...');
  105. // read the input
  106. messenger.printMsg('Reading data from ' + readMode + '...');
  107. md = read(enc);
  108. // process the input
  109. messenger.printMsg('Parsing markdown...');
  110. html = converter.makeHtml(md);
  111. // write the output
  112. messenger.printMsg('Writing data to ' + writeMode + '...');
  113. write(html, append);
  114. messenger.okExit();
  115. function parseOptions(flavor) {
  116. var options = {},
  117. flavorOpts = showdown.getFlavorOptions(flavor) || {};
  118. // if flavor is not undefined, let's tell the user we're loading that preset
  119. if (flavor) {
  120. messenger.printMsg('Loading ' + flavor + ' flavor.');
  121. }
  122. for (var opt in argv) {
  123. if (argv.hasOwnProperty(opt)) {
  124. // first we load the default options
  125. if (showdownOptions.hasOwnProperty(opt) && showdownOptions[opt].default !== null) {
  126. options[opt] = showdownOptions[opt].default;
  127. }
  128. // we now override defaults with flavor, if a flavor was indeed passed
  129. if (flavorOpts.hasOwnProperty(opt)) {
  130. options[opt] = flavorOpts[opt];
  131. }
  132. // lastly we override with explicit passed options
  133. // being careful not to pass CLI specific options, such as -v, -h or --extensions
  134. if (showdownOptions.hasOwnProperty(opt)) {
  135. if (argv[opt] === true) {
  136. messenger.printMsg('Enabling option ' + opt);
  137. options[opt] = argv[opt];
  138. } else if (argv[opt] === false) {
  139. options[opt] = argv[opt];
  140. }
  141. }
  142. }
  143. }
  144. return options;
  145. }
  146. function readFromStdIn() {
  147. try {
  148. var size = fs.fstatSync(process.stdin.fd).size;
  149. return size > 0 ? fs.readSync(process.stdin.fd, size)[0] : '';
  150. } catch (e) {
  151. var err = new Error('Could not read from stdin, reason: ' + e.message);
  152. messenger.errorExit(err);
  153. }
  154. }
  155. function readFromFile(encoding) {
  156. try {
  157. return fs.readFileSync(argv.i, encoding);
  158. } catch (err) {
  159. messenger.errorExit(err);
  160. }
  161. }
  162. function writeToStdOut(html) {
  163. return process.stdout.write(html);
  164. }
  165. function writeToFile(html, append) {
  166. // If a flag is passed, it means we should append instead of overwriting.
  167. // Only works with files, obviously
  168. var write = (append) ? fs.appendFileSync : fs.writeFileSync;
  169. try {
  170. write(argv.o, html);
  171. } catch (err) {
  172. messenger.errorExit(err);
  173. }
  174. }
  175. }
  176. module.exports = exports = {
  177. run: run
  178. };