starting to split options by type
This commit is contained in:
parent
229b916cd5
commit
3f0b9fad79
@ -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 ();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 };
|
||||||
|
@ -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';
|
|
||||||
|
|
0
lib/Options/ArrayOption.ts
Normal file
0
lib/Options/ArrayOption.ts
Normal file
45
lib/Options/BaseOption.ts
Normal file
45
lib/Options/BaseOption.ts
Normal 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
0
lib/Options/BooleanOption.ts
Normal file
0
lib/Options/BooleanOption.ts
Normal file
0
lib/Options/FileOption.ts
Normal file
0
lib/Options/FileOption.ts
Normal file
0
lib/Options/FolderOption.ts
Normal file
0
lib/Options/FolderOption.ts
Normal file
0
lib/Options/NumberOption.ts
Normal file
0
lib/Options/NumberOption.ts
Normal file
0
lib/Options/PathOption.ts
Normal file
0
lib/Options/PathOption.ts
Normal file
14
lib/Options/StringOption.ts
Normal file
14
lib/Options/StringOption.ts
Normal 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> {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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
12
lib/TypeRegister.ts
Normal 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')
|
||||||
|
};
|
@ -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');
|
||||||
|
@ -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');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user