@eeue56/baner
Version:
Flag parsing library in Typescript
464 lines (463 loc) • 13.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parse = exports.allMissing = exports.allErrors = exports.help = exports.parser = exports.bothFlag = exports.longFlag = exports.shortFlag = exports.variableList = exports.oneOf = exports.list = exports.empty = exports.boolean = exports.number = exports.string = void 0;
var result_1 = require("@eeue56/ts-core/build/main/lib/result");
function StringArgument() {
return {
kind: "StringArgument",
};
}
/**
* An argument parser that treats an argument as a string
*/
function string() {
return StringArgument();
}
exports.string = string;
function NumberArgument() {
return {
kind: "NumberArgument",
};
}
/**
* An argument parser that treats an argument as a number
*/
function number() {
return NumberArgument();
}
exports.number = number;
function BooleanArgument() {
return {
kind: "BooleanArgument",
};
}
/**
* An argument parser that treats an argument as a boolean
*/
function boolean() {
return BooleanArgument();
}
exports.boolean = boolean;
function EmptyArgument() {
return {
kind: "EmptyArgument",
};
}
/**
* An argument parser that always passes
*/
function empty() {
return EmptyArgument();
}
exports.empty = empty;
function ListArgument(items) {
return {
kind: "ListArgument",
items: items,
};
}
/**
* An argument parser that treats an argument as a list
*/
function list(flagArgumentParsers) {
return ListArgument(flagArgumentParsers);
}
exports.list = list;
function VariableListArgument(item) {
return {
kind: "VariableListArgument",
item: item,
};
}
/**
* An argument parser that treats an argument as an enum
*/
function oneOf(items) {
return OneOfArgument(items);
}
exports.oneOf = oneOf;
function OneOfArgument(items) {
return {
kind: "OneOfArgument",
items: items,
};
}
/**
* An argument parser that treats an argument as a list
*/
function variableList(flagArgumentParser) {
return VariableListArgument(flagArgumentParser);
}
exports.variableList = variableList;
function Short(name, help, parser) {
return {
kind: "Short",
name: name,
help: help,
parser: parser,
};
}
function Long(name, help, parser) {
return {
kind: "Long",
name: name,
help: help,
parser: parser,
};
}
function Both(shortName, longName, help, parser) {
return {
kind: "Both",
shortName: shortName,
longName: longName,
help: help,
parser: parser,
};
}
/**
* A short flag, like -y
*/
function shortFlag(name, help, parser) {
return Short(name, help, parser);
}
exports.shortFlag = shortFlag;
/**
* A long flag, like --yes
*/
function longFlag(name, help, parser) {
return Long(name, help, parser);
}
exports.longFlag = longFlag;
/**
* A short or long flag, like -y or --yes
*/
function bothFlag(shortName, longName, help, parser) {
return Both(shortName, longName, help, parser);
}
exports.bothFlag = bothFlag;
/**
* A parser is composed of an array of flags
*/
function parser(flags) {
return {
flags: flags,
};
}
exports.parser = parser;
function isFlag(string) {
var isNumber = isNaN(parseFloat(string));
if (isNumber) {
return string.startsWith("-");
}
return false;
}
function runEmpty(parseable) {
return result_1.Ok(null);
}
function runString(parseable) {
if (parseable.length === 0 || isFlag(parseable[0]))
return result_1.Err("Not enough arguments. Expected a string.");
return result_1.Ok(parseable[0]);
}
function runNumber(parseable) {
if (parseable.length === 0 || isFlag(parseable[0]))
return result_1.Err("Not enough arguments. Expected a number.");
var parsed = parseFloat(parseable[0]);
if (isNaN(parsed))
return result_1.Err("Not a number argument");
return result_1.Ok(parsed);
}
function runBoolean(parseable) {
if (parseable.length === 0 || isFlag(parseable[0]))
return result_1.Err("Not enough arguments. Expected a boolean.");
var parsed = parseable[0] === "true" || parseable[0] === "false";
if (!parsed)
return result_1.Err("Not a boolean argument");
return result_1.Ok(parseable[0] === "true");
}
function runList(flagArguments, parseable) {
var results = [];
for (var i = 0; i < flagArguments.length; i++) {
var argument = flagArguments[i];
var res = runArgument(argument, parseable.slice(i));
if (res.kind === "Err") {
if (i >= parseable.length || isFlag(parseable[i])) {
return result_1.Err(res.error + " at index " + i);
}
return res;
}
else {
results.push(res.value);
}
}
return result_1.Ok(results);
}
function runOneOf(items, parseable) {
if (parseable.length === 0 || isFlag(parseable[0]))
return result_1.Err("Not enough arguments. Expected one of: " + items.join(" | ") + ".");
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item === parseable[0])
return result_1.Ok(item);
}
return result_1.Err("Didn't match any of: " + items.join(" | "));
}
function runVariableList(flagArgument, parseable) {
var results = [];
for (var i = 0; i < parseable.length; i++) {
if (isFlag(parseable[i]))
break;
var res = runArgument(flagArgument, parseable.slice(i));
if (res.kind === "Err")
return res;
results.push(res.value);
}
return result_1.Ok(results);
}
function runArgument(argument, parseable) {
switch (argument.kind) {
case "StringArgument": {
return runString(parseable);
}
case "NumberArgument": {
return runNumber(parseable);
}
case "BooleanArgument": {
return runBoolean(parseable);
}
case "EmptyArgument": {
return runEmpty(parseable);
}
case "ListArgument": {
return runList(argument.items, parseable);
}
case "VariableListArgument": {
return runVariableList(argument.item, parseable);
}
case "OneOfArgument": {
return runOneOf(argument.items, parseable);
}
}
}
function runShortFlag(flagName, innerParser, parseable) {
if (parseable.length === 0) {
return {
name: flagName,
isPresent: false,
arguments: result_1.Err("Short flag -" + flagName + " not found"),
};
}
for (var i = 0; i < parseable.length; i++) {
var value = parseable[i];
if (value === "-" + flagName) {
var res = runArgument(innerParser, parseable.slice(i + 1));
if (res.kind === "Err") {
res = result_1.Err("Error parsing -" + flagName + " due to: " + res.error);
}
return {
name: flagName,
isPresent: true,
arguments: res,
};
}
}
return {
name: flagName,
isPresent: false,
arguments: result_1.Err("Short flag -" + flagName + " not found"),
};
}
function runLongFlag(flagName, innerParser, parseable) {
if (parseable.length === 0) {
return {
name: flagName,
isPresent: false,
arguments: result_1.Err("Long flag --" + flagName + " not found"),
};
}
for (var i = 0; i < parseable.length; i++) {
var value = parseable[i];
if (value === "--" + flagName) {
var res = runArgument(innerParser, parseable.slice(i + 1));
if (res.kind === "Err") {
res = result_1.Err("Error parsing --" + flagName + " due to: " + res.error);
}
return {
name: flagName,
isPresent: true,
arguments: res,
};
}
}
return {
name: flagName,
isPresent: false,
arguments: result_1.Err("Long flag --" + flagName + " not found"),
};
}
function runBothFlag(shortFlagName, longFlagName, innerParser, parseable) {
var combinedFlagName = shortFlagName + "/" + longFlagName;
if (parseable.length === 0) {
return {
name: combinedFlagName,
isPresent: false,
arguments: result_1.Err("Mixed flag -" + shortFlagName + "/--" + longFlagName + " not found"),
};
}
for (var i = 0; i < parseable.length; i++) {
var value = parseable[i];
if (value === "-" + shortFlagName || value === "--" + longFlagName) {
var res = runArgument(innerParser, parseable.slice(i + 1));
if (res.kind === "Err") {
res = result_1.Err("Error parsing -" + shortFlag + "/--" + longFlagName + " due to: " + res.error);
}
return {
name: combinedFlagName,
isPresent: true,
arguments: res,
};
}
}
return {
name: combinedFlagName,
isPresent: false,
arguments: result_1.Err("Mixed flag -" + shortFlagName + "/--" + longFlagName + " not found"),
};
}
function runParser(programParser, parseable) {
var emptyRecord = {};
for (var i = 0; i < programParser.flags.length; i++) {
var flag = programParser.flags[i];
var res = void 0;
switch (flag.kind) {
case "Short": {
res = runShortFlag(flag.name, flag.parser, parseable);
break;
}
case "Long": {
res = runLongFlag(flag.name, flag.parser, parseable);
break;
}
case "Both": {
var bothFlag_1 = flag;
res = runBothFlag(bothFlag_1.shortName, bothFlag_1.longName, bothFlag_1.parser, parseable);
}
}
var name_1 = void 0;
switch (flag.kind) {
case "Short": {
name_1 = flag.name;
break;
}
case "Long": {
name_1 = flag.name;
break;
}
case "Both": {
var bothFlag_2 = flag;
name_1 = bothFlag_2.shortName + "/" + bothFlag_2.longName;
}
}
emptyRecord[name_1] = {
isPresent: res.isPresent,
arguments: res.arguments,
};
}
return {
args: parseable,
flags: emptyRecord,
};
}
function helpFlagArgumentParser(parser) {
switch (parser.kind) {
case "BooleanArgument":
return "boolean";
case "NumberArgument":
return "number";
case "StringArgument":
return "string";
case "EmptyArgument":
return "";
case "ListArgument":
return ("[" + parser.items.map(helpFlagArgumentParser).join(" ") + "]");
case "VariableListArgument":
return "[" + helpFlagArgumentParser(parser.item) + "...]";
case "OneOfArgument":
return parser.items.join(" | ");
}
}
/**
* Creates a help text for a given program parser
*/
function help(flagParser) {
return flagParser.flags
.map(function (flag) {
switch (flag.kind) {
case "Short": {
return " -" + flag.name + " " + helpFlagArgumentParser(flag.parser) + ":\t\t" + flag.help;
}
case "Long": {
return " --" + flag.name + " " + helpFlagArgumentParser(flag.parser) + ":\t\t" + flag.help;
}
case "Both": {
return " -" + flag.shortName + ", --" + flag.longName + " " + helpFlagArgumentParser(flag.parser) + ":\t\t" + flag.help;
}
}
})
.join("\n");
}
exports.help = help;
/**
* Reports all errors in a program, ignoring missing flags.
*/
function allErrors(program) {
var errors = [];
Object.keys(program.flags).map(function (key) {
if (!program.flags[key].isPresent)
return;
var argument = program.flags[key].arguments;
if (argument.kind === "Err") {
errors.push(argument.error);
}
});
return errors;
}
exports.allErrors = allErrors;
/**
* Reports missing flags, ignoring the ones you don't care about.
*/
function allMissing(program, ignore) {
var errors = [];
Object.keys(program.flags).map(function (key) {
if (ignore.indexOf(key) > -1)
return;
if (!program.flags[key].isPresent)
errors.push(key);
});
return errors;
}
exports.allMissing = allMissing;
/**
* Runs a flag parser on the args
*/
function parse(flagParser, args) {
var parseable = [];
args.forEach(function (arg) {
if (arg.indexOf("=") > -1) {
parseable.push(arg.split("=")[0]);
arg.split("=")[1]
.split(",")
.forEach(function (splitArg) {
parseable.push(splitArg);
});
}
else {
arg.split(",").forEach(function (splitArg) {
parseable.push(splitArg);
});
}
});
var res = runParser(flagParser, parseable);
return res;
}
exports.parse = parse;