UNPKG

@knennigtri/merge-markdown

Version:

Prepare input files to merge together and optionally output html/pdf/word presentation

263 lines (257 loc) • 23.7 kB
"use strict"; function _regeneratorRuntime() { "use strict"; var r = _regenerator(), e = r.m(_regeneratorRuntime), t = (Object.getPrototypeOf ? Object.getPrototypeOf(e) : e.__proto__).constructor; function n(r) { var e = "function" == typeof r && r.constructor; return !!e && (e === t || "GeneratorFunction" === (e.displayName || e.name)); } var o = { "throw": 1, "return": 2, "break": 3, "continue": 3 }; function a(r) { var e, t; return function (n) { e || (e = { stop: function stop() { return t(n.a, 2); }, "catch": function _catch() { return n.v; }, abrupt: function abrupt(r, e) { return t(n.a, o[r], e); }, delegateYield: function delegateYield(r, o, a) { return e.resultName = o, t(n.d, _regeneratorValues(r), a); }, finish: function finish(r) { return t(n.f, r); } }, t = function t(r, _t, o) { n.p = e.prev, n.n = e.next; try { return r(_t, o); } finally { e.next = n.n; } }), e.resultName && (e[e.resultName] = n.v, e.resultName = void 0), e.sent = n.v, e.next = n.n; try { return r.call(this, e); } finally { n.p = e.prev, n.n = e.next; } }; } return (_regeneratorRuntime = function _regeneratorRuntime() { return { wrap: function wrap(e, t, n, o) { return r.w(a(e), t, n, o && o.reverse()); }, isGeneratorFunction: n, mark: r.m, awrap: function awrap(r, e) { return new _OverloadYield(r, e); }, AsyncIterator: _regeneratorAsyncIterator, async: function async(r, e, t, o, u) { return (n(e) ? _regeneratorAsyncGen : _regeneratorAsync)(a(r), e, t, o, u); }, keys: _regeneratorKeys, values: _regeneratorValues }; })(); } function _regeneratorValues(e) { if (null != e) { var t = e["function" == typeof Symbol && Symbol.iterator || "@@iterator"], r = 0; if (t) return t.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) return { next: function next() { return e && r >= e.length && (e = void 0), { value: e && e[r++], done: !e }; } }; } throw new TypeError(_typeof(e) + " is not iterable"); } function _regeneratorKeys(e) { var n = Object(e), r = []; for (var t in n) r.unshift(t); return function e() { for (; r.length;) if ((t = r.pop()) in n) return e.value = t, e.done = !1, e; return e.done = !0, e; }; } function _regeneratorAsync(n, e, r, t, o) { var a = _regeneratorAsyncGen(n, e, r, t, o); return a.next().then(function (n) { return n.done ? n.value : a.next(); }); } function _regeneratorAsyncGen(r, e, t, o, n) { return new _regeneratorAsyncIterator(_regenerator().w(r, e, t, o), n || Promise); } function _regeneratorAsyncIterator(t, e) { function n(r, o, i, f) { try { var c = t[r](o), u = c.value; return u instanceof _OverloadYield ? e.resolve(u.v).then(function (t) { n("next", t, i, f); }, function (t) { n("throw", t, i, f); }) : e.resolve(u).then(function (t) { c.value = t, i(c); }, function (t) { return n("throw", t, i, f); }); } catch (t) { f(t); } } var r; this.next || (_regeneratorDefine2(_regeneratorAsyncIterator.prototype), _regeneratorDefine2(_regeneratorAsyncIterator.prototype, "function" == typeof Symbol && Symbol.asyncIterator || "@asyncIterator", function () { return this; })), _regeneratorDefine2(this, "_invoke", function (t, o, i) { function f() { return new e(function (e, r) { n(t, i, e, r); }); } return r = r ? r.then(f, f) : f(); }, !0); } function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); } function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { if (r) i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n;else { var o = function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); }; o("next", 0), o("throw", 1), o("return", 2); } }, _regeneratorDefine2(e, r, n, t); } function _OverloadYield(e, d) { this.v = e, this.k = d; } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); } function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } var packageInfo = require("../package.json"); var npmModuleName = packageInfo.name.replace(/@[^/]+\//, ""); var manifestUtil = require("./manifest.js"); var merge = require("./merge.js"); var presentation = require("./presentation.js"); var dockerMerger = require("./docker.js"); var assetCleaner = require("./asset-cleaner.js"); var path = require("path"); var fs = require("fs"); var minimist = require("minimist"); var args = minimist(process.argv.slice(2)); //https://www.npmjs.com/package/debug //Mac: DEBUG=* merge-markdown.... //WIN: set DEBUG=* & merge-markdown.... var debug = require("debug"); var debugArgs = debug("args"); var debugCLI = debug("cli"); var debbugOptions = _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, { "*": "Output all debugging messages", "args": "See CLI argument messages", "cli": "Validate CLI logic" }), manifestUtil.debbugOptions), merge.debbugOptions), presentation.debbugOptions), dockerMerger.debbugOptions), {}, { "asset-cleaner": "Asset cleaning debug messages" }); function run() { return _run.apply(this, arguments); } function _run() { _run = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee() { var argsHelp, argsVersion, argsDebug, argsManifest, argsQA, argsSkipLinkcheck, argsCreate, argsMaintainAssetPaths, argsGetDockerFiles, argsUseDocker, argsFullProject, argsPDF, argsHTML, argsWORD, argsLang, argsCleanAssets, argsAssetsDir, argsFix, argsNoAssetPreview, helpType, activeModes, inputFilesPath, themeSourcePath, themeDestPath, quickstartPath, manifestFilePath, relativeManifest, resultMarkdownFile, outputFormat, resultFile, relativePath; return _regeneratorRuntime().wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: argsHelp = args.h || args.help; argsVersion = args.v || args.version; argsDebug = args.d || args.debug; argsManifest = args.m || args.manifest; argsQA = args.qa; argsSkipLinkcheck = args.skipLinkcheck; argsCreate = args.c || args.create; argsMaintainAssetPaths = args.maintainAssetPaths; argsGetDockerFiles = args.getDockerFiles; argsUseDocker = args.docker || args.Docker; argsFullProject = args.fullProject || args.fullproject || args.FullProject; argsPDF = args.pdf || args.PDF; argsHTML = args.html || args.HTML; argsWORD = args.word || args.WORD; argsLang = args.lang; argsCleanAssets = args["clean-assets"]; argsAssetsDir = args["assets-dir"]; argsFix = args.fix; argsNoAssetPreview = args["no-asset-preview"]; debugArgs(JSON.stringify(args, null, 2)); // Show CLI help if (!argsHelp) { _context.next = 24; break; } helpType = argsHelp === true ? "default" : argsHelp.toLowerCase(); if (HELP[helpType]) console.log(HELP[helpType]);else console.log(HELP["default"]); return _context.abrupt("return"); case 24: if (!argsVersion) { _context.next = 27; break; } console.log(packageInfo.version); return _context.abrupt("return"); case 27: if (!argsDebug) { _context.next = 32; break; } console.log("[Mac] $ DEBUG=<option> ".concat(npmModuleName, " -m <file>")); console.log("[Win] $ set DEBUG=<option> & ".concat(npmModuleName, " -m <file>")); console.log("Options: ".concat(JSON.stringify(debbugOptions, null, 2))); return _context.abrupt("return"); case 32: // Show active modes activeModes = []; if (argsQA) activeModes.push("QA"); if (argsSkipLinkcheck) activeModes.push("Skip Linkcheck"); if (argsMaintainAssetPaths) activeModes.push("Maintain Asset Paths"); if (argsLang) activeModes.push("Language: " + argsLang); if (argsNoAssetPreview) activeModes.push("No Asset Preview"); if (activeModes.length > 0) { console.log("āš™ļø Modes: " + activeModes.join(", ")); } if (!argsCreate) { _context.next = 47; break; } if (argsUseDocker) console.log("Docker cannot be used with --Create mode"); inputFilesPath = "."; if (typeof argsCreate === "string") { inputFilesPath = argsCreate; } _context.next = 45; return manifestUtil.createManifestFile(inputFilesPath, argsFullProject); case 45: if (argsFullProject) { themeSourcePath = path.join(__dirname, "theme"); debugCLI("Theme folder source: " + themeSourcePath); themeDestPath = path.join(process.cwd(), "theme"); fs.cpSync(themeSourcePath, themeDestPath, { recursive: true }); debugCLI("Theme folder copied to: " + themeDestPath); quickstartPath = path.join(__dirname, "quickstart.md"); fs.cpSync(quickstartPath, path.join(process.cwd(), "quickstart.md")); debugCLI("Quickstart file copied to: " + path.join(process.cwd(), "quickstart.md")); } return _context.abrupt("return"); case 47: if (!argsGetDockerFiles) { _context.next = 50; break; } downloadDockerFiles(); return _context.abrupt("return"); case 50: if (!(argsCleanAssets !== undefined)) { _context.next = 53; break; } runAssetCleaning(argsCleanAssets, argsAssetsDir, argsFix); return _context.abrupt("return"); case 53: try { if (argsManifest && typeof argsManifest === "string") { manifestFilePath = manifestUtil.exists(argsManifest); } else { //if there is no -m check for a default manifest file manifestFilePath = manifestUtil.exists("./"); } } catch (err) { console.error(err); console.log(HELP); } if (manifestFilePath) { _context.next = 58; break; } console.log("No manifest found. Consider auto-creating with -c or specify a manifest with -m \n"); console.log(HELP["default"]); return _context.abrupt("return"); case 58: if (!argsUseDocker) { _context.next = 63; break; } console.log("[Docker Mode] Building ".concat(npmModuleName, " in a container.")); _context.next = 62; return dockerMerger.runMergeMarkdownInDocker(manifestFilePath, process.argv.slice(2).join(" ")); case 62: return _context.abrupt("return"); case 63: debugCLI("manifest found at: " + manifestFilePath); relativeManifest = path.relative(process.cwd(), manifestFilePath); console.log("šŸ“‹ Manifest: " + relativeManifest); _context.prev = 66; _context.next = 69; return merge.start(manifestFilePath, argsQA, argsSkipLinkcheck, argsMaintainAssetPaths, argsLang, argsNoAssetPreview); case 69: resultMarkdownFile = _context.sent; //Add presentation outputFormat = ""; if (argsWORD) outputFormat = presentation.EXTS.docx; if (argsHTML) outputFormat = presentation.EXTS.html; if (argsPDF) outputFormat = presentation.EXTS.pdf; _context.next = 76; return presentation.build(resultMarkdownFile, outputFormat, manifestFilePath); case 76: resultFile = _context.sent; relativePath = path.relative(process.cwd(), resultFile); console.log("\nāœ… Output: " + relativePath); _context.next = 84; break; case 81: _context.prev = 81; _context.t0 = _context["catch"](66); // Error details already logged by the respective functions // Just exit with error code process.exit(1); case 84: case "end": return _context.stop(); } }, _callee, null, [[66, 81]]); })); return _run.apply(this, arguments); } function downloadDockerFiles(manifestPath) { var downloadPath = manifestPath || "./"; console.log("[Docker Mode] Downloading docker files..."); var dockerFileNames = ["docker-compose.yml", "Dockerfile"]; dockerFileNames.forEach(function (fileName) { var sourcePath = path.join(__dirname, "../docker/", fileName); var destinationPath = path.join(downloadPath, fileName); // Copy the Docker file fs.copyFileSync(sourcePath, destinationPath); console.log(" Copied " + fileName + " to " + path.resolve(destinationPath)); }); } function runAssetCleaning(targetDir, assetsDir, fixMode) { debugCLI("Running asset cleaning"); // Determine target directory var cleanTargetDir; if (typeof targetDir === "string") { // User provided a specific directory cleanTargetDir = path.isAbsolute(targetDir) ? targetDir : path.join(process.cwd(), targetDir); } else { // No directory specified, use current working directory cleanTargetDir = process.cwd(); } // Use provided assets directory name or default var assetsFolderName = assetsDir || "assets"; var isFixMode = fixMode || false; debugCLI("Target directory: ".concat(cleanTargetDir)); debugCLI("Assets folder: ".concat(assetsFolderName)); debugCLI("Fix mode: ".concat(isFixMode)); // Run the asset cleaning var result = assetCleaner.cleanAssets(cleanTargetDir, assetsFolderName, isFixMode, true); if (result.error) { console.error("\u274C Error: ".concat(result.error)); process.exit(1); } } var HELP = { "default": "Usage: ".concat(npmModuleName, " [ARGS]\nArguments:\n -m, --manifest <manifestFile> Path to input folder, yaml, or json manifest\n -v, --version Displays version of this package\n -c, --create <path> auto-creates ./manifest.yml with input files from <path>\n --fullProject Add to -c to include a basic theme, frontmatter, and npm scripts\n --docker Run ").concat(npmModuleName, " commands in docker\n --getDockerFiles Downloads the Docker files to your local project\n --qa QA mode.\n --skipLinkcheck Skips linkchecking\n --maintainAssetPaths Retains original asset paths\n --lang <language> Language code for multilingual support (e.g., --lang=es)\n --clean-assets [directory] Clean unused assets in specified directory (or current directory)\n --assets-dir <name> Name of assets folder (default: 'assets')\n --fix Actually delete unused assets (default: preview mode)\n --no-asset-preview Disable asset preview during normal merge workflow\n --pdf Output to PDF. Must have Pandoc and wkhtmltopdf installed!\n --html --word Output to HTML or Word. Must have Pandoc installed!\n -h, --help Displays this screen\n -h manifest | options |\n outputOptions | qa | docker | assets See examples\n -d, --debug See debug Options\nDefault is ").concat(manifestUtil.DEFAULT_MANIFEST.FILE_TYPES, " unless specified in -m.\n\nDownload Docker: https://docs.docker.com/get-docker/\n"), manifest: "Example yaml in a manifest file:\n input:\n global-frontmatter.md: {noYAML: false, doctoc: false}\n module1Folder/file1.md: {fileOptions}\n module2Folder/file2.md: {replace: {key:value}}\n noYAML: true\n doctoc: true\n output: \n name: merged/myOutput.md\n {outputOptions}\n qa: {exclude: regex}\n {projectOptions}\n\nAlso, consider auto creating a manifest for your project:\n\n$ ".concat(npmModuleName, " --create /path/to/project --fullProject\n"), options: "fileOptions are applied first and then projectOptions second.\nSupported key/value pairs for {options}:\n noYAML: true|false Optionlly removes YAML. Default=false\n doctoc: true|false|\"TOC title\" doctoc arguments. See https://www.npmjs.com/package/doctoc\n option: <value>\n replace: Searches for key and replaces with value\n key: value\n <!--{key}-->: value Example key for a useful identifier\n *: \"stringVal\" Regular expressions are allowed\n", outputOptions: // TODO: Easier help options for understanding PDF, HTML, Word branding settings "Supported key/value pairs for {outputOptions}:\n doctoc: true|false|\"TOC title\" doctoc arguments. See https://www.npmjs.com/package/doctoc\n option: <value>\n pandoc: pandoc arguments added to <value>. See https://pandoc.org/MANUAL.html#options\n key1: \"-c mystyle.css\"\n key2: \"--template mytemplate.html\"\n key3: \"--reference-doc path/to/reference.docx\"\n wkhtmltopdf: wkhtmltopdf options. See https://www.npmjs.com/package/wkhtmltopdf#options\n pageSize: Letter\n footerLine: true\n", qa: "QA mode can optionally exclude files from the output.\nExample: exclude all filenames with \"frontmatter\" by default\n qa: {exclude: \"(frontmatter|preamble)\"}\n ", docker: "REQUIRED: Download Docker: https://docs.docker.com/get-docker/\n\n 1. Start Docker\n 2. Run:\n ".concat(npmModuleName, " -m manifest.yml --docker\n\n Alternatively you can download the docker files directly:\n ").concat(npmModuleName, " --getDockerFiles\n "), assets: "Asset cleaning helps remove unused image files from your project directories.\n\nExamples:\n ".concat(npmModuleName, " --clean-assets # Preview unused assets in current directory\n ").concat(npmModuleName, " --clean-assets ./modules --fix # Delete unused assets in modules directory\n ").concat(npmModuleName, " --clean-assets --assets-dir images # Use 'images' folder instead of 'assets'\n \nAsset Preview (automatic during merge):\n ").concat(npmModuleName, " -m manifest.yml # Shows unused assets summary after merge\n ").concat(npmModuleName, " -m manifest.yml --no-asset-preview # Disable asset preview\n \nThe tool scans markdown files for image references and identifies unused assets.\nIt supports YAML frontmatter 'copy-images-to' key for custom asset folder names.\n ") }; exports.run = run;