split interactive source

This commit is contained in:
Timo Hocker 2020-06-15 11:56:33 +02:00
parent 089519844f
commit f7c03f82f1
11 changed files with 150 additions and 73 deletions

View File

@ -34,6 +34,20 @@ class OptionValue {
public constructor (type_validation: TypeValidation) { public constructor (type_validation: TypeValidation) {
this.type_validation = type_validation; this.type_validation = type_validation;
} }
public async assign_arg (
opt: Option,
value: unknown
): Promise<void> {
try {
this.value = await this.type_validation.to_type (value);
this.filled = true;
}
catch (e) {
if (typeof opt.error_callback !== 'undefined')
opt.error_callback (opt.name, value, e);
}
}
} }
export { Option, OptionValue }; export { Option, OptionValue };

View File

@ -45,6 +45,6 @@ export class ArgSource extends OptionSource {
) )
return; return;
await this.assign_arg (opt, val, argv[opt.name]); await val.assign_arg (opt, argv[opt.name]);
} }
} }

View File

@ -64,6 +64,6 @@ export class ConfigSource extends OptionSource {
const keys = Object.keys (data); const keys = Object.keys (data);
if (keys.includes (opt.name)) if (keys.includes (opt.name))
await this.assign_arg (opt, val, data[opt.name]); await val.assign_arg (opt, data[opt.name]);
} }
} }

View File

@ -25,6 +25,6 @@ export class EnvSource extends OptionSource {
return; return;
} }
await this.assign_arg (opt, val, process.env[opt.env]); await val.assign_arg (opt, process.env[opt.env]);
} }
} }

View File

@ -0,0 +1,19 @@
import { List } from 'enquirer';
import { InteractiveSubSource } from './InteractiveSubSource';
export class ArraySubSource extends InteractiveSubSource {
protected condition ():boolean {
return this.val.type_validation.option_type === 'array';
}
protected async run ():Promise<void> {
await this.val.assign_arg (
this.opt,
await new List ({
message: this.get_message (),
default: this.opt.default
})
.run ()
);
}
}

View File

@ -0,0 +1,19 @@
import { Confirm } from 'enquirer';
import { InteractiveSubSource } from './InteractiveSubSource';
export class BooleanSubSource extends InteractiveSubSource {
protected condition ():boolean {
return this.val.type_validation.option_type === 'boolean';
}
protected async run ():Promise<void> {
await this.val.assign_arg (
this.opt,
await new Confirm ({
message: this.get_message (),
default: this.opt.default
})
.run ()
);
}
}

View File

@ -0,0 +1,28 @@
import { OptionValue, Option } from '../../Option';
export abstract class InteractiveSubSource {
protected val: OptionValue;
protected opt: Option;
protected abstract condition():boolean;
protected abstract async run():Promise<void>;
public constructor (
val:OptionValue,
opt:Option
) {
this.val = val;
this.opt = opt;
}
public async parse ():Promise<void> {
if (this.condition ())
await this.run ();
}
protected get_message (): string {
return typeof this.opt.message === 'undefined'
? `input ${this.opt.name}`
: this.opt.message;
}
}

View File

@ -0,0 +1,28 @@
import { AutoComplete } from 'enquirer';
import { StringOptionConfig } from '../../SubConfigs';
import { InteractiveSubSource } from './InteractiveSubSource';
export class PresetSubSource extends InteractiveSubSource {
protected condition ():boolean {
return [
'string',
'file',
'folder',
'path'
].includes (this.val.type_validation.option_type)
&& typeof (this.opt as StringOptionConfig).preset !== 'undefined';
}
protected async run ():Promise<void> {
await this.val.assign_arg (
this.opt,
await new AutoComplete ({
message: this.get_message (),
default: this.opt.default,
choices: (this.opt as StringOptionConfig).preset,
limit: 10
})
.run ()
);
}
}

View File

