starting to split options by type

This commit is contained in:
Timo Hocker 2020-06-09 13:13:27 +02:00
parent 229b916cd5
commit 3f0b9fad79
20 changed files with 96 additions and 144 deletions

View File

@ -1,108 +0,0 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of console-app which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
import { Persistent } from '@sapphirecode/modelling';
import { TypeValidation } from './Types/TypeValidation';
import { PathType } from './Types/PathType';
import { OptionType } from './OptionType';
import { OptionSource } from './Sources/OptionSource';
import { EnvSource } from './Sources/EnvSource';
import { ArgSource } from './Sources/ArgSource';
import { ConfigSource } from './Sources/ConfigSource';
import { InteractiveSource } from './Sources/InteractiveSource';
import { Option, OptionProcess } from './Option';
import { ErrorCallback } from './Types/ErrorCallback';
const types: Record<OptionType, TypeValidation> = {
string: new TypeValidation ('string'),
number: new TypeValidation ('number'),
boolean: new TypeValidation ('boolean'),
file: new PathType ('file'),
folder: new PathType ('folder'),
path: new PathType ('path'),
array: new TypeValidation ('array')
};
interface SourceConfig {
env?: boolean;
args?: boolean;
interactive?: boolean;
configs?: string[];
exit_on_interrupt?: boolean;
error_callback?: ErrorCallback;
}
export class InteractiveOptions extends Persistent {
protected options: Array<OptionProcess>;
protected quiet = false;
protected sources: OptionSource[] = [];
public constructor (
options: Array<Option>,
source_config: SourceConfig = {}
) {
super ();
this.options = options
.map ((v) => ({
filled: false,
type_validation: types[v.type],
...v
} as OptionProcess));
for (const option of this.options) {
if (
typeof option.default !== 'undefined'
&& typeof option.default !== option.type_validation.string_type
) {
throw new Error (
`default does not match option type on ${option.name}`
);
}
this.properties[option.name] = option.type_validation.persistent_type;
}
const exit_on_interrupt
= typeof source_config.exit_on_interrupt === 'boolean'
? source_config.exit_on_interrupt
: false;
if (
typeof source_config.configs !== 'undefined'
&& Array.isArray (source_config.configs)
) {
this.sources.push (new ConfigSource (
source_config.configs,
source_config.error_callback
));
}
if (source_config.env !== false)
this.sources.push (new EnvSource (source_config.error_callback));
if (source_config.args !== false)
this.sources.push (new ArgSource (source_config.error_callback));
if (source_config.interactive !== false) {
this.sources.push (new InteractiveSource (
exit_on_interrupt,
source_config.error_callback
));
}
}
public async parse (): Promise<Record<string, unknown>> {
for (const src of this.sources) {
// eslint-disable-next-line no-await-in-loop
await src.parse (this.options);
}
for (const opt of this.options) {
if (!opt.filled) {
opt.value = opt.default;
opt.filled = true;
}
this.set (opt.name, opt.value);
}
return this.to_object ();
}
}

View File

@ -5,26 +5,31 @@
* Created by Timo Hocker <timo@scode.ovh>, May 2020 * Created by Timo Hocker <timo@scode.ovh>, May 2020
*/ */
import { TypeValidation } from './Types/TypeValidation'; interface SourceConfig {
import { OptionType } from './OptionType'; console?: boolean,
configs?: string[],
env?: boolean,
interactive?: boolean,
}
interface Option { interface Option {
name: string; name: string;
type: OptionType;
required?: boolean; required?: boolean;
default?: unknown; default?: unknown;
alias?: string; sources?: SourceConfig;
env?: string;
description?: string; /*
message?: string; * alias?: string;
preset?: unknown[]; * env?: string;
error?: string; * message?: string;
* preset?: unknown[];
* error?: string;
*/
} }
interface OptionProcess extends Option { interface OptionValue {
filled: boolean; filled: boolean;
value?: unknown; value?: unknown;
type_validation: TypeValidation;
} }
export { Option, OptionProcess }; export { Option, OptionValue };

View File

@ -1,16 +0,0 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of console-app which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
export type OptionType =
'string'
| 'number'
| 'boolean'
| 'file'
| 'folder'
| 'path'
| 'array';

View File

45
lib/Options/BaseOption.ts Normal file
View File

