starting to split options by type
This commit is contained in:
		| @@ -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 | ||||
|  */ | ||||
|  | ||||
| import { TypeValidation } from './Types/TypeValidation'; | ||||
| import { OptionType } from './OptionType'; | ||||
| interface SourceConfig { | ||||
|   console?: boolean, | ||||
|   configs?: string[], | ||||
|   env?: boolean, | ||||
|   interactive?: boolean, | ||||
| } | ||||
|  | ||||
| interface Option { | ||||
|   name: string; | ||||
|   type: OptionType; | ||||
|   required?: boolean; | ||||
|   default?: unknown; | ||||
|   alias?: string; | ||||
|   env?: string; | ||||
|   description?: string; | ||||
|   message?: string; | ||||
|   preset?: unknown[]; | ||||
|   error?: string; | ||||
|   sources?: SourceConfig; | ||||
|  | ||||
|   /* | ||||
|    * alias?: string; | ||||
|    * env?: string; | ||||
|    * message?: string; | ||||
|    * preset?: unknown[]; | ||||
|    * error?: string; | ||||
|    */ | ||||
| } | ||||
|  | ||||
| interface OptionProcess extends Option { | ||||
| interface OptionValue { | ||||
|   filled: boolean; | ||||
|   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 hjson from 'hjson'; | ||||
| import { OptionProcess } from '../Option'; | ||||
| import { ErrorCallback } from '../Types/ErrorCallback'; | ||||
| import { ErrorCallback } from '../ErrorCallback'; | ||||
| import { OptionSource } from './OptionSource'; | ||||
|  | ||||
| export class ConfigSource extends OptionSource { | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
| /* eslint-disable no-process-exit */ | ||||
| import { Confirm, Input, List, AutoComplete } from 'enquirer'; | ||||
| import { OptionProcess, Option } from '../Option'; | ||||
| import { ErrorCallback } from '../Types/ErrorCallback'; | ||||
| import { ErrorCallback } from '../ErrorCallback'; | ||||
| import { OptionSource } from './OptionSource'; | ||||
|  | ||||
| export class InteractiveSource extends OptionSource { | ||||
|   | ||||
| @@ -5,11 +5,11 @@ | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, May 2020 | ||||
|  */ | ||||
|  | ||||
| import { OptionProcess } from '../Option'; | ||||
| import { ErrorCallback } from '../Types/ErrorCallback'; | ||||
| import { ErrorCallback } from '../ErrorCallback'; | ||||
| import { OptionValue, Option } from '../Option'; | ||||
|  | ||||
| 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; | ||||
|  | ||||
| @@ -18,7 +18,7 @@ export abstract class OptionSource { | ||||
|   } | ||||
|  | ||||
|   protected async assign_arg ( | ||||
|     opt: OptionProcess, | ||||
|     opt: OptionValue, | ||||
|     value: unknown | ||||
|   ): Promise<void> { | ||||
|     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 { PathType } from '../lib/Types/PathType'; | ||||
| import { PathType } from '../lib/TypeValidation/PathType'; | ||||
|  | ||||
| test ('no file', async (t) => { | ||||
|   const validator = new PathType ('file'); | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
|  */ | ||||
|  | ||||
| import test from 'ava'; | ||||
| import { TypeValidation } from '../lib/Types/TypeValidation'; | ||||
| import { TypeValidation } from '../lib/TypeValidation/TypeValidation'; | ||||
|  | ||||
| test ('string', async (t) => { | ||||
|   const validator = new TypeValidation ('string'); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user