This repository has been archived by the owner on Aug 22, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 23
/
flags.ts
114 lines (98 loc) · 2.74 KB
/
flags.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// tslint:disable interface-over-type-literal
import {AlphabetLowercase, AlphabetUppercase} from './alphabet'
export type DefaultContext<T> = {
options: IOptionFlag<T>;
flags: {[k: string]: string};
}
export type Default<T> = T | ((context: DefaultContext<T>) => T)
export type IFlagBase<T, I> = {
name: string;
char?: AlphabetLowercase | AlphabetUppercase;
description?: string;
helpLabel?: string;
hidden?: boolean;
required?: boolean;
dependsOn?: string[];
exclusive?: string[];
exactlyOne?: string[];
/**
* also accept an environment variable as input
*/
env?: string;
parse(input: I, context: any): T;
}
export type IBooleanFlag<T> = IFlagBase<T, boolean> & {
type: 'boolean';
allowNo: boolean;
/**
* specifying a default of false is the same not specifying a default
*/
default?: Default<boolean>;
}
export type IOptionFlag<T> = IFlagBase<T, string> & {
type: 'option';
helpValue?: string;
default?: Default<T | undefined>;
multiple: boolean;
input: string[];
options?: string[];
}
export type Definition<T> = {
(options: {multiple: true} & Partial<IOptionFlag<T[]>>): IOptionFlag<T[]>;
(
options: ({required: true} | {default: Default<T>}) &
Partial<IOptionFlag<T>>,
): IOptionFlag<T>;
(options?: Partial<IOptionFlag<T>>): IOptionFlag<T | undefined>;
}
export type EnumFlagOptions<T> = Partial<IOptionFlag<T>> & {
options: T[];
}
export type IFlag<T> = IBooleanFlag<T> | IOptionFlag<T>
export function build<T>(
defaults: {parse: IOptionFlag<T>['parse']} & Partial<IOptionFlag<T>>,
): Definition<T>
export function build(
defaults: Partial<IOptionFlag<string>>,
): Definition<string>
export function build<T>(defaults: Partial<IOptionFlag<T>>): Definition<T> {
return (options: any = {}): any => {
return {
parse: (i: string, _: any) => i,
...defaults,
...options,
input: [] as string[],
multiple: Boolean(options.multiple),
type: 'option',
} as any
}
}
export function boolean<T = boolean>(
options: Partial<IBooleanFlag<T>> = {},
): IBooleanFlag<T> {
return {
parse: (b, _) => b,
...options,
allowNo: Boolean(options.allowNo),
type: 'boolean',
} as IBooleanFlag<T>
}
export const integer = build({
parse: input => {
if (!/^-?\d+$/.test(input))
throw new Error(`Expected an integer but received: ${input}`)
return parseInt(input, 10)
},
})
export function option<T>(
options: {parse: IOptionFlag<T>['parse']} & Partial<IOptionFlag<T>>,
) {
return build<T>(options)()
}
const stringFlag = build({})
export {stringFlag as string}
export const defaultFlags = {
color: boolean({allowNo: true}),
}
export type Output = {[name: string]: any}
export type Input<T extends Output> = {[P in keyof T]: IFlag<T[P]>}