@ -0,0 +1,45 @@
import { OptionSource } from '../Sources/OptionSource';
import { Option } from '../Option';
import { EnvSource } from '../Sources/EnvSource';
import { ErrorCallback } from '../ErrorCallback';
import { ArgSource } from '../Sources/ArgSource';
import { ConfigSource } from '../Sources/ConfigSource';
import { TypeValidation } from '../TypeValidation/TypeValidation';
export abstract class BaseOption<T> {
protected readonly sources: OptionSource[] = [];
private _config: Option;
public constructor (
config: Option,
error_callback?: ErrorCallback,
exit_on_interrupt = true
) {
this._config = config;
const sources = config.sources || {};
if (typeof sources.configs !== 'undefined')
this.sources.push (new ConfigSource (sources.configs, error_callback));
if (sources.env !== false)
this.sources.push (new EnvSource (error_callback));
if (sources.console !== false)
this.sources.push (new ArgSource (error_callback));
if (sources.interactive !== false) {
this.sources.push (new InteractiveSource (
exit_on_interrupt,
error_callback
));
}
}
protected abstract get validation(): TypeValidation;
public async parse(): Promise<T> {
for (let source of this.sources) {
source.parse(this._config);
}
};
}

View File

View File

View File

View File

View File

View File

@ -0,0 +1,14 @@
import { Option } from '../Option';
import { BaseOption } from './BaseOption';
export class StringOption extends BaseOption<string> {
private _config: Option;
public constructor (config: Option) {
this._config = config;
}
public async parse (): Promise<string> {
}
}

View File

@ -11,7 +11,7 @@ import fs from 'fs-extra';
import { run_regex } from '@sapphirecode/utilities'; import { run_regex } from '@sapphirecode/utilities';
import hjson from 'hjson'; import hjson from 'hjson';
import { OptionProcess } from '../Option'; import { OptionProcess } from '../Option';
import { ErrorCallback } from '../Types/ErrorCallback'; import { ErrorCallback } from '../ErrorCallback';
import { OptionSource } from './OptionSource'; import { OptionSource } from './OptionSource';
export class ConfigSource extends OptionSource { export class ConfigSource extends OptionSource {

View File

@ -9,7 +9,7 @@
/* eslint-disable no-process-exit */ /* eslint-disable no-process-exit */
import { Confirm, Input, List, AutoComplete } from 'enquirer'; import { Confirm, Input, List, AutoComplete } from 'enquirer';
import { OptionProcess, Option } from '../Option'; import { OptionProcess, Option } from '../Option';
import { ErrorCallback } from '../Types/ErrorCallback'; import { ErrorCallback } from '../ErrorCallback';
import { OptionSource } from './OptionSource'; import { OptionSource } from './OptionSource';
export class InteractiveSource extends OptionSource { export class InteractiveSource extends OptionSource {

View File

@ -5,11 +5,11 @@
* Created by Timo Hocker <timo@scode.ovh>, May 2020 * Created by Timo Hocker <timo@scode.ovh>, May 2020
*/ */
import { OptionProcess } from '../Option'; import { ErrorCallback } from '../ErrorCallback';
import { ErrorCallback } from '../Types/ErrorCallback'; import { OptionValue, Option } from '../Option';
export abstract class OptionSource { export abstract class OptionSource {
public abstract async parse(opt: OptionProcess[]): Promise<void>; public abstract async parse(opt: Option, value: OptionValue): Promise<void>;
protected error_callback?: ErrorCallback; protected error_callback?: ErrorCallback;
@ -18,7 +18,7 @@ export abstract class OptionSource {
} }
protected async assign_arg ( protected async assign_arg (
opt: OptionProcess, opt: OptionValue,
value: unknown value: unknown
): Promise<void> { ): Promise<void> {
try { try {

12
lib/TypeRegister.ts Normal file
View File

@ -0,0 +1,12 @@
import { TypeValidation } from './TypeValidation/TypeValidation';
import { PathType } from './TypeValidation/PathType';
export const types: Record<OptionType, TypeValidation> = {
string: new TypeValidation ('string'),
number: new TypeValidation ('number'),
boolean: new TypeValidation ('boolean'),
file: new PathType ('file'),
folder: new PathType ('folder'),
path: new PathType ('path'),
array: new TypeValidation ('array')
};

View File

@ -6,7 +6,7 @@
*/ */
import test from 'ava'; import test from 'ava';
import { PathType } from '../lib/Types/PathType'; import { PathType } from '../lib/TypeValidation/PathType';
test ('no file', async (t) => { test ('no file', async (t) => {
const validator = new PathType ('file'); const validator = new PathType ('file');

View File

@ -6,7 +6,7 @@
*/ */
import test from 'ava'; import test from 'ava';
import { TypeValidation } from '../lib/Types/TypeValidation'; import { TypeValidation } from '../lib/TypeValidation/TypeValidation';
test ('string', async (t) => { test ('string', async (t) => {
const validator = new TypeValidation ('string'); const validator = new TypeValidation ('string');