@sudoo/coco
Version:
:ocean: A simple command line tool framework
136 lines (135 loc) • 4.72 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const declare_1 = require("../panic/declare");
const util_1 = require("./util");
class Command {
constructor(command) {
this._command = command;
this._arguments = [];
this._options = [];
this._listeners = [];
}
static create(command) {
return new Command([command]);
}
static commands(commands) {
return new Command(commands);
}
static multiple(...commands) {
return new Command(commands);
}
static root() {
return new Command([]);
}
get commands() {
return this._command;
}
get simulate() {
return this._command.join(' ');
}
match(argv) {
return this._command.every((value, index) => {
if (value === argv[index]) {
return true;
}
return false;
});
}
argument(arg, ...args) {
this._arguments.push(arg, ...args);
return this;
}
arguments(args) {
this._arguments.push(...args);
return this;
}
option(option, ...options) {
this._options.push(option, ...options);
return this;
}
options(options) {
this._options.push(...options);
return this;
}
execute(args, globalOptions) {
return __awaiter(this, void 0, void 0, function* () {
const shifted = args.slice(this._command.length);
const record = this.parseArgs(shifted, globalOptions);
const promises = this._listeners.map((executable) => {
return executable(record);
});
yield Promise.all(promises);
return;
});
}
then(func) {
this._listeners.push(func);
return this;
}
findOption(key, globalOptions) {
for (const option of this._options.concat(globalOptions)) {
if (option.match(key)) {
return option;
}
}
return null;
}
parseArgs(args, globalOptions) {
const result = {};
const tempArguments = [];
const matchOptionSet = new Set();
for (let pointer = 0; pointer < args.length; pointer++) {
const current = args[pointer];
if (util_1.isOption(current)) {
const option = this.findOption(current, globalOptions);
if (!option) {
throw declare_1.panic.code(declare_1.ERROR_CODE.OPTION_NOT_FOUND, current);
}
if (matchOptionSet.has(option)) {
throw declare_1.panic.code(declare_1.ERROR_CODE.DUPLICATED_OPTION, current);
}
if (option.isBoolean) {
result[option.name] = "true";
}
else {
const next = args[++pointer];
result[option.name] = next;
}
matchOptionSet.add(option);
}
else {
tempArguments.push(current);
}
}
if (tempArguments.length > this._arguments.length) {
throw declare_1.panic.code(declare_1.ERROR_CODE.TOO_MANY_ARGUMENTS);
}
for (const argument of this._arguments) {
const first = tempArguments.shift();
if (!first) {
if (!argument.isOptional) {
throw declare_1.panic.code(declare_1.ERROR_CODE.INSUFFICIENT_ARGUMENTS);
}
return result;
}
result[argument.name] = first;
}
const optionRequirementsMat = [...this._options, ...globalOptions]
.filter((option) => option.isRequired)
.every((option) => matchOptionSet.has(option));
if (!optionRequirementsMat) {
throw declare_1.panic.code(declare_1.ERROR_CODE.REQUIRED_OPTION_INSUFFICIENT);
}
return result;
}
}
exports.Command = Command;