Compare commits
33 Commits
229b916cd5
...
master
Author | SHA1 | Date | |
---|---|---|---|
d9de76b188 | |||
b81b77b924 | |||
ee6be8317d | |||
390cc10305 | |||
e1507edd5d | |||
7268ed1643 | |||
04aa24a75d | |||
8eb8deb855 | |||
c0eb113036 | |||
6207de8e5b | |||
7521fb310c | |||
125fb7b5e6 | |||
8f040c38eb | |||
7ad999878a | |||
7395241329 | |||
ed2d0ba047 | |||
78c09809e6 | |||
85b02b552f | |||
3e178b28ae | |||
f5ee4665dc | |||
fe4057d0b5 | |||
551b5c89a7 | |||
5dcd54e451 | |||
d477124973 | |||
f7c03f82f1 | |||
089519844f | |||
bc960f632e | |||
88a35265d0 | |||
3fa23c1697 | |||
7574c250af | |||
021f55833d | |||
742d77d29f | |||
3f0b9fad79 |
14
.drone.yml
Normal file
14
.drone.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
kind: pipeline
|
||||||
|
name: default
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: setup
|
||||||
|
image: registry:5000/node-build
|
||||||
|
commands:
|
||||||
|
- yarn
|
||||||
|
- curl https://git.scode.ovh/Timo/standard/raw/branch/master/ci.js > ci.js
|
||||||
|
|
||||||
|
- name: build
|
||||||
|
image: registry:5000/node-build
|
||||||
|
commands:
|
||||||
|
- node ci.js
|
42
AppTest.js
42
AppTest.js
@ -7,23 +7,35 @@
|
|||||||
|
|
||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
|
/* eslint-disable id-match */
|
||||||
|
/* eslint-disable node/no-missing-require */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// eslint-disable-next-line node/no-missing-require, id-match
|
const {
|
||||||
const { InteractiveOptions } = require ('./dist/lib/index.js');
|
StringOption,
|
||||||
|
BooleanOption,
|
||||||
|
NumberOption,
|
||||||
|
ArrayOption,
|
||||||
|
FolderOption,
|
||||||
|
IntegerOption
|
||||||
|
} = require ('./dist/lib/index.js');
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const reader = new InteractiveOptions ([
|
const str = await new StringOption ({ name: 'str' })
|
||||||
{ name: 'str', type: 'string', env: 'TEST_STR' },
|
.parse ();
|
||||||
{ name: 'bool', type: 'boolean', env: 'TEST_BOOL' },
|
const bool = await new BooleanOption ({ name: 'bool' })
|
||||||
{ name: 'num', type: 'number', env: 'TEST_NUM' },
|
.parse ();
|
||||||
{ name: 'arr', type: 'array', env: 'TEST_ARR' },
|
const num = await new NumberOption ({ name: 'num' })
|
||||||
{ name: 'fld', type: 'folder', env: 'TEST_FOLDER' }
|
.parse ();
|
||||||
], {
|
const int = await new IntegerOption ({ name: 'num' })
|
||||||
exit_on_interrupt: true,
|
.parse ();
|
||||||
configs: [ 'test.json' ],
|
const arr = await new ArrayOption ({ name: 'arr' })
|
||||||
error_callback: console.log
|
.parse ();
|
||||||
});
|
const fld = await new FolderOption ({ name: 'fld' })
|
||||||
await reader.parse ();
|
.parse ();
|
||||||
console.log (reader.serialize (true));
|
|
||||||
|
const data = { str, bool, num, int, arr, fld };
|
||||||
|
|
||||||
|
console.log (data);
|
||||||
}) ();
|
}) ();
|
||||||
|
17
CHANGELOG.md
17
CHANGELOG.md
@ -1,5 +1,22 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
|
||||||
|
- Fix for NumberOption: do not cut off float values
|
||||||
|
- New type IntegerOption: only allows integer values
|
||||||
|
|
||||||
|
## 2.0.0
|
||||||
|
|
||||||
|
Restructuring to split different Option types and keep specific parameters separate
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
- new structure
|
||||||
|
- option 'required' has been removed
|
||||||
|
- automatic console parameters have been removed
|
||||||
|
- help page
|
||||||
|
- quiet switch (interactive prompts can be disabled using the sources option)
|
||||||
|
|
||||||
## 1.8.0
|
## 1.8.0
|
||||||
|
|
||||||
callback in case an option could not be assigned instead of silently skipping
|
callback in case an option could not be assigned instead of silently skipping
|
||||||
|
23
Jenkinsfile
vendored
23
Jenkinsfile
vendored
@ -1,23 +0,0 @@
|
|||||||
pipeline {
|
|
||||||
agent any
|
|
||||||
|
|
||||||
environment {
|
|
||||||
VERSION = VersionNumber([
|
|
||||||
versionNumberString:
|
|
||||||
'${BUILDS_ALL_TIME}',
|
|
||||||
versionPrefix: '1.8.',
|
|
||||||
worstResultForIncrement: 'SUCCESS'
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
stages {
|
|
||||||
stage('Building') {
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
currentBuild.displayName = env.VERSION
|
|
||||||
}
|
|
||||||
sh 'yarn ci ${VERSION}'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
81
README.md
81
README.md
@ -1,8 +1,8 @@
|
|||||||
# @sapphirecode/console-app
|
# @sapphirecode/console-app
|
||||||
|
|
||||||
version: 1.8.x
|
version: 2.1.x
|
||||||
|
|
||||||
read parameters from env, console args or interactively
|
read parameters from env, config files, console args or interactively
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@ -17,46 +17,37 @@ yarn:
|
|||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const {InteractiveOptions} = require('@sapphirecode/console-app');
|
const {
|
||||||
|
ArrayOption, // arrays made out of numbers, strings and booleans
|
||||||
|
BooleanOption,
|
||||||
|
FileOption, // paths that exist and are a file
|
||||||
|
FolderOption, // paths that exist and are a folder
|
||||||
|
NumberOption, // integer and float values
|
||||||
|
IntegerOption, // only integer values
|
||||||
|
PathOption, // paths that exist in the file system
|
||||||
|
StringOption,
|
||||||
|
} = require('@sapphirecode/console-app');
|
||||||
|
|
||||||
const reader = new InteractiveOptions([
|
const input = await new BooleanOption({
|
||||||
{
|
name: 'foo', // option name used in configs and console arguments
|
||||||
name: 'foo', // name of the option
|
|
||||||
type: 'boolean', // data type
|
// optional settings:
|
||||||
required: true, // require option to be specified (optional)
|
default: false, // default value
|
||||||
default: false, // default value (optional)
|
sources: {
|
||||||
alias: 'f', // shorthand alias in the console (optional)
|
configs: [], // config files to read from. none by default
|
||||||
env: 'fooenv', // environment variable to read from (optional)
|
interactive: true, // use interactive prompts
|
||||||
description: 'the switch foo', // description in the help page (optional)
|
console: true // read from console arguments
|
||||||
message: 'should foo be true?', // message when asking interactively (optional)
|
// environment is always on if the 'env' option below is specified
|
||||||
preset: [], // preset choices for string and path types (optional)
|
|
||||||
error: 'wrong input' // message to display when the user gives invalid input
|
|
||||||
},
|
},
|
||||||
]);
|
alias: 'f', // shorthand console argument name
|
||||||
|
env: 'foo_env', // name of the environment variable to read from
|
||||||
const result = await reader.parse();
|
message: 'input foo', // message to display in interactive prompt
|
||||||
console.log(result.foo);
|
error: 'failed to read foo', // message to display when input was invalid
|
||||||
|
error_callback: (opt, val, err)=>{...}, // function to call when an option value could not be read
|
||||||
|
exit_on_interrupt: true, // exit program when user cancels the interactive prompt
|
||||||
|
}).parse();
|
||||||
```
|
```
|
||||||
|
|
||||||
available data types:
|
|
||||||
|
|
||||||
- string
|
|
||||||
- number
|
|
||||||
- boolean
|
|
||||||
- path: expects a path that exists
|
|
||||||
- file: expects a path that exists and is a file
|
|
||||||
- folder: expects a path that exists and is a folder
|
|
||||||
- array: arrays made out of strings, numbers and booleans
|
|
||||||
|
|
||||||
the console reader automatically adds the options --help (-h) and --quiet (-q)
|
|
||||||
|
|
||||||
- help: shows the yargs help screen
|
|
||||||
- quiet: prevents interactive queries and throws an error when not all required
|
|
||||||
parameters are specified
|
|
||||||
|
|
||||||
the reader can also be constructed with additional options that specify which
|
|
||||||
sources should be used. It reads from all, except config files by default
|
|
||||||
|
|
||||||
config files can import other config files with #include. example:
|
config files can import other config files with #include. example:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@ -68,20 +59,6 @@ config files can import other config files with #include. example:
|
|||||||
|
|
||||||
config files are parsed using [hjson](https://github.com/hjson/hjson-js)
|
config files are parsed using [hjson](https://github.com/hjson/hjson-js)
|
||||||
|
|
||||||
the option exit_on_interrupt determines whether an error should be thrown or the
|
|
||||||
process should exit when the user presses control + c in an interactive prompt.
|
|
||||||
|
|
||||||
```js
|
|
||||||
const reader = new InteractiveOptions([], {
|
|
||||||
args: true,
|
|
||||||
env: true,
|
|
||||||
interactive: true,
|
|
||||||
configs: ['json files to search for options'],
|
|
||||||
exit_on_interrupt: true, // exit when user cancels prompt
|
|
||||||
error_callback: (opt, val, err)=>{...} // function to call when an option value could not be read
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT © Timo Hocker <timo@scode.ovh>
|
MIT © Timo Hocker <timo@scode.ovh>
|
||||||
|
14
jasmine.json
Normal file
14
jasmine.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
{
|
||||||
|
"spec_dir": "test",
|
||||||
|
"spec_files": [
|
||||||
|
"spec/*.js",
|
||||||
|
"spec/*.ts"
|
||||||
|
],
|
||||||
|
"helpers": [
|
||||||
|
"helpers/*.js",
|
||||||
|
"helpers/*.ts"
|
||||||
|
],
|
||||||
|
"stopSpecOnExpectationFailure": false,
|
||||||
|
"random": false
|
||||||
|
}
|
29
jenkins.js
29
jenkins.js
@ -1,29 +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
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const https = require ('https');
|
|
||||||
const fs = require ('fs');
|
|
||||||
const { execSync: exec_sync } = require ('child_process');
|
|
||||||
|
|
||||||
const run_file = fs.createWriteStream ('.jenkins.run.js');
|
|
||||||
|
|
||||||
const [
|
|
||||||
,, ...args
|
|
||||||
] = process.argv;
|
|
||||||
|
|
||||||
run_file.on ('close', () => {
|
|
||||||
exec_sync (`node .jenkins.run.js ${args.join (' ')}`, { stdio: 'inherit' });
|
|
||||||
});
|
|
||||||
|
|
||||||
https.get (
|
|
||||||
'https://git.scode.ovh/Timo/standard/raw/branch/master/jenkins.run.js',
|
|
||||||
(msg) => {
|
|
||||||
msg.pipe (run_file);
|
|
||||||
}
|
|
||||||
);
|
|
12
lib/ErrorCallback.ts
Normal file
12
lib/ErrorCallback.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type ErrorCallback = (
|
||||||
|
option: string,
|
||||||
|
value: unknown,
|
||||||
|
e: Error
|
||||||
|
) => unknown;
|
@ -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,49 @@
|
|||||||
* Created by Timo Hocker <timo@scode.ovh>, May 2020
|
* Created by Timo Hocker <timo@scode.ovh>, May 2020
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { TypeValidation } from './Types/TypeValidation';
|
import { TypeValidation } from './TypeValidation/TypeValidation';
|
||||||
import { OptionType } from './OptionType';
|
import { ErrorCallback } from './ErrorCallback';
|
||||||
|
|
||||||
|
interface SourceConfig {
|
||||||
|
console?: boolean,
|
||||||
|
configs?: string[],
|
||||||
|
interactive?: boolean,
|
||||||
|
}
|
||||||
|
|
||||||
interface Option {
|
interface Option {
|
||||||
name: string;
|
name: string;
|
||||||
type: OptionType;
|
|
||||||
required?: boolean;
|
|
||||||
default?: unknown;
|
default?: unknown;
|
||||||
|
sources?: SourceConfig;
|
||||||
alias?: string;
|
alias?: string;
|
||||||
env?: string;
|
env?: string;
|
||||||
description?: string;
|
|
||||||
message?: string;
|
message?: string;
|
||||||
preset?: unknown[];
|
|
||||||
error?: string;
|
error?: string;
|
||||||
|
error_callback?: ErrorCallback;
|
||||||
|
exit_on_interrupt?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OptionProcess extends Option {
|
class OptionValue {
|
||||||
filled: boolean;
|
public filled = false;
|
||||||
value?: unknown;
|
public value?: unknown;
|
||||||
type_validation: TypeValidation;
|
public readonly type_validation: TypeValidation;
|
||||||
|
|
||||||
|
public constructor (type_validation: TypeValidation) {
|
||||||
|
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, OptionProcess };
|
export { Option, OptionValue };
|
||||||
|
@ -8,9 +8,9 @@
|
|||||||
export type OptionType =
|
export type OptionType =
|
||||||
'string'
|
'string'
|
||||||
| 'number'
|
| 'number'
|
||||||
|
| 'int'
|
||||||
| 'boolean'
|
| 'boolean'
|
||||||
| 'file'
|
| 'file'
|
||||||
| 'folder'
|
| 'folder'
|
||||||
| 'path'
|
| 'path'
|
||||||
| 'array';
|
| 'array';
|
||||||
|
|
||||||
|
15
lib/Options/ArrayOption.ts
Normal file
15
lib/Options/ArrayOption.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { TypeValidation } from '../TypeValidation/TypeValidation';
|
||||||
|
import { BaseOption } from './BaseOption';
|
||||||
|
|
||||||
|
export class ArrayOption extends BaseOption<(string|number|boolean)[]> {
|
||||||
|
protected get validation ():TypeValidation {
|
||||||
|
return new TypeValidation ('array');
|
||||||
|
}
|
||||||
|
}
|
61
lib/Options/BaseOption.ts
Normal file
61
lib/Options/BaseOption.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { OptionSource } from '../Sources/OptionSource';
|
||||||
|
import { Option, OptionValue } from '../Option';
|
||||||
|
import { EnvSource } from '../Sources/EnvSource';
|
||||||
|
import { ArgSource } from '../Sources/ArgSource';
|
||||||
|
import { ConfigSource } from '../Sources/ConfigSource';
|
||||||
|
import { TypeValidation } from '../TypeValidation/TypeValidation';
|
||||||
|
import { InteractiveSource } from '../Sources/InteractiveSource';
|
||||||
|
|
||||||
|
export abstract class BaseOption<T> {
|
||||||
|
protected readonly sources: OptionSource[] = [];
|
||||||
|
private _config: Option;
|
||||||
|
|
||||||
|
public constructor (
|
||||||
|
config: Option
|
||||||
|
) {
|
||||||
|
this._config = config;
|
||||||
|
|
||||||
|
const sources = config.sources || {};
|
||||||
|
const exit_on_interrupt = config.exit_on_interrupt !== false;
|
||||||
|
|
||||||
|
if (typeof sources.configs !== 'undefined') {
|
||||||
|
this.sources.push (new ConfigSource (
|
||||||
|
sources.configs,
|
||||||
|
config.error_callback
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sources.push (new EnvSource (config.error_callback));
|
||||||
|
|
||||||
|
if (sources.console !== false)
|
||||||
|
this.sources.push (new ArgSource (config.error_callback));
|
||||||
|
|
||||||
|
if (sources.interactive !== false) {
|
||||||
|
this.sources.push (new InteractiveSource (
|
||||||
|
exit_on_interrupt,
|
||||||
|
config.error_callback
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract get validation(): TypeValidation;
|
||||||
|
|
||||||
|
public async parse (): Promise<T> {
|
||||||
|
const val = new OptionValue (this.validation);
|
||||||
|
|
||||||
|
for (const source of this.sources)
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
await source.parse (this._config, val);
|
||||||
|
|
||||||
|
if (!val.filled)
|
||||||
|
return this._config.default as T;
|
||||||
|
return val.value as T;
|
||||||
|
}
|
||||||
|
}
|
15
lib/Options/BooleanOption.ts
Normal file
15
lib/Options/BooleanOption.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { TypeValidation } from '../TypeValidation/TypeValidation';
|
||||||
|
import { BaseOption } from './BaseOption';
|
||||||
|
|
||||||
|
export class BooleanOption extends BaseOption<boolean> {
|
||||||
|
protected get validation ():TypeValidation {
|
||||||
|
return new TypeValidation ('boolean');
|
||||||
|
}
|
||||||
|
}
|
16
lib/Options/FileOption.ts
Normal file
16
lib/Options/FileOption.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { PathType } from '../TypeValidation/PathType';
|
||||||
|
import { TypeValidation } from '../TypeValidation/TypeValidation';
|
||||||
|
import { StringOption } from './StringOption';
|
||||||
|
|
||||||
|
export class FileOption extends StringOption {
|
||||||
|
protected get validation ():TypeValidation {
|
||||||
|
return new PathType ('file');
|
||||||
|
}
|
||||||
|
}
|
16
lib/Options/FolderOption.ts
Normal file
16
lib/Options/FolderOption.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { PathType } from '../TypeValidation/PathType';
|
||||||
|
import { TypeValidation } from '../TypeValidation/TypeValidation';
|
||||||
|
import { StringOption } from './StringOption';
|
||||||
|
|
||||||
|
export class FolderOption extends StringOption {
|
||||||
|
protected get validation (): TypeValidation {
|
||||||
|
return new PathType ('folder');
|
||||||
|
}
|
||||||
|
}
|
15
lib/Options/IntegerOption.ts
Normal file
15
lib/Options/IntegerOption.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { TypeValidation } from '../TypeValidation/TypeValidation';
|
||||||
|
import { BaseOption } from './BaseOption';
|
||||||
|
|
||||||
|
export class IntegerOption extends BaseOption<number> {
|
||||||
|
protected get validation ():TypeValidation {
|
||||||
|
return new TypeValidation ('int');
|
||||||
|
}
|
||||||
|
}
|
15
lib/Options/NumberOption.ts
Normal file
15
lib/Options/NumberOption.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { TypeValidation } from '../TypeValidation/TypeValidation';
|
||||||
|
import { BaseOption } from './BaseOption';
|
||||||
|
|
||||||
|
export class NumberOption extends BaseOption<number> {
|
||||||
|
protected get validation ():TypeValidation {
|
||||||
|
return new TypeValidation ('number');
|
||||||
|
}
|
||||||
|
}
|
16
lib/Options/PathOption.ts
Normal file
16
lib/Options/PathOption.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { PathType } from '../TypeValidation/PathType';
|
||||||
|
import { TypeValidation } from '../TypeValidation/TypeValidation';
|
||||||
|
import { StringOption } from './StringOption';
|
||||||
|
|
||||||
|
export class PathOption extends StringOption {
|
||||||
|
protected get validation (): TypeValidation {
|
||||||
|
return new PathType ('path');
|
||||||
|
}
|
||||||
|
}
|
21
lib/Options/StringOption.ts
Normal file
21
lib/Options/StringOption.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { TypeValidation } from '../TypeValidation/TypeValidation';
|
||||||
|
import { StringOptionConfig } from '../SubConfigs';
|
||||||
|
import { BaseOption } from './BaseOption';
|
||||||
|
|
||||||
|
export class StringOption extends BaseOption<string> {
|
||||||
|
protected get validation ():TypeValidation {
|
||||||
|
return new TypeValidation ('string');
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-useless-constructor
|
||||||
|
public constructor (config: StringOptionConfig) {
|
||||||
|
super (config);
|
||||||
|
}
|
||||||
|
}
|
@ -8,68 +8,43 @@
|
|||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
/* eslint-disable no-process-exit */
|
/* eslint-disable no-process-exit */
|
||||||
import yargs, { Options } from 'yargs';
|
import yargs, { Options } from 'yargs';
|
||||||
import { OptionProcess } from '../Option';
|
import { Option, OptionValue } from '../Option';
|
||||||
import { OptionSource } from './OptionSource';
|
import { OptionSource } from './OptionSource';
|
||||||
|
|
||||||
export class ArgSource extends OptionSource {
|
export class ArgSource extends OptionSource {
|
||||||
private create_config (options: OptionProcess[]): Record<string, Options> {
|
private create_config (
|
||||||
const yargs_config: Record<string, Options> = {
|
config: Option,
|
||||||
quiet: {
|
persistent_type: string
|
||||||
alias: 'q',
|
): Record<string, Options> {
|
||||||
default: false,
|
return {
|
||||||
type: 'boolean',
|
[config.name]: {
|
||||||
describe: 'do not ask for options interactively'
|
alias: config.alias,
|
||||||
},
|
|
||||||
help: {
|
|
||||||
alias: 'h',
|
|
||||||
default: false,
|
|
||||||
type: 'boolean',
|
|
||||||
describe: ''
|
|
||||||
}
|
|
||||||
};
|
|
||||||
for (const opt of options) {
|
|
||||||
const type = opt.type_validation.persistent_type;
|
|
||||||
yargs_config[opt.name] = {
|
|
||||||
alias: opt.alias,
|
|
||||||
// eslint-disable-next-line no-undefined
|
// eslint-disable-next-line no-undefined
|
||||||
default: type === 'boolean' ? undefined : opt.default,
|
default: undefined,
|
||||||
type,
|
type: persistent_type
|
||||||
describe: opt.description
|
}
|
||||||
};
|
} as Record<string, Options>;
|
||||||
}
|
|
||||||
return yargs_config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async parse (options: OptionProcess[]): Promise<void> {
|
public async parse (opt: Option, val: OptionValue): Promise<void> {
|
||||||
const yargs_config = this.create_config (options);
|
const yargs_config = this.create_config (
|
||||||
|
opt,
|
||||||
|
val.type_validation.persistent_type
|
||||||
|
);
|
||||||
|
|
||||||
const argv = yargs.options (yargs_config)
|
const argv = yargs.options (yargs_config)
|
||||||
.parse ();
|
.parse ();
|
||||||
if (argv.help) {
|
|
||||||
yargs.options (yargs_config)
|
|
||||||
.showHelp ();
|
|
||||||
process.exit (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.all (options.map ((opt) => {
|
if (typeof argv[opt.name] === 'undefined')
|
||||||
if (typeof argv[opt.name] === 'undefined')
|
return;
|
||||||
return Promise.resolve ();
|
|
||||||
if (
|
if (
|
||||||
opt.type === 'array'
|
val.type_validation.option_type === 'array'
|
||||||
&& (argv[opt.name] as Array<unknown>)
|
&& (argv[opt.name] as Array<unknown>)
|
||||||
.filter ((v) => typeof v !== 'undefined').length <= 0
|
.filter ((v) => typeof v !== 'undefined').length <= 0
|
||||||
)
|
)
|
||||||
return Promise.resolve ();
|
return;
|
||||||
return this.assign_arg (opt, argv[opt.name]);
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (argv.quiet) {
|
await val.assign_arg (opt, argv[opt.name]);
|
||||||
const missing = options.filter ((o) => !o.filled && o.required)
|
|
||||||
.map ((o) => o.name);
|
|
||||||
if (missing.length > 0) {
|
|
||||||
console.error ('missing arguments:');
|
|
||||||
console.error (missing.join (', '));
|
|
||||||
process.exit (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,8 @@ import { dirname, join } from 'path';
|
|||||||
import fs from 'fs-extra';
|
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 { OptionValue, Option } 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 {
|
||||||
@ -46,7 +46,7 @@ export class ConfigSource extends OptionSource {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async parse (options: OptionProcess[]): Promise<void> {
|
public async parse (opt: Option, val: OptionValue): Promise<void> {
|
||||||
const data: Record<string, unknown> = {};
|
const data: Record<string, unknown> = {};
|
||||||
for (const f of this._config_files) {
|
for (const f of this._config_files) {
|
||||||
try {
|
try {
|
||||||
@ -63,9 +63,7 @@ export class ConfigSource extends OptionSource {
|
|||||||
|
|
||||||
const keys = Object.keys (data);
|
const keys = Object.keys (data);
|
||||||
|
|
||||||
for (const opt of options) {
|
if (keys.includes (opt.name))
|
||||||
if (keys.includes (opt.name))
|
await val.assign_arg (opt, data[opt.name]);
|
||||||
await this.assign_arg (opt, data[opt.name]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,18 +6,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable no-process-env */
|
/* eslint-disable no-process-env */
|
||||||
import { OptionProcess } from '../Option';
|
import { Option, OptionValue } from '../Option';
|
||||||
import { OptionSource } from './OptionSource';
|
import { OptionSource } from './OptionSource';
|
||||||
|
|
||||||
export class EnvSource extends OptionSource {
|
export class EnvSource extends OptionSource {
|
||||||
public async parse (options: OptionProcess[]): Promise<void> {
|
public async parse (opt: Option, val:OptionValue): Promise<void> {
|
||||||
await Promise.all (options.map ((opt) => {
|
if (typeof opt.env === 'undefined')
|
||||||
if (
|
return;
|
||||||
typeof opt.env !== 'undefined'
|
|
||||||
&& typeof process.env[opt.env] !== 'undefined'
|
if (typeof process.env[opt.env] === 'undefined') {
|
||||||
)
|
if (typeof this.error_callback !== 'undefined') {
|
||||||
return this.assign_arg (opt, process.env[opt.env]);
|
this.error_callback (
|
||||||
return Promise.resolve ();
|
opt.name,
|
||||||
}));
|
null,
|
||||||
|
new Error ('environment variable does not exist')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await val.assign_arg (opt, process.env[opt.env]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
lib/Sources/Interactive/ArraySubSource.ts
Normal file
26
lib/Sources/Interactive/ArraySubSource.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 ()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
26
lib/Sources/Interactive/BooleanSubSource.ts
Normal file
26
lib/Sources/Interactive/BooleanSubSource.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 ()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
38
lib/Sources/Interactive/InteractiveSubSource.ts
Normal file
38
lib/Sources/Interactive/InteractiveSubSource.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<boolean> {
|
||||||
|
if (this.condition ()) {
|
||||||
|
await this.run ();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected get_message (): string {
|
||||||
|
return typeof this.opt.message === 'undefined'
|
||||||
|
? `input ${this.opt.name}`
|
||||||
|
: this.opt.message;
|
||||||
|
}
|
||||||
|
}
|
26
lib/Sources/Interactive/NumberSubSource.ts
Normal file
26
lib/Sources/Interactive/NumberSubSource.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { NumberPrompt } from 'enquirer';
|
||||||
|
import { InteractiveSubSource } from './InteractiveSubSource';
|
||||||
|
|
||||||
|
export class NumberSubSource extends InteractiveSubSource {
|
||||||
|
protected condition ():boolean {
|
||||||
|
return this.val.type_validation.option_type === 'number';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async run ():Promise<void> {
|
||||||
|
await this.val.assign_arg (
|
||||||
|
this.opt,
|
||||||
|
await new NumberPrompt ({
|
||||||
|
message: this.get_message (),
|
||||||
|
default: this.opt.default
|
||||||
|
})
|
||||||
|
.run ()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
29
lib/Sources/Interactive/PresetSubSource.ts
Normal file
29
lib/Sources/Interactive/PresetSubSource.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { AutoComplete } from 'enquirer';
|
||||||
|
import { StringOptionConfig } from '../../SubConfigs';
|
||||||
|
import { InteractiveSubSource } from './InteractiveSubSource';
|
||||||
|
|
||||||
|
export class PresetSubSource extends InteractiveSubSource {
|
||||||
|
protected condition ():boolean {
|
||||||
|
return 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 ()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
26
lib/Sources/Interactive/StringSubSource.ts
Normal file
26
lib/Sources/Interactive/StringSubSource.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Input } from 'enquirer';
|
||||||
|
import { InteractiveSubSource } from './InteractiveSubSource';
|
||||||
|
|
||||||
|
export class StringSubSource extends InteractiveSubSource {
|
||||||
|
protected condition ():boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async run ():Promise<void> {
|
||||||
|
await this.val.assign_arg (
|
||||||
|
this.opt,
|
||||||
|
await new Input ({
|
||||||
|
message: this.get_message (),
|
||||||
|
default: this.opt.default
|
||||||
|
})
|
||||||
|
.run ()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
20
lib/Sources/Interactive/index.ts
Normal file
20
lib/Sources/Interactive/index.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ArraySubSource } from './ArraySubSource';
|
||||||
|
import { BooleanSubSource } from './BooleanSubSource';
|
||||||
|
import { PresetSubSource } from './PresetSubSource';
|
||||||
|
import { StringSubSource } from './StringSubSource';
|
||||||
|
import { NumberSubSource } from './NumberSubSource';
|
||||||
|
|
||||||
|
export const sources = [
|
||||||
|
ArraySubSource,
|
||||||
|
BooleanSubSource,
|
||||||
|
PresetSubSource,
|
||||||
|
NumberSubSource,
|
||||||
|
StringSubSource
|
||||||
|
];
|
@ -7,10 +7,10 @@
|
|||||||
|
|
||||||
/* 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 { OptionProcess, Option } from '../Option';
|
import { Option, OptionValue } from '../Option';
|
||||||
import { ErrorCallback } from '../Types/ErrorCallback';
|
|
||||||
import { OptionSource } from './OptionSource';
|
import { OptionSource } from './OptionSource';
|
||||||
|
import { sources } from './Interactive';
|
||||||
|
|
||||||
export class InteractiveSource extends OptionSource {
|
export class InteractiveSource extends OptionSource {
|
||||||
private _exit_on_interrupt: boolean;
|
private _exit_on_interrupt: boolean;
|
||||||
@ -23,75 +23,29 @@ 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 {
|
private async prompt (opt: Option, val:OptionValue): Promise<void> {
|
||||||
return typeof opt.message === 'undefined'
|
if (val.filled)
|
||||||
? `input ${opt.name}`
|
|
||||||
: opt.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async prompt (opt: OptionProcess): Promise<void> {
|
|
||||||
if (opt.filled)
|
|
||||||
return;
|
|
||||||
let value = null;
|
|
||||||
if (
|
|
||||||
opt.type === 'string'
|
|
||||||
|| opt.type === 'file'
|
|
||||||
|| opt.type === 'folder'
|
|
||||||
|| opt.type === 'path'
|
|
||||||
|| opt.type === 'number'
|
|
||||||
) {
|
|
||||||
if (typeof opt.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: opt.preset,
|
|
||||||
limit: 10
|
|
||||||
})
|
|
||||||
.run ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
opt.type === 'boolean'
|
|
||||||
) {
|
|
||||||
value = await new Confirm ({
|
|
||||||
message: this.get_message (opt),
|
|
||||||
default: opt.default
|
|
||||||
})
|
|
||||||
.run ();
|
|
||||||
}
|
|
||||||
if (opt.type === 'array') {
|
|
||||||
value = await new List ({
|
|
||||||
message: this.get_message (opt),
|
|
||||||
default: opt.default
|
|
||||||
})
|
|
||||||
.run ();
|
|
||||||
}
|
|
||||||
if (value === null)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await this.assign_arg (opt, value);
|
for (const src of sources) {
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
if (await new src (val, opt)
|
||||||
|
.parse ())
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async parse (options: OptionProcess[]): Promise<void> {
|
public async parse (opt: Option, val:OptionValue): Promise<void> {
|
||||||
for (const opt of options) {
|
while (!val.filled) {
|
||||||
while (!opt.filled) {
|
// eslint-disable-next-line no-await-in-loop
|
||||||
// eslint-disable-next-line no-await-in-loop
|
await this.prompt (opt, val)
|
||||||
await this.prompt (opt)
|
.catch ((e) => {
|
||||||
.catch ((e) => {
|
if (this._exit_on_interrupt)
|
||||||
if (this._exit_on_interrupt)
|
process.exit (0);
|
||||||
process.exit (0);
|
throw e;
|
||||||
throw e;
|
});
|
||||||
});
|
if (!val.filled)
|
||||||
if (!opt.filled)
|
console.log (opt.error || 'input was invalid');
|
||||||
console.log (opt.error || 'input was invalid');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,29 +5,15 @@
|
|||||||
* 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;
|
||||||
|
|
||||||
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: OptionProcess,
|
|
||||||
value: unknown
|
|
||||||
): Promise<void> {
|
|
||||||
try {
|
|
||||||
opt.value = await opt.type_validation.to_type (value);
|
|
||||||
opt.filled = true;
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
if (typeof this.error_callback !== 'undefined')
|
|
||||||
this.error_callback (opt.name, value, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
14
lib/SubConfigs.ts
Normal file
14
lib/SubConfigs.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Option } from './Option';
|
||||||
|
|
||||||
|
interface StringOptionConfig extends Option {
|
||||||
|
preset?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export { StringOptionConfig };
|
@ -20,14 +20,17 @@ export class PathType extends TypeValidation {
|
|||||||
public async to_type (value: unknown): Promise<unknown> {
|
public async to_type (value: unknown): Promise<unknown> {
|
||||||
if (typeof value !== 'string')
|
if (typeof value !== 'string')
|
||||||
throw new Error (`invalid type for ${this.option_type}`);
|
throw new Error (`invalid type for ${this.option_type}`);
|
||||||
if (!await fs.pathExists (value))
|
|
||||||
|
const escaped = value.replace (/\\$/u, '')
|
||||||
|
.replace (/"$/u, '');
|
||||||
|
if (!await fs.pathExists (escaped))
|
||||||
throw new Error ('path does not exist');
|
throw new Error ('path does not exist');
|
||||||
if (this.option_type === 'path')
|
if (this.option_type === 'path')
|
||||||
return value;
|
return escaped;
|
||||||
|
|
||||||
const stat = await fs.stat (value);
|
const stat = await fs.stat (escaped);
|
||||||
if (stat.isDirectory () === (this.option_type === 'folder'))
|
if (stat.isDirectory () === (this.option_type === 'folder'))
|
||||||
return value;
|
return escaped;
|
||||||
|
|
||||||
throw new Error ('cannot assign folder to file');
|
throw new Error ('cannot assign folder to file');
|
||||||
}
|
}
|
@ -40,6 +40,13 @@ export class TypeValidation {
|
|||||||
return Promise.resolve (String (value));
|
return Promise.resolve (String (value));
|
||||||
|
|
||||||
if (this.option_type === 'number') {
|
if (this.option_type === 'number') {
|
||||||
|
const as_num = parseFloat (String (value));
|
||||||
|
if (isNaN (as_num))
|
||||||
|
throw new Error ('value is not a number');
|
||||||
|
return Promise.resolve (as_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.option_type === 'int') {
|
||||||
const as_num = parseInt (String (value));
|
const as_num = parseInt (String (value));
|
||||||
if (isNaN (as_num))
|
if (isNaN (as_num))
|
||||||
throw new Error ('value is not a number');
|
throw new Error ('value is not a number');
|
@ -1,5 +0,0 @@
|
|||||||
export type ErrorCallback = (
|
|
||||||
option: string,
|
|
||||||
value: unknown,
|
|
||||||
e: Error
|
|
||||||
) => unknown;
|
|
@ -5,4 +5,11 @@
|
|||||||
* Created by Timo Hocker <timo@scode.ovh>, May 2020
|
* Created by Timo Hocker <timo@scode.ovh>, May 2020
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export { InteractiveOptions } from './InteractiveOptions';
|
export { ArrayOption } from './Options/ArrayOption';
|
||||||
|
export { BooleanOption } from './Options/BooleanOption';
|
||||||
|
export { FileOption } from './Options/FileOption';
|
||||||
|
export { FolderOption } from './Options/FolderOption';
|
||||||
|
export { NumberOption } from './Options/NumberOption';
|
||||||
|
export { PathOption } from './Options/PathOption';
|
||||||
|
export { StringOption } from './Options/StringOption';
|
||||||
|
export { IntegerOption } from './Options/IntegerOption';
|
||||||
|
35
package.json
35
package.json
@ -1,30 +1,35 @@
|
|||||||
{
|
{
|
||||||
"name": "@sapphirecode/console-app",
|
"name": "@sapphirecode/console-app",
|
||||||
"version": "1.0.0",
|
"version": "2.1.7",
|
||||||
"main": "dist/lib/index.js",
|
"main": "dist/lib/index.js",
|
||||||
"author": "Timo Hocker <timo@scode.ovh>",
|
"author": {
|
||||||
|
"name": "Timo Hocker",
|
||||||
|
"email": "timo@scode.ovh"
|
||||||
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git@git.scode.ovh:timo/console-app"
|
"url": "https://git.scode.ovh:timo/console-app.git"
|
||||||
},
|
},
|
||||||
"description": "read parameters from env, console args or interactively",
|
"bugs": "https://redmine.scode.ovh/projects/console-app",
|
||||||
|
"description": "read parameters from env, config files, console args or interactively",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ava/typescript": "^1.1.1",
|
|
||||||
"@sapphirecode/eslint-config-ts": "^1.1.4",
|
"@sapphirecode/eslint-config-ts": "^1.1.4",
|
||||||
"@types/fs-extra": "^9.0.0",
|
"@types/fs-extra": "^9.0.0",
|
||||||
"@types/hjson": "^2.4.1",
|
"@types/hjson": "^2.4.1",
|
||||||
|
"@types/jasmine": "^3.5.14",
|
||||||
"@types/yargs": "^15.0.5",
|
"@types/yargs": "^15.0.5",
|
||||||
"ava": "^3.8.2",
|
|
||||||
"eslint": "^7.0.0",
|
"eslint": "^7.0.0",
|
||||||
|
"jasmine": "^3.6.1",
|
||||||
|
"jasmine-ts": "^0.3.0",
|
||||||
"nyc": "^15.0.1",
|
"nyc": "^15.0.1",
|
||||||
"typescript": "^3.9.2"
|
"ts-node": "^9.0.0",
|
||||||
|
"typescript": "^4.0.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx,.vue,.mjs",
|
"lint": "eslint . --ext .js,.jsx,.ts,.tsx,.vue,.mjs",
|
||||||
"test": "tsc && nyc ava",
|
"test": "nyc jasmine-ts --config=\"jasmine.json\"",
|
||||||
"compile": "tsc",
|
"compile": "tsc"
|
||||||
"ci": "yarn && node jenkins.js"
|
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"LICENSE",
|
"LICENSE",
|
||||||
@ -38,5 +43,13 @@
|
|||||||
"fs-extra": "^9.0.0",
|
"fs-extra": "^9.0.0",
|
||||||
"hjson": "^3.2.1",
|
"hjson": "^3.2.1",
|
||||||
"yargs": "^15.3.1"
|
"yargs": "^15.3.1"
|
||||||
}
|
},
|
||||||
|
"keywords": [
|
||||||
|
"interactive",
|
||||||
|
"console input",
|
||||||
|
"config",
|
||||||
|
"command line args",
|
||||||
|
"environment variables",
|
||||||
|
"parsing"
|
||||||
|
]
|
||||||
}
|
}
|
@ -1,46 +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 test from 'ava';
|
|
||||||
import { PathType } from '../lib/Types/PathType';
|
|
||||||
|
|
||||||
test ('no file', async (t) => {
|
|
||||||
const validator = new PathType ('file');
|
|
||||||
await t.throwsAsync (
|
|
||||||
() => validator.to_type ('test'),
|
|
||||||
{ message: 'cannot assign folder to file' }
|
|
||||||
);
|
|
||||||
});
|
|
||||||
test ('file', async (t) => {
|
|
||||||
const validator = new PathType ('file');
|
|
||||||
const res = await validator.to_type ('package.json');
|
|
||||||
t.is (res, 'package.json');
|
|
||||||
});
|
|
||||||
test ('no folder', async (t) => {
|
|
||||||
const validator = new PathType ('folder');
|
|
||||||
await t.throwsAsync (
|
|
||||||
() => validator.to_type ('package.json'),
|
|
||||||
{ message: 'cannot assign folder to file' }
|
|
||||||
);
|
|
||||||
});
|
|
||||||
test ('folder', async (t) => {
|
|
||||||
const validator = new PathType ('folder');
|
|
||||||
const res = await validator.to_type ('test');
|
|
||||||
t.is (res, 'test');
|
|
||||||
});
|
|
||||||
test ('no path', async (t) => {
|
|
||||||
const validator = new PathType ('path');
|
|
||||||
await t.throwsAsync (
|
|
||||||
() => validator.to_type ('doesnotexist.file'),
|
|
||||||
{ message: 'path does not exist' }
|
|
||||||
);
|
|
||||||
});
|
|
||||||
test ('path', async (t) => {
|
|
||||||
const validator = new PathType ('path');
|
|
||||||
const res = await validator.to_type ('test');
|
|
||||||
t.is (res, 'test');
|
|
||||||
});
|
|
@ -1,85 +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 test from 'ava';
|
|
||||||
import { TypeValidation } from '../lib/Types/TypeValidation';
|
|
||||||
|
|
||||||
test ('string', async (t) => {
|
|
||||||
const validator = new TypeValidation ('string');
|
|
||||||
const res = await validator.to_type ('foo');
|
|
||||||
t.is (res, 'foo');
|
|
||||||
});
|
|
||||||
|
|
||||||
test ('no number', (t) => {
|
|
||||||
const validator = new TypeValidation ('number');
|
|
||||||
t.throws (
|
|
||||||
() => validator.to_type ('foo'),
|
|
||||||
{ message: 'value is not a number' }
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test ('number', async (t) => {
|
|
||||||
const validator = new TypeValidation ('number');
|
|
||||||
const res = await validator.to_type ('123');
|
|
||||||
t.is (res, 123);
|
|
||||||
});
|
|
||||||
|
|
||||||
test ('no boolean', (t) => {
|
|
||||||
const validator = new TypeValidation ('boolean');
|
|
||||||
t.throws (
|
|
||||||
() => validator.to_type ('foo'),
|
|
||||||
{ message: 'value is not a boolean' }
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test ('boolean', async (t) => {
|
|
||||||
const validator = new TypeValidation ('boolean');
|
|
||||||
const r1 = await validator.to_type ('false');
|
|
||||||
const r2 = await validator.to_type ('true');
|
|
||||||
t.is (r1, false);
|
|
||||||
t.is (r2, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test ('boolean number', async (t) => {
|
|
||||||
const validator = new TypeValidation ('boolean');
|
|
||||||
const r1 = await validator.to_type (0);
|
|
||||||
const r2 = await validator.to_type (1);
|
|
||||||
t.is (r1, false);
|
|
||||||
t.is (r2, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test ('no array', (t) => {
|
|
||||||
const validator = new TypeValidation ('array');
|
|
||||||
t.throws (
|
|
||||||
() => validator.to_type (1),
|
|
||||||
{ message: 'value is not an array' }
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test ('array', async (t) => {
|
|
||||||
const validator = new TypeValidation ('array');
|
|
||||||
const res = await validator.to_type ([
|
|
||||||
'foo',
|
|
||||||
'bar',
|
|
||||||
'baz'
|
|
||||||
]);
|
|
||||||
t.deepEqual (res, [
|
|
||||||
'foo',
|
|
||||||
'bar',
|
|
||||||
'baz'
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test ('string array', async (t) => {
|
|
||||||
const validator = new TypeValidation ('array');
|
|
||||||
const res = await validator.to_type ('f o o,bar , baz');
|
|
||||||
t.deepEqual (res, [
|
|
||||||
'f o o',
|
|
||||||
'bar',
|
|
||||||
'baz'
|
|
||||||
]);
|
|
||||||
});
|
|
46
test/spec/paths.ts
Normal file
46
test/spec/paths.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { PathType } from '../../lib/TypeValidation/PathType';
|
||||||
|
|
||||||
|
describe ('paths', () => {
|
||||||
|
it ('no file', async () => {
|
||||||
|
const validator = new PathType ('file');
|
||||||
|
await expectAsync (
|
||||||
|
validator.to_type ('test')
|
||||||
|
)
|
||||||
|
.toBeRejectedWithError ('cannot assign folder to file');
|
||||||
|
});
|
||||||
|
it ('file', async () => {
|
||||||
|
const validator = new PathType ('file');
|
||||||
|
const res = await validator.to_type ('package.json');
|
||||||
|
expect (res)
|
||||||
|
.toEqual ('package.json');
|
||||||
|
});
|
||||||
|
it ('no folder', async () => {
|
||||||
|
const validator = new PathType ('folder');
|
||||||
|
await expectAsync (validator.to_type ('package.json'))
|
||||||
|
.toBeRejectedWithError ('cannot assign folder to file');
|
||||||
|
});
|
||||||
|
it ('folder', async () => {
|
||||||
|
const validator = new PathType ('folder');
|
||||||
|
const res = await validator.to_type ('test');
|
||||||
|
expect (res)
|
||||||
|
.toEqual ('test');
|
||||||
|
});
|
||||||
|
it ('no path', async () => {
|
||||||
|
const validator = new PathType ('path');
|
||||||
|
await expectAsync (validator.to_type ('doesnotexist.file'))
|
||||||
|
.toBeRejectedWithError ('path does not exist');
|
||||||
|
});
|
||||||
|
it ('path', async () => {
|
||||||
|
const validator = new PathType ('path');
|
||||||
|
const res = await validator.to_type ('test');
|
||||||
|
expect (res)
|
||||||
|
.toEqual ('test');
|
||||||
|
});
|
||||||
|
});
|
102
test/spec/types.ts
Normal file
102
test/spec/types.ts
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* 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>, October 2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { TypeValidation } from '../../lib/TypeValidation/TypeValidation';
|
||||||
|
|
||||||
|
// eslint-disable-next-line max-lines-per-function
|
||||||
|
describe ('type validation', () => {
|
||||||
|
it ('string', async () => {
|
||||||
|
const validator = new TypeValidation ('string');
|
||||||
|
const res = await validator.to_type ('foo');
|
||||||
|
expect (res)
|
||||||
|
.toEqual ('foo');
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('no number', () => {
|
||||||
|
const validator = new TypeValidation ('number');
|
||||||
|
expect (
|
||||||
|
() => validator.to_type ('foo')
|
||||||
|
)
|
||||||
|
.toThrowError ('value is not a number');
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('number', async () => {
|
||||||
|
const validator = new TypeValidation ('number');
|
||||||
|
const res = await validator.to_type ('123.4');
|
||||||
|
expect (res)
|
||||||
|
.toEqual (123.4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('int', async () => {
|
||||||
|
const validator = new TypeValidation ('int');
|
||||||
|
const res = await validator.to_type ('123.4');
|
||||||
|
expect (res)
|
||||||
|
.toEqual (123);
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('no boolean', () => {
|
||||||
|
const validator = new TypeValidation ('boolean');
|
||||||
|
expect (
|
||||||
|
() => validator.to_type ('foo')
|
||||||
|
)
|
||||||
|
.toThrowError ('value is not a boolean');
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('boolean', async () => {
|
||||||
|
const validator = new TypeValidation ('boolean');
|
||||||
|
const r1 = await validator.to_type ('false');
|
||||||
|
const r2 = await validator.to_type ('true');
|
||||||
|
expect (r1)
|
||||||
|
.toEqual (false);
|
||||||
|
expect (r2)
|
||||||
|
.toEqual (true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('boolean number', async () => {
|
||||||
|
const validator = new TypeValidation ('boolean');
|
||||||
|
const r1 = await validator.to_type (0);
|
||||||
|
const r2 = await validator.to_type (1);
|
||||||
|
expect (r1)
|
||||||
|
.toEqual (false);
|
||||||
|
expect (r2)
|
||||||
|
.toEqual (true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('no array', () => {
|
||||||
|
const validator = new TypeValidation ('array');
|
||||||
|
expect (
|
||||||
|
() => validator.to_type (1)
|
||||||
|
)
|
||||||
|
.toThrowError ('value is not an array');
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('array', async () => {
|
||||||
|
const validator = new TypeValidation ('array');
|
||||||
|
const res = await validator.to_type ([
|
||||||
|
'foo',
|
||||||
|
'bar',
|
||||||
|
'baz'
|
||||||
|
]);
|
||||||
|
expect (res)
|
||||||
|
.toEqual ([
|
||||||
|
'foo',
|
||||||
|
'bar',
|
||||||
|
'baz'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('string array', async () => {
|
||||||
|
const validator = new TypeValidation ('array');
|
||||||
|
const res = await validator.to_type ('f o o,bar , baz');
|
||||||
|
expect (res)
|
||||||
|
.toEqual ([
|
||||||
|
'f o o',
|
||||||
|
'bar',
|
||||||
|
'baz'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
3464
yarn-error.log
3464
yarn-error.log
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user