UNPKG

@knennigtri/merge-markdown

Version:

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

770 lines (728 loc) 39.4 kB
"use strict"; 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 _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 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 _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } 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); } function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } var fs = require("fs"); var path = require("path"); var yaml = require("js-yaml"); var _require = require("child_process"), spawn = _require.spawn; var debug = require("debug")("manifest"); var debugDeprecation = require("debug")("manifest:deprecation"); var debugJson = require("debug")("manifest:json"); var debugMultilang = require("debug")("manifest:multilang"); exports.debbugOptions = { "manifest": "", "manifest:deprecation": "", "manifest:json": "", "manifest:multilang": "multilingual file resolution" }; var DEFAULT_MANIFEST = { NAME: "manifest", EXT_TYPES: ["yml", "yaml", "json"], get EXTS() { return this.EXT_TYPES.map(function (ext) { return ".".concat(ext); }); }, get FILE() { return "".concat(this.NAME).concat(this.EXTS[0]); }, get FILE_TYPES() { return "".concat(this.NAME, "[").concat(this.EXTS.join("|"), "]"); } }; // TODO A super simple manifest should not error out. Example: // input: // course-website-agenda.md // course-website-topics.md // output: // name: merged/website.md var manifestWriteDir = process.cwd(); // When using -c relative/path/to/markdown/files, the manifest will where the command is run /** * Resolves multilingual file paths by checking for translated versions first, then fallback * @param {string} originalPath - The original file path from manifest * @param {string} baseDir - The base directory for resolving relative paths * @param {string} lang - The language code (e.g., 'es', 'fr') * @returns {object} - Object with resolvedPath and isTranslated flag */ function resolveMultilingualPath(originalPath, baseDir, lang) { if (!lang) { // No language specified, return original path var absPath = path.resolve(baseDir, originalPath); return { resolvedPath: absPath, isTranslated: false }; } var absOriginalPath = path.resolve(baseDir, originalPath); // Parse the original path var dir = path.dirname(absOriginalPath); var ext = path.extname(absOriginalPath); var baseName = path.basename(absOriginalPath, ext); // Create translated file path: filename -> lang_filename.md var translatedFileName = "".concat(lang, "_").concat(baseName).concat(ext); var translatedPath = path.join(dir, translatedFileName); // Check if translated file exists if (fs.existsSync(translatedPath)) { debugMultilang("Found translated file: ".concat(translatedPath)); return { resolvedPath: translatedPath, isTranslated: true }; } else { debugMultilang("Translated file not found: ".concat(translatedPath, ", using fallback: ").concat(absOriginalPath)); return { resolvedPath: absOriginalPath, isTranslated: false }; } } /** * Expands a folder path to all immediate .md files (non-recursive) * @param {string} folderPath - The folder path from manifest (ending with /) * @param {string} baseDir - The base directory for resolving relative paths * @returns {array} - Array of relative file paths */ function expandFolderInput(folderPath, baseDir) { var absFolder = path.resolve(baseDir, folderPath); var mdFiles = []; try { if (!fs.existsSync(absFolder)) { console.log("Warning: Folder does not exist: ".concat(folderPath)); return mdFiles; } var stat = fs.statSync(absFolder); if (!stat.isDirectory()) { console.log("Warning: Path is not a directory: ".concat(folderPath)); return mdFiles; } // Read immediate files only (non-recursive) var files = fs.readdirSync(absFolder); var _iterator = _createForOfIteratorHelper(files), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var file = _step.value; // Skip hidden files if (file.startsWith(".")) continue; var filePath = path.join(absFolder, file); var fileStat = fs.statSync(filePath); // Only include files, not directories if (fileStat.isFile() && path.extname(file).toLowerCase() === ".md") { // Return relative path from baseDir var relativePath = path.relative(baseDir, filePath); mdFiles.push(relativePath); } } // Sort alphabetically for consistent ordering } catch (err) { _iterator.e(err); } finally { _iterator.f(); } mdFiles.sort(); } catch (error) { console.log("Error reading folder ".concat(folderPath, ": ").concat(error.message)); } return mdFiles; } /** * Recursively finds all .md files in a directory and returns relative paths * @param {string} directory - The directory to search * @param {string} baseDir - The base directory for relative path calculation * @returns {array} - Array of relative file paths */ function findMarkdownFilesRecursive(directory, baseDir) { var markdownFiles = []; try { var files = fs.readdirSync(directory); var _iterator2 = _createForOfIteratorHelper(files), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var file = _step2.value; // Skip hidden files and directories if (file.startsWith(".")) continue; var filePath = path.join(directory, file); var stats = fs.statSync(filePath); if (stats.isDirectory()) { // Recursively search subdirectories markdownFiles = markdownFiles.concat(findMarkdownFilesRecursive(filePath, baseDir)); } else if (path.extname(file).toLowerCase() === ".md") { // Return relative path from baseDir var relativePath = path.relative(baseDir, filePath); markdownFiles.push(relativePath); } } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } } catch (error) { // Silently skip directories that can't be read debug("Error reading directory ".concat(directory, ": ").concat(error.message)); } return markdownFiles; } /** * Expands a regex pattern to all matching .md files (recursive) * @param {string} patternStr - The pattern string from manifest (starting with pattern:) * @param {string} baseDir - The base directory for resolving relative paths * @returns {array} - Array of relative file paths matching the pattern */ function expandPatternInput(patternStr, baseDir) { var mdFiles = []; try { // Remove 'pattern:' prefix var regexStr = patternStr.substring("pattern:".length); // Create RegExp from pattern string (similar to optionReplaceStrings in merge.js) var regex = new RegExp(regexStr); // Find all .md files recursively var allMdFiles = findMarkdownFilesRecursive(baseDir, baseDir); // Filter files that match the regex pattern var _iterator3 = _createForOfIteratorHelper(allMdFiles), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var file = _step3.value; if (regex.test(file)) { mdFiles.push(file); } } // Sort alphabetically for consistent ordering } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } mdFiles.sort(); } catch (error) { console.log("Error processing pattern '".concat(patternStr, "': ").concat(error.message)); console.log("Please ensure your pattern is a valid regex expression."); } return mdFiles; } /** * Creates a valid manifest JSON based on input (or no input) * DEBUG=manifest:json */ function getManifestObj(inputManifestFile, qaMode) { var fileType = path.extname(inputManifestFile).toLowerCase(); if (!DEFAULT_MANIFEST.EXTS.includes(fileType)) { console.log("Manifest extension must be: [" + DEFAULT_MANIFEST.EXTS.join("|") + "]"); return; } debug("Found manifest to use: " + inputManifestFile); var fileContents = fs.readFileSync(inputManifestFile, "utf8"); var jsonObj = ""; try { //Attempt to read the YAML and output JSON var data = yaml.loadAll(fileContents, "json"); var yamlContents = JSON.stringify(data[0], null, 2); jsonObj = JSON.parse(yamlContents); } catch (_unused) { debugJson("Could not read YAML, attemping JSON"); try { //Attempt to read JSON jsonObj = JSON.parse(fileContents); } catch (e) { console.log("Manifest file does not contain valid YAML or JSON content."); throw e; } } // If the manifest doesn"t have an output, generate the output name based on the manifest directory if (!jsonObj.output || !jsonObj.output.name) throw new Error("Manifest is missing output.name. Consider auto-creating an initial manifest"); // jsonObj = fixDeprecatedEntry(jsonObj); if (jsonObj.output.name.split(".").pop() != "md") throw new Error("output.name needs to be a .md file but found: " + jsonObj.output.name); if (!jsonObj.input) throw new Error("Manifest is missing input. Consider auto-creating an initial manifest"); jsonObj = fixDeprecatedEntry(jsonObj); if (qaMode) { if (!jsonObj.qa || !jsonObj.qa.exclude) { console.log("No exclude patterns given for QA. Using default `frontmatter` for exclusion."); jsonObj.qa = { "exclude": "frontmatter" }; } } return jsonObj; } /** * * @param {*} inputManifestFile * @param {*} qaMode * @returns */ /** TODO implement this method to guarantee minimum fields are set or FAIL * !m.input - fail * At least one m.input[key] - fail * !m.output - create default * !m.output.name - create default * !m.output.pandoc - create default * !m.output.wkhtmltopdf - create default * !m.qa.exclude - create default */ exports.getJSON_withABSPaths = function (inputManifestFile, qaMode, lang) { var manifestObj = getManifestObj(inputManifestFile, qaMode); var baseDir = path.dirname(inputManifestFile); // Update input paths to absolute paths with multilingual support if (manifestObj.input) { // manifest.input[key] var inputObjABS = {}; var translationStats = { translated: 0, fallback: 0 }; for (var keyPath in manifestObj.input) { var filesToProcess = []; // Detect input type: folder, pattern, or regular file if (keyPath.endsWith("/")) { // Folder input - expand to all immediate .md files filesToProcess = expandFolderInput(keyPath, baseDir); if (filesToProcess.length === 0) { console.log("Warning: No .md files found in folder: ".concat(keyPath)); } else { console.log("[Folder Expansion] Found ".concat(filesToProcess.length, " file(s) in ").concat(keyPath, ":")); filesToProcess.forEach(function (file) { return console.log(" - ".concat(path.basename(file))); }); } } else if (keyPath.startsWith("pattern:")) { // Pattern input - expand to all matching .md files (recursive) filesToProcess = expandPatternInput(keyPath, baseDir); if (filesToProcess.length === 0) { console.log("Warning: No files matched pattern: ".concat(keyPath)); } else { console.log("[Pattern Match] Found ".concat(filesToProcess.length, " file(s) matching '").concat(keyPath, "':")); filesToProcess.forEach(function (file) { return console.log(" - ".concat(file)); }); } } else { // Regular file path filesToProcess = [keyPath]; } // Process each file with multilingual support var _iterator4 = _createForOfIteratorHelper(filesToProcess), _step4; try { for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { var filePath = _step4.value; var _resolveMultilingualP = resolveMultilingualPath(filePath, baseDir, lang), resolvedPath = _resolveMultilingualP.resolvedPath, isTranslated = _resolveMultilingualP.isTranslated; // Track translation statistics if (isTranslated) { translationStats.translated++; } else { translationStats.fallback++; } inputObjABS = _objectSpread(_objectSpread({}, inputObjABS), {}, _defineProperty({}, resolvedPath, _objectSpread({}, manifestObj.input[keyPath]))); } } catch (err) { _iterator4.e(err); } finally { _iterator4.f(); } } debugJson("manifest.input (ABS): ".concat(JSON.stringify(inputObjABS, null, 2))); // Log translation statistics if language is specified if (lang) { console.log("[Multilingual] Language: ".concat(lang)); console.log("[Multilingual] Files translated: ".concat(translationStats.translated, ", fallback: ").concat(translationStats.fallback)); } manifestObj.input = inputObjABS; } // Update output paths to absolute paths if (manifestObj.output) { for (var _keyPath in manifestObj.output) { // manifest.output.name if (_keyPath === "name") { manifestObj.output.name = path.resolve(baseDir, manifestObj.output.name); debugJson("manifestObj.output.name (ABS): ".concat(manifestObj.output.name)); } // manifest.output.pandoc[key]: "-c relPath/to/theme.css" // manifest.output.pandoc[key]: "--template relPath/to/latex/template.html" // manifest.output.pandoc[key]: "--reference-doc relPath/to/reference.docx">" if (_keyPath === "pandoc") { // let p = manifestObj.output.pandoc; // Iterate through all pandoc keys and resolve paths for specific options for (var _i = 0, _Object$entries = Object.entries(manifestObj.output.pandoc); _i < _Object$entries.length; _i++) { var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), key = _Object$entries$_i[0], value = _Object$entries$_i[1]; debugJson("Key: ".concat(key, ", Value: ").concat(value)); if (typeof value === "string") { if (value.startsWith("-c ") || value.startsWith("--template") || value.startsWith("--reference-doc")) { var splitPath = value.split(" "); var command = splitPath[0]; // Get the command part var relativePath = splitPath.slice(1).join(" "); // Join the rest as the path var newValue = "".concat(command, " ").concat(path.resolve(baseDir, relativePath)); manifestObj.output.pandoc[key] = newValue; debugJson("manifest.output.pandoc (ABS): ".concat(manifestObj.output.pandoc[key])); } } } } } } return manifestObj; }; /** * Method to organize the manifest for merge and presentation to * allow for non-destructive updates to merge-markdown. * Important if users are coming from earlier versions of merge-markdown */ function fixDeprecatedEntry(manifestFix) { var updatesNeeded = ""; //Fix output to allow for keys under the output if (typeof manifestFix.output === "string") { debugDeprecation("Found: manifest.output"); var name = manifestFix.output; delete manifestFix.output; manifestFix.output = {}; manifestFix.output.name = name; updatesNeeded += " manifest.output >> manifest.output.name.\n"; } //Move all outputOptions under the output if (Object.prototype.hasOwnProperty.call(manifestFix, "mergedTOC")) { debugDeprecation("Found: manifest.mergedTOC"); manifestFix.output.doctoc = manifestFix.mergedTOC; delete manifestFix.mergedTOC; updatesNeeded += " manifest.mergedTOC >> manifest.output.doctoc.\n"; } if (Object.prototype.hasOwnProperty.call(manifestFix, "pandoc")) { debugDeprecation("Found: manifest.pandoc"); manifestFix.output.pandoc = manifestFix.pandoc; delete manifestFix.pandoc; updatesNeeded += " manifest.pandoc >> manifest.output.pandoc.\n"; } if (Object.prototype.hasOwnProperty.call(manifestFix, "wkhtmltopdf")) { debugDeprecation("Found: manifest.wkhtmltopdf"); manifestFix.output.wkhtmltopdf = manifestFix.wkhtmltopdf; delete manifestFix.wkhtmltopdf; updatesNeeded += " manifest.wkhtmltopdf >> manifest.output.wkhtmltopdf.\n"; } //Update all TOC and mergedTOC keys to doctoc if (Object.prototype.hasOwnProperty.call(manifestFix.output, "TOC")) { debugDeprecation("Found: manifest.output.TOC"); manifestFix.output.doctoc = manifestFix.output.TOC; delete manifestFix.output.TOC; updatesNeeded += " manifest.output.TOC >> manifest.output.doctoc.\n"; } if (Object.prototype.hasOwnProperty.call(manifestFix.output, "mergedTOC")) { debugDeprecation("Found: manifest.output.mergedTOC"); manifestFix.output.doctoc = manifestFix.output.mergedTOC; delete manifestFix.output.mergedTOC; updatesNeeded += " manifest.output.mergedTOC >> manifest.output.doctoc.\n"; } if (Object.prototype.hasOwnProperty.call(manifestFix, "TOC")) { debugDeprecation("Found: manifest.TOC"); manifestFix.doctoc = manifestFix.TOC; delete manifestFix.TOC; updatesNeeded += " manifest.TOC >> manifest.doctoc.\n"; } if (Object.prototype.hasOwnProperty.call(manifestFix, "input")) { var update = false; for (var i in manifestFix.input) { if (Object.prototype.hasOwnProperty.call(manifestFix.input[i], "TOC")) { debugDeprecation("Found: manifest.input[".concat(i, "].TOC")); manifestFix.input[i].doctoc = manifestFix.input[i].TOC; delete manifestFix.input[i].TOC; update = true; } } if (update) updatesNeeded += " manifest.input[item].TOC >> manifest.input[item].doctoc.\n"; } //Display to the user which keys should be updated in their manifest if (updatesNeeded) { console.log("[WARNING] Below entries are old. Consider updating your manifest:"); console.log(updatesNeeded); } return manifestFix; } /** * Checks if a manifest file exists * @param {*} inputArg file/directory given in -m param * @returns valid manifest file or false */ exports.exists = function (inputArg) { try { var fsStat = fs.lstatSync(inputArg); if (fsStat.isFile()) { //Set if file is given var e = path.extname(inputArg).toLowerCase(); if (DEFAULT_MANIFEST.EXTS.includes(e)) { debug("Found Manifest: ".concat(inputArg)); return inputArg; } else { console.log("Manifest file can only be [".concat(DEFAULT_MANIFEST.EXTS.join("|"), "]")); return false; } } else if (fsStat.isDirectory()) { //Search for default manifest if directory debug("Searching for ".concat(DEFAULT_MANIFEST.FILE_TYPES, " in ").concat(inputArg)); var directory = inputArg; var possibleFileNames = DEFAULT_MANIFEST.EXTS.map(function (ext) { return "".concat(DEFAULT_MANIFEST.NAME).concat(ext); }); //Look for a manifest file in the given directory var _iterator5 = _createForOfIteratorHelper(possibleFileNames), _step5; try { for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { var fileName = _step5.value; var filePath = path.join(directory, fileName); var fileStat = fs.lstatSync(filePath); if (fileStat.isFile()) { debug("Found Default Manifest: ".concat(filePath)); return filePath; } } } catch (err) { _iterator5.e(err); } finally { _iterator5.f(); } console.log("No default ".concat(DEFAULT_MANIFEST.FILE_TYPES, " file found in ").concat(directory)); } } catch (err) { console.log("".concat(inputArg, " is not a valid file or directory")); return false; } }; /** * Autocreates a starter manifest file * @param {*} dir location of input files * @param {*} fullProject boolean to add 'full project on create' paths */ exports.createManifestFile = /*#__PURE__*/function () { var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(dir, fullProject) { var jsonObject, inputArr, counter, yamlString, manifestPath; return _regeneratorRuntime().wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: jsonObject = { input: {}, noYAML: true, doctoc: true, replace: { "<!--{timestamp}-->": "01/01/2024", "<!--{title}-->": "My Title", "<!--{author}-->": "Chuck Grant", "<!--{documentType}-->": "Instruction Manual", "### My h3 title": "#### My h4 title", "({#(.*?)})": "" }, output: { "name": "target/mergedFile.md", "doctoc": true, "pandoc": { "css": "-c path/to/theme.css", "latexTemplate": "--template path/to/latex/template.html", "referenceDoc": "--reference-doc path/to/reference.docx" }, "wkhtmltopdf": { "marginBottom": ".7in", "marginTop": "1in", "marginLeft": ".7in", "marginRight": ".7in", "pageSize": "Letter", "headerFontSize": 8, "headerSpacing": 5, "headerRight": "[section]", "footerLine": true, "footerFontSize": 8, "footerLeft": "[doctitle]", "footerCenter": "", "footerRight": "[page]" } }, docker: { excludePaths: ["/target/", "/dist/"] }, qa: { exclude: "(frontmatter|preamble)" } }; if (fullProject) { jsonObject.input["theme/frontmatter.md"] = { noYAML: false, doctoc: false }; jsonObject.output.pandoc.css = "-c theme/theme.css"; jsonObject.output.pandoc.latexTemplate = "--template theme/template.html"; jsonObject.output.pandoc.referenceDoc = "--reference-doc theme/reference.docx"; } inputArr = findMarkdownFiles(dir); counter = 0; inputArr.forEach(function (file) { var inputOptions = { replace: { "\\[#\\]": counter } }; jsonObject.input[file] = inputOptions; counter++; }); //Write YAML File yamlString = yaml.dump(jsonObject); manifestPath = path.join(manifestWriteDir, "".concat(DEFAULT_MANIFEST.FILE)); try { fs.writeFileSync(manifestPath, yamlString); console.log("YAML file successfully created: " + manifestPath); } catch (error) { console.error("Error writing: " + manifestPath, error); } // Write the package.json file if the fullProject flag is set if (!fullProject) { _context.next = 11; break; } _context.next = 11; return writeNPMFile(); case 11: case "end": return _context.stop(); } }, _callee); })); return function (_x, _x2) { return _ref.apply(this, arguments); }; }(); /** * Finds all markdown (.md) files within a directory * @param {*} directoryPath path to search * @returns array of .md paths */ function findMarkdownFiles(directoryPath) { var markdownFiles = []; // Synchronously read the contents of the directory var files = fs.readdirSync(directoryPath); // Iterate through each file in the directory var _iterator6 = _createForOfIteratorHelper(files), _step6; try { for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) { var file = _step6.value; var filePath = path.join(directoryPath, file); var stats = fs.statSync(filePath); // Check if the file is a directory if (stats.isDirectory()) { // Recursively search for .md files in the subdirectory markdownFiles = markdownFiles.concat(findMarkdownFiles(filePath)); } else { if (path.extname(file).toLowerCase() === ".md") { markdownFiles.push(filePath); } } } } catch (err) { _iterator6.e(err); } finally { _iterator6.f(); } return markdownFiles; } function writeNPMFile() { return _writeNPMFile.apply(this, arguments); } function _writeNPMFile() { _writeNPMFile = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee2() { var packageJsonPath; return _regeneratorRuntime().wrap(function _callee2$(_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: packageJsonPath = path.join(process.cwd(), "package.json"); // Check if package.json already exists if (!fs.existsSync(packageJsonPath)) { _context2.next = 4; break; } console.log("package.json already exists, skipping npm init"); return _context2.abrupt("return"); case 4: return _context2.abrupt("return", new Promise(function (resolve, reject) { console.log("Running npm init - please fill out your project details..."); // Run npm init interactively var npmInit = spawn("npm", ["init"], { stdio: "inherit", shell: true }); npmInit.on("close", function (code) { if (code === 0) { debug("package.json created successfully"); // Now read and modify the package.json try { var packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); // Add your custom fields to package.json packageJson.scripts = _objectSpread(_objectSpread({}, packageJson.scripts), {}, { "pre": "rimraf merged || rimraf target || true", "merge-markdown": "npm run pre && npm run mm:docker && npm run cleanup", "cleanup": "", "mm:docker": "merge-markdown -m manifest.yml --pdf --docker", "mm:html": "merge-markdown -m manifest.yml --html", "mm:word": "merge-markdown -m manifest.yml --word", "install:docker:mac": "brew install caskroom/cask/brew-cask; brew cask install docker", "install:docker:win": "powershell -Command \"Start-Process -Wait -FilePath 'winget' -ArgumentList 'install -e --id Docker.DockerDesktop'\"" }); packageJson.dependencies = _objectSpread(_objectSpread({}, packageJson.dependencies), {}, { "@knennigtri/merge-markdown": "*", "rimraf": "^5.0.0" }); packageJson.devDependencies = _objectSpread({}, packageJson.devDependencies); packageJson.bugs = { "url": "https://github.com/knennigtri/merge-markdown/issues/new/choose" }; // Write the modified package.json back fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); console.log("package.json updated with merge-markdown configurations."); console.log("Run `npm install` to install the project dependencies to use the npm scripts."); console.log("It's highly recommended to install docker for optimal use: https://docs.docker.com/engine/install"); console.log("Run `npm run merge-markdown` to build your project. (Requires docker)"); resolve(packageJsonPath); } catch (error) { console.error("Error modifying package.json:", error); reject(error); } } else { console.error("npm init failed with code:", code); reject(new Error("npm init failed with code: ".concat(code))); } }); npmInit.on("error", function (error) { console.error("Error running npm init:", error); reject(error); }); })); case 5: case "end": return _context2.stop(); } }, _callee2); })); return _writeNPMFile.apply(this, arguments); } exports.DEFAULT_MANIFEST = DEFAULT_MANIFEST;