An even more educational version of the Bandolier for Learn JS the Hard Way.
https://learnjsthehardway.com/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
2.3 KiB
86 lines
2.3 KiB
9 months ago
|
#!/usr/bin/env node
|
||
|
|
||
|
import { Command } from "commander";
|
||
|
// NOTE: this changed in node 18 to be node:url for...stupid
|
||
|
import { fileURLToPath } from "url";
|
||
|
import { glob } from "../lib/tooling.js";
|
||
|
import path from "path";
|
||
|
import assert from "assert";
|
||
|
import fs from "fs";
|
||
|
|
||
|
// BUG: this will load the commands but most of them assume the root
|
||
|
const __filename = fileURLToPath(import.meta.url);
|
||
|
const { dir } = path.parse(__filename);
|
||
|
let __dirname = path.resolve(dir);
|
||
|
|
||
|
// now even exec commands will know where the project root is
|
||
|
process.env['PROJECT_ROOT'] = path.resolve(path.join(__dirname, ".."));
|
||
|
|
||
|
const program = new Command();
|
||
|
// remember that glob doesn't like windows \
|
||
|
const command_dir = path.resolve(path.join(__dirname, "..", "commands"));
|
||
|
|
||
|
if(!fs.existsSync(command_dir)) {
|
||
|
console.error("ERROR: there is no command directory at", command_dir);
|
||
|
process.exit(1);
|
||
|
}
|
||
|
|
||
|
program
|
||
|
.name("bando")
|
||
|
.description("Command runner for the bando project.")
|
||
|
.version("0.1.0");
|
||
|
|
||
|
// only load the commands modules if any options are given
|
||
|
|
||
|
if(process.argv.length === 2) {
|
||
|
console.log("COMMANDS:\n");
|
||
|
const commands = glob(`${command_dir}/*.js`).map(cmd => {
|
||
|
console.log(path.parse(cmd).name);
|
||
|
});
|
||
|
|
||
|
|
||
|
if(process.platform === "win32") {
|
||
|
console.log("\nUse './bando help' for full help.");
|
||
|
} else {
|
||
|
console.log("\nUse './bando.js help' for full help.");
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
try {
|
||
|
const name = process.argv[2];
|
||
|
const command = path.join(command_dir, `${name}.js`);
|
||
|
if(fs.existsSync(command)) {
|
||
|
const mod = await import(`file://${command}`);
|
||
|
|
||
|
assert(mod.description, `export const description missing in ${command}`);
|
||
|
assert(mod.main, `export const main missing in ${command}`);
|
||
|
|
||
|
const build = program.command(name)
|
||
|
.description(mod.description)
|
||
|
.action(mod.main);
|
||
|
|
||
|
if(mod.options) {
|
||
|
mod.options.forEach(opt => build.option(...opt));
|
||
|
}
|
||
|
|
||
|
if(mod.required) {
|
||
|
mod.required.forEach(opt => build.requiredOption(...opt));
|
||
|
}
|
||
|
|
||
|
if(mod.argument) {
|
||
|
build.argument(...mod.argument);
|
||
|
}
|
||
|
}
|
||
|
} catch(error) {
|
||
|
console.log(error, `Loading file ${process.argv[2]}`);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
program.parse();
|
||
|
} catch(error) {
|
||
|
console.log("------------- ERROR, here's the stack trace.");
|
||
|
console.error(error.stack);
|
||
|
process.exit(1);
|
||
|
}
|