Skip to content

Commit 8051c42

Browse files
committed
feat: allow input from std in or shell globbing for multiple files
1 parent 0e3faf3 commit 8051c42

22 files changed

+685
-1193
lines changed

lib/get-md-files-in-dir.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

package-lock.json

Lines changed: 442 additions & 1026 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
"engines": {
1818
"node": ">= 8.3.0"
1919
},
20-
"main": "index.js",
20+
"main": "dist/index.js",
21+
"types": "dist/index.d.ts",
2122
"scripts": {
2223
"start": "node . --help",
2324
"build": "tsc",
2425
"prepare": "npm run build",
25-
"pretest": "npm run build",
26-
"test": "xo && nyc ava test/lib.spec.js && ava test/api.spec.js && ava test/cli.spec.js",
26+
"test": "xo && nyc ava test/lib.spec.ts && ava test/api.spec.ts && ava test/cli.spec.ts",
2727
"release": "npx standard-version --infile=changelog.md && git push --follow-tags origin master && npm publish"
2828
},
2929
"bin": {
@@ -41,7 +41,7 @@
4141
"get-port": "5.1.1",
4242
"get-stdin": "7.0.0",
4343
"gray-matter": "4.0.2",
44-
"highlight.js": "9.17.1",
44+
"highlight.js": "9.18.0",
4545
"iconv-lite": "0.5.1",
4646
"listr": "0.14.3",
4747
"marked": "0.8.0",
@@ -54,11 +54,12 @@
5454
"@types/marked": "0.7.2",
5555
"@types/puppeteer": "2.0.0",
5656
"@types/serve-handler": "6.1.0",
57-
"ava": "2.4.0",
58-
"husky": "4.0.10",
57+
"ava": "3.0.0",
58+
"husky": "4.2.1",
5959
"nyc": "15.0.0",
6060
"prettier": "1.19.1",
6161
"tap-xunit": "2.4.1",
62+
"ts-node": "8.6.2",
6263
"typescript": "3.7.5",
6364
"xo": "0.25.3"
6465
},
@@ -67,6 +68,14 @@
6768
"post-merge": "git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD | grep --quiet package-lock.json && npm install"
6869
}
6970
},
71+
"ava": {
72+
"extensions": [
73+
"ts"
74+
],
75+
"require": [
76+
"ts-node/register"
77+
]
78+
},
7079
"prettier": {
7180
"printWidth": 120,
7281
"singleQuote": true,

cli.ts renamed to src/cli.ts

Lines changed: 55 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@ import path from 'path';
77
import arg from 'arg';
88
import chalk from 'chalk';
99
import Listr from 'listr';
10+
import getStdin from 'get-stdin';
1011
import getPort from 'get-port';
1112
import { watch } from 'chokidar';
1213

1314
import { help } from './lib/help';
14-
import { getMdFilesInDir } from './lib/get-md-files-in-dir';
15-
import { serveDirectory } from './lib/serve-dir';
15+
import { serveDirectory, closeServer } from './lib/serve-dir';
1616
import { defaultConfig, Config } from './lib/config';
17-
import { getDir } from './lib/helpers';
1817
import { convertMdToPdf } from './lib/md-to-pdf';
1918
import { setProcessAndTermTitle } from './lib/helpers';
2019

@@ -24,6 +23,7 @@ import { setProcessAndTermTitle } from './lib/helpers';
2423
const cliFlags = arg({
2524
'--help': Boolean,
2625
'--version': Boolean,
26+
'--basedir': String,
2727
'--watch': Boolean,
2828
'--stylesheet': [String],
2929
'--css': String,
@@ -48,7 +48,15 @@ const cliFlags = arg({
4848
});
4949

5050
// --
51-
// Main
51+
// Run
52+
53+
main(cliFlags, defaultConfig).catch(error => {
54+
console.error(error);
55+
process.exit(1);
56+
});
57+
58+
// --
59+
// Define Main Function
5260

5361
async function main(args: typeof cliFlags, config: Config) {
5462
setProcessAndTermTitle('md-to-pdf');
@@ -61,19 +69,22 @@ async function main(args: typeof cliFlags, config: Config) {
6169
return help();
6270
}
6371

64-
const [input, dest] = args._;
72+
/**
73+
* 1. Get input.
74+
*/
75+
76+
const files = args._;
6577

66-
const mdFiles = input ? [input] : await getMdFilesInDir('.');
78+
const stdin = await getStdin();
6779

68-
if (mdFiles.length === 0) {
80+
if (files.length === 0 && !stdin) {
6981
return help();
7082
}
7183

72-
if (dest) {
73-
config.dest = dest;
74-
}
84+
/**
85+
* 2. Read config file and merge it into the config object.
86+
*/
7587

76-
// merge config from config file
7788
if (args['--config-file']) {
7889
try {
7990
const configFile: Partial<Config> = require(path.resolve(args['--config-file']));
@@ -92,38 +103,52 @@ async function main(args: typeof cliFlags, config: Config) {
92103
}
93104
}
94105

95-
// serve directory of first file because all files will be in the same dir
106+
/**
107+
* 3. Start the file server.
108+
*/
109+
110+
if (args['--basedir']) {
111+
config.basedir = args['--basedir'];
112+
}
113+
96114
config.port = args['--port'] || (await getPort());
97-
const server = await serveDirectory(getDir(mdFiles[0]), config.port);
98115

99-
const getListrTask = (mdFile: string) => ({
100-
title: `generating ${args['--as-html'] ? 'HTML' : 'PDF'} from ${chalk.underline(mdFile)}`,
101-
task: () => convertMdToPdf(mdFile, config, args),
116+
const server = await serveDirectory(config);
117+
118+
/**
119+
* 4. Either process stdin or create a Listr task for each file.
120+
*/
121+
122+
if (stdin) {
123+
await convertMdToPdf({ content: stdin }, config, args).catch(async (error: Error) => {
124+
await closeServer(server);
125+
126+
console.error(error);
127+
process.exit(1);
128+
});
129+
130+
await closeServer(server);
131+
132+
return;
133+
}
134+
135+
const getListrTask = (file: string) => ({
136+
title: `generating ${args['--as-html'] ? 'HTML' : 'PDF'} from ${chalk.underline(file)}`,
137+
task: () => convertMdToPdf({ path: file }, config, args),
102138
});
103139

104-
// create list of tasks and run concurrently
105-
await new Listr(mdFiles.map(getListrTask), { concurrent: true, exitOnError: false })
140+
await new Listr(files.map(getListrTask), { concurrent: true, exitOnError: false })
106141
.run()
107142
.then(() => {
108143
if (args['--watch']) {
109144
console.log(chalk.bgBlue('\n watching for changes \n'));
110145

111-
watch(mdFiles).on('change', async mdFile => {
112-
await new Listr([getListrTask(mdFile)])
113-
.run()
114-
.catch((error: Error) => args['--debug'] && console.error(error));
146+
watch(files).on('change', async file => {
147+
await new Listr([getListrTask(file)]).run().catch((error: Error) => args['--debug'] && console.error(error));
115148
});
116149
} else {
117150
server.close();
118151
}
119152
})
120153
.catch((error: Error) => (args['--debug'] && console.error(error)) || process.exit(1));
121154
}
122-
123-
// --
124-
// Run
125-
126-
main(cliFlags, defaultConfig).catch(error => {
127-
console.error(error);
128-
process.exit(1);
129-
});

index.ts renamed to src/index.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,36 @@ import getPort from 'get-port';
44

55
import { defaultConfig, Config } from './lib/config';
66
import { serveDirectory } from './lib/serve-dir';
7-
import { getDir } from './lib/helpers';
87
import { convertMdToPdf } from './lib/md-to-pdf';
8+
import { getDir } from './lib/helpers';
99

1010
/**
1111
* Convert a markdown file to PDF.
1212
*
1313
* @returns the path that the PDF was written to
1414
*/
15-
export const mdToPdf = async (mdFile: string, config: Partial<Config> = {}) => {
16-
if (typeof mdFile !== 'string') {
17-
throw new TypeError(`mdFile has to be a string, received ${typeof mdFile}`);
15+
export const mdToPdf = async (input: { path: string } | { content: string }, config: Partial<Config> = {}) => {
16+
if (!('path' in input ? input.path : input.content)) {
17+
throw new Error('Specify either content or path.');
18+
}
19+
20+
if (!config.port) {
21+
config.port = await getPort();
1822
}
1923

20-
config.port = config.port || (await getPort());
21-
const server = await serveDirectory(getDir(mdFile), config.port);
24+
if (!config.basedir) {
25+
config.basedir = 'path' in input ? getDir(input.path) : process.cwd();
26+
}
2227

2328
const mergedConfig: Config = {
2429
...defaultConfig,
2530
...config,
2631
pdf_options: { ...defaultConfig.pdf_options, ...config.pdf_options },
2732
};
2833

29-
const pdf = await convertMdToPdf(mdFile, mergedConfig);
34+
const server = await serveDirectory(mergedConfig);
35+
36+
const pdf = await convertMdToPdf(input, mergedConfig);
3037

3138
server.close();
3239

lib/config.ts renamed to src/lib/config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { MarkedOptions } from 'marked';
33
import { PDFOptions, LaunchOptions } from 'puppeteer';
44

55
export const defaultConfig: Config = {
6+
basedir: process.cwd(),
67
stylesheet: [resolve(__dirname, '..', '..', 'markdown.css')],
78
css: '',
89
body_class: [],
@@ -29,6 +30,11 @@ export const defaultConfig: Config = {
2930
* In config keys, dashes of cli flag names are replaced with underscores.
3031
*/
3132
export interface Config {
33+
/**
34+
* Base directory to be served by the file server.
35+
*/
36+
basedir: string;
37+
3238
/**
3339
* Optional destination path for the output file (including the extension).
3440
*/
File renamed without changes.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ export const getMarked = (options: MarkedOptions) => {
88
if (!Object.prototype.hasOwnProperty.call(renderer, 'code')) {
99
renderer.code = (code, language) => {
1010
// if the given language is not available in highlight.js, fall back to plaintext
11-
language = (getLanguage(language) && language) || 'plaintext';
11+
const languageName = language && getLanguage(language) ? language : 'plaintext';
1212

13-
return `<pre><code class="hljs ${language}">${highlight(language, code).value}</code></pre>`;
13+
return `<pre><code class="hljs ${languageName}">${highlight(languageName, code).value}</code></pre>`;
1414
};
1515
}
1616

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Config } from './config';
44
/**
55
* Derive the output file path from the source markdown file.
66
*/
7-
export const getOutputFilePath = (mdFilePath: string, config: Config) => {
7+
export const getOutputFilePath = (mdFilePath: string, config: Partial<Config>) => {
88
const { dir, name } = parse(mdFilePath);
99
const extension = config.as_html ? 'html' : 'pdf';
1010

lib/help.ts renamed to src/lib/help.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const helpText = `
88
-h, --help ${chalk.dim('...............')} Output usage information
99
-v, --version ${chalk.dim('............')} Output version
1010
-w, --watch ${chalk.dim('..............')} Watch the current file(s) for changes
11+
--basedir ${chalk.dim('................')} Base directory to be served by the file server
1112
--stylesheet ${chalk.dim('.............')} Path to a local or remote stylesheet (can be passed multiple times)
1213
--css ${chalk.dim('....................')} String of styles
1314
--body-class ${chalk.dim('.............')} Classes to be added to the body tag (can be passed multiple times)

0 commit comments

Comments
 (0)