@ -0,0 +1,27 @@
import { Input } from 'enquirer';
import { StringOptionConfig } from '../../SubConfigs';
import { InteractiveSubSource } from './InteractiveSubSource';
export class StringSubSource extends InteractiveSubSource {
protected condition ():boolean {
return [
'string',
'file',
'folder',
'path',
'number'
].includes (this.val.type_validation.option_type)
&& typeof (this.opt as StringOptionConfig).preset === 'undefined';
}
protected async run ():Promise<void> {
await this.val.assign_arg (
this.opt,
await new Input ({
message: this.get_message (),
default: this.opt.default
})
.run ()
);
}
}

View File

@ -7,11 +7,13 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
/* eslint-disable no-process-exit */ /* eslint-disable no-process-exit */
import { Confirm, Input, List, AutoComplete } from 'enquirer';
import { ErrorCallback } from '../ErrorCallback'; import { ErrorCallback } from '../ErrorCallback';
import { Option, OptionValue } from '../Option'; import { Option, OptionValue } from '../Option';
import { StringOptionConfig } from '../SubConfigs';
import { OptionSource } from './OptionSource'; import { OptionSource } from './OptionSource';
import { ArraySubSource } from './Interactive/ArraySubSource';
import { BooleanSubSource } from './Interactive/BooleanSubSource';
import { PresetSubSource } from './Interactive/PresetSubSource';
import { StringSubSource } from './Interactive/StringSubSource';
export class InteractiveSource extends OptionSource { export class InteractiveSource extends OptionSource {
private _exit_on_interrupt: boolean; private _exit_on_interrupt: boolean;
@ -24,62 +26,17 @@ export class InteractiveSource extends OptionSource {
this._exit_on_interrupt = exit_on_interrupt; this._exit_on_interrupt = exit_on_interrupt;
} }
private get_message (opt: Option): string {
return typeof opt.message === 'undefined'
? `input ${opt.name}`
: opt.message;
}
private async prompt (opt: Option, val:OptionValue): Promise<void> { private async prompt (opt: Option, val:OptionValue): Promise<void> {
if (val.filled) if (val.filled)
return; return;
let value = null; await new StringSubSource (val, opt)
const { option_type } = val.type_validation; .parse ();
const { preset } = opt as StringOptionConfig; await new PresetSubSource (val, opt)
if ( .parse ();
option_type === 'string' await new BooleanSubSource (val, opt)
|| option_type === 'file' .parse ();
|| option_type === 'folder' await new ArraySubSource (val, opt)
|| option_type === 'path' .parse ();
|| option_type === 'number'
) {
if (typeof preset === 'undefined') {
value = await new Input ({
message: this.get_message (opt),
default: opt.default
})
.run ();
}
else {
value = await new AutoComplete ({
message: this.get_message (opt),
default: opt.default,
choices: preset,
limit: 10
})
.run ();
}
}
if (
option_type === 'boolean'
) {
value = await new Confirm ({
message: this.get_message (opt),
default: opt.default
})
.run ();
}
if (option_type === 'array') {
value = await new List ({
message: this.get_message (opt),
default: opt.default
})
.run ();
}
if (value === null)
return;
await this.assign_arg (opt, val, value);
} }
public async parse (opt: Option, val:OptionValue): Promise<void> { public async parse (opt: Option, val:OptionValue): Promise<void> {

View File

@ -16,19 +16,4 @@ export abstract class OptionSource {
public constructor (error_callback?: ErrorCallback) { public constructor (error_callback?: ErrorCallback) {
this.error_callback = error_callback; this.error_callback = error_callback;
} }
protected async assign_arg (
opt: Option,
val: OptionValue,
value: unknown
): Promise<void> {
try {
val.value = await val.type_validation.to_type (value);
val.filled = true;
}
catch (e) {
if (typeof this.error_callback !== 'undefined')
this.error_callback (opt.name, value, e);
}
}
} }