UNPKG

@eeue56/baner

Version:

Flag parsing library in Typescript

464 lines (463 loc) 13.4 kB
"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;