@plugjs/plug
Version:
PlugJS Build System ===================
220 lines (218 loc) • 9.27 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// fork.ts
var fork_exports = {};
__export(fork_exports, {
ForkingPlug: () => ForkingPlug,
installForking: () => installForking
});
module.exports = __toCommonJS(fork_exports);
var import_node_child_process = require("node:child_process");
var import_node_console = require("node:console");
var import_node_stream = require("node:stream");
var import_asserts = require("./asserts.cjs");
var import_async = require("./async.cjs");
var import_files = require("./files.cjs");
var import_logging = require("./logging.cjs");
var import_emit = require("./logging/emit.cjs");
var import_paths = require("./paths.cjs");
var import_pipe = require("./pipe.cjs");
var ForkingPlug = class {
constructor(_scriptFile, _arguments, _exportName) {
this._scriptFile = _scriptFile;
this._arguments = _arguments;
this._exportName = _exportName;
}
pipe(files, context) {
const request = {
scriptFile: this._scriptFile,
exportName: this._exportName,
constructorArgs: this._arguments,
taskName: context.taskName,
buildFile: context.buildFile,
filesDir: files.directory,
filesList: [...files.absolutePaths()],
logIndent: context.log.indent
};
const script = (0, import_paths.requireFilename)(__filename);
context.log.debug("About to fork plug from", (0, import_logging.$p)(this._scriptFile));
const env = { ...process.env, ...import_logging.logOptions.forkEnv(context.taskName) };
for (let i = this._arguments.length - 1; i >= 0; i--) {
if (this._arguments[i] == null) continue;
if (typeof this._arguments[i] === "object") {
if (typeof this._arguments[i].coverageDir === "string") {
const dir = env.NODE_V8_COVERAGE = context.resolve(this._arguments[i].coverageDir);
context.log.debug("Forked process will produce coverage in", (0, import_logging.$p)(dir));
}
if (typeof this._arguments[i].forceModule === "string") {
const force = env.__TS_LOADER_FORCE_TYPE = this._arguments[i].forceModule;
context.log.debug("Forked process will force module type as", (0, import_logging.$p)(force));
}
}
}
const child = (0, import_node_child_process.fork)(script, {
stdio: ["ignore", "inherit", "inherit", "ipc"],
serialization: "advanced",
env
});
context.log.info("Running", (0, import_logging.$p)(script), (0, import_logging.$gry)(`(pid=${child.pid})`));
let done = false;
return new Promise((resolve, reject) => {
let response = void 0;
child.on("error", (error) => {
context.log.error("Forked plug process error", error);
return done || reject(import_asserts.BuildFailure.fail());
});
child.on("message", (message) => {
if ("logLevel" in message) {
const { logLevel, taskName, lines } = message;
lines.forEach((line) => {
context.log._emit(logLevel, [line], taskName);
});
} else {
context.log.debug("Message from forked plug process with PID", child.pid, message);
response = message;
}
});
child.on("exit", (code, signal) => {
if (signal) {
context.log.error(`Forked plug process exited with signal ${signal}`, (0, import_logging.$gry)(`(pid=${child.pid})`));
return done || reject(import_asserts.BuildFailure.fail());
} else if (code !== 0) {
context.log.error(`Forked plug process exited with code ${code}`, (0, import_logging.$gry)(`(pid=${child.pid})`));
return done || reject(import_asserts.BuildFailure.fail());
} else if (!response) {
context.log.error("Forked plug process exited with no result", (0, import_logging.$gry)(`(pid=${child.pid})`));
return done || reject(import_asserts.BuildFailure.fail());
} else if (response.failed) {
return done || reject(import_asserts.BuildFailure.fail());
}
return done || resolve(response.filesDir && response.filesList ? import_files.Files.builder(response.filesDir).add(...response.filesList).build() : void 0);
});
try {
child.send(request, (error) => {
if (error) {
context.log.error("Error sending message to forked plug process (callback failure)", error);
reject(import_asserts.BuildFailure.fail());
}
});
} catch (error) {
context.log.error("Error sending message to forked plug process (exception caught)", error);
reject(import_asserts.BuildFailure.fail());
}
}).finally(() => done = true);
}
};
if (process.argv[1] === (0, import_paths.requireFilename)(__filename) && process.send) {
const originalConsole = globalThis.console;
process.on("uncaughtException", (error, origin) => {
originalConsole.error(
(0, import_logging.$red)("\n= UNCAUGHT EXCEPTION ========================================="),
`
Error (${origin}):`,
error,
`
Node.js ${process.version} (pid=${process.pid})
`
);
process.nextTick(() => process.exit(3));
});
const timeout = setTimeout(() => {
originalConsole.error("Fork not initialized in 5 seconds");
process.exit(2);
}, 5e3).unref();
process.on("message", (message) => {
clearTimeout(timeout);
const {
scriptFile,
exportName,
constructorArgs,
taskName,
buildFile,
filesDir,
filesList,
logIndent
} = message;
import_emit.emit.emitter = import_emit.emitForked;
const makeWritable = (level) => new class extends import_node_stream.Writable {
_write(chunk, _, callback) {
const string = chunk.toString();
const message2 = string.endsWith("\n") ? string.slice(0, -1) : string;
import_emit.emit.emitter({ level, taskName }, [message2]);
callback();
}
}();
globalThis.console = new import_node_console.Console(makeWritable(import_logging.NOTICE), makeWritable(import_logging.WARN));
const context = new import_pipe.Context(buildFile, taskName);
context.log.indent = logIndent;
context.log.debug("Message from parent process for PID", process.pid, message);
process.exitCode = 0;
const result = (0, import_async.runAsync)(context, async () => {
(0, import_asserts.assert)((0, import_paths.resolveFile)(scriptFile), `Script file ${(0, import_logging.$p)(scriptFile)} not found`);
const script = await import(scriptFile);
let Ctor;
if (exportName === "default") {
Ctor = script;
while (Ctor && typeof Ctor !== "function") Ctor = Ctor.default;
(0, import_asserts.assert)(typeof Ctor === "function", `Script ${(0, import_logging.$p)(scriptFile)} does not export a default constructor`);
} else {
Ctor = script[exportName];
if (!Ctor && script.default) Ctor = script.default[exportName];
(0, import_asserts.assert)(typeof Ctor === "function", `Script ${(0, import_logging.$p)(scriptFile)} does not export "${exportName}"`);
}
const plug = new Ctor(...constructorArgs);
const files = import_files.Files.builder(filesDir).add(...filesList).build();
return plug.pipe(files, context);
});
const promise = result.then((result2) => {
const message2 = result2 ? { failed: false, filesDir: result2.directory, filesList: [...result2.absolutePaths()] } : { failed: false };
return new Promise((resolve, reject) => {
process.send(message2, (err) => err ? reject(err) : resolve());
});
}, (error) => {
context.log.error(error);
return new Promise((resolve, reject) => {
process.send({ failed: true }, (err) => err ? reject(err) : resolve());
});
});
promise.then(() => {
context.log.debug("Forked plug with pid", process.pid, "exiting");
}, (error) => {
originalConsole.error("\n\nError sending message back to parent process", error);
process.exitCode = 1;
}).finally(() => {
process.disconnect();
process.exit(process.exitCode);
});
});
}
function installForking(plugName, scriptFile, exportName = "default") {
const ctor = class extends ForkingPlug {
constructor(...args) {
super(scriptFile, args, exportName);
}
};
(0, import_pipe.install)(plugName, ctor);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ForkingPlug,
installForking
});
//# sourceMappingURL=fork.cjs.map