decline-ts
Version:
Composable command-line parser for TypeScript - a (partial) porting of Scala decline using fp-ts
147 lines (146 loc) • 6.85 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Opts = void 0;
const fp_ts_1 = require("fp-ts");
const function_1 = require("fp-ts/function");
const Command_1 = require("./Command");
const ValidatedNea_1 = require("./ValidatedNea");
const URI_ = 'Opts';
var Opts;
(function (Opts) {
/**
* Constructors
*/
Opts.pure = (a) => ({ _tag: 'Pure', a });
Opts.app = (f, fa) => ({ _tag: 'App', f, a: fa });
Opts.orElse = (a, b) => ({ _tag: 'OrElse', a, b });
function single(opt) {
return { _tag: 'Single', opt };
}
Opts.single = single;
function repeated(opt) {
return { _tag: 'Repeated', opt };
}
Opts.repeated = repeated;
function subcommand(arg) {
return isCommand(arg)
? { _tag: 'Subcommand', command: arg }
: o => ({ _tag: 'Subcommand', command: Command_1.Command(arg)(o) });
}
Opts.subcommand = subcommand;
const Validate = (value, vNea) => ({ _tag: 'Validate', value, validate: vNea });
Opts.helpFlag = (flag) => ({ _tag: 'HelpFlag', flag });
Opts.unit = Opts.pure(undefined);
function option(codec = fp_ts_1.either.right) {
return ({ long, help, short = '', metavar }) => function_1.pipe(single(Opt.regular(Name.namesFor(long, short), metavar, help)), Opts.mapValidated(codec));
}
Opts.option = option;
function options(codec = fp_ts_1.either.right) {
return ({ long, help, short = '', metavar }) => function_1.pipe(repeated(Opt.regular(Name.namesFor(long, short), metavar, help)), Opts.mapValidated(args => fp_ts_1.readonlyNonEmptyArray.readonlyNonEmptyArray.traverse(stringValidation)(args, codec)));
}
Opts.options = options;
Opts.flag = ({ long, help, short = '' }) => single(Opt.flag(Name.namesFor(long, short), help));
Opts.flags = ({ long, help, short = '' }) => function_1.pipe(repeated(Opt.flag(Name.namesFor(long, short), help)), Opts.map(l => l.length));
function argument(codec = fp_ts_1.either.right) {
return (metavar = '') => function_1.pipe(single(Opt.argument(metavar)), Opts.mapValidated(codec));
}
Opts.argument = argument;
function argumentS(codec = fp_ts_1.either.right) {
return metavar => function_1.pipe(repeated(Opt.argument(metavar)), Opts.mapValidated(args => fp_ts_1.readonlyNonEmptyArray.readonlyNonEmptyArray.traverse(stringValidation)(args, codec)));
}
Opts.argumentS = argumentS;
function param(codec = fp_ts_1.either.right) {
return metavar => function_1.pipe(single(Opt.argument(metavar)), Opts.mapValidated(codec));
}
Opts.param = param;
function params(codec = fp_ts_1.either.right) {
return metavar => function_1.pipe(repeated(Opt.argument(metavar)), Opts.mapValidated(args => fp_ts_1.readonlyNonEmptyArray.readonlyNonEmptyArray.traverse(fp_ts_1.either.getValidation(fp_ts_1.readonlyNonEmptyArray.getSemigroup()))(args, codec)));
}
Opts.params = params;
/**
* Methods
*/
Opts.mapValidated = (f) => (fa) => fa._tag === 'Validate'
? Validate(fa.value, function_1.flow(fa.validate, fp_ts_1.either.chain(f)))
: Validate(fa, f);
Opts.validate = (message) => (pred) => (fa) => function_1.pipe(fa, Opts.mapValidated(a => (pred(a) ? ValidatedNea_1.ValidatedNea.right(a) : ValidatedNea_1.ValidatedNea.left(message))));
Opts.withDefault = (fy) => Opts.alt(() => Opts.pure(fy()));
Opts.orNone = (fa) => function_1.pipe(fa, Opts.map(fp_ts_1.option.some), Opts.withDefault(() => fp_ts_1.option.none));
Opts.orEmpty = (fa) => function_1.pipe(fa, Opts.withDefault(() => []));
Opts.orFalse = (fa) => function_1.pipe(fa, Opts.map(() => true), Opts.withDefault(() => false));
Opts.asHelp = (fa) => function_1.pipe(fa, Opts.map(() => { }), Opts.helpFlag);
Opts.map = (f) => (fa) => Opts.mapValidated(function_1.flow(f, fp_ts_1.either.right))(fa);
Opts.ap = (fab) => (fa) => Opts.app(fab, fa);
Opts.alt = (that) => (fa) => Opts.orElse(fa, that());
/**
* Instance
*/
Opts.URI = URI_;
Opts.opts = {
URI: Opts.URI,
map: (fa, f) => function_1.pipe(fa, Opts.map(f)),
ap: (fab, fa) => function_1.pipe(fa, Opts.ap(fab)),
alt: (fa, that) => function_1.pipe(fa, Opts.alt(that)),
};
let Name;
(function (Name) {
// eslint-disable-next-line no-shadow
Name.longName = (flag) => ({ _tag: 'LongName', flag });
// eslint-disable-next-line no-shadow
Name.shortName = (flag) => ({ _tag: 'ShortName', flag });
Name.stringify = (name) => name._tag === 'LongName' ? `--${name.flag}` : `-${name.flag}`;
Name.namesFor = (long, short) => fp_ts_1.readonlyArray.cons(Name.longName(long), short.split('').map(Name.shortName));
Name.eq = fp_ts_1.eq.getStructEq({
_tag: fp_ts_1.eq.eqString,
flag: fp_ts_1.eq.eqString,
});
})(Name = Opts.Name || (Opts.Name = {}));
let Opt;
(function (Opt) {
Opt.regular = (names, metavar, help) => ({
_tag: 'Regular',
names,
metavar,
help,
});
// eslint-disable-next-line no-shadow
Opt.flag = (names, help) => ({
_tag: 'Flag',
names,
help,
});
// eslint-disable-next-line no-shadow
Opt.argument = (metavar) => ({ _tag: 'Argument', metavar });
const regularEq = fp_ts_1.eq.getStructEq({
names: fp_ts_1.readonlyArray.getEq(Name.eq),
metavar: fp_ts_1.eq.eqString,
help: fp_ts_1.eq.eqString,
});
const flagEq = fp_ts_1.eq.getStructEq({
names: fp_ts_1.readonlyArray.getEq(Name.eq),
help: fp_ts_1.eq.eqString,
});
const argumentEq = fp_ts_1.eq.getStructEq({
metavar: fp_ts_1.eq.eqString,
});
function eq() {
return {
equals: (x, y) => {
switch (x._tag) {
case 'Regular':
return y._tag === 'Regular' ? regularEq.equals(x, y) : false;
case 'Flag':
return y._tag === 'Flag' ? flagEq.equals(x, y) : false;
case 'Argument':
return y._tag === 'Argument' ? argumentEq.equals(x, y) : false;
}
},
};
}
Opt.eq = eq;
})(Opt = Opts.Opt || (Opts.Opt = {}));
})(Opts = exports.Opts || (exports.Opts = {}));
const stringValidation = fp_ts_1.either.getValidation(fp_ts_1.readonlyNonEmptyArray.getSemigroup());
const tagKey = '_tag';
const tagVal = 'Command';
const isCommand = (arg) => function_1.pipe(fp_ts_1.readonlyRecord.lookup(tagKey, arg), fp_ts_1.option.exists(t => t === tagVal));