@plugjs/plug
Version:
PlugJS Build System ===================
223 lines (221 loc) • 8.42 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);
// build.ts
var build_exports = {};
__export(build_exports, {
build: () => build,
hookAfter: () => hookAfter,
hookBefore: () => hookBefore,
invokeTasks: () => invokeTasks,
isBuild: () => isBuild,
plugjs: () => plugjs
});
module.exports = __toCommonJS(build_exports);
var import_asserts = require("./asserts.cjs");
var import_async = require("./async.cjs");
var import_logging = require("./logging.cjs");
var import_pipe = require("./pipe.cjs");
var import_caller = require("./utils/caller.cjs");
var import_singleton = require("./utils/singleton.cjs");
var buildMarker = /* @__PURE__ */ Symbol.for("plugjs:plug:types:Build");
var taskCallMarker = /* @__PURE__ */ Symbol.for("plugjs:plug:types:TaskCall");
function isTaskCall(something) {
return something[taskCallMarker] === taskCallMarker;
}
function merge(a, b) {
return Object.assign(/* @__PURE__ */ Object.create(null), a, b);
}
function makeState(state) {
const {
cache = /* @__PURE__ */ new Map(),
fails = /* @__PURE__ */ new Set(),
stack = [],
tasks = {},
props = {}
} = state;
return { cache, fails, stack, tasks, props };
}
var lastIdKey = /* @__PURE__ */ Symbol.for("plugjs:plug:singleton:taskId");
var taskId = (0, import_singleton.getSingleton)(lastIdKey, () => ({ id: 0 }));
var TaskImpl = class {
constructor(name, buildFile, _def, _tasks, _props) {
this.name = name;
this.buildFile = buildFile;
this._def = _def;
this.tasks = _tasks;
this.props = _props;
}
name;
buildFile;
_def;
before = [];
after = [];
id = ++taskId.id;
props;
tasks;
async invoke(state, taskName) {
(0, import_asserts.assert)(!state.stack.includes(this), `Recursion detected calling ${(0, import_logging.$t)(taskName)}`);
const cached = state.cache.get(this);
if (cached) return cached;
state = makeState({
props: merge(this.props, state.props),
tasks: merge(this.tasks, state.tasks),
stack: [...state.stack, this],
cache: state.cache,
fails: state.fails
});
const context = new import_pipe.Context(this.buildFile, taskName);
const build2 = new Proxy({}, {
get: (_, name) => {
if (name in state.tasks) {
return () => {
const promise2 = state.tasks[name].invoke(state, name);
return new import_pipe.PipeImpl(context, promise2);
};
} else if (name in state.props) {
return state.props[name];
}
}
});
for (const before of this.before) await before.invoke(state, before.name);
context.log.info("Running...");
const now = Date.now();
const promise = (0, import_async.runAsync)(context, async () => {
return await this._def.call(build2) || void 0;
}).then(async (result) => {
const level = taskName.startsWith("_") ? "info" : "notice";
context.log[level](`Success ${(0, import_logging.$ms)(Date.now() - now)}`);
return result;
}).catch((error) => {
state.fails.add(this);
context.log.error(`Failure ${(0, import_logging.$ms)(Date.now() - now)}`, error);
throw import_asserts.BuildFailure.fail();
}).finally(async () => {
await import_pipe.ContextPromises.wait(context);
}).then(async (result) => {
for (const after of this.after) await after.invoke(state, after.name);
return result;
});
state.cache.set(this, promise);
return promise;
}
};
function plugjs(def) {
const buildFile = (0, import_caller.findCaller)(plugjs);
const tasks = {};
const props = {};
for (const [key, val] of Object.entries(def)) {
let len = 0;
if (isTaskCall(val)) {
tasks[key] = val.task;
len = key.length;
} else if (typeof val === "string") {
props[key] = val;
} else if (typeof val === "function") {
tasks[key] = new TaskImpl(key, buildFile, val, tasks, props);
len = key.length;
}
if (import_logging.logOptions.level >= import_logging.NOTICE && key.startsWith("_")) continue;
if (len > import_logging.logOptions.taskLength) import_logging.logOptions.taskLength = len;
}
const start = async function start2(callback, overrideProps = {}) {
const state = makeState({ tasks, props: merge(props, overrideProps) });
const logger = (0, import_logging.getLogger)();
logger.notice("Starting...");
const now = Date.now();
try {
const result = await callback(state);
logger.notice(`Build successful ${(0, import_logging.$ms)(Date.now() - now)}`);
return result;
} catch (error) {
if (state.fails.size) {
logger.error("");
logger.error((0, import_logging.$plur)(state.fails.size, "task", "tasks"), "failed:");
state.fails.forEach((task) => logger.error((0, import_logging.$gry)("*"), (0, import_logging.$t)(task.name)));
logger.error("");
}
throw logger.fail(`Build failed ${(0, import_logging.$ms)(Date.now() - now)}`, error);
}
};
const invoke = async function invoke2(taskNames, overrideProps = {}) {
await start(async (state) => {
for (const name of taskNames) {
const task = tasks[name];
(0, import_asserts.assert)(task, `Task ${(0, import_logging.$t)(name)} not found in build ${(0, import_logging.$p)(buildFile)}`);
await task.invoke(state, name);
}
}, overrideProps);
};
const callables = {};
for (const [name, task] of Object.entries(tasks)) {
const callable = async (overrideProps) => start(async (state) => task.invoke(state, name), overrideProps);
callables[name] = Object.defineProperties(callable, {
[taskCallMarker]: { value: taskCallMarker },
"task": { value: task },
"name": { value: name }
});
}
const compiled = merge(props, callables);
Object.defineProperty(compiled, buildMarker, { value: invoke });
return compiled;
}
var build = function(def) {
import_logging.log.warn(`Use of deprecated ${(0, import_logging.$ylw)("build")} entry point, please use ${(0, import_logging.$grn)("plugjs")}`);
return plugjs(def);
};
function isBuild(build2) {
return build2 && typeof build2[buildMarker] === "function";
}
function invokeTasks(build2, tasks, props) {
if (isBuild(build2)) {
return build2[buildMarker](tasks, props);
} else {
throw new TypeError("Invalid build instance");
}
}
function hookBefore(build2, taskName, hooks) {
const taskCall = build2[taskName];
(0, import_asserts.assert)(isTaskCall(taskCall), `Task "${(0, import_logging.$t)(taskName)}" not found in build`);
for (const hook of hooks) {
const beforeHook = build2[hook];
(0, import_asserts.assert)(isTaskCall(beforeHook), `Task "${(0, import_logging.$t)(hook)}" to hook before "${(0, import_logging.$t)(taskName)}" not found in build`);
if (taskCall.task.before.includes(beforeHook.task)) continue;
taskCall.task.before.push(beforeHook.task);
}
}
function hookAfter(build2, taskName, hooks) {
const taskCall = build2[taskName];
(0, import_asserts.assert)(isTaskCall(taskCall), `Task "${(0, import_logging.$t)(taskName)}" not found in build`);
for (const hook of hooks) {
const afterHook = build2[hook];
(0, import_asserts.assert)(isTaskCall(afterHook), `Task "${(0, import_logging.$t)(hook)}" to hook after "${(0, import_logging.$t)(taskName)}" not found in build`);
if (taskCall.task.after.includes(afterHook.task)) continue;
taskCall.task.after.push(afterHook.task);
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
build,
hookAfter,
hookBefore,
invokeTasks,
isBuild,
plugjs
});
//# sourceMappingURL=build.cjs.map