1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22'use strict'; 23 24const { promises: fs } = require('fs'); 25const path = require('path'); 26const unified = require('unified'); 27const markdown = require('remark-parse'); 28const remark2rehype = require('remark-rehype'); 29const raw = require('rehype-raw'); 30const htmlStringify = require('rehype-stringify'); 31 32const { replaceLinks } = require('./markdown'); 33const linksMapper = require('./links-mapper'); 34const html = require('./html'); 35const json = require('./json'); 36 37// Parse the args. 38// Don't use nopt or whatever for this. It's simple enough. 39 40const args = process.argv.slice(2); 41let filename = null; 42let nodeVersion = null; 43let outputDir = null; 44let apilinks = {}; 45let versions = {}; 46 47async function main() { 48 for (const arg of args) { 49 if (!arg.startsWith('--')) { 50 filename = arg; 51 } else if (arg.startsWith('--node-version=')) { 52 nodeVersion = arg.replace(/^--node-version=/, ''); 53 } else if (arg.startsWith('--output-directory=')) { 54 outputDir = arg.replace(/^--output-directory=/, ''); 55 } else if (arg.startsWith('--apilinks=')) { 56 const linkFile = arg.replace(/^--apilinks=/, ''); 57 const data = await fs.readFile(linkFile, 'utf8'); 58 if (!data.trim()) { 59 throw new Error(`${linkFile} is empty`); 60 } 61 apilinks = JSON.parse(data); 62 } else if (arg.startsWith('--versions-file=')) { 63 const versionsFile = arg.replace(/^--versions-file=/, ''); 64 const data = await fs.readFile(versionsFile, 'utf8'); 65 if (!data.trim()) { 66 throw new Error(`${versionsFile} is empty`); 67 } 68 versions = JSON.parse(data); 69 } 70 } 71 72 nodeVersion = nodeVersion || process.version; 73 74 if (!filename) { 75 throw new Error('No input file specified'); 76 } else if (!outputDir) { 77 throw new Error('No output directory specified'); 78 } 79 80 const input = await fs.readFile(filename, 'utf8'); 81 82 const content = await unified() 83 .use(replaceLinks, { filename, linksMapper }) 84 .use(markdown) 85 .use(html.preprocessText, { nodeVersion }) 86 .use(json.jsonAPI, { filename }) 87 .use(html.firstHeader) 88 .use(html.preprocessElements, { filename }) 89 .use(html.buildToc, { filename, apilinks }) 90 .use(remark2rehype, { allowDangerousHtml: true }) 91 .use(raw) 92 .use(htmlStringify) 93 .process(input); 94 95 const myHtml = await html.toHTML({ input, content, filename, nodeVersion, 96 versions }); 97 const basename = path.basename(filename, '.md'); 98 const htmlTarget = path.join(outputDir, `${basename}.html`); 99 const jsonTarget = path.join(outputDir, `${basename}.json`); 100 101 return Promise.allSettled([ 102 fs.writeFile(htmlTarget, myHtml), 103 fs.writeFile(jsonTarget, JSON.stringify(content.json, null, 2)), 104 ]); 105} 106 107main() 108 .then((tasks) => { 109 // Filter rejected tasks 110 const errors = tasks.filter(({ status }) => status === 'rejected') 111 .map(({ reason }) => reason); 112 113 // Log errors 114 for (const error of errors) { 115 console.error(error); 116 } 117 118 // Exit process with code 1 if some errors 119 if (errors.length > 0) { 120 return process.exit(1); 121 } 122 123 // Else with code 0 124 process.exit(0); 125 }) 126 .catch((error) => { 127 console.error(error); 128 129 process.exit(1); 130 }); 131