"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { HTML_EXPORT_PDF_CLI: () => HTML_EXPORT_PDF_CLI, Printer: () => Printer, afterParse: () => afterParse, beforeParse: () => beforeParse, collectParameters: () => collectParameters, commaSeparatedList: () => commaSeparatedList, createHtmlExportPdf: () => createHtmlExportPdf, createProgress: () => createProgress, formatOutlineContainerSelector: () => formatOutlineContainerSelector, getAbsFileName: () => getAbsFileName, getDirname: () => getDirname, getOutline: () => getOutline, htmlExportPdf: () => htmlExportPdf, isValidUrl: () => isValidUrl, registerCommands: () => registerCommands, replaceExt: () => replaceExt, runCli: () => runCli, setMetadata: () => setMetadata, setOutline: () => setOutline, writeFileSafe: () => writeFileSafe }); module.exports = __toCommonJS(src_exports); // src/utils/fs.ts var import_node_path = require("path"); var import_node_fs = require("fs"); function writeFileSafe(path4, data = "") { const directory = (0, import_node_path.dirname)(path4); if (!(0, import_node_fs.existsSync)(directory)) import_node_fs.promises.mkdir(directory, { recursive: true }); return import_node_fs.promises.writeFile(path4, data).then(() => true).catch(() => false); } // src/utils/replaceExt.ts var import_node_path2 = __toESM(require("path"), 1); function startsWithSingleDot(filePath) { const first2chars = filePath.slice(0, 2); return first2chars === `.${import_node_path2.default.sep}` || first2chars === "./"; } function replaceExt(npath, ext) { if (typeof npath !== "string" || npath.length === 0) return npath; const nFileName = import_node_path2.default.basename(npath, import_node_path2.default.extname(npath)) + ext; const nFilepath = import_node_path2.default.join(import_node_path2.default.dirname(npath), nFileName); if (startsWithSingleDot(npath)) return `.${import_node_path2.default.sep}${nFilepath}`; return nFilepath; } // src/utils/isValidUrl.ts function isValidUrl(url) { return /^(?:https?|file|data):/i.test(url); } // src/utils/getDirname.ts var import_node_path3 = require("path"); // src/utils/getAbsFileName.ts var import_node_url = require("url"); function getAbsFileName(metaURL) { return (0, import_node_url.fileURLToPath)(metaURL); } // src/utils/getDirname.ts function getDirname(metaURL) { return (0, import_node_path3.dirname)(getAbsFileName(metaURL)); } // node_modules/.pnpm/colorette@https+++registry.npmmirror.com+colorette+-+colorette-2.0.20.tgz/node_modules/colorette/index.js var tty = __toESM(require("tty"), 1); var { env = {}, argv = [], platform = "" } = typeof process === "undefined" ? {} : process; var isDisabled = "NO_COLOR" in env || argv.includes("--no-color"); var isForced = "FORCE_COLOR" in env || argv.includes("--color"); var isWindows = platform === "win32"; var isDumbTerminal = env.TERM === "dumb"; var isCompatibleTerminal = tty && tty.isatty && tty.isatty(1) && env.TERM && !isDumbTerminal; var isCI = "CI" in env && ("GITHUB_ACTIONS" in env || "GITLAB_CI" in env || "CIRCLECI" in env); var isColorSupported = !isDisabled && (isForced || isWindows && !isDumbTerminal || isCompatibleTerminal || isCI); var replaceClose = (index, string, close, replace, head = string.substring(0, index) + replace, tail = string.substring(index + close.length), next = tail.indexOf(close)) => head + (next < 0 ? tail : replaceClose(next, tail, close, replace)); var clearBleed = (index, string, open, close, replace) => index < 0 ? open + string + close : open + replaceClose(index, string, close, replace) + close; var filterEmpty = (open, close, replace = open, at = open.length + 1) => (string) => string || !(string === "" || string === void 0) ? clearBleed( ("" + string).indexOf(close, at), string, open, close, replace ) : ""; var init = (open, close, replace) => filterEmpty(`\x1B[${open}m`, `\x1B[${close}m`, replace); var colors = { reset: init(0, 0), bold: init(1, 22, "\x1B[22m\x1B[1m"), dim: init(2, 22, "\x1B[22m\x1B[2m"), italic: init(3, 23), underline: init(4, 24), inverse: init(7, 27), hidden: init(8, 28), strikethrough: init(9, 29), black: init(30, 39), red: init(31, 39), green: init(32, 39), yellow: init(33, 39), blue: init(34, 39), magenta: init(35, 39), cyan: init(36, 39), white: init(37, 39), gray: init(90, 39), bgBlack: init(40, 49), bgRed: init(41, 49), bgGreen: init(42, 49), bgYellow: init(43, 49), bgBlue: init(44, 49), bgMagenta: init(45, 49), bgCyan: init(46, 49), bgWhite: init(47, 49), blackBright: init(90, 39), redBright: init(91, 39), greenBright: init(92, 39), yellowBright: init(93, 39), blueBright: init(94, 39), magentaBright: init(95, 39), cyanBright: init(96, 39), whiteBright: init(97, 39), bgBlackBright: init(100, 49), bgRedBright: init(101, 49), bgGreenBright: init(102, 49), bgYellowBright: init(103, 49), bgBlueBright: init(104, 49), bgMagentaBright: init(105, 49), bgCyanBright: init(106, 49), bgWhiteBright: init(107, 49) }; var createColors = ({ useColor = isColorSupported } = {}) => useColor ? colors : Object.keys(colors).reduce( (colors2, key) => ({ ...colors2, [key]: String }), {} ); var { reset, bold, dim, italic, underline, inverse, hidden, strikethrough, black, red, green, yellow, blue, magenta, cyan, white, gray, bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite, blackBright, redBright, greenBright, yellowBright, blueBright, magentaBright, cyanBright, whiteBright, bgBlackBright, bgRedBright, bgGreenBright, bgYellowBright, bgBlueBright, bgMagentaBright, bgCyanBright, bgWhiteBright } = createColors(); // src/utils/cliProgress.ts var import_cli_progress = require("cli-progress"); function replaceTitle(title) { return title.length ? `|| ${title}` : ""; } function createProgress(indeterminate = false) { function getSpinner(n = 0) { return [cyan("\u25CF"), green("\u25C6"), blue("\u25A0"), yellow("\u25B2")][n % 4]; } let current = 0; let spinner = 0; let text = "Generating"; let title = ""; let timer; const progress = new import_cli_progress.SingleBar({ clearOnComplete: false, hideCursor: true, format: ` {spin} {text} ${indeterminate ? dim(yellow("...")) : " {bar} {value}/{total}"} {title} `, linewrap: false, barsize: 30 }, import_cli_progress.Presets.shades_grey); return { bar: progress, start(total) { progress.start(total, 0, { spin: getSpinner(spinner), text, title: replaceTitle(title) }); timer = setInterval(() => { spinner += 1; progress.update({ spin: getSpinner(spinner), text, title: replaceTitle(title) }); }, 200); }, updateNumber(v) { current = v; progress.update(v, { spin: getSpinner(spinner), text, title: replaceTitle(title) }); }, increment(step, { txt, headTitle } = { txt: "", headTitle: "" }) { text = txt?.length ? txt : text; title = headTitle?.length ? headTitle : title; progress.increment(step, { spin: getSpinner(spinner), text, title: replaceTitle(title) }); }, updateText(t) { text = t; progress.update(current, { spin: getSpinner(spinner), text, title: replaceTitle(title) }); }, updateTitle(t) { title = t; progress.update(current, { spin: getSpinner(spinner), text, title: replaceTitle(title) }); }, stop() { clearInterval(timer); progress.stop(); } }; } // src/utils/optionsCustomProcessing.ts function collectParameters(value, previous) { return previous.concat([value]); } function commaSeparatedList(value) { return value.split(","); } // src/core/outline.ts var import_html_entities = require("html-entities"); var import_pdf_lib = require("pdf-lib"); function formatOutlineContainerSelector(outlineContainerSelector) { if (!outlineContainerSelector) return ""; const selectors = outlineContainerSelector.split(/\s+/); const validSelectors = selectors.filter((selector) => selector); const formattedSelector = `${validSelectors.join(" ")} `; return formattedSelector; } async function getOutline(page, tags, outlineContainerSelector = "") { const preSelector = formatOutlineContainerSelector(outlineContainerSelector); return await page.evaluate((tags2, outlineSelector) => { const tagsToProcess = Array.from(document.querySelectorAll(outlineSelector)).reverse(); const root = { children: [], depth: -1, parent: void 0 }; let currentOutlineNode = root; const linkHolder = document.createElement("div"); const body = document.querySelector("body"); linkHolder.style.display = "none"; body?.insertBefore(linkHolder, body.firstChild); while (tagsToProcess.length > 0) { const tag = tagsToProcess.pop(); const orderDepth = tags2.indexOf(tag.tagName.toLowerCase()); const dest = encodeURIComponent(tag.id); const hiddenLink = document.createElement("a"); hiddenLink.href = `#${dest}`; linkHolder.appendChild(hiddenLink); if (orderDepth < currentOutlineNode.depth) { currentOutlineNode = currentOutlineNode.parent; tagsToProcess.push(tag); } else { const newNode = { // http://perfectionkills.com/the-poor-misunderstood-innerText/ title: tag.textContent?.trim() ?? "", destination: dest, children: [], depth: orderDepth, parent: void 0 }; if (orderDepth === currentOutlineNode.depth) { if (currentOutlineNode.parent) { newNode.parent = currentOutlineNode.parent; currentOutlineNode.parent.children.push(newNode); } else { newNode.parent = currentOutlineNode; currentOutlineNode.children.push(newNode); } currentOutlineNode = newNode; } else if (orderDepth > currentOutlineNode.depth) { newNode.parent = currentOutlineNode; currentOutlineNode.children.push(newNode); currentOutlineNode = newNode; } } } const stripParentProperty = (node) => { node.parent = void 0; for (const child of node.children) stripParentProperty(child); }; stripParentProperty(root); return root.children; }, tags, tags.map((titleItem) => `${preSelector}${titleItem}`).join(",")); } function addRefsForOutlineItems(outlines, context, parentRef) { return outlines.map((item) => { const itemRef = context.nextRef(); return { ...item, ref: itemRef, parentRef, children: addRefsForOutlineItems(item.children, context, itemRef) }; }); } function countChildrenOfOutline(outlines) { let count = 0; for (const item of outlines) { ++count; count += countChildrenOfOutline(item.children); } return count; } function buildPdfObjectsForOutline(outlinesWithRef, context) { for (const [i, item] of outlinesWithRef.entries()) { const prev = outlinesWithRef[i - 1]; const next = outlinesWithRef[i + 1]; const pdfObject = /* @__PURE__ */ new Map([]); pdfObject.set(import_pdf_lib.PDFName.of("Title"), import_pdf_lib.PDFHexString.fromText((0, import_html_entities.decode)(item.title))); pdfObject.set(import_pdf_lib.PDFName.of("Dest"), import_pdf_lib.PDFName.of(item.destination)); pdfObject.set(import_pdf_lib.PDFName.of("Parent"), item.parentRef); pdfObject.set(import_pdf_lib.PDFName.of("F"), import_pdf_lib.PDFNumber.of((item.italic ? 1 : 0) | (item.bold ? 2 : 0))); if (Array.isArray(item.color)) { const pdfArr = import_pdf_lib.PDFArray.withContext(context); pdfArr.push(import_pdf_lib.PDFNumber.of(item.color[0] ?? 0)); pdfArr.push(import_pdf_lib.PDFNumber.of(item.color[1] ?? 0)); pdfArr.push(import_pdf_lib.PDFNumber.of(item.color[2] ?? 0)); pdfObject.set(import_pdf_lib.PDFName.of("C"), pdfArr); } if (prev) pdfObject.set(import_pdf_lib.PDFName.of("Prev"), prev.ref); if (next) pdfObject.set(import_pdf_lib.PDFName.of("Next"), next.ref); if (item.children.length > 0) { pdfObject.set(import_pdf_lib.PDFName.of("First"), item.children[0].ref); pdfObject.set(import_pdf_lib.PDFName.of("Last"), item.children[item.children.length - 1].ref); pdfObject.set(import_pdf_lib.PDFName.of("Count"), import_pdf_lib.PDFNumber.of(countChildrenOfOutline(item.children))); } context.assign(item.ref, import_pdf_lib.PDFDict.fromMapWithContext(pdfObject, context)); buildPdfObjectsForOutline(item.children, context); } } function generateWarningsAboutMissingDestinations(layer, pdfDoc) { const dests = pdfDoc.context.lookup(pdfDoc.catalog.get(import_pdf_lib.PDFName.of("Dests")), import_pdf_lib.PDFDict); if (dests) { const validDestinationTargets = dests.entries().map(([key]) => key.asString()); for (const item of layer) { if (item.destination && !validDestinationTargets.includes(`/${item.destination}`)) console.warn(`Unable to find destination "${item.destination}" while generating PDF outline.`); generateWarningsAboutMissingDestinations(item.children, pdfDoc); } } } async function setOutline(pdfDoc, outlines, enableWarnings = false) { const context = pdfDoc.context; const rootOutlineRef = context.nextRef(); if (!outlines.length) return pdfDoc; if (enableWarnings) generateWarningsAboutMissingDestinations(outlines, pdfDoc); const outlinesWithRef = addRefsForOutlineItems(outlines, context, rootOutlineRef); buildPdfObjectsForOutline(outlinesWithRef, context); const outlineObject = /* @__PURE__ */ new Map([]); outlineObject.set(import_pdf_lib.PDFName.of("Type"), import_pdf_lib.PDFName.of("Outlines")); outlineObject.set(import_pdf_lib.PDFName.of("First"), outlinesWithRef[0].ref); outlineObject.set(import_pdf_lib.PDFName.of("Last"), outlinesWithRef[outlinesWithRef.length - 1].ref); outlineObject.set(import_pdf_lib.PDFName.of("Count"), import_pdf_lib.PDFNumber.of(countChildrenOfOutline(outlinesWithRef))); context.assign(rootOutlineRef, import_pdf_lib.PDFDict.fromMapWithContext(outlineObject, context)); pdfDoc.catalog.set(import_pdf_lib.PDFName.of("Outlines"), rootOutlineRef); return pdfDoc; } // src/core/printer.ts var import_node_events = __toESM(require("events"), 1); var import_node_path4 = __toESM(require("path"), 1); var import_node_process = __toESM(require("process"), 1); var import_pdf_lib2 = require("pdf-lib"); var import_puppeteer = __toESM(require("puppeteer"), 1); // package.json var package_default = { name: "html-export-pdf-cli", type: "module", version: "1.2.0", packageManager: "pnpm@9.6.0", description: "Render HTML to PDF(with outline) using Puppeteer.", author: "CondorHero", license: "MIT", homepage: "https://github.com/condorheroblog/html-export-pdf-cli#readme", repository: { type: "git", url: "git+https://github.com/condorheroblog/html-export-pdf-cli.git" }, bugs: { url: "https://github.com/condorheroblog/html-export-pdf-cli/issues" }, keywords: [ "html-export-pdf-cli", "html-export-outline-pdf", "html-export-bookmark-pdf", "html-export-pdf", "html-to-pdf-cli", "bookmark-pdf", "outline-pdf", "html-to-pdf", "htmltopdf", "html2pdf", "pdf-cli" ], exports: { ".": { import: "./dist/index.js", require: "./dist/index.cjs" } }, main: "dist/index.cjs", module: "dist/index.js", types: "dist/index.d.ts", typesVersions: { "*": { "*": [ "./dist/*", "./dist/index.d.ts" ] } }, bin: { "html-export-pdf-cli": "bin/html-export-pdf-cli.mjs" }, files: [ "bin", "dist" ], engines: { node: ">=18.12.0" }, scripts: { prepublishOnly: "nr build", lint: "eslint .", "lint:fix": "eslint . --fix", dev: "jiti ./src/index.ts", coverage: "vitest run --coverage", test: "vitest", build: "tsup", "build:watch": "tsup --watch", typecheck: "tsc --noEmit", release: "bumpp -r && npm publish" }, workspaces: [ "examples/*" ], dependencies: { "cli-progress": "^3.12.0", commander: "^12.1.0", "fast-glob": "^3.3.2", "html-entities": "^2.5.2", "pdf-lib": "1.17.1", puppeteer: "^22.15.0" }, devDependencies: { "@antfu/eslint-config": "^2.24.1", "@types/cli-progress": "^3.11.6", "@types/node": "^22.0.2", bumpp: "^9.4.1", colorette: "^2.0.20", eslint: "^9.8.0", jiti: "^1.21.6", "lint-staged": "^15.2.7", "simple-git-hooks": "^2.11.1", tsup: "^8.2.3", typescript: "^5.5.4", vitest: "^2.0.5" }, "simple-git-hooks": { "pre-commit": "npx lint-staged" }, "lint-staged": { "*": "eslint --fix" }, publishConfig: { access: "public", registry: "https://registry.npmjs.org" } }; // src/core/postprocesser.ts function setMetadata(pdfDoc, meta) { if (meta.keywords && typeof meta.keywords === "string") meta.keywords = meta.keywords.split(","); if (!meta.keywords) meta.keywords = []; if (!(meta.creationDate instanceof Date)) meta.creationDate = /* @__PURE__ */ new Date(); meta.modDate = /* @__PURE__ */ new Date(); meta.metadataDate = /* @__PURE__ */ new Date(); if (!meta.creator) { const creator = pdfDoc.getCreator(); meta.creator = `${creator} + ${package_default.name}`; } if (!meta.producer) { const producer = pdfDoc.getProducer(); meta.producer = producer; } if (meta.title) pdfDoc.setTitle(meta.title); if (meta.subject) pdfDoc.setSubject(meta.subject); if (Array.isArray(meta.keywords)) pdfDoc.setKeywords(meta.keywords); if (meta.author) pdfDoc.setAuthor(meta.author); if (meta.creationDate) pdfDoc.setCreationDate(meta.creationDate); if (meta.modDate) pdfDoc.setModificationDate(meta.modDate); if (meta.creator) pdfDoc.setCreator(meta.creator); if (meta.producer) pdfDoc.setProducer(meta.producer); } // src/core/printer.ts var Printer = class extends import_node_events.default { debug; headless; allowLocal; outlineTags; allowRemote; additionalScripts; allowedPaths; allowedDomains; ignoreHTTPSErrors; browserWSEndpoint; browserArgs; timeout; emulateMedia; additionalStyles; enableWarnings; pages; browser; outlineContainerSelector; content; constructor(options = {}) { super(); this.debug = options.debug ?? false; this.headless = options.headless ?? true; this.allowLocal = options.allowLocal ?? false; this.allowRemote = options.allowRemote ?? true; this.outlineTags = options.outlineTags ?? ["h1", "h2", "h3", "h4", "h5", "h6"]; this.additionalScripts = options.additionalScripts ?? []; this.allowedPaths = options.allowedPaths ?? []; this.allowedDomains = options.allowedDomains ?? []; this.ignoreHTTPSErrors = options.ignoreHTTPSErrors ?? false; this.browserWSEndpoint = options.browserEndpoint; this.browserArgs = options.browserArgs ?? []; this.timeout = options.timeout ?? 0; this.emulateMedia = options.emulateMedia ?? "print"; this.additionalStyles = options.additionalStyles ?? []; this.enableWarnings = options.enableWarnings ?? false; this.outlineContainerSelector = options.outlineContainerSelector ?? ""; this.pages = /* @__PURE__ */ new Map(); if (this.debug) this.headless = false; } async setup(puppeteerLaunchOptions) { const puppeteerOptions = { // https://github.com/puppeteer/puppeteer/issues/2735#issuecomment-470309033 // pipe: true, headless: this.headless, args: ["--disable-dev-shm-usage", "--export-tagged-pdf"], ignoreHTTPSErrors: this.ignoreHTTPSErrors, ...puppeteerLaunchOptions }; if (this.allowLocal) puppeteerOptions.args.push("--allow-file-access-from-files"); if (this.browserArgs) puppeteerOptions.args.push(...this.browserArgs); if (this.browserWSEndpoint) { this.browser = await import_puppeteer.default.connect({ ...puppeteerOptions, browserWSEndpoint: this.browserWSEndpoint }); } else { this.browser = await import_puppeteer.default.launch(puppeteerOptions); } return this.browser; } async createNewPage(input) { if (!this.browser) await this.setup(); const page = await this.browser.newPage(); this.pages.set(input, page); page.setDefaultTimeout(this.timeout); await page.emulateMediaType(this.emulateMedia); if (this.needsAllowedRules()) { await page.setRequestInterception(true); page.on("request", (request) => { const uri = new URL(request.url()); const { host, protocol, pathname } = uri; const local = protocol === "file:"; if (local && !this.withinAllowedPath(pathname)) { request.abort(); return; } if (local && !this.allowLocal) { request.abort(); return; } if (host && !this.isAllowedDomain(host)) { request.abort(); return; } if (host && !this.allowRemote) { request.abort(); return; } request.continue(); }); } return page; } async render(input) { if (!this.browser) await this.setup(); try { let page = this.pages.get(input); if (!page) { page = await this.createNewPage(input).catch((e) => { throw e; }); } await page.goto(input, { waitUntil: "networkidle2" }); this.content = await page.content(); for (const style of this.additionalStyles) { await page.addStyleTag({ path: style }); } for (const script of this.additionalScripts) { await page.addScriptTag({ path: script }); } await page.waitForNetworkIdle({ timeout: this.timeout }); return page; } catch (error) { await this.closeBrowser(); throw error; } } async pdf(input, options = {}, pageContainerSelector) { let page = this.pages.get(input); if (!page) { page = await this.render(input).catch((e) => { throw e; }); } try { const meta = await page.evaluate(() => { const meta2 = {}; const title = document.querySelector("title"); if (title) meta2.title = title.textContent.trim(); const lang = document.querySelector("html")?.getAttribute("lang"); if (lang) meta2.lang = lang; const metaTags = document.querySelectorAll("meta"); [...metaTags].forEach((tag) => { if (tag.name) meta2[tag.name] = tag.content; }); return meta2; }); const pdfExportOptions = { scale: !options.scale ? 1 : options.scale, timeout: this.timeout, displayHeaderFooter: false, headerTemplate: options.headerTemplate, footerTemplate: options.footerTemplate, preferCSSPageSize: options.preferCSSPageSize, printBackground: options.printBackground, omitBackground: options.omitBackground, width: options.width, height: options.height, landscape: options.landscape, format: options.format ?? "letter" }; if (options.margin) pdfExportOptions.margin = options.margin; if (options.pageRanges) pdfExportOptions.pageRanges = options.pageRanges; if (options.headerTemplate || options.footerTemplate) pdfExportOptions.displayHeaderFooter = true; const outline = await getOutline(page, this.outlineTags ?? [], pageContainerSelector ?? this.outlineContainerSelector); const pdf = await page.pdf(pdfExportOptions).catch((e) => { throw e; }); this.emit("postprocessing"); const pdfDoc = await import_pdf_lib2.PDFDocument.load(pdf); setMetadata(pdfDoc, meta); setOutline(pdfDoc, outline, this.enableWarnings); return await pdfDoc.save(); } catch (error) { await this.closeBrowser(); throw error; } } async html(input) { let page = this.pages.get(input); if (!page) { page = await this.render(input).catch((e) => { throw e; }); } const content = await page.content(); return content; } async closePage(input) { const page = this.pages.get(input); if (page) { await page.close(); this.pages.delete(input); } else { import_node_process.default.stdout.write(red(`Could not find page with input: ${input}`)); } } async closeBrowser() { if (this.browser) { await this.browser.close(); this.browser = void 0; } else { import_node_process.default.stdout.write(red("Browser instance not found")); } } needsAllowedRules() { if (Array.isArray(this.allowedPaths) && this.allowedPaths.length) return true; if (Array.isArray(this.allowedDomains) && this.allowedDomains.length) return true; return false; } withinAllowedPath(pathname) { if (!this.allowedPaths || !this.allowedPaths.length) return true; for (const parent of this.allowedPaths) { const relative = import_node_path4.default.relative(parent, pathname); if (relative && !relative.startsWith("..") && !import_node_path4.default.isAbsolute(relative)) return true; } return false; } isAllowedDomain(domain) { if (!this.allowedDomains || !this.allowedDomains.length) return true; return this.allowedDomains.includes(domain); } }; // src/commands/runner.ts var import_node_process3 = __toESM(require("process"), 1); var import_commander = require("commander"); // src/constants/bin.ts var HTML_EXPORT_PDF_CLI = package_default.name; // src/commands/htmlExportPdf/htmlExportPdf.ts var import_node_path5 = __toESM(require("path"), 1); var import_node_fs2 = require("fs"); var import_node_process2 = __toESM(require("process"), 1); var import_fast_glob = __toESM(require("fast-glob"), 1); async function htmlExportPdf(args, options) { const inputArr = options.inputs.length ? options.inputs : args ?? []; if (!inputArr.length) { import_node_process2.default.stdout.write(red("You must include an input path")); import_node_process2.default.exit(1); } const dir = import_node_process2.default.cwd(); const globPaths = inputArr.reduce((acc, inputPath) => { if (!isValidUrl(inputPath)) { if (![".htm", ".html", ".xhtml"].includes(import_node_path5.default.extname(inputPath))) { import_node_process2.default.stdout.write(red(`${inputPath} is must a html or xhtml file`)); import_node_process2.default.exit(1); } try { (0, import_node_fs2.accessSync)(inputPath, import_node_fs2.constants.F_OK); } catch (e) { console.error(`${inputPath} Input cannot be found`, e); import_node_process2.default.exit(1); } const absolutePathArr = import_fast_glob.default.sync([inputPath], { ignore: ["node_modules"], onlyFiles: true, cwd: dir, absolute: true }); return [...acc, ...absolutePathArr.map((item) => `file://${item}`)]; } return [...acc, inputPath]; }, []); const isSingleFile = globPaths.length === 1; const progress = createProgress(isSingleFile); progress.start(globPaths.length); const printerOptions = { debug: options.debug, headless: options.headless, allowLocal: !options.blockLocal, allowRemote: !options.blockRemote, allowedPaths: options.allowedPaths, allowedDomains: options.allowedDomains, ignoreHTTPSErrors: options.ignoreHTTPSErrors, additionalScripts: options.additionalScripts, additionalStyles: options.additionalStyles, browserEndpoint: options.browserEndpoint, timeout: options.timeout, browserArgs: options.browserArgs, emulateMedia: options.media, enableWarnings: options.warn, outlineContainerSelector: options.outlineContainerSelector }; const printer = new Printer(printerOptions); const getOutFileName = (inputPath) => { if (globPaths.length === 1 && options.outFile) return options.outFile.endsWith(".pdf") ? options.outFile : `${options.outFile}.pdf`; const baseName = import_node_path5.default.basename(inputPath); const splitBaseName = baseName.split(":")[0]; const hostName = new URL(inputPath).hostname; if (splitBaseName === hostName) { return `${hostName}.pdf`; } const filename = baseName.split("/").pop(); if (!filename?.length) return `${baseName.split("/").filter(Boolean).join("_")}.pdf`; return replaceExt(import_node_path5.default.basename(inputPath), ".pdf"); }; for (const inputPath of globPaths) { try { const outFileName = getOutFileName(inputPath); let output = import_node_path5.default.join(dir, options.outDir ?? "", outFileName); let file; if (options.html) { file = await printer.html(inputPath).catch((e) => { console.error(e); import_node_process2.default.exit(1); }); output = replaceExt(output, ".html"); } else if (options.debug === true) { await printer.render(inputPath); } else { const format = options.pageSize; let margin = {}; if (options.margin) { margin = options.margin.split(",").reduce((obj, item) => { const [key, value] = item.split("="); if (key === "top" || key === "bottom" || key === "left" || key === "right") obj[key] = value; return obj; }, {}); } file = await printer.pdf(inputPath, { ...options, margin, format }).catch((e) => { console.error(e); import_node_process2.default.exit(1); }); } if (file && output) { const isWrite = await writeFileSafe(output, file); if (isWrite) { progress.increment(1); if (isSingleFile) { import_node_process2.default.stdout.write(` ${green(" \u2713 ")}${dim("Saved to ")} ${output} `); } } else { import_node_process2.default.exit(1); } } else if (file) { import_node_process2.default.stdout.write(file); } await printer.closePage(inputPath); } catch (error) { console.error(error); } } await printer.closeBrowser(); progress.stop(); if (!isSingleFile) { import_node_process2.default.stdout.write(` ${green(" \u2713 ")}${dim("Saved to ")} ${import_node_path5.default.join(dir, options.outDir ?? "")} `); } import_node_process2.default.exit(0); } // src/commands/htmlExportPdf/createHtmlExportPdf.ts function createHtmlExportPdf(program2) { program2.arguments("[inputs...]").option("-i, --inputs ", "Input one or more local or online paths", collectParameters, []).option("-o, --outFile [outFile]", "Output file name(default: {input}.pdf)").option("--outDir [outDir]", "Output directory(default: process.cwd())").option("--headless [headless]", "Whether to run the browser in headless mode(default: true)", (v) => { if (v === "false") return false; if (v === "true") return true; return v; }, true).option("--scale ", "Scales the rendering of the web page. Amount must be between 0.1 and 2(default: 1)", (v) => Number(v), 1).option("--headerTemplate ", "HTML template for the print header").option("--footerTemplate ", "HTML template for the print footer").option("--preferCSSPageSize", "Give any CSS @page size declared in the page priority over what is declared in the width or height or format option(default: false)", false).option("--printBackground", "Set to print background graphics(default: false)", false).option("--omitBackground", "Hides default white background and allows generating PDFs with transparency(default: false)", false).option("--pageRanges ", "Paper ranges to print, e.g. 1-5, 8, 11-13").option("-m, --margin ", "Set the PDF margins. e.g. top=10,bottom=10,left=10,right=10").option("-l, --landscape", "Whether to print in landscape orientation(default: false)", false).option("-s, --page-size ", "Print to Page Size", "letter").option("-w, --width ", "Print to Page Width").option("-h --height ", "Print to Page Height").option("-t, --timeout ", "Set a max timeout of ms").option("-x, --html", "output html file").option("-b, --blockLocal", "Disallow access to filesystem for local files(default: false)", false).option("-r, --blockRemote", "Disallow requests to remote servers(default: false)", false).option("--outlineContainerSelector ", "Specify an outline container selector").option("--allowedPaths ", "Only allow access to given filesystem paths, repeatable", collectParameters, []).option("--allowedDomains ", "Only allow access to given remote domains, repeatable", collectParameters, []).option("--ignoreHTTPSErrors", "Whether to ignore HTTPS errors during navigation(default: false)", false).option("--outline-tags ", "Add outlines (bookmarks) to PDF", commaSeparatedList, ["h1", "h2", "h3", "h4", "h5", "h6"]).option("--additional-scripts ", "additional script tags to the HTML document", collectParameters, []).option("--additional-styles ", "additional style tags to the HTML document", collectParameters, []).option("--browserEndpoint", "Use a remote Chrome server with browserWSEndpoint").option("--browserArgs ", "Launch Chrome with comma separated args", commaSeparatedList).option("--media ", "Emulate print or screen media, defaults to print(default: 'print')", "print").option("-d, --debug", "Debug").option("--warn", "Enable warning logs").action(htmlExportPdf); } // src/commands/runner.ts function registerCommands(cliInstance, programName) { switch (programName) { case HTML_EXPORT_PDF_CLI: createHtmlExportPdf(cliInstance); break; default: import_node_process3.default.stdout.write(red("no command name")); break; } } function beforeParse(cliInstance) { cliInstance.version(package_default.version); } function afterParse(cliInstance) { if (!import_node_process3.default.argv.slice(2).filter(Boolean).length) cliInstance.outputHelp(); } function runCli(programName) { registerCommands(import_commander.program, programName); if (beforeParse) { beforeParse(import_commander.program); } import_commander.program.parse(import_node_process3.default.argv); if (afterParse) { afterParse(import_commander.program); } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { HTML_EXPORT_PDF_CLI, Printer, afterParse, beforeParse, collectParameters, commaSeparatedList, createHtmlExportPdf, createProgress, formatOutlineContainerSelector, getAbsFileName, getDirname, getOutline, htmlExportPdf, isValidUrl, registerCommands, replaceExt, runCli, setMetadata, setOutline, writeFileSafe });