interface SchemaFieldBase {
long: `--${string}`
short?: `-${string}`
default?: never
}
interface SchemaFlag extends SchemaFieldBase {
type: 'flag'
}
interface SchemaString extends Omit<SchemaFieldBase, 'default'> {
type: 'string'
default?: string
}
interface SchemaNumber extends Omit<SchemaFieldBase, 'default'> {
type: 'number'
default?: number
}
type SchemaField = SchemaFlag | SchemaString | SchemaNumber
type SchemaFieldType<T extends SchemaField> =
T['type'] extends 'flag' ? boolean :
T['type'] extends 'string' ? string :
T['type'] extends 'number' ? number :
unknown;
type SchemaFieldTypeUndefinable<T extends SchemaField> =
T['default'] extends string ? SchemaFieldType<T> :
T['default'] extends number ? SchemaFieldType<T> :
T['type'] extends 'flag' ? boolean :
SchemaFieldType<T> | undefined;
const args = [...Deno.args];
const inputs: Record<string, string | boolean> = {}
while(args.length) {
const arg = args.splice(0, 1)[0];
if(arg.startsWith('-')) {
if(args.length && !args[0].startsWith('-')) {
const value = args.splice(0, 1)[0];
inputs[arg] = value;
} else {
inputs[arg] = true;
}
}
}
export class Args {
private constructor() {}
static Parse<const T extends Record<string, SchemaField>>(schema: T) {
const out: Record<string, unknown> = {}
for(const [key, value] of Object.entries(schema)) {
const tag_value = (value.short ? inputs[value.short] : undefined) || inputs[value.long];
switch(value.type) {
case "string": {
out[key] = tag_value || value.default;
break;
}
case "number": {
if(typeof tag_value == 'string') {
out[key] = Number(tag_value) || value.default;
} else {
out[key] = value.default;
}
break;
}
case "flag": {
out[key] = !!tag_value;
}
}
}
return out as {[K in keyof T]: SchemaFieldTypeUndefinable<T[K]>}
}
}