marked.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #!/usr/bin/env node
  2. /**
  3. * Marked CLI
  4. * Copyright (c) 2011-2013, Christopher Jeffrey (MIT License)
  5. */
  6. import { promises } from 'fs';
  7. import { marked } from '../lib/marked.esm.js';
  8. const { readFile, writeFile } = promises;
  9. /**
  10. * Man Page
  11. */
  12. async function help() {
  13. const { spawn } = await import('child_process');
  14. const options = {
  15. cwd: process.cwd(),
  16. env: process.env,
  17. setsid: false,
  18. stdio: 'inherit'
  19. };
  20. const { dirname, resolve } = await import('path');
  21. const { fileURLToPath } = await import('url');
  22. const __dirname = dirname(fileURLToPath(import.meta.url));
  23. const helpText = await readFile(resolve(__dirname, '../man/marked.1.txt'), 'utf8');
  24. // eslint-disable-next-line promise/param-names
  25. await new Promise(res => {
  26. spawn('man', [resolve(__dirname, '../man/marked.1')], options)
  27. .on('error', () => {
  28. console.log(helpText);
  29. })
  30. .on('close', res);
  31. });
  32. }
  33. async function version() {
  34. const { createRequire } = await import('module');
  35. const require = createRequire(import.meta.url);
  36. const pkg = require('../package.json');
  37. console.log(pkg.version);
  38. }
  39. /**
  40. * Main
  41. */
  42. async function main(argv) {
  43. const files = [];
  44. const options = {};
  45. let input;
  46. let output;
  47. let string;
  48. let arg;
  49. let tokens;
  50. let opt;
  51. function getarg() {
  52. let arg = argv.shift();
  53. if (arg.indexOf('--') === 0) {
  54. // e.g. --opt
  55. arg = arg.split('=');
  56. if (arg.length > 1) {
  57. // e.g. --opt=val
  58. argv.unshift(arg.slice(1).join('='));
  59. }
  60. arg = arg[0];
  61. } else if (arg[0] === '-') {
  62. if (arg.length > 2) {
  63. // e.g. -abc
  64. argv = arg.substring(1).split('').map(function(ch) {
  65. return '-' + ch;
  66. }).concat(argv);
  67. arg = argv.shift();
  68. } else {
  69. // e.g. -a
  70. }
  71. } else {
  72. // e.g. foo
  73. }
  74. return arg;
  75. }
  76. while (argv.length) {
  77. arg = getarg();
  78. switch (arg) {
  79. case '-o':
  80. case '--output':
  81. output = argv.shift();
  82. break;
  83. case '-i':
  84. case '--input':
  85. input = argv.shift();
  86. break;
  87. case '-s':
  88. case '--string':
  89. string = argv.shift();
  90. break;
  91. case '-t':
  92. case '--tokens':
  93. tokens = true;
  94. break;
  95. case '-h':
  96. case '--help':
  97. return await help();
  98. case '-v':
  99. case '--version':
  100. return await version();
  101. default:
  102. if (arg.indexOf('--') === 0) {
  103. opt = camelize(arg.replace(/^--(no-)?/, ''));
  104. if (!marked.defaults.hasOwnProperty(opt)) {
  105. continue;
  106. }
  107. if (arg.indexOf('--no-') === 0) {
  108. options[opt] = typeof marked.defaults[opt] !== 'boolean'
  109. ? null
  110. : false;
  111. } else {
  112. options[opt] = typeof marked.defaults[opt] !== 'boolean'
  113. ? argv.shift()
  114. : true;
  115. }
  116. } else {
  117. files.push(arg);
  118. }
  119. break;
  120. }
  121. }
  122. async function getData() {
  123. if (!input) {
  124. if (files.length <= 2) {
  125. if (string) {
  126. return string;
  127. }
  128. return await getStdin();
  129. }
  130. input = files.pop();
  131. }
  132. return await readFile(input, 'utf8');
  133. }
  134. const data = await getData();
  135. const html = tokens
  136. ? JSON.stringify(marked.lexer(data, options), null, 2)
  137. : marked(data, options);
  138. if (output) {
  139. return await writeFile(output, html);
  140. }
  141. process.stdout.write(html + '\n');
  142. }
  143. /**
  144. * Helpers
  145. */
  146. function getStdin() {
  147. return new Promise((resolve, reject) => {
  148. const stdin = process.stdin;
  149. let buff = '';
  150. stdin.setEncoding('utf8');
  151. stdin.on('data', function(data) {
  152. buff += data;
  153. });
  154. stdin.on('error', function(err) {
  155. reject(err);
  156. });
  157. stdin.on('end', function() {
  158. resolve(buff);
  159. });
  160. stdin.resume();
  161. });
  162. }
  163. function camelize(text) {
  164. return text.replace(/(\w)-(\w)/g, function(_, a, b) {
  165. return a + b.toUpperCase();
  166. });
  167. }
  168. function handleError(err) {
  169. if (err.code === 'ENOENT') {
  170. console.error('marked: output to ' + err.path + ': No such directory');
  171. return process.exit(1);
  172. }
  173. throw err;
  174. }
  175. /**
  176. * Expose / Entry Point
  177. */
  178. process.title = 'marked';
  179. main(process.argv.slice()).then(code => {
  180. process.exit(code || 0);
  181. }).catch(err => {
  182. handleError(err);
  183. });