@knennigtri/merge-markdown
Version:
Prepare input files to merge together and optionally output html/pdf/word presentation
924 lines (904 loc) • 46.7 kB
JavaScript
;
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 _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
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 _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
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; }
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); }); }; }
var packageInfo = require("../package.json");
var dockerode = require("dockerode");
var fs = require("fs");
var path = require("path");
var tar = require("tar");
var manifestUtil = require("./manifest.js");
var presentationUtil = require("./presentation.js");
var mergeUtil = require("./merge.js");
var _require = require("child_process"),
exec = _require.exec;
var debug = require("debug");
var debugDocker = debug("docker");
var debugDockerPaths = debug("docker:paths");
exports.debbugOptions = {
docker: "docker",
dockerPaths: "docker:paths"
};
var docker = new dockerode();
var IMAGE_NAME = "node";
var IMAGE_TAG = "mergemarkdown";
var CONTAINER_NAME = "mergemarkdown";
var WORKING_DIR = "/home/runner/workspace/cli";
var TAR_NAME = "archive.tar.gz";
var EXCLUDE_PATHS = [/node_modules/,
// Matches any path containing 'node_modules'
/quickstart.md/, /merged/,
// Matches any path containing 'merged'
/target/,
// Matches any path containing 'target'
".git/", ".vscode/", "archive.tar.gz"];
function runMergeMarkdownInDocker(_x, _x2) {
return _runMergeMarkdownInDocker.apply(this, arguments);
}
/* Starts a docker container or returns the running container */
function _runMergeMarkdownInDocker() {
_runMergeMarkdownInDocker = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(manifestFileStr, cmdArgs) {
var _manifest$docker;
var manifest, manifestOutputName, excludePaths, manifestRelDir, dockerRunning, imageExists, needsRebuild, rebuildReason, hasCompatibleNodeVersion, hasMatchingVersion, versionToUse, command, output, fallbackOutput, container, info, cleanCommand, extractCommand, isDevelopment, _commands, checkCommand, versionToInstall, installCommand, fallbackCommand, npmModuleName, requestedCMD, envPrefix, commands, dockerCMD, relManifestOutputName, absManifestOutputName_inDocker, absManifestOutputName_parsed, absManifestOutputName_name, absManifestOutputName_dir, outputPaths, destPath, fileToDel;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
manifest = manifestUtil.getJSON_withABSPaths(manifestFileStr);
manifestOutputName = manifest.output.name;
excludePaths = [].concat(EXCLUDE_PATHS, _toConsumableArray(Array.isArray((_manifest$docker = manifest.docker) === null || _manifest$docker === void 0 ? void 0 : _manifest$docker.excludePaths) ? manifest.docker.excludePaths : []));
debugDocker("excludePaths:\n".concat(excludePaths.map(function (regex) {
return " ".concat(regex.toString());
}).join("\n")));
// relDir given in -m dir/manifest.yml to help build docker upload/download paths
manifestRelDir = path.parse(manifestFileStr).dir || "./";
debugDocker("manifestDir: ".concat(manifestRelDir));
_context.prev = 6;
_context.next = 9;
return isDockerRunning();
case 9:
dockerRunning = _context.sent;
if (dockerRunning) {
_context.next = 13;
break;
}
console.error("Docker is not running. Start the Docker engine and retry.");
return _context.abrupt("return");
case 13:
_context.next = 15;
return dockerImageExists("".concat(IMAGE_NAME, ":").concat(IMAGE_TAG));
case 15:
imageExists = _context.sent;
needsRebuild = false;
rebuildReason = "";
if (imageExists) {
_context.next = 24;
break;
}
console.log("Docker Image DNE. Creating...");
needsRebuild = true;
rebuildReason = "Image does not exist";
_context.next = 37;
break;
case 24:
_context.next = 26;
return checkDockerImageNodeVersion("".concat(IMAGE_NAME, ":").concat(IMAGE_TAG));
case 26:
hasCompatibleNodeVersion = _context.sent;
if (hasCompatibleNodeVersion) {
_context.next = 33;
break;
}
console.log("Docker Image exists but has incompatible Node.js version. Rebuilding with Node.js 20+...");
needsRebuild = true;
rebuildReason = "Incompatible Node.js version";
_context.next = 37;
break;
case 33:
_context.next = 35;
return checkDockerImageMergeMarkdownVersion("".concat(IMAGE_NAME, ":").concat(IMAGE_TAG));
case 35:
hasMatchingVersion = _context.sent;
if (!hasMatchingVersion) {
console.log("Docker Image exists but merge-markdown version doesn't match local version (".concat(packageInfo.version, "). Rebuilding..."));
needsRebuild = true;
rebuildReason = "Version mismatch";
} else {
debugDocker("Docker Image exists with compatible Node.js version and matching merge-markdown version");
}
case 37:
if (!needsRebuild) {
_context.next = 75;
break;
}
debugDocker("Rebuilding Docker image. Reason: ".concat(rebuildReason));
// Set environment variable for docker-compose to use the correct version
_context.next = 41;
return getValidMergeMarkdownVersion(packageInfo.version);
case 41:
versionToUse = _context.sent;
process.env.MERGE_MARKDOWN_VERSION = versionToUse;
if (versionToUse !== packageInfo.version) {
console.log("Warning: Local version ".concat(packageInfo.version, " not available on npm registry. Using ").concat(versionToUse, " instead."));
}
command = "docker compose -f ".concat(path.join(__dirname, "../docker/docker-compose.yml"), " up -d --build");
console.log(command);
_context.prev = 46;
_context.next = 49;
return runExecCommands(command, manifestRelDir);
case 49:
output = _context.sent;
console.log("Docker build completed successfully.");
debugDocker(output);
_context.next = 75;
break;
case 54:
_context.prev = 54;
_context.t0 = _context["catch"](46);
console.error("Error executing:", _context.t0);
// If build fails, try with latest as fallback
if (!(versionToUse !== "latest")) {
_context.next = 74;
break;
}
console.log("Build failed, attempting fallback to latest version...");
process.env.MERGE_MARKDOWN_VERSION = "latest";
_context.prev = 60;
_context.next = 63;
return runExecCommands(command, manifestRelDir);
case 63:
fallbackOutput = _context.sent;
console.log("Fallback build completed successfully.");
debugDocker(fallbackOutput);
_context.next = 72;
break;
case 68:
_context.prev = 68;
_context.t1 = _context["catch"](60);
console.error("Fallback build also failed:", _context.t1);
throw _context.t1;
case 72:
_context.next = 75;
break;
case 74:
throw _context.t0;
case 75:
console.log("--------Docker Container START--------");
_context.prev = 76;
_context.next = 79;
return getContainer();
case 79:
container = _context.sent;
_context.next = 82;
return container.inspect();
case 82:
info = _context.sent;
if (info.State.Running) {
_context.next = 87;
break;
}
_context.next = 86;
return startContainer(container);
case 86:
container = _context.sent;
case 87:
// Clean working directory
console.log("Cleaning the docker working directory.");
cleanCommand = "rm -rf ".concat(WORKING_DIR, "/*");
debugDocker(cleanCommand);
_context.next = 92;
return execContainer(container, cleanCommand);
case 92:
container = _context.sent;
// Create and copy archive
console.log("Copying this project to the docker container.");
console.log("Exclude Copying These Paths:\n".concat(excludePaths.map(function (regex) {
return " ".concat(regex.toString());
}).join("\n")));
_context.next = 97;
return createTarArchive("./", TAR_NAME, excludePaths);
case 97:
console.log("Tar archive created successfully");
_context.next = 100;
return copyIntoContainer(container, TAR_NAME, WORKING_DIR);
case 100:
container = _context.sent;
// Extract files
console.log("Extracting files into the container.");
extractCommand = "tar xzf ".concat(WORKING_DIR, "/").concat(TAR_NAME, " -C ").concat(WORKING_DIR);
debugDocker(extractCommand);
_context.next = 106;
return execContainer(container, extractCommand);
case 106:
container = _context.sent;
// Install merge-markdown
debugDocker("Running container is ".concat(container.id));
isDevelopment = process.env.NODE_ENV === "dev";
if (!isDevelopment) {
_context.next = 118;
break;
}
// Development mode: Install from local source
console.log("🔧 Development mode: Installing from local source...");
_commands = ["cd ".concat(WORKING_DIR), "npm install --silent", "npm link --silent"].join(" && ");
debugDocker("Dev install command: ".concat(_commands));
_context.next = 115;
return execContainer(container, ["/bin/sh", "-c", "export NODE_ENV=dev && ".concat(_commands)], true);
case 115:
container = _context.sent;
_context.next = 154;
break;
case 118:
// Production mode: Install from npm registry
console.log("Verifying merge-markdown installation in container...");
checkCommand = "npm list -g @knennigtri/merge-markdown";
debugDocker("Checking installation: ".concat(checkCommand));
_context.prev = 121;
_context.next = 124;
return execContainer(container, checkCommand, false);
case 124:
container = _context.sent;
debugDocker("merge-markdown is already installed");
_context.next = 154;
break;
case 128:
_context.prev = 128;
_context.t2 = _context["catch"](121);
console.log("merge-markdown not found in container, installing...");
_context.next = 133;
return getValidMergeMarkdownVersion(packageInfo.version);
case 133:
versionToInstall = _context.sent;
if (versionToInstall !== packageInfo.version) {
console.log("Warning: Local version ".concat(packageInfo.version, " not available on npm registry. Installing ").concat(versionToInstall, " instead."));
}
installCommand = "npm install -g @knennigtri/merge-markdown@".concat(versionToInstall, " --silent");
console.log("Installing: ".concat(installCommand));
_context.prev = 137;
_context.next = 140;
return execContainer(container, installCommand, true);
case 140:
container = _context.sent;
_context.next = 154;
break;
case 143:
_context.prev = 143;
_context.t3 = _context["catch"](137);
if (!(versionToInstall !== "latest")) {
_context.next = 153;
break;
}
console.log("Installation failed, trying latest version as fallback...");
fallbackCommand = "npm install -g @knennigtri/merge-markdown@latest --silent";
_context.next = 150;
return execContainer(container, fallbackCommand, true);
case 150:
container = _context.sent;
_context.next = 154;
break;
case 153:
throw _context.t3;
case 154:
// Run merge-markdown command
debugDocker("Running container is ".concat(container.id));
npmModuleName = packageInfo.name.replace(/@[^/]+\//, "");
requestedCMD = "".concat(npmModuleName, " ").concat(cmdArgs);
requestedCMD = requestedCMD.replace("--docker", "");
envPrefix = isDevelopment ? "export NODE_ENV=dev && " : "";
commands = ["cd ".concat(WORKING_DIR), "".concat(envPrefix).concat(requestedCMD)].join(" && ");
dockerCMD = ["/bin/sh", "-c", commands];
debugDocker(dockerCMD);
debugDocker("Merging in Docker");
_context.next = 165;
return execContainer(container, dockerCMD, true);
case 165:
container = _context.sent;
// Download results
debugDocker("Downloading locally");
debugDockerPaths("WORKING_DIR: ".concat(WORKING_DIR));
debugDockerPaths("manifestOutputName: ".concat(manifestOutputName));
debugDockerPaths("manifestRelDir: ".concat(manifestRelDir));
debugDockerPaths("process.cwd(): ".concat(process.cwd()));
relManifestOutputName = path.relative(process.cwd(), manifestOutputName);
absManifestOutputName_inDocker = path.join(WORKING_DIR, relManifestOutputName);
absManifestOutputName_parsed = path.parse(absManifestOutputName_inDocker);
absManifestOutputName_name = absManifestOutputName_parsed.name;
absManifestOutputName_dir = absManifestOutputName_parsed.dir;
debugDockerPaths("Downloading merged Files from: ".concat(absManifestOutputName_dir));
outputPaths = [absManifestOutputName_inDocker].concat(_toConsumableArray(Object.values(presentationUtil.EXTS).map(function (ext) {
return path.join(absManifestOutputName_dir, "".concat(absManifestOutputName_name).concat(ext));
})), _toConsumableArray(Object.values(mergeUtil.EXTS).map(function (ext) {
return path.join(absManifestOutputName_dir, "".concat(absManifestOutputName_name).concat(ext));
})), [path.join(absManifestOutputName_dir, "temp.html")]);
debugDockerPaths("Downloading files if they exist:\n".concat(outputPaths.map(function (p) {
return " ".concat(p);
}).join("\n")));
destPath = path.parse(manifestOutputName).dir;
debugDockerPaths("Downloading to ".concat(destPath));
// Ensure destination directory exists
if (!fs.existsSync(destPath)) {
fs.mkdirSync(destPath, {
recursive: true
});
debugDockerPaths("Created directory: ".concat(destPath));
} else {
debugDockerPaths("Directory already exists: ".concat(destPath));
}
_context.next = 184;
return downloadFromContainer(container, outputPaths, destPath);
case 184:
// Cleanup
if (debug.enabled("docker")) {
debugDocker("Skipping ".concat(TAR_NAME, " file deletion in debug mode"));
} else {
fileToDel = path.join("./", TAR_NAME);
fs.unlink(fileToDel, function (err) {
if (err) {
console.error("Could not delete ".concat(fileToDel));
}
});
}
console.log("--------Docker Container END--------");
_context.next = 192;
break;
case 188:
_context.prev = 188;
_context.t4 = _context["catch"](76);
console.error("Error in Docker container workflow:", _context.t4);
throw _context.t4;
case 192:
_context.next = 198;
break;
case 194:
_context.prev = 194;
_context.t5 = _context["catch"](6);
console.error("Error getting or creating container:", _context.t5);
throw _context.t5;
case 198:
case "end":
return _context.stop();
}
}, _callee, null, [[6, 194], [46, 54], [60, 68], [76, 188], [121, 128], [137, 143]]);
}));
return _runMergeMarkdownInDocker.apply(this, arguments);
}
function startContainer(container) {
return new Promise(function (resolve, reject) {
debugDocker("Starting container: ".concat(container.id));
container.start(function (err) {
if (err) {
if (err.statusCode === 304) {
debugDocker("304. Container already running.");
resolve(container);
} else {
console.error("Error starting container:", err);
reject(err);
}
} else {
debugDocker("Container started successfully");
resolve(container);
}
});
});
}
/* Gets the running container or starts and returns it */
function getContainer(containerName) {
var name = containerName || CONTAINER_NAME;
debugDocker("Getting containter: ".concat(name));
return new Promise(function (resolve, reject) {
docker.getContainer(name).inspect(function (err, data) {
if (err) {
if (err.statusCode === 404) {
debugDocker("404. Container doesn't exist. Creating...");
resolve(createContainer());
} else reject(err);
} else {
debugDocker("Found container ".concat(name, " with ID: ").concat(data.Id));
resolve(docker.getContainer(data.Id)); //returns a container
}
});
});
}
/* Function to create a container based on an existing image */
function createContainer(containerName, imageName) {
var name = containerName || CONTAINER_NAME;
var img = imageName || "".concat(IMAGE_NAME, ":").concat(IMAGE_TAG);
debugDocker("Creating container ".concat(name, " from image ").concat(img));
return new Promise(function (resolve, reject) {
docker.createContainer({
Image: img,
Tty: true,
name: name
}, function (err, container) {
if (err) reject(err); // Failed to create container
debugDocker("Container created: ".concat(container.id));
resolve(startContainer(container));
});
});
}
/* execute commands within the running container */
function execContainer(_x3, _x4, _x5) {
return _execContainer.apply(this, arguments);
}
function _execContainer() {
_execContainer = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee2(container, command, attachStd) {
var execOptions;
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
execOptions = {
Cmd: typeof command === "string" ? command.split(" ") : Array.isArray(command) ? command : [],
AttachStdout: attachStd,
AttachStderr: attachStd
};
return _context2.abrupt("return", new Promise(function (resolve, reject) {
container.exec(execOptions, function (err, exec) {
console.log("Executing command: ", execOptions.Cmd.join(" "));
var dockerConsole = " ";
var rawOutput = ""; // Buffer all output first
if (err) {
console.error("Error creating exec instance:", err);
reject(err);
} else {
exec.start(function (err, stream) {
if (err) {
console.error("Error starting exec instance:", err);
reject(err);
} else {
stream.on("data", function (chunk) {
// Docker streams include an 8-byte header, skip it if present
var data = chunk;
if (chunk.length > 8) {
// Header format: [stream_type, 0, 0, 0, size1, size2, size3, size4]
// Check if this looks like a Docker multiplexed stream header
var isHeader = (chunk[0] === 0 || chunk[0] === 1 || chunk[0] === 2) && chunk[1] === 0 && chunk[2] === 0 && chunk[3] === 0;
if (isHeader) {
data = chunk.slice(8);
}
}
rawOutput += data.toString();
});
stream.on("end", function () {
// Clean the complete output after all chunks received
/* eslint-disable no-control-regex */
var cleanOutput = rawOutput
// Remove ALL ANSI escape sequences (most comprehensive approach)
.replace(/\x1b\[[0-9;?]*[a-zA-Z]/g, "") // CSI sequences (including ? for private modes)
.replace(/\x1b\][0-9;]*\x07/g, "") // OSC sequences ending with BEL
.replace(/\x1b\][0-9;]*\x1b\\/g, "") // OSC sequences ending with ST
.replace(/\x1b[=>()]/g, "") // Set modes and character sets
.replace(/\x1b[78]/g, "") // Save/restore cursor
.replace(/\x1b[HM]/g, "") // Home and reverse index
.replace(/\x1b[c]/g, "") // Reset
.replace(/\x1b\[[0-9;]*m/g, "") // SGR (color/style) sequences
.replace(/\x1b[PX^_]/g, "") // Various escape sequences
// Remove ALL control characters except newline and tab
.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F-\x9F]/g, "");
/* eslint-enable no-control-regex */
// Split into lines and indent
var lines = cleanOutput.split("\n").map(function (line) {
return line.trim();
}).filter(function (line) {
return line.length > 0;
}).map(function (line) {
return dockerConsole + line;
}).join("\n");
if (lines.trim()) {
console.log(lines);
}
resolve(container);
});
}
});
}
});
}));
case 2:
case "end":
return _context2.stop();
}
}, _callee2);
}));
return _execContainer.apply(this, arguments);
}
function dockerImageExists(imageName) {
var img = imageName || "".concat(IMAGE_NAME, ":").concat(IMAGE_TAG);
return new Promise(function (resolve) {
docker.listImages({
filters: {
reference: [img]
}
}, function (err, images) {
if (images.length > 0) {
resolve(true);
} else {
resolve(false);
}
});
});
}
/* Validate that a specific version exists on npm registry, fallback to latest if not */
function getValidMergeMarkdownVersion(_x6) {
return _getValidMergeMarkdownVersion.apply(this, arguments);
}
/* Check if the Docker image has the correct merge-markdown version */
function _getValidMergeMarkdownVersion() {
_getValidMergeMarkdownVersion = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee3(requestedVersion) {
var _require2, _exec, checkCommand;
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
while (1) switch (_context3.prev = _context3.next) {
case 0:
debugDocker("Validating merge-markdown version: ".concat(requestedVersion));
_context3.prev = 1;
// Check if the requested version exists on npm registry
_require2 = require("child_process"), _exec = _require2.exec;
checkCommand = "npm view @knennigtri/merge-markdown@".concat(requestedVersion, " version");
return _context3.abrupt("return", new Promise(function (resolve) {
_exec(checkCommand, {
timeout: 10000
}, function (error, stdout, stderr) {
if (error || stderr) {
debugDocker("Version ".concat(requestedVersion, " not found on npm registry: ").concat((error === null || error === void 0 ? void 0 : error.message) || stderr));
debugDocker("Falling back to latest version");
resolve("latest");
} else {
var foundVersion = stdout.trim();
if (foundVersion === requestedVersion) {
debugDocker("Version ".concat(requestedVersion, " confirmed on npm registry"));
resolve(requestedVersion);
} else {
debugDocker("Version mismatch. Requested: ".concat(requestedVersion, ", Found: ").concat(foundVersion, ". Using latest."));
resolve("latest");
}
}
});
}));
case 7:
_context3.prev = 7;
_context3.t0 = _context3["catch"](1);
debugDocker("Error validating version: ".concat(_context3.t0.message, ". Using latest."));
return _context3.abrupt("return", "latest");
case 11:
case "end":
return _context3.stop();
}
}, _callee3, null, [[1, 7]]);
}));
return _getValidMergeMarkdownVersion.apply(this, arguments);
}
function checkDockerImageMergeMarkdownVersion(_x7) {
return _checkDockerImageMergeMarkdownVersion.apply(this, arguments);
}
/* Check if the Docker image has a compatible Node.js version */
function _checkDockerImageMergeMarkdownVersion() {
_checkDockerImageMergeMarkdownVersion = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee4(imageName) {
var img, localVersion, container, stream, output, versionMatch, dockerVersion, versionsMatch;
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
while (1) switch (_context4.prev = _context4.next) {
case 0:
img = imageName || "".concat(IMAGE_NAME, ":").concat(IMAGE_TAG);
localVersion = packageInfo.version;
debugDocker("Checking merge-markdown version in image: ".concat(img, ", local version: ").concat(localVersion));
_context4.prev = 3;
_context4.next = 6;
return docker.createContainer({
Image: img,
Cmd: ["npm", "list", "-g", "--depth=0", "@knennigtri/merge-markdown"],
AttachStdout: true,
AttachStderr: true
});
case 6:
container = _context4.sent;
_context4.next = 9;
return container.attach({
stream: true,
stdout: true,
stderr: true
});
case 9:
stream = _context4.sent;
output = "";
stream.on("data", function (chunk) {
output += chunk.toString();
});
_context4.next = 14;
return container.start();
case 14:
_context4.next = 16;
return container.wait();
case 16:
_context4.next = 18;
return container.remove();
case 18:
// Extract version number from npm list output
versionMatch = output.match(/@knennigtri\/merge-markdown@(\d+\.\d+\.\d+)/);
if (!versionMatch) {
_context4.next = 25;
break;
}
dockerVersion = versionMatch[1];
debugDocker("Found Docker merge-markdown version: ".concat(dockerVersion));
// Check if versions match
versionsMatch = dockerVersion === localVersion;
debugDocker("Version match: ".concat(versionsMatch, " (Docker: ").concat(dockerVersion, ", Local: ").concat(localVersion, ")"));
return _context4.abrupt("return", versionsMatch);
case 25:
debugDocker("Could not parse merge-markdown version from: ".concat(output));
return _context4.abrupt("return", false);
case 29:
_context4.prev = 29;
_context4.t0 = _context4["catch"](3);
debugDocker("Error checking merge-markdown version: ".concat(_context4.t0.message));
// If we can't check the version, assume it needs rebuild
return _context4.abrupt("return", false);
case 33:
case "end":
return _context4.stop();
}
}, _callee4, null, [[3, 29]]);
}));
return _checkDockerImageMergeMarkdownVersion.apply(this, arguments);
}
function checkDockerImageNodeVersion(_x8) {
return _checkDockerImageNodeVersion.apply(this, arguments);
}
function _checkDockerImageNodeVersion() {
_checkDockerImageNodeVersion = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee5(imageName) {
var img, container, stream, output, versionMatch, majorVersion;
return _regeneratorRuntime().wrap(function _callee5$(_context5) {
while (1) switch (_context5.prev = _context5.next) {
case 0:
img = imageName || "".concat(IMAGE_NAME, ":").concat(IMAGE_TAG);
debugDocker("Checking Node.js version in image: ".concat(img));
_context5.prev = 2;
_context5.next = 5;
return docker.createContainer({
Image: img,
Cmd: ["node", "--version"],
AttachStdout: true,
AttachStderr: true
});
case 5:
container = _context5.sent;
_context5.next = 8;
return container.attach({
stream: true,
stdout: true,
stderr: true
});
case 8:
stream = _context5.sent;
output = "";
stream.on("data", function (chunk) {
output += chunk.toString();
});
_context5.next = 13;
return container.start();
case 13:
_context5.next = 15;
return container.wait();
case 15:
_context5.next = 17;
return container.remove();
case 17:
// Extract version number (e.g., "v20.1.0" -> 20)
versionMatch = output.match(/v(\d+)\./);
if (!versionMatch) {
_context5.next = 22;
break;
}
majorVersion = parseInt(versionMatch[1]);
debugDocker("Found Node.js version: ".concat(majorVersion));
// Require Node.js 20 or higher for proper Web API support
return _context5.abrupt("return", majorVersion >= 20);
case 22:
debugDocker("Could not parse Node.js version from: ".concat(output));
return _context5.abrupt("return", false);
case 26:
_context5.prev = 26;
_context5.t0 = _context5["catch"](2);
debugDocker("Error checking Node.js version: ".concat(_context5.t0.message));
// If we can't check the version, assume it's outdated and needs rebuild
return _context5.abrupt("return", false);
case 30:
case "end":
return _context5.stop();
}
}, _callee5, null, [[2, 26]]);
}));
return _checkDockerImageNodeVersion.apply(this, arguments);
}
function isDockerRunning() {
return new Promise(function (resolve) {
docker.ping(function (err) {
if (err) {
resolve(false); // Docker is not running or not accessible
} else {
resolve(true); // Docker is running
}
});
});
}
/* Run command line arguments with exec */
function runExecCommands(command, cwd) {
return new Promise(function (resolve, reject) {
exec(command, {
cwd: cwd
}, function (error, stdout, stderr) {
if (error) {
reject(error);
return;
}
// Docker Compose writes status messages to stderr, but these aren't errors
// Only reject if stderr contains actual error indicators
if (stderr && (stderr.includes("ERROR") || stderr.includes("FAILED") || stderr.includes("Error"))) {
reject(stderr);
return;
}
// Return both stdout and stderr as Docker Compose uses both for status
resolve(stdout + (stderr ? "\n" + stderr : ""));
});
});
}
/* Copy the local tarFilePath into the destDir in the container */
function copyIntoContainer(container, tarFilePath, destDir) {
debugDocker("Copying ".concat(tarFilePath, " to ").concat(destDir));
return new Promise(function (resolve, reject) {
var tarStream = fs.createReadStream(tarFilePath);
container.putArchive(tarStream, {
path: destDir
}, function (err) {
if (err) {
reject(err);
return;
}
resolve(container);
});
});
}
/* Takes the sourceDir and compresses it into a tar at tarFilePath, excluding specified paths using regex */
function createTarArchive(sourceDir, tarFilePath) {
var excludedPaths = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
debugDocker("".concat(sourceDir, " to tarball ").concat(tarFilePath));
return new Promise(function (resolve, reject) {
var includedCount = 0;
var tarStream = tar.c({
gzip: true,
cwd: sourceDir,
filter: function filter(filePath) {
var relativePath = path.relative(sourceDir, filePath);
// Normalize path separators to forward slashes for consistent regex matching
var normalizedPath = relativePath.replace(/\\/g, "/");
// Check if this path or any parent path should be excluded
var shouldExclude = excludedPaths.some(function (excludedPath) {
var regex = typeof excludedPath === "string" ? new RegExp(excludedPath) : excludedPath;
// Check if the current path matches
if (regex.test(normalizedPath)) {
debugDockerPaths("Excluding: ".concat(normalizedPath, " (matched: ").concat(regex.toString(), ")"));
return true;
}
// Check if this path is inside an excluded directory
var pathParts = normalizedPath.split("/");
for (var i = 0; i < pathParts.length; i++) {
var partialPath = pathParts.slice(0, i + 1).join("/");
if (regex.test(partialPath)) {
debugDockerPaths("Excluding: ".concat(normalizedPath, " (parent matched: ").concat(regex.toString(), ")"));
return true;
}
}
return false;
});
if (!shouldExclude) {
includedCount++;
debugDockerPaths("Including: ".concat(normalizedPath));
}
return !shouldExclude;
}
}, ["."]);
var fileStream = fs.createWriteStream(tarFilePath);
tarStream.pipe(fileStream);
tarStream.on("end", function () {
debugDocker("Archive created with ".concat(includedCount, " files"));
if (includedCount === 0) {
console.warn("Warning: No files were included in the archive. Check exclude patterns.");
}
resolve();
});
tarStream.on("error", function (err) {
console.error("Error creating tar archive:", err);
reject(err);
});
fileStream.on("error", function (err) {
console.error("Error writing tar file:", err);
reject(err);
});
});
}
/* Downloads the srcPath in the container to the local destPath */
function downloadFromContainer(_x9, _x10, _x11) {
return _downloadFromContainer.apply(this, arguments);
}
function _downloadFromContainer() {
_downloadFromContainer = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee7(container, srcPaths, destPath) {
var downloadPromises;
return _regeneratorRuntime().wrap(function _callee7$(_context7) {
while (1) switch (_context7.prev = _context7.next) {
case 0:
if (!Array.isArray(srcPaths)) {
srcPaths = [srcPaths];
}
if (!destPath) destPath = "./";
// Ensure the destination directory exists
if (!fs.existsSync(destPath)) {
fs.mkdirSync(destPath, {
recursive: true
});
}
console.log("Downloading files to ".concat(destPath));
downloadPromises = srcPaths.map(/*#__PURE__*/function () {
var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee6(srcPath) {
var stream;
return _regeneratorRuntime().wrap(function _callee6$(_context6) {
while (1) switch (_context6.prev = _context6.next) {
case 0:
_context6.prev = 0;
_context6.next = 3;
return container.getArchive({
path: srcPath
});
case 3:
stream = _context6.sent;
return _context6.abrupt("return", new Promise(function (resolve, reject) {
stream.pipe(tar.extract({
cwd: destPath
}));
stream.on("end", function () {
debugDocker("Output ".concat(srcPath.replace(WORKING_DIR, "."), " downloading.."));
resolve();
});
stream.on("error", function (err) {
reject(err);
});
}));
case 7:
_context6.prev = 7;
_context6.t0 = _context6["catch"](0);
debugDocker("File ".concat(srcPath, " not found, skipping"));
return _context6.abrupt("return", null);
case 11:
case "end":
return _context6.stop();
}
}, _callee6, null, [[0, 7]]);
}));
return function (_x12) {
return _ref.apply(this, arguments);
};
}());
_context7.next = 7;
return Promise.all(downloadPromises);
case 7:
return _context7.abrupt("return", container);
case 8:
case "end":
return _context7.stop();
}
}, _callee7);
}));
return _downloadFromContainer.apply(this, arguments);
}
exports.runMergeMarkdownInDocker = runMergeMarkdownInDocker;