| 
									
										
										
										
											2025-07-10 08:52:41 +08:00
										 |  |  | #!/usr/bin/env node
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Marked CLI | 
					
						
							|  |  |  |  * Copyright (c) 2011-2013, Christopher Jeffrey (MIT License) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-10 09:41:17 +08:00
										 |  |  | import { promises } from 'fs'; | 
					
						
							|  |  |  | import { marked } from '../lib/marked.esm.js'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const { readFile, writeFile } = promises; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Man Page | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function help() { | 
					
						
							|  |  |  |   const { spawn } = await import('child_process'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const options = { | 
					
						
							|  |  |  |     cwd: process.cwd(), | 
					
						
							|  |  |  |     env: process.env, | 
					
						
							|  |  |  |     setsid: false, | 
					
						
							|  |  |  |     stdio: 'inherit' | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { dirname, resolve } = await import('path'); | 
					
						
							|  |  |  |   const { fileURLToPath } = await import('url'); | 
					
						
							|  |  |  |   const __dirname = dirname(fileURLToPath(import.meta.url)); | 
					
						
							|  |  |  |   const helpText = await readFile(resolve(__dirname, '../man/marked.1.txt'), 'utf8'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // eslint-disable-next-line promise/param-names
 | 
					
						
							|  |  |  |   await new Promise(res => { | 
					
						
							|  |  |  |     spawn('man', [resolve(__dirname, '../man/marked.1')], options) | 
					
						
							|  |  |  |       .on('error', () => { | 
					
						
							|  |  |  |         console.log(helpText); | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       .on('close', res); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function version() { | 
					
						
							|  |  |  |   const { createRequire } = await import('module'); | 
					
						
							|  |  |  |   const require = createRequire(import.meta.url); | 
					
						
							|  |  |  |   const pkg = require('../package.json'); | 
					
						
							|  |  |  |   console.log(pkg.version); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Main | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function main(argv) { | 
					
						
							|  |  |  |   const files = []; | 
					
						
							|  |  |  |   const options = {}; | 
					
						
							|  |  |  |   let input; | 
					
						
							|  |  |  |   let output; | 
					
						
							|  |  |  |   let string; | 
					
						
							|  |  |  |   let arg; | 
					
						
							|  |  |  |   let tokens; | 
					
						
							|  |  |  |   let opt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function getarg() { | 
					
						
							|  |  |  |     let arg = argv.shift(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (arg.indexOf('--') === 0) { | 
					
						
							|  |  |  |       // e.g. --opt
 | 
					
						
							|  |  |  |       arg = arg.split('='); | 
					
						
							|  |  |  |       if (arg.length > 1) { | 
					
						
							|  |  |  |         // e.g. --opt=val
 | 
					
						
							|  |  |  |         argv.unshift(arg.slice(1).join('=')); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       arg = arg[0]; | 
					
						
							|  |  |  |     } else if (arg[0] === '-') { | 
					
						
							|  |  |  |       if (arg.length > 2) { | 
					
						
							|  |  |  |         // e.g. -abc
 | 
					
						
							|  |  |  |         argv = arg.substring(1).split('').map(function(ch) { | 
					
						
							|  |  |  |           return '-' + ch; | 
					
						
							|  |  |  |         }).concat(argv); | 
					
						
							|  |  |  |         arg = argv.shift(); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         // e.g. -a
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       // e.g. foo
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return arg; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (argv.length) { | 
					
						
							|  |  |  |     arg = getarg(); | 
					
						
							|  |  |  |     switch (arg) { | 
					
						
							|  |  |  |       case '-o': | 
					
						
							|  |  |  |       case '--output': | 
					
						
							|  |  |  |         output = argv.shift(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case '-i': | 
					
						
							|  |  |  |       case '--input': | 
					
						
							|  |  |  |         input = argv.shift(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case '-s': | 
					
						
							|  |  |  |       case '--string': | 
					
						
							|  |  |  |         string = argv.shift(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case '-t': | 
					
						
							|  |  |  |       case '--tokens': | 
					
						
							|  |  |  |         tokens = true; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case '-h': | 
					
						
							|  |  |  |       case '--help': | 
					
						
							|  |  |  |         return await help(); | 
					
						
							|  |  |  |       case '-v': | 
					
						
							|  |  |  |       case '--version': | 
					
						
							|  |  |  |         return await version(); | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         if (arg.indexOf('--') === 0) { | 
					
						
							|  |  |  |           opt = camelize(arg.replace(/^--(no-)?/, '')); | 
					
						
							|  |  |  |           if (!marked.defaults.hasOwnProperty(opt)) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           if (arg.indexOf('--no-') === 0) { | 
					
						
							|  |  |  |             options[opt] = typeof marked.defaults[opt] !== 'boolean' | 
					
						
							|  |  |  |               ? null | 
					
						
							|  |  |  |               : false; | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             options[opt] = typeof marked.defaults[opt] !== 'boolean' | 
					
						
							|  |  |  |               ? argv.shift() | 
					
						
							|  |  |  |               : true; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           files.push(arg); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async function getData() { | 
					
						
							|  |  |  |     if (!input) { | 
					
						
							|  |  |  |       if (files.length <= 2) { | 
					
						
							|  |  |  |         if (string) { | 
					
						
							|  |  |  |           return string; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return await getStdin(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       input = files.pop(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return await readFile(input, 'utf8'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const data = await getData(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const html = tokens | 
					
						
							|  |  |  |     ? JSON.stringify(marked.lexer(data, options), null, 2) | 
					
						
							|  |  |  |     : marked(data, options); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (output) { | 
					
						
							|  |  |  |     return await writeFile(output, html); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   process.stdout.write(html + '\n'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Helpers | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function getStdin() { | 
					
						
							|  |  |  |   return new Promise((resolve, reject) => { | 
					
						
							|  |  |  |     const stdin = process.stdin; | 
					
						
							|  |  |  |     let buff = ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     stdin.setEncoding('utf8'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     stdin.on('data', function(data) { | 
					
						
							|  |  |  |       buff += data; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     stdin.on('error', function(err) { | 
					
						
							|  |  |  |       reject(err); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     stdin.on('end', function() { | 
					
						
							|  |  |  |       resolve(buff); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     stdin.resume(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {string} text | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function camelize(text) { | 
					
						
							|  |  |  |   return text.replace(/(\w)-(\w)/g, function(_, a, b) { | 
					
						
							|  |  |  |     return a + b.toUpperCase(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function handleError(err) { | 
					
						
							|  |  |  |   if (err.code === 'ENOENT') { | 
					
						
							|  |  |  |     console.error('marked: output to ' + err.path + ': No such directory'); | 
					
						
							|  |  |  |     return process.exit(1); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   throw err; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-07-10 08:52:41 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Expose / Entry Point | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | process.title = 'marked'; | 
					
						
							| 
									
										
										
										
											2025-07-10 09:41:17 +08:00
										 |  |  | main(process.argv.slice()).then(code => { | 
					
						
							|  |  |  |   process.exit(code || 0); | 
					
						
							|  |  |  | }).catch(err => { | 
					
						
							|  |  |  |   handleError(err); | 
					
						
							|  |  |  | }); |