123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- #!/usr/bin/env node
- /**
- * Marked CLI
- * Copyright (c) 2011-2013, Christopher Jeffrey (MIT License)
- */
- import { promises } from 'node:fs';
- import { dirname, resolve } from 'node:path';
- import { homedir } from 'node:os';
- import { createRequire } from 'node:module';
- import { marked } from '../lib/marked.esm.js';
- const { access, readFile, writeFile } = promises;
- const require = createRequire(import.meta.url);
- /**
- * @param {Process} nodeProcess inject process so it can be mocked in tests.
- */
- export async function main(nodeProcess) {
- /**
- * Man Page
- */
- async function help() {
- const { spawn } = await import('child_process');
- const { fileURLToPath } = await import('url');
- const options = {
- cwd: nodeProcess.cwd(),
- env: nodeProcess.env,
- stdio: 'inherit'
- };
- const __dirname = dirname(fileURLToPath(import.meta.url));
- const helpText = await readFile(resolve(__dirname, '../man/marked.1.md'), '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 pkg = require('../package.json');
- console.log(pkg.version);
- }
- /**
- * Main
- */
- async function start(argv) {
- const files = [];
- const options = {};
- let input;
- let output;
- let string;
- let arg;
- let tokens;
- let config;
- let opt;
- let noclobber;
- 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 '-c':
- case '--config':
- config = argv.shift();
- break;
- case '-n':
- case '--no-clobber':
- noclobber = 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');
- }
- function resolveFile(file) {
- return resolve(file.replace(/^~/, homedir));
- }
- function fileExists(file) {
- return access(resolveFile(file)).then(() => true, () => false);
- }
- async function runConfig(file) {
- const configFile = resolveFile(file);
- let markedConfig;
- try {
- // try require for json
- markedConfig = require(configFile);
- } catch (err) {
- if (err.code !== 'ERR_REQUIRE_ESM') {
- throw err;
- }
- // must import esm
- markedConfig = await import('file:///' + configFile);
- }
- if (markedConfig.default) {
- markedConfig = markedConfig.default;
- }
- if (typeof markedConfig === 'function') {
- markedConfig(marked);
- } else {
- marked.use(markedConfig);
- }
- }
- const data = await getData();
- if (config) {
- if (!await fileExists(config)) {
- throw Error(`Cannot load config file '${config}'`);
- }
- await runConfig(config);
- } else {
- const defaultConfig = [
- '~/.marked.json',
- '~/.marked.js',
- '~/.marked/index.js'
- ];
- for (const configFile of defaultConfig) {
- if (await fileExists(configFile)) {
- await runConfig(configFile);
- break;
- }
- }
- }
- const html = tokens
- ? JSON.stringify(marked.lexer(data, options), null, 2)
- : await marked.parse(data, options);
- if (output) {
- if (noclobber && await fileExists(output)) {
- nodeProcess.stderr.write('marked: output file \'' + output + '\' already exists, disable the \'-n\' / \'--no-clobber\' flag to overwrite\n');
- nodeProcess.exit(1);
- }
- return await writeFile(output, html);
- }
- nodeProcess.stdout.write(html + '\n');
- }
- /**
- * Helpers
- */
- function getStdin() {
- return new Promise((resolve, reject) => {
- const stdin = nodeProcess.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();
- });
- }
- try {
- await start(nodeProcess.argv.slice());
- nodeProcess.exit(0);
- } catch (err) {
- if (err.code === 'ENOENT') {
- nodeProcess.stderr.write('marked: output to ' + err.path + ': No such directory');
- }
- nodeProcess.stderr.write(err);
- return nodeProcess.exit(1);
- }
- }
|