-
-
Notifications
You must be signed in to change notification settings - Fork 112
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This refactors the main convertToPdf function and exposes it from `util/md-to-pdf.js`, so it can be shared between the new programmatic API and the CLI. The CLI has been moved to `cli.js` and `index.js` exposes a wrapper around `mdToPdf` instead. Closes #25
- Loading branch information
1 parent
e5cdfa9
commit 8c86807
Showing
7 changed files
with
235 additions
and
178 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
#!/usr/bin/env node | ||
|
||
// -- | ||
// Packages | ||
|
||
const path = require('path'); | ||
const arg = require('arg'); | ||
const chalk = require('chalk').default; | ||
const Listr = require('listr'); | ||
const getPort = require('get-port'); | ||
const { watch } = require('chokidar'); | ||
|
||
// -- | ||
// Utils | ||
|
||
const help = require('./util/help'); | ||
const getMdFilesInDir = require('./util/get-md-files-in-dir'); | ||
const serveDirectory = require('./util/serve-dir'); | ||
const config = require('./util/config'); | ||
const { getDir } = require('./util/helpers'); | ||
const mdToPdf = require('./util/md-to-pdf'); | ||
|
||
// -- | ||
// Configure CLI Arguments | ||
|
||
const args = arg({ | ||
'--help': Boolean, | ||
'--version': Boolean, | ||
'--watch': Boolean, | ||
'--stylesheet': [String], | ||
'--css': String, | ||
'--body-class': [String], | ||
'--highlight-style': String, | ||
'--marked-options': String, | ||
'--html-pdf-options': String, | ||
'--pdf-options': String, | ||
'--launch-options': String, | ||
'--md-file-encoding': String, | ||
'--stylesheet-encoding': String, | ||
'--config-file': String, | ||
'--devtools': Boolean, | ||
'--debug': Boolean, | ||
|
||
// aliases | ||
'-h': '--help', | ||
'-v': '--version', | ||
'-w': '--watch', | ||
}); | ||
|
||
// -- | ||
// Main | ||
|
||
async function main(args, config) { | ||
const input = args._[0]; | ||
const dest = args._[1]; | ||
|
||
if (args['--version']) { | ||
return console.log(require('./package').version); | ||
} | ||
|
||
if (args['--help']) { | ||
return help(); | ||
} | ||
|
||
/** | ||
* throw warning when using --html-pdf-options flag | ||
* @todo remove in a future version | ||
*/ | ||
if (args['--html-pdf-options']) { | ||
console.warn( | ||
[ | ||
chalk.red(`--html-pdf-options is not a valid argument anymore. Use --pdf-options instead.`), | ||
chalk.gray(`valid options: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagepdfoptions`), | ||
].join('\n'), | ||
); | ||
} | ||
|
||
const mdFiles = input ? [input] : await getMdFilesInDir('.'); | ||
|
||
if (mdFiles.length === 0) { | ||
return help(); | ||
} | ||
|
||
if (dest) { | ||
config.dest = dest; | ||
} | ||
|
||
// merge config from config file | ||
if (args['--config-file']) { | ||
try { | ||
config = { ...config, ...require(path.resolve(args['--config-file'])) }; | ||
} catch (error) { | ||
console.warn(chalk.red(`Warning: couldn't read config file: ${args['--config-file']}`)); | ||
|
||
if (args['--debug']) { | ||
console.error(error); | ||
} | ||
} | ||
} | ||
|
||
// serve directory of first file because all files will be in the same dir | ||
const port = await getPort(); | ||
const server = await serveDirectory(getDir(mdFiles[0]), port); | ||
|
||
const getListrTask = mdFile => ({ | ||
title: `generating PDF from ${chalk.underline(mdFile)}`, | ||
task: () => mdToPdf(mdFile, config, port, args), | ||
}); | ||
|
||
// create list of tasks and run concurrently | ||
await new Listr(mdFiles.map(getListrTask), { concurrent: true, exitOnError: false }) | ||
.run() | ||
.then(() => { | ||
if (args['--watch']) { | ||
console.log(chalk.bgBlue('\n watching for changes \n')); | ||
|
||
watch(mdFiles).on('change', async mdFile => { | ||
await new Listr([getListrTask(mdFile)]).run().catch(error => args['--debug'] && console.error(error)); | ||
}); | ||
} else { | ||
server.close(); | ||
} | ||
}) | ||
.catch(error => (args['--debug'] && console.error(error)) || process.exit(1)); | ||
} | ||
|
||
// -- | ||
// Run | ||
|
||
main(args, config).catch(error => console.error(error) || process.exit(1)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,176 +1,27 @@ | ||
#!/usr/bin/env node | ||
|
||
// -- | ||
// Packages | ||
|
||
const path = require('path'); | ||
const arg = require('arg'); | ||
const chalk = require('chalk').default; | ||
const Listr = require('listr'); | ||
const grayMatter = require('gray-matter'); | ||
const getPort = require('get-port'); | ||
const { watch } = require('chokidar'); | ||
|
||
// -- | ||
// Utils | ||
|
||
const help = require('./util/help'); | ||
const getMdFilesInDir = require('./util/get-md-files-in-dir'); | ||
const readFile = require('./util/read-file'); | ||
const defaultConfig = require('./util/config'); | ||
const serveDirectory = require('./util/serve-dir'); | ||
const getHtml = require('./util/get-html'); | ||
const writePdf = require('./util/write-pdf'); | ||
const config = require('./util/config'); | ||
const { getMarginObject, getDir } = require('./util/helpers'); | ||
|
||
// -- | ||
// Configure CLI Arguments | ||
|
||
const args = arg({ | ||
'--help': Boolean, | ||
'--version': Boolean, | ||
'--watch': Boolean, | ||
'--stylesheet': [String], | ||
'--css': String, | ||
'--body-class': [String], | ||
'--highlight-style': String, | ||
'--marked-options': String, | ||
'--html-pdf-options': String, | ||
'--pdf-options': String, | ||
'--launch-options': String, | ||
'--md-file-encoding': String, | ||
'--stylesheet-encoding': String, | ||
'--config-file': String, | ||
'--devtools': Boolean, | ||
'--debug': Boolean, | ||
|
||
// aliases | ||
'-h': '--help', | ||
'-v': '--version', | ||
'-w': '--watch', | ||
}); | ||
|
||
// -- | ||
// Main | ||
|
||
async function main(args, config) { | ||
const input = args._[0]; | ||
const output = args._[1]; | ||
|
||
if (args['--version']) { | ||
return console.log(require('./package').version); | ||
} | ||
|
||
if (args['--help']) { | ||
return help(); | ||
} | ||
|
||
/** | ||
* throw warning when using --html-pdf-options flag | ||
* @todo remove in a future version | ||
*/ | ||
if (args['--html-pdf-options']) { | ||
console.warn( | ||
[ | ||
chalk.red(`--html-pdf-options is not a valid argument anymore. Use --pdf-options instead.`), | ||
chalk.gray(`valid options: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagepdfoptions`), | ||
].join('\n'), | ||
); | ||
} | ||
|
||
const mdFiles = input ? [input] : await getMdFilesInDir('.'); | ||
|
||
if (mdFiles.length === 0) { | ||
return help(); | ||
} | ||
|
||
// merge config from config file | ||
if (args['--config-file']) { | ||
try { | ||
config = { ...config, ...require(path.resolve(args['--config-file'])) }; | ||
} catch (error) { | ||
console.warn(chalk.red(`Warning: couldn't read config file: ${args['--config-file']}`)); | ||
|
||
if (args['--debug']) { | ||
console.error(error); | ||
} | ||
} | ||
} | ||
|
||
// serve directory of first file because all files will be in the same dir | ||
const { getDir } = require('./util/helpers'); | ||
const mdToPdf = require('./util/md-to-pdf'); | ||
|
||
/** | ||
* Convert a markdown file to PDF. | ||
* | ||
* @param {string} mdFile path to markdown file | ||
* @param {*} config config object | ||
* | ||
* @returns the path that the PDF was written to | ||
*/ | ||
module.exports = async (mdFile, config) => { | ||
const port = await getPort(); | ||
const server = await serveDirectory(getDir(mdFiles[0]), port); | ||
|
||
const getListrTask = mdFile => ({ | ||
title: `generating PDF from ${chalk.underline(mdFile)}`, | ||
task: () => convertToPdf(mdFile), | ||
}); | ||
|
||
// create list of tasks and run concurrently | ||
await new Listr(mdFiles.map(getListrTask), { concurrent: true, exitOnError: false }) | ||
.run() | ||
.then(() => { | ||
if (args['--watch']) { | ||
console.log(chalk.bgBlue('\n watching for changes \n')); | ||
|
||
watch(mdFiles).on('change', async mdFile => { | ||
await new Listr([getListrTask(mdFile)]).run().catch(error => args['--debug'] && console.error(error)); | ||
}); | ||
} else { | ||
server.close(); | ||
} | ||
}) | ||
.catch(error => (args['--debug'] && console.error(error)) || process.exit(1)); | ||
|
||
// this is the actual function to convert a file | ||
async function convertToPdf(mdFile) { | ||
const mdFileContent = await readFile(path.resolve(mdFile), args['--md-file-encoding'] || config.md_file_encoding); | ||
|
||
const { content: md, data: frontMatterConfig } = grayMatter(mdFileContent); | ||
|
||
// merge front-matter config | ||
config = { ...config, ...frontMatterConfig }; | ||
|
||
// sanitize array cli arguments | ||
for (const option of ['stylesheet', 'body_class']) { | ||
if (!Array.isArray(config[option])) { | ||
config[option] = [config[option]].filter(value => Boolean(value)); | ||
} | ||
} | ||
|
||
// merge cli args into config | ||
const jsonArgs = ['--marked-options', '--pdf-options', '--launch-options']; | ||
for (const arg of Object.entries(args)) { | ||
const [argKey, argValue] = arg; | ||
const key = argKey.substring(2).replace(/-/g, '_'); | ||
config[key] = jsonArgs.includes(argKey) ? JSON.parse(argValue) : argValue; | ||
} | ||
|
||
// sanitize the margin in pdf_options | ||
if (typeof config.pdf_options.margin === 'string') { | ||
config.pdf_options.margin = getMarginObject(config.pdf_options.margin); | ||
} | ||
|
||
const highlightStylesheet = path.resolve( | ||
path.dirname(require.resolve('highlight.js')), | ||
'..', | ||
'styles', | ||
`${config.highlight_style}.css`, | ||
); | ||
|
||
config.stylesheet = [...new Set([...config.stylesheet, highlightStylesheet])]; | ||
|
||
const html = getHtml(md, config); | ||
const server = await serveDirectory(getDir(mdFile), port); | ||
|
||
const pdf = await writePdf(mdFile, output, html, { ...config, port }); | ||
config = { ...defaultConfig, ...config }; | ||
|
||
if (!pdf.filename) { | ||
throw new Error(`Failed to create PDF`); | ||
} | ||
} | ||
} | ||
const pdf = await mdToPdf(mdFile, config, port); | ||
|
||
// -- | ||
// Run | ||
server.close(); | ||
|
||
main(args, config).catch(error => console.error(error) || process.exit(1)); | ||
return pdf; | ||
}; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.