@backstage/cli
Version:
CLI for developing Backstage plugins and apps
168 lines (162 loc) • 6.2 kB
JavaScript
;
var CommandGraph = require('./CommandGraph.cjs.js');
var InternalCliModule = require('../cli-internal/src/InternalCliModule.cjs.js');
var InternalCommandNode = require('../cli-internal/src/InternalCommandNode.cjs.js');
require('node:fs');
require('node:os');
require('node:path');
require('../cli-internal/src/knownPluginPackages.cjs.js');
var commander = require('commander');
var version = require('./version.cjs.js');
var chalk = require('chalk');
var errors = require('./errors.cjs.js');
var errors$1 = require('@backstage/errors');
var types = require('node:util/types');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk);
class CliInitializer {
graph = new CommandGraph.CommandGraph();
#uninitiazedFeatures = [];
add(feature) {
if (types.isPromise(feature)) {
this.#uninitiazedFeatures.push(
feature.then((f) => {
const unwrapped = unwrapFeature(f.default);
if (Array.isArray(unwrapped)) {
return unwrapped.map((m) => ({ feature: m, fromArray: true }));
}
return [{ feature: unwrapped, fromArray: false }];
})
);
} else if (Array.isArray(feature)) {
this.#uninitiazedFeatures.push(
Promise.resolve(feature.map((m) => ({ feature: m, fromArray: true })))
);
} else {
this.#uninitiazedFeatures.push(
Promise.resolve([{ feature, fromArray: false }])
);
}
}
async #register(feature) {
if (InternalCliModule.OpaqueCliModule.isType(feature)) {
for (const command of await InternalCliModule.OpaqueCliModule.toInternal(feature).commands) {
this.graph.add(command, feature);
}
} else {
throw new Error(`Unsupported feature type: ${feature.$$type}`);
}
}
async #doInit() {
const resolvedGroups = await Promise.all(this.#uninitiazedFeatures);
const allFeatures = resolvedGroups.flat();
const individualPaths = /* @__PURE__ */ new Set();
for (const { feature, fromArray } of allFeatures) {
if (!fromArray && InternalCliModule.OpaqueCliModule.isType(feature)) {
const cmds = await InternalCliModule.OpaqueCliModule.toInternal(feature).commands;
for (const cmd of cmds) {
individualPaths.add(cmd.path.join(" "));
}
}
}
for (const { feature, fromArray } of allFeatures) {
if (fromArray && InternalCliModule.OpaqueCliModule.isType(feature)) {
const cmds = await InternalCliModule.OpaqueCliModule.toInternal(feature).commands;
if (cmds.some((cmd) => individualPaths.has(cmd.path.join(" ")))) {
continue;
}
}
await this.#register(feature);
}
}
/**
* Actually parse argv and pass it to the command.
*/
async run() {
await this.#doInit();
const programName = "backstage-cli";
const program = new commander.Command();
program.name(programName).version(version.version).allowUnknownOption(true).allowExcessArguments(true);
const queue = this.graph.atDepth(0).map((node) => ({
node,
argParser: program
}));
while (queue.length) {
const { node, argParser } = queue.shift();
if (InternalCommandNode.OpaqueCommandTreeNode.isType(node)) {
const internal = InternalCommandNode.OpaqueCommandTreeNode.toInternal(node);
const treeParser = argParser.command(`${internal.name} [command]`, {
hidden: InternalCommandNode.isCommandNodeHidden(node)
}).description(internal.name);
queue.push(
...internal.children.map((child) => ({
node: child,
argParser: treeParser
}))
);
} else {
const internal = InternalCommandNode.OpaqueCommandLeafNode.toInternal(node);
argParser.command(internal.name, {
hidden: !!internal.command.deprecated || !!internal.command.experimental
}).description(internal.command.description).helpOption(false).allowUnknownOption(true).allowExcessArguments(true).action(async () => {
try {
const args = program.parseOptions(process.argv);
const nonProcessArgs = args.operands.slice(2);
const positionalArgs = [];
let index = 0;
for (let argIndex = 0; argIndex < nonProcessArgs.length; argIndex++) {
if (argIndex === index && internal.command.path[argIndex] === nonProcessArgs[argIndex]) {
index += 1;
continue;
}
positionalArgs.push(nonProcessArgs[argIndex]);
}
const context = {
args: [...positionalArgs, ...args.unknown],
info: {
usage: [programName, ...internal.command.path].join(" "),
name: internal.command.path.join(" ")
}
};
if (typeof internal.command.execute === "function") {
await internal.command.execute(context);
} else {
const mod = await internal.command.execute.loader();
const fn = typeof mod.default === "function" ? mod.default : mod.default.default;
await fn(context);
}
process.exit(0);
} catch (error) {
errors.exitWithError(error);
}
});
}
}
program.on("command:*", () => {
console.log();
console.log(chalk__default.default.red(`Invalid command: ${program.args.join(" ")}`));
console.log();
program.outputHelp();
process.exit(1);
});
process.on("unhandledRejection", (rejection) => {
errors.exitWithError(new errors$1.ForwardedError("Unhandled rejection", rejection));
});
await program.parseAsync(process.argv);
}
}
function unwrapFeature(feature) {
if (Array.isArray(feature)) {
return feature;
}
if ("$$type" in feature) {
return feature;
}
if ("default" in feature) {
return feature.default;
}
return feature;
}
exports.CliInitializer = CliInitializer;
exports.unwrapFeature = unwrapFeature;
//# sourceMappingURL=CliInitializer.cjs.js.map