@lwys-pkg-releaser/node-bullshit-generator
Version:
Port of menzi11/BullshitGenerator@github.com to JavaScript
143 lines (129 loc) • 4.19 kB
JavaScript
/**
* 需要串联运行的生成步骤
* @author Dobby233Liu
* @see {@link https://docgov.dev/posts/npm-scripts/}
*/
const process = require("process");
const { spawnSync } = require("child_process");
const path = require("path");
const fs = require("fs");
const rimraf = require("rimraf");
const cwdTrue = path.join(__dirname, "..");
const exec = (cmd, args = [], cwd = cwdTrue) => {
console.log(`> ${cmd} ${args.join(" ")}`);
const data = spawnSync(cmd, args, {
stdio: "inherit",
shell: true,
cwd: cwd,
});
if (data.status != 0 || data.signal) {
console.log("");
console.error(data);
console.error(
`Process ${
data.signal
? `was killed with signal ${data.signal}`
: `exited with code ${data.status}`
}`
);
process.exit(data.signal ? 1 : data.status);
}
};
const srcDir = "src";
const libDir = "lib";
const distDir = "dist";
const libBrowserName = "bullshit";
/* not 狗屁库.js, otherwise when the script gets to the
browserify step, it would just fail mysteriously */
const libFile = "bullshit.js";
const libFileDistTemp = `${distDir}/bullshit.js`;
const libMinifiedFileTemp = `${distDir}/bullshit.min.js`;
const libFileDist = `${distDir}/狗屁库.js`;
const libMinifiedFile = `${distDir}/狗屁库.min.js`;
/**
* @param {string} exe executable name (without extension if on Windows)
* @return {Promise<string|null>} executable path if found
* @see {@link https://abdus.dev/posts/checking-executable-exists-in-path-using-node/}
* */
function findExecutable(exe) {
const envPath = process.env.PATH || "";
const envExt = process.env.PATHEXT || "";
const pathDirs = envPath
.replace(/["]+/g, "")
.split(path.delimiter)
.filter(Boolean);
const extensions = envExt.split(";");
const candidates = pathDirs.flatMap((d) =>
extensions.map((ext) => path.join(d, exe + ext))
);
for (filePath of candidates)
try {
if (fs.statSync(filePath).isFile()) return filePath;
} catch (e) {}
throw new Error("Did not find executable: " + exe);
}
const npx = `"${findExecutable("npx")}"`;
// TODO: probably rewrite this to use babel api
// when my brain is ready
const runBabel = () => exec(npx, ["babel", srcDir, "--out-dir", libDir]);
// TODO: probably rewrite this to use browserify api
const runBundle = () =>
exec(npx, [
"browserify",
"-e",
`${libDir}/${libFile}`,
"-s",
libBrowserName,
"-o",
libFileDistTemp,
// ignore the nasty browser field that is just for stupid cdns
"--no-bf",
]);
// TODO: probably rewrite this to use terser api
const runMinifyBundle = (bundleFile, outputFile) => () =>
exec(npx, ["terser", bundleFile, "-o", outputFile, "-m", "-c", "--warn"]);
const doMoveFile = (fnOld, fnNew) => {
console.log(`> mv "${fnOld}" "${fnNew}"`);
fs.renameSync(fnOld, fnNew);
};
const fixFilenames = () => {
doMoveFile(libFileDistTemp, libFileDist);
doMoveFile(libMinifiedFileTemp, libMinifiedFile);
};
const doRm = (dir) => {
console.log(`> rm -rf "${dir}"`);
rimraf.sync(dir);
};
const runClean = () => {
doRm(libDir);
doRm(distDir);
};
const steps = {
babel: runBabel,
bundle: [runClean, runBabel, runBundle, fixFilenames],
"minify-bundle": [
runMinifyBundle(libFileDistTemp, libMinifiedFileTemp),
fixFilenames,
],
"bundle+min": [
runClean,
runBabel,
runBundle,
runMinifyBundle(libFileDistTemp, libMinifiedFileTemp),
fixFilenames,
],
clean: runClean,
};
function main() {
const param = process.argv[2];
console.log(`> ${param}`);
const step = steps[param];
if (step)
if (typeof step == "function") step();
else for (func of step) func();
else {
console.error("No such step: " + step);
process.exit(1);
}
}
main();