@oclif/core 1.14.2 → 1.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/lib/config/config.js +1 -0
- package/lib/flags.d.ts +5 -14
- package/lib/flags.js +15 -21
- package/lib/interfaces/flags.d.ts +34 -0
- package/lib/interfaces/flags.js +1 -0
- package/lib/interfaces/index.d.ts +1 -0
- package/lib/interfaces/parser.d.ts +69 -27
- package/lib/parser/errors.d.ts +11 -0
- package/lib/parser/errors.js +14 -2
- package/lib/parser/flags.d.ts +43 -80
- package/lib/parser/flags.js +44 -48
- package/lib/parser/index.d.ts +1 -3
- package/lib/parser/index.js +12 -8
- package/lib/parser/parse.js +13 -7
- package/lib/parser/validate.d.ts +1 -1
- package/lib/parser/validate.js +115 -40
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [1.16.1](https://github.com/oclif/core/compare/v1.16.0...v1.16.1) (2022-09-08)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* support environment variables for boolean flags ([#488](https://github.com/oclif/core/issues/488)) ([#490](https://github.com/oclif/core/issues/490)) ([506945c](https://github.com/oclif/core/commit/506945c6ea2f8b75f0d56ad1f6e62a3717384a42)), closes [#487](https://github.com/oclif/core/issues/487)
|
|
11
|
+
|
|
12
|
+
## [1.16.0](https://github.com/oclif/core/compare/v1.15.0...v1.16.0) (2022-08-24)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* support complex flag relationships ([#468](https://github.com/oclif/core/issues/468)) ([222d1f6](https://github.com/oclif/core/commit/222d1f67012557ac0707077d6c8840966dbf00cb))
|
|
18
|
+
|
|
19
|
+
## [1.15.0](https://github.com/oclif/core/compare/v1.14.2...v1.15.0) (2022-08-23)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
* add InferredFlags type ([#473](https://github.com/oclif/core/issues/473)) ([ee5ce65](https://github.com/oclif/core/commit/ee5ce651899c0ef586d425567ef3b78468dca627))
|
|
25
|
+
|
|
5
26
|
### [1.14.2](https://github.com/oclif/core/compare/v1.14.1...v1.14.2) (2022-08-18)
|
|
6
27
|
|
|
7
28
|
|
package/lib/config/config.js
CHANGED
package/lib/flags.d.ts
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
import { OptionFlag,
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
} & Partial<OptionFlag<T>>): Definition<T>;
|
|
5
|
-
export declare function build(defaults: Partial<OptionFlag<string>>): Definition<string>;
|
|
6
|
-
export declare function option<T>(options: {
|
|
7
|
-
parse: OptionFlag<T>['parse'];
|
|
8
|
-
} & Partial<OptionFlag<T>>): OptionFlag<T | undefined>;
|
|
9
|
-
export declare function _enum<T = string>(opts: EnumFlagOptions<T> & {
|
|
1
|
+
import { OptionFlag, BooleanFlag, EnumFlagOptions, Default } from './interfaces';
|
|
2
|
+
export { boolean, integer, url, directory, file, string, build, option, custom } from './parser';
|
|
3
|
+
export declare function _enum<T = string>(opts: EnumFlagOptions<T, true> & {
|
|
10
4
|
multiple: true;
|
|
11
5
|
} & ({
|
|
12
6
|
required: true;
|
|
13
7
|
} | {
|
|
14
|
-
default: Default<T>;
|
|
8
|
+
default: Default<T[]>;
|
|
15
9
|
})): OptionFlag<T[]>;
|
|
16
|
-
export declare function _enum<T = string>(opts: EnumFlagOptions<T> & {
|
|
10
|
+
export declare function _enum<T = string>(opts: EnumFlagOptions<T, true> & {
|
|
17
11
|
multiple: true;
|
|
18
12
|
}): OptionFlag<T[] | undefined>;
|
|
19
13
|
export declare function _enum<T = string>(opts: EnumFlagOptions<T> & ({
|
|
@@ -23,8 +17,5 @@ export declare function _enum<T = string>(opts: EnumFlagOptions<T> & ({
|
|
|
23
17
|
})): OptionFlag<T>;
|
|
24
18
|
export declare function _enum<T = string>(opts: EnumFlagOptions<T>): OptionFlag<T | undefined>;
|
|
25
19
|
export { _enum as enum };
|
|
26
|
-
declare const stringFlag: Definition<string>;
|
|
27
|
-
export { stringFlag as string };
|
|
28
|
-
export { boolean, integer, url, directory, file } from './parser';
|
|
29
20
|
export declare const version: (opts?: Partial<BooleanFlag<boolean>>) => BooleanFlag<void>;
|
|
30
21
|
export declare const help: (opts?: Partial<BooleanFlag<boolean>>) => BooleanFlag<void>;
|
package/lib/flags.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.help = exports.version = exports.
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
exports.
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
exports.
|
|
3
|
+
exports.help = exports.version = exports.enum = exports._enum = exports.custom = exports.option = exports.build = exports.string = exports.file = exports.directory = exports.url = exports.integer = exports.boolean = void 0;
|
|
4
|
+
const parser_1 = require("./parser");
|
|
5
|
+
var parser_2 = require("./parser");
|
|
6
|
+
Object.defineProperty(exports, "boolean", { enumerable: true, get: function () { return parser_2.boolean; } });
|
|
7
|
+
Object.defineProperty(exports, "integer", { enumerable: true, get: function () { return parser_2.integer; } });
|
|
8
|
+
Object.defineProperty(exports, "url", { enumerable: true, get: function () { return parser_2.url; } });
|
|
9
|
+
Object.defineProperty(exports, "directory", { enumerable: true, get: function () { return parser_2.directory; } });
|
|
10
|
+
Object.defineProperty(exports, "file", { enumerable: true, get: function () { return parser_2.file; } });
|
|
11
|
+
Object.defineProperty(exports, "string", { enumerable: true, get: function () { return parser_2.string; } });
|
|
12
|
+
Object.defineProperty(exports, "build", { enumerable: true, get: function () { return parser_2.build; } });
|
|
13
|
+
Object.defineProperty(exports, "option", { enumerable: true, get: function () { return parser_2.option; } });
|
|
14
|
+
Object.defineProperty(exports, "custom", { enumerable: true, get: function () { return parser_2.custom; } });
|
|
13
15
|
function _enum(opts) {
|
|
14
|
-
return
|
|
16
|
+
return (0, parser_1.custom)({
|
|
15
17
|
async parse(input) {
|
|
16
18
|
if (!opts.options.includes(input))
|
|
17
19
|
throw new Error(`Expected --${this.name}=${input} to be one of: ${opts.options.join(', ')}`);
|
|
@@ -23,16 +25,8 @@ function _enum(opts) {
|
|
|
23
25
|
}
|
|
24
26
|
exports._enum = _enum;
|
|
25
27
|
exports.enum = _enum;
|
|
26
|
-
const stringFlag = build({});
|
|
27
|
-
exports.string = stringFlag;
|
|
28
|
-
var parser_1 = require("./parser");
|
|
29
|
-
Object.defineProperty(exports, "boolean", { enumerable: true, get: function () { return parser_1.boolean; } });
|
|
30
|
-
Object.defineProperty(exports, "integer", { enumerable: true, get: function () { return parser_1.integer; } });
|
|
31
|
-
Object.defineProperty(exports, "url", { enumerable: true, get: function () { return parser_1.url; } });
|
|
32
|
-
Object.defineProperty(exports, "directory", { enumerable: true, get: function () { return parser_1.directory; } });
|
|
33
|
-
Object.defineProperty(exports, "file", { enumerable: true, get: function () { return parser_1.file; } });
|
|
34
28
|
const version = (opts = {}) => {
|
|
35
|
-
return
|
|
29
|
+
return (0, parser_1.boolean)({
|
|
36
30
|
description: 'Show CLI version.',
|
|
37
31
|
...opts,
|
|
38
32
|
parse: async (_, cmd) => {
|
|
@@ -43,7 +37,7 @@ const version = (opts = {}) => {
|
|
|
43
37
|
};
|
|
44
38
|
exports.version = version;
|
|
45
39
|
const help = (opts = {}) => {
|
|
46
|
-
return
|
|
40
|
+
return (0, parser_1.boolean)({
|
|
47
41
|
description: 'Show CLI help.',
|
|
48
42
|
...opts,
|
|
49
43
|
parse: async (_, cmd) => {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { FlagInput } from './parser';
|
|
2
|
+
/**
|
|
3
|
+
* Infer the flags that are returned by Command.parse. This is useful for when you want to assign the flags as a class property.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* export type StatusFlags = Interfaces.InferredFlags<typeof Status.flags & typeof Status.globalFlags>
|
|
7
|
+
*
|
|
8
|
+
* export abstract class BaseCommand extends Command {
|
|
9
|
+
* static enableJsonFlag = true
|
|
10
|
+
*
|
|
11
|
+
* static globalFlags = {
|
|
12
|
+
* config: Flags.string({
|
|
13
|
+
* description: 'specify config file',
|
|
14
|
+
* }),
|
|
15
|
+
* }
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* export default class Status extends BaseCommand {
|
|
19
|
+
* static flags = {
|
|
20
|
+
* force: Flags.boolean({char: 'f', description: 'a flag'}),
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* public flags!: StatusFlags
|
|
24
|
+
*
|
|
25
|
+
* public async run(): Promise<StatusFlags> {
|
|
26
|
+
* const result = await this.parse(Status)
|
|
27
|
+
* this.flags = result.flags
|
|
28
|
+
* return result.flags
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
*/
|
|
32
|
+
export declare type InferredFlags<T> = T extends FlagInput<infer F> ? F & {
|
|
33
|
+
json: boolean | undefined;
|
|
34
|
+
} : unknown;
|
package/lib/interfaces/flags.js
CHANGED
|
@@ -78,14 +78,20 @@ declare type MetadataFlag = {
|
|
|
78
78
|
};
|
|
79
79
|
export declare type ListItem = [string, string | undefined];
|
|
80
80
|
export declare type List = ListItem[];
|
|
81
|
-
export declare type DefaultContext<T> = {
|
|
82
|
-
options: OptionFlag<T>;
|
|
83
|
-
flags:
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
export declare type DefaultContext<T, P> = {
|
|
82
|
+
options: P & OptionFlag<T>;
|
|
83
|
+
flags: Record<string, string>;
|
|
84
|
+
};
|
|
85
|
+
export declare type Default<T, P = Record<string, unknown>> = T | ((context: DefaultContext<T, P>) => Promise<T>);
|
|
86
|
+
export declare type DefaultHelp<T, P = Record<string, unknown>> = T | ((context: DefaultContext<T, P>) => Promise<string | undefined>);
|
|
87
|
+
export declare type FlagRelationship = string | {
|
|
88
|
+
name: string;
|
|
89
|
+
when: (flags: Record<string, unknown>) => Promise<boolean>;
|
|
90
|
+
};
|
|
91
|
+
export declare type Relationship = {
|
|
92
|
+
type: 'all' | 'some' | 'none';
|
|
93
|
+
flags: FlagRelationship[];
|
|
86
94
|
};
|
|
87
|
-
export declare type Default<T> = T | ((context: DefaultContext<T>) => Promise<T>);
|
|
88
|
-
export declare type DefaultHelp<T> = T | ((context: DefaultContext<T>) => Promise<string | undefined>);
|
|
89
95
|
export declare type FlagProps = {
|
|
90
96
|
name: string;
|
|
91
97
|
char?: AlphabetLowercase | AlphabetUppercase;
|
|
@@ -109,10 +115,34 @@ export declare type FlagProps = {
|
|
|
109
115
|
* Shows this flag in a separate list in the help.
|
|
110
116
|
*/
|
|
111
117
|
helpGroup?: string;
|
|
118
|
+
/**
|
|
119
|
+
* Accept an environment variable as input
|
|
120
|
+
*/
|
|
121
|
+
env?: string;
|
|
122
|
+
/**
|
|
123
|
+
* If true, the flag will not be shown in the help.
|
|
124
|
+
*/
|
|
112
125
|
hidden?: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* If true, the flag will be required.
|
|
128
|
+
*/
|
|
113
129
|
required?: boolean;
|
|
130
|
+
/**
|
|
131
|
+
* List of flags that this flag depends on.
|
|
132
|
+
*/
|
|
114
133
|
dependsOn?: string[];
|
|
134
|
+
/**
|
|
135
|
+
* List of flags that cannot be used with this flag.
|
|
136
|
+
*/
|
|
115
137
|
exclusive?: string[];
|
|
138
|
+
/**
|
|
139
|
+
* Exactly one of these flags must be provided.
|
|
140
|
+
*/
|
|
141
|
+
exactlyOne?: string[];
|
|
142
|
+
/**
|
|
143
|
+
* Define complex relationships between flags.
|
|
144
|
+
*/
|
|
145
|
+
relationships?: Relationship[];
|
|
116
146
|
};
|
|
117
147
|
export declare type BooleanFlagProps = FlagProps & {
|
|
118
148
|
type: 'boolean';
|
|
@@ -122,48 +152,60 @@ export declare type OptionFlagProps = FlagProps & {
|
|
|
122
152
|
type: 'option';
|
|
123
153
|
helpValue?: string;
|
|
124
154
|
options?: string[];
|
|
125
|
-
multiple
|
|
155
|
+
multiple?: boolean;
|
|
126
156
|
};
|
|
127
|
-
export declare type
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
* also accept an environment variable as input
|
|
131
|
-
*/
|
|
132
|
-
env?: string;
|
|
133
|
-
parse(input: I, context: any): Promise<T>;
|
|
157
|
+
export declare type FlagParser<T, I, P = any> = (input: I, context: any, opts: P & OptionFlag<T>) => Promise<T>;
|
|
158
|
+
export declare type FlagBase<T, I, P = any> = FlagProps & {
|
|
159
|
+
parse: FlagParser<T, I, P>;
|
|
134
160
|
};
|
|
135
161
|
export declare type BooleanFlag<T> = FlagBase<T, boolean> & BooleanFlagProps & {
|
|
136
162
|
/**
|
|
137
|
-
* specifying a default of false is the same not specifying a default
|
|
163
|
+
* specifying a default of false is the same as not specifying a default
|
|
138
164
|
*/
|
|
139
165
|
default?: Default<boolean>;
|
|
140
166
|
};
|
|
141
|
-
export declare type
|
|
142
|
-
default?: Default<T | undefined>;
|
|
167
|
+
export declare type CustomOptionFlag<T, P = any, M = false> = FlagBase<T, string, P> & OptionFlagProps & {
|
|
143
168
|
defaultHelp?: DefaultHelp<T>;
|
|
144
169
|
input: string[];
|
|
170
|
+
default?: M extends true ? Default<T[] | undefined, P> : Default<T | undefined, P>;
|
|
145
171
|
};
|
|
146
|
-
export declare type
|
|
147
|
-
|
|
172
|
+
export declare type OptionFlag<T> = FlagBase<T, string> & OptionFlagProps & {
|
|
173
|
+
defaultHelp?: DefaultHelp<T>;
|
|
174
|
+
input: string[];
|
|
175
|
+
} & ({
|
|
176
|
+
default?: Default<T | undefined>;
|
|
177
|
+
multiple: false;
|
|
178
|
+
} | {
|
|
179
|
+
default?: Default<T[] | undefined>;
|
|
180
|
+
multiple: true;
|
|
181
|
+
});
|
|
182
|
+
export declare type Definition<T, P = Record<string, unknown>> = {
|
|
183
|
+
(options: P & {
|
|
148
184
|
multiple: true;
|
|
149
185
|
} & ({
|
|
150
186
|
required: true;
|
|
151
187
|
} | {
|
|
152
|
-
default: Default<T>;
|
|
188
|
+
default: Default<T[]>;
|
|
153
189
|
}) & Partial<OptionFlag<T>>): OptionFlag<T[]>;
|
|
154
|
-
(options: {
|
|
190
|
+
(options: P & {
|
|
155
191
|
multiple: true;
|
|
156
|
-
} & Partial<OptionFlag<T
|
|
157
|
-
(options: ({
|
|
192
|
+
} & Partial<OptionFlag<T>>): OptionFlag<T[] | undefined>;
|
|
193
|
+
(options: P & ({
|
|
158
194
|
required: true;
|
|
159
195
|
} | {
|
|
160
196
|
default: Default<T>;
|
|
161
197
|
}) & Partial<OptionFlag<T>>): OptionFlag<T>;
|
|
162
|
-
(options?: Partial<OptionFlag<T>>): OptionFlag<T | undefined>;
|
|
198
|
+
(options?: P & Partial<OptionFlag<T>>): OptionFlag<T | undefined>;
|
|
163
199
|
};
|
|
164
|
-
export declare type EnumFlagOptions<T> = Partial<
|
|
200
|
+
export declare type EnumFlagOptions<T, M = false> = Partial<CustomOptionFlag<T, any, M>> & {
|
|
165
201
|
options: T[];
|
|
166
|
-
}
|
|
202
|
+
} & ({
|
|
203
|
+
default?: Default<T | undefined>;
|
|
204
|
+
multiple?: false;
|
|
205
|
+
} | {
|
|
206
|
+
default?: Default<T[] | undefined>;
|
|
207
|
+
multiple: true;
|
|
208
|
+
});
|
|
167
209
|
export declare type Flag<T> = BooleanFlag<T> | OptionFlag<T>;
|
|
168
210
|
export declare type Input<TFlags extends FlagOutput, GFlags extends FlagOutput> = {
|
|
169
211
|
flags?: FlagInput<TFlags>;
|
package/lib/parser/errors.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { CLIError } from '../errors';
|
|
2
2
|
import { ParserArg, CLIParseErrorOptions, OptionFlag, Flag } from '../interfaces';
|
|
3
3
|
export { CLIError } from '../errors';
|
|
4
|
+
export declare type Validation = {
|
|
5
|
+
name: string;
|
|
6
|
+
status: 'success' | 'failed';
|
|
7
|
+
validationFn: string;
|
|
8
|
+
reason?: string;
|
|
9
|
+
};
|
|
4
10
|
export declare class CLIParseError extends CLIError {
|
|
5
11
|
parse: CLIParseErrorOptions['parse'];
|
|
6
12
|
constructor(options: CLIParseErrorOptions & {
|
|
@@ -37,3 +43,8 @@ export declare class FlagInvalidOptionError extends CLIParseError {
|
|
|
37
43
|
export declare class ArgInvalidOptionError extends CLIParseError {
|
|
38
44
|
constructor(arg: ParserArg<any>, input: string);
|
|
39
45
|
}
|
|
46
|
+
export declare class FailedFlagValidationError extends CLIParseError {
|
|
47
|
+
constructor({ parse, failed }: CLIParseErrorOptions & {
|
|
48
|
+
failed: Validation[];
|
|
49
|
+
});
|
|
50
|
+
}
|
package/lib/parser/errors.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ArgInvalidOptionError = exports.FlagInvalidOptionError = exports.UnexpectedArgsError = exports.RequiredFlagError = exports.RequiredArgsError = exports.InvalidArgsSpecError = exports.CLIParseError = exports.CLIError = void 0;
|
|
3
|
+
exports.FailedFlagValidationError = exports.ArgInvalidOptionError = exports.FlagInvalidOptionError = exports.UnexpectedArgsError = exports.RequiredFlagError = exports.RequiredArgsError = exports.InvalidArgsSpecError = exports.CLIParseError = exports.CLIError = void 0;
|
|
4
4
|
const errors_1 = require("../errors");
|
|
5
5
|
const deps_1 = require("./deps");
|
|
6
|
+
const util_1 = require("../config/util");
|
|
6
7
|
var errors_2 = require("../errors");
|
|
7
8
|
Object.defineProperty(exports, "CLIError", { enumerable: true, get: function () { return errors_2.CLIError; } });
|
|
8
9
|
// eslint-disable-next-line new-cap
|
|
@@ -10,7 +11,8 @@ const m = (0, deps_1.default)()
|
|
|
10
11
|
// eslint-disable-next-line node/no-missing-require
|
|
11
12
|
.add('help', () => require('./help'))
|
|
12
13
|
// eslint-disable-next-line node/no-missing-require
|
|
13
|
-
.add('list', () => require('./list'))
|
|
14
|
+
.add('list', () => require('./list'))
|
|
15
|
+
.add('chalk', () => require('chalk'));
|
|
14
16
|
class CLIParseError extends errors_1.CLIError {
|
|
15
17
|
constructor(options) {
|
|
16
18
|
options.message += '\nSee more help with --help';
|
|
@@ -76,3 +78,13 @@ class ArgInvalidOptionError extends CLIParseError {
|
|
|
76
78
|
}
|
|
77
79
|
}
|
|
78
80
|
exports.ArgInvalidOptionError = ArgInvalidOptionError;
|
|
81
|
+
class FailedFlagValidationError extends CLIParseError {
|
|
82
|
+
constructor({ parse, failed }) {
|
|
83
|
+
const reasons = failed.map(r => r.reason);
|
|
84
|
+
const deduped = (0, util_1.uniq)(reasons);
|
|
85
|
+
const errString = deduped.length === 1 ? 'error' : 'errors';
|
|
86
|
+
const message = `The following ${errString} occurred:\n ${m.chalk.dim(deduped.join('\n '))}`;
|
|
87
|
+
super({ parse, message });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.FailedFlagValidationError = FailedFlagValidationError;
|
package/lib/parser/flags.d.ts
CHANGED
|
@@ -1,96 +1,59 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { URL } from 'url';
|
|
3
|
-
import { Definition, OptionFlag, BooleanFlag
|
|
3
|
+
import { Definition, OptionFlag, BooleanFlag } from '../interfaces';
|
|
4
|
+
import { FlagParser, CustomOptionFlag } from '../interfaces/parser';
|
|
5
|
+
/**
|
|
6
|
+
* Create a custom flag.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* type Id = string
|
|
10
|
+
* type IdOpts = { startsWith: string; length: number };
|
|
11
|
+
*
|
|
12
|
+
* export const myFlag = custom<Id, IdOpts>({
|
|
13
|
+
* parse: async (input, opts) => {
|
|
14
|
+
* if (input.startsWith(opts.startsWith) && input.length === opts.length) {
|
|
15
|
+
* return input
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* throw new Error('Invalid id')
|
|
19
|
+
* },
|
|
20
|
+
* })
|
|
21
|
+
*/
|
|
22
|
+
export declare function custom<T, P = Record<string, unknown>>(defaults: {
|
|
23
|
+
parse: FlagParser<T, string, P>;
|
|
24
|
+
multiple: true;
|
|
25
|
+
} & Partial<CustomOptionFlag<T, P, true>>): Definition<T, P>;
|
|
26
|
+
export declare function custom<T, P = Record<string, unknown>>(defaults: {
|
|
27
|
+
parse: FlagParser<T, string, P>;
|
|
28
|
+
} & Partial<CustomOptionFlag<T, P>>): Definition<T, P>;
|
|
29
|
+
export declare function custom<T = string, P = Record<string, unknown>>(defaults: Partial<CustomOptionFlag<T, P>>): Definition<T, P>;
|
|
30
|
+
/**
|
|
31
|
+
* @deprecated Use Flags.custom instead.
|
|
32
|
+
*/
|
|
4
33
|
export declare function build<T>(defaults: {
|
|
5
34
|
parse: OptionFlag<T>['parse'];
|
|
6
35
|
} & Partial<OptionFlag<T>>): Definition<T>;
|
|
7
36
|
export declare function build(defaults: Partial<OptionFlag<string>>): Definition<string>;
|
|
8
37
|
export declare function boolean<T = boolean>(options?: Partial<BooleanFlag<T>>): BooleanFlag<T>;
|
|
9
|
-
export declare
|
|
10
|
-
min?: number;
|
|
11
|
-
max?: number;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
export declare function integer(opts: Partial<OptionFlag<number>> & {
|
|
20
|
-
min?: number;
|
|
21
|
-
max?: number;
|
|
22
|
-
} & {
|
|
23
|
-
multiple: true;
|
|
24
|
-
}): OptionFlag<number[] | undefined>;
|
|
25
|
-
export declare function integer(opts: Partial<OptionFlag<number>> & {
|
|
26
|
-
min?: number;
|
|
27
|
-
max?: number;
|
|
28
|
-
} & ({
|
|
29
|
-
required: true;
|
|
30
|
-
} | {
|
|
31
|
-
default: Default<number>;
|
|
32
|
-
})): OptionFlag<number>;
|
|
33
|
-
export declare function integer(opts?: Partial<OptionFlag<number>> & {
|
|
34
|
-
min?: number;
|
|
35
|
-
max?: number;
|
|
36
|
-
}): OptionFlag<number | undefined>;
|
|
37
|
-
export declare function directory(opts: Partial<OptionFlag<string>> & {
|
|
38
|
-
exists?: boolean;
|
|
39
|
-
} & {
|
|
40
|
-
multiple: true;
|
|
41
|
-
} & ({
|
|
42
|
-
required: true;
|
|
43
|
-
} | {
|
|
44
|
-
default: Default<string>;
|
|
45
|
-
})): OptionFlag<string[]>;
|
|
46
|
-
export declare function directory(opts: Partial<OptionFlag<string>> & {
|
|
47
|
-
exists?: boolean;
|
|
48
|
-
} & {
|
|
49
|
-
multiple: true;
|
|
50
|
-
}): OptionFlag<string[] | undefined>;
|
|
51
|
-
export declare function directory(opts: {
|
|
52
|
-
exists?: boolean;
|
|
53
|
-
} & Partial<OptionFlag<string>> & ({
|
|
54
|
-
required: true;
|
|
55
|
-
} | {
|
|
56
|
-
default: Default<string>;
|
|
57
|
-
})): OptionFlag<string>;
|
|
58
|
-
export declare function directory(opts?: {
|
|
59
|
-
exists?: boolean;
|
|
60
|
-
} & Partial<OptionFlag<string>>): OptionFlag<string | undefined>;
|
|
61
|
-
export declare function file(opts: Partial<OptionFlag<string>> & {
|
|
62
|
-
exists?: boolean;
|
|
63
|
-
} & {
|
|
64
|
-
multiple: true;
|
|
65
|
-
} & ({
|
|
66
|
-
required: true;
|
|
67
|
-
} | {
|
|
68
|
-
default: Default<string>;
|
|
69
|
-
})): OptionFlag<string[]>;
|
|
70
|
-
export declare function file(opts: Partial<OptionFlag<string>> & {
|
|
71
|
-
exists?: boolean;
|
|
72
|
-
} & {
|
|
73
|
-
multiple: true;
|
|
74
|
-
}): OptionFlag<string[] | undefined>;
|
|
75
|
-
export declare function file(opts: {
|
|
76
|
-
exists?: boolean;
|
|
77
|
-
} & Partial<OptionFlag<string>> & ({
|
|
78
|
-
required: true;
|
|
79
|
-
} | {
|
|
80
|
-
default: Default<string>;
|
|
81
|
-
})): OptionFlag<string>;
|
|
82
|
-
export declare function file(opts?: {
|
|
83
|
-
exists?: boolean;
|
|
84
|
-
} & Partial<OptionFlag<string>>): OptionFlag<string | undefined>;
|
|
38
|
+
export declare const integer: Definition<number, {
|
|
39
|
+
min?: number | undefined;
|
|
40
|
+
max?: number | undefined;
|
|
41
|
+
}>;
|
|
42
|
+
export declare const directory: Definition<string, {
|
|
43
|
+
exists?: boolean | undefined;
|
|
44
|
+
}>;
|
|
45
|
+
export declare const file: Definition<string, {
|
|
46
|
+
exists?: boolean | undefined;
|
|
47
|
+
}>;
|
|
85
48
|
/**
|
|
86
49
|
* Initializes a string as a URL. Throws an error
|
|
87
50
|
* if the string is not a valid URL.
|
|
88
51
|
*/
|
|
89
|
-
export declare const url: Definition<URL
|
|
52
|
+
export declare const url: Definition<URL, Record<string, unknown>>;
|
|
90
53
|
export declare function option<T>(options: {
|
|
91
54
|
parse: OptionFlag<T>['parse'];
|
|
92
|
-
} & Partial<
|
|
93
|
-
declare const stringFlag: Definition<string
|
|
55
|
+
} & Partial<CustomOptionFlag<T>>): OptionFlag<T | undefined>;
|
|
56
|
+
declare const stringFlag: Definition<string, Record<string, unknown>>;
|
|
94
57
|
export { stringFlag as string };
|
|
95
58
|
export declare const defaultFlags: {
|
|
96
59
|
color: BooleanFlag<boolean>;
|
package/lib/parser/flags.js
CHANGED
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// tslint:disable interface-over-type-literal
|
|
3
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.defaultFlags = exports.string = exports.option = exports.url = exports.file = exports.directory = exports.integer = exports.boolean = exports.build = void 0;
|
|
3
|
+
exports.defaultFlags = exports.string = exports.option = exports.url = exports.file = exports.directory = exports.integer = exports.boolean = exports.build = exports.custom = void 0;
|
|
5
4
|
const url_1 = require("url");
|
|
6
5
|
const fs = require("fs");
|
|
6
|
+
function custom(defaults) {
|
|
7
|
+
return (options = {}) => {
|
|
8
|
+
return {
|
|
9
|
+
parse: async (i, _context, _opts) => i,
|
|
10
|
+
...defaults,
|
|
11
|
+
...options,
|
|
12
|
+
input: [],
|
|
13
|
+
multiple: Boolean(options.multiple === undefined ? defaults.multiple : options.multiple),
|
|
14
|
+
type: 'option',
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
exports.custom = custom;
|
|
7
19
|
function build(defaults) {
|
|
8
20
|
return (options = {}) => {
|
|
9
21
|
return {
|
|
10
|
-
parse: async (i,
|
|
22
|
+
parse: async (i, _context) => i,
|
|
11
23
|
...defaults,
|
|
12
24
|
...options,
|
|
13
25
|
input: [],
|
|
@@ -26,53 +38,37 @@ function boolean(options = {}) {
|
|
|
26
38
|
};
|
|
27
39
|
}
|
|
28
40
|
exports.boolean = boolean;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
})();
|
|
56
|
-
}
|
|
57
|
-
exports.directory = directory;
|
|
58
|
-
function file(opts = {}) {
|
|
59
|
-
return build({
|
|
60
|
-
...opts,
|
|
61
|
-
parse: async (input) => {
|
|
62
|
-
if (opts.exists) {
|
|
63
|
-
// 2nd "context" arg is required but unused
|
|
64
|
-
return opts.parse ? opts.parse(await fileExists(input), true) : fileExists(input);
|
|
65
|
-
}
|
|
66
|
-
return opts.parse ? opts.parse(input, true) : input;
|
|
67
|
-
},
|
|
68
|
-
})();
|
|
69
|
-
}
|
|
70
|
-
exports.file = file;
|
|
41
|
+
exports.integer = custom({
|
|
42
|
+
parse: async (input, _, opts) => {
|
|
43
|
+
if (!/^-?\d+$/.test(input))
|
|
44
|
+
throw new Error(`Expected an integer but received: ${input}`);
|
|
45
|
+
const num = Number.parseInt(input, 10);
|
|
46
|
+
if (opts.min !== undefined && num < opts.min)
|
|
47
|
+
throw new Error(`Expected an integer greater than or equal to ${opts.min} but received: ${input}`);
|
|
48
|
+
if (opts.max !== undefined && num > opts.max)
|
|
49
|
+
throw new Error(`Expected an integer less than or equal to ${opts.max} but received: ${input}`);
|
|
50
|
+
return num;
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
exports.directory = custom({
|
|
54
|
+
parse: async (input, _, opts) => {
|
|
55
|
+
if (opts.exists)
|
|
56
|
+
return dirExists(input);
|
|
57
|
+
return input;
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
exports.file = custom({
|
|
61
|
+
parse: async (input, _, opts) => {
|
|
62
|
+
if (opts.exists)
|
|
63
|
+
return fileExists(input);
|
|
64
|
+
return input;
|
|
65
|
+
},
|
|
66
|
+
});
|
|
71
67
|
/**
|
|
72
68
|
* Initializes a string as a URL. Throws an error
|
|
73
69
|
* if the string is not a valid URL.
|
|
74
70
|
*/
|
|
75
|
-
exports.url =
|
|
71
|
+
exports.url = custom({
|
|
76
72
|
parse: async (input) => {
|
|
77
73
|
try {
|
|
78
74
|
return new url_1.URL(input);
|
|
@@ -83,10 +79,10 @@ exports.url = build({
|
|
|
83
79
|
},
|
|
84
80
|
});
|
|
85
81
|
function option(options) {
|
|
86
|
-
return
|
|
82
|
+
return custom(options)();
|
|
87
83
|
}
|
|
88
84
|
exports.option = option;
|
|
89
|
-
const stringFlag =
|
|
85
|
+
const stringFlag = custom({});
|
|
90
86
|
exports.string = stringFlag;
|
|
91
87
|
exports.defaultFlags = {
|
|
92
88
|
color: boolean({ allowNo: true }),
|
package/lib/parser/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import * as args from './args';
|
|
3
2
|
import * as flags from './flags';
|
|
4
3
|
import { Input, ParserOutput } from '../interfaces';
|
|
@@ -8,5 +7,4 @@ export { flagUsages } from './help';
|
|
|
8
7
|
export declare function parse<TFlags, GFlags, TArgs extends {
|
|
9
8
|
[name: string]: string;
|
|
10
9
|
}>(argv: string[], options: Input<TFlags, GFlags>): Promise<ParserOutput<TFlags, GFlags, TArgs>>;
|
|
11
|
-
|
|
12
|
-
export { boolean, integer, url, directory, file };
|
|
10
|
+
export { boolean, integer, url, directory, file, string, build, option, custom } from './flags';
|
package/lib/parser/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.file = exports.directory = exports.url = exports.integer = exports.boolean = exports.parse = exports.flagUsages = exports.flags = exports.args = void 0;
|
|
3
|
+
exports.custom = exports.option = exports.build = exports.string = exports.file = exports.directory = exports.url = exports.integer = exports.boolean = exports.parse = exports.flagUsages = exports.flags = exports.args = void 0;
|
|
4
4
|
const args = require("./args");
|
|
5
5
|
exports.args = args;
|
|
6
6
|
const deps_1 = require("./deps");
|
|
@@ -27,13 +27,17 @@ async function parse(argv, options) {
|
|
|
27
27
|
};
|
|
28
28
|
const parser = new parse_1.Parser(input);
|
|
29
29
|
const output = await parser.parse();
|
|
30
|
-
m.validate({ input, output });
|
|
30
|
+
await m.validate({ input, output });
|
|
31
31
|
return output;
|
|
32
32
|
}
|
|
33
33
|
exports.parse = parse;
|
|
34
|
-
|
|
35
|
-
exports
|
|
36
|
-
exports
|
|
37
|
-
exports
|
|
38
|
-
exports
|
|
39
|
-
exports
|
|
34
|
+
var flags_1 = require("./flags");
|
|
35
|
+
Object.defineProperty(exports, "boolean", { enumerable: true, get: function () { return flags_1.boolean; } });
|
|
36
|
+
Object.defineProperty(exports, "integer", { enumerable: true, get: function () { return flags_1.integer; } });
|
|
37
|
+
Object.defineProperty(exports, "url", { enumerable: true, get: function () { return flags_1.url; } });
|
|
38
|
+
Object.defineProperty(exports, "directory", { enumerable: true, get: function () { return flags_1.directory; } });
|
|
39
|
+
Object.defineProperty(exports, "file", { enumerable: true, get: function () { return flags_1.file; } });
|
|
40
|
+
Object.defineProperty(exports, "string", { enumerable: true, get: function () { return flags_1.string; } });
|
|
41
|
+
Object.defineProperty(exports, "build", { enumerable: true, get: function () { return flags_1.build; } });
|
|
42
|
+
Object.defineProperty(exports, "option", { enumerable: true, get: function () { return flags_1.option; } });
|
|
43
|
+
Object.defineProperty(exports, "custom", { enumerable: true, get: function () { return flags_1.custom; } });
|
package/lib/parser/parse.js
CHANGED
|
@@ -149,13 +149,13 @@ class Parser {
|
|
|
149
149
|
flags[token.flag] = true;
|
|
150
150
|
}
|
|
151
151
|
// eslint-disable-next-line no-await-in-loop
|
|
152
|
-
flags[token.flag] = await flag.parse(flags[token.flag], this.context);
|
|
152
|
+
flags[token.flag] = await flag.parse(flags[token.flag], this.context, flag);
|
|
153
153
|
}
|
|
154
154
|
else {
|
|
155
155
|
const input = token.input;
|
|
156
156
|
this._validateOptions(flag, input);
|
|
157
157
|
// eslint-disable-next-line no-await-in-loop
|
|
158
|
-
const value = flag.parse ? await flag.parse(input, this.context) : input;
|
|
158
|
+
const value = flag.parse ? await flag.parse(input, this.context, flag) : input;
|
|
159
159
|
if (flag.multiple) {
|
|
160
160
|
flags[token.flag] = flags[token.flag] || [];
|
|
161
161
|
flags[token.flag].push(value);
|
|
@@ -169,12 +169,18 @@ class Parser {
|
|
|
169
169
|
const flag = this.input.flags[k];
|
|
170
170
|
if (flags[k])
|
|
171
171
|
continue;
|
|
172
|
-
if (flag.
|
|
172
|
+
if (flag.env) {
|
|
173
173
|
const input = process.env[flag.env];
|
|
174
|
-
if (
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
174
|
+
if (flag.type === 'option') {
|
|
175
|
+
if (input) {
|
|
176
|
+
this._validateOptions(flag, input);
|
|
177
|
+
// eslint-disable-next-line no-await-in-loop
|
|
178
|
+
flags[k] = await flag.parse(input, this.context, flag);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if (flag.type === 'boolean') {
|
|
182
|
+
// eslint-disable-next-line no-negated-condition
|
|
183
|
+
flags[k] = input !== undefined ? ['true', 'TRUE', '1', 'yes', 'YES', 'y', 'Y'].includes(input) : false;
|
|
178
184
|
}
|
|
179
185
|
}
|
|
180
186
|
if (!(k in flags) && flag.default !== undefined) {
|
package/lib/parser/validate.d.ts
CHANGED
package/lib/parser/validate.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validate = void 0;
|
|
4
|
-
const errors_1 = require("
|
|
5
|
-
const
|
|
6
|
-
function validate(parse) {
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
const util_1 = require("../config/util");
|
|
6
|
+
async function validate(parse) {
|
|
7
7
|
function validateArgs() {
|
|
8
8
|
const maxArgs = parse.input.args.length;
|
|
9
9
|
if (parse.input.strict && parse.output.argv.length > maxArgs) {
|
|
10
10
|
const extras = parse.output.argv.slice(maxArgs);
|
|
11
|
-
throw new
|
|
11
|
+
throw new errors_1.UnexpectedArgsError({ parse, args: extras });
|
|
12
12
|
}
|
|
13
13
|
const missingRequiredArgs = [];
|
|
14
14
|
let hasOptional = false;
|
|
@@ -19,63 +19,138 @@ function validate(parse) {
|
|
|
19
19
|
else if (hasOptional) {
|
|
20
20
|
// (required arg) check whether an optional has occurred before
|
|
21
21
|
// optionals should follow required, not before
|
|
22
|
-
throw new
|
|
22
|
+
throw new errors_1.InvalidArgsSpecError({ parse, args: parse.input.args });
|
|
23
23
|
}
|
|
24
24
|
if (arg.required && !parse.output.argv[index] && parse.output.argv[index] !== 0) {
|
|
25
25
|
missingRequiredArgs.push(arg);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
if (missingRequiredArgs.length > 0) {
|
|
29
|
-
throw new
|
|
29
|
+
throw new errors_1.RequiredArgsError({ parse, args: missingRequiredArgs });
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
+
async function validateFlags() {
|
|
33
|
+
const promises = Object.entries(parse.input.flags).map(async ([name, flag]) => {
|
|
34
|
+
const results = [];
|
|
35
|
+
if (parse.output.flags[name] !== undefined) {
|
|
36
|
+
results.push(...await validateRelationships(name, flag), await validateDependsOn(name, flag.dependsOn ?? []), await validateExclusive(name, flag.exclusive ?? []), await validateExactlyOne(name, flag.exactlyOne ?? []));
|
|
37
|
+
}
|
|
38
|
+
else if (flag.required) {
|
|
39
|
+
results.push({ status: 'failed', name, validationFn: 'required', reason: `Missing required flag ${name}` });
|
|
40
|
+
}
|
|
41
|
+
else if (flag.exactlyOne && flag.exactlyOne.length > 0) {
|
|
42
|
+
results.push(validateAcrossFlags(flag));
|
|
43
|
+
}
|
|
44
|
+
return results;
|
|
45
|
+
});
|
|
46
|
+
const results = (await Promise.all(promises)).flat();
|
|
47
|
+
const failed = results.filter(r => r.status === 'failed');
|
|
48
|
+
if (failed.length > 0)
|
|
49
|
+
throw new errors_1.FailedFlagValidationError({ parse, failed });
|
|
50
|
+
}
|
|
51
|
+
async function resolveFlags(flags) {
|
|
52
|
+
const promises = flags.map(async (flag) => {
|
|
53
|
+
if (typeof flag === 'string') {
|
|
54
|
+
return [flag, parse.output.flags[flag]];
|
|
55
|
+
}
|
|
56
|
+
const result = await flag.when(parse.output.flags);
|
|
57
|
+
return result ? [flag.name, parse.output.flags[flag.name]] : null;
|
|
58
|
+
});
|
|
59
|
+
const resolved = await Promise.all(promises);
|
|
60
|
+
return Object.fromEntries(resolved.filter(r => r !== null));
|
|
61
|
+
}
|
|
62
|
+
function getPresentFlags(flags) {
|
|
63
|
+
return Object.keys(flags).reduce((acc, key) => {
|
|
64
|
+
if (flags[key])
|
|
65
|
+
acc.push(key);
|
|
66
|
+
return acc;
|
|
67
|
+
}, []);
|
|
68
|
+
}
|
|
32
69
|
function validateAcrossFlags(flag) {
|
|
70
|
+
const base = { name: flag.name, validationFn: 'validateAcrossFlags' };
|
|
33
71
|
const intersection = Object.entries(parse.input.flags)
|
|
34
72
|
.map(entry => entry[0]) // array of flag names
|
|
35
73
|
.filter(flagName => parse.output.flags[flagName] !== undefined) // with values
|
|
36
74
|
.filter(flagName => flag.exactlyOne && flag.exactlyOne.includes(flagName)); // and in the exactlyOne list
|
|
37
75
|
if (intersection.length === 0) {
|
|
38
76
|
// the command's exactlyOne may or may not include itself, so we'll use Set to add + de-dupe
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
77
|
+
const deduped = (0, util_1.uniq)(flag.exactlyOne?.map(flag => `--${flag}`) ?? []).join(', ');
|
|
78
|
+
const reason = `Exactly one of the following must be provided: ${deduped}`;
|
|
79
|
+
return { ...base, status: 'failed', reason };
|
|
42
80
|
}
|
|
81
|
+
return { ...base, status: 'success' };
|
|
43
82
|
}
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
continue;
|
|
57
|
-
if (parse.output.metadata.flags[name] &&
|
|
58
|
-
parse.output.metadata.flags[name].setFromDefault)
|
|
59
|
-
continue;
|
|
60
|
-
if (parse.output.flags[also]) {
|
|
61
|
-
throw new errors_1.CLIError(`--${also}= cannot also be provided when using --${name}=`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
for (const also of flag.exactlyOne || []) {
|
|
65
|
-
if (also !== name && parse.output.flags[also]) {
|
|
66
|
-
throw new errors_1.CLIError(`--${also}= cannot also be provided when using --${name}=`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
83
|
+
async function validateExclusive(name, flags) {
|
|
84
|
+
const base = { name, validationFn: 'validateExclusive' };
|
|
85
|
+
const resolved = await resolveFlags(flags);
|
|
86
|
+
const keys = getPresentFlags(resolved);
|
|
87
|
+
for (const flag of keys) {
|
|
88
|
+
// do not enforce exclusivity for flags that were defaulted
|
|
89
|
+
if (parse.output.metadata.flags && parse.output.metadata.flags[flag]?.setFromDefault)
|
|
90
|
+
continue;
|
|
91
|
+
if (parse.output.metadata.flags && parse.output.metadata.flags[name]?.setFromDefault)
|
|
92
|
+
continue;
|
|
93
|
+
if (parse.output.flags[flag]) {
|
|
94
|
+
return { ...base, status: 'failed', reason: `--${flag}=${parse.output.flags[flag]} cannot also be provided when using --${name}` };
|
|
69
95
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
96
|
+
}
|
|
97
|
+
return { ...base, status: 'success' };
|
|
98
|
+
}
|
|
99
|
+
async function validateExactlyOne(name, flags) {
|
|
100
|
+
const base = { name, validationFn: 'validateExactlyOne' };
|
|
101
|
+
const resolved = await resolveFlags(flags);
|
|
102
|
+
const keys = getPresentFlags(resolved);
|
|
103
|
+
for (const flag of keys) {
|
|
104
|
+
if (flag !== name && parse.output.flags[flag]) {
|
|
105
|
+
return { ...base, status: 'failed', reason: `--${flag} cannot also be provided when using --${name}` };
|
|
75
106
|
}
|
|
76
107
|
}
|
|
108
|
+
return { ...base, status: 'success' };
|
|
109
|
+
}
|
|
110
|
+
async function validateDependsOn(name, flags) {
|
|
111
|
+
const base = { name, validationFn: 'validateDependsOn' };
|
|
112
|
+
const resolved = await resolveFlags(flags);
|
|
113
|
+
const foundAll = Object.values(resolved).every(Boolean);
|
|
114
|
+
if (!foundAll) {
|
|
115
|
+
const formattedFlags = Object.keys(resolved).map(f => `--${f}`).join(', ');
|
|
116
|
+
return { ...base, status: 'failed', reason: `All of the following must be provided when using --${name}: ${formattedFlags}` };
|
|
117
|
+
}
|
|
118
|
+
return { ...base, status: 'success' };
|
|
119
|
+
}
|
|
120
|
+
async function validateSome(name, flags) {
|
|
121
|
+
const base = { name, validationFn: 'validateSome' };
|
|
122
|
+
const resolved = await resolveFlags(flags);
|
|
123
|
+
const foundAtLeastOne = Object.values(resolved).some(Boolean);
|
|
124
|
+
if (!foundAtLeastOne) {
|
|
125
|
+
const formattedFlags = Object.keys(resolved).map(f => `--${f}`).join(', ');
|
|
126
|
+
return { ...base, status: 'failed', reason: `One of the following must be provided when using --${name}: ${formattedFlags}` };
|
|
127
|
+
}
|
|
128
|
+
return { ...base, status: 'success' };
|
|
129
|
+
}
|
|
130
|
+
async function validateRelationships(name, flag) {
|
|
131
|
+
if (!flag.relationships)
|
|
132
|
+
return [];
|
|
133
|
+
const results = await Promise.all(flag.relationships.map(async (relationship) => {
|
|
134
|
+
const flags = relationship.flags ?? [];
|
|
135
|
+
const results = [];
|
|
136
|
+
switch (relationship.type) {
|
|
137
|
+
case 'all':
|
|
138
|
+
results.push(await validateDependsOn(name, flags));
|
|
139
|
+
break;
|
|
140
|
+
case 'some':
|
|
141
|
+
results.push(await validateSome(name, flags));
|
|
142
|
+
break;
|
|
143
|
+
case 'none':
|
|
144
|
+
results.push(await validateExclusive(name, flags));
|
|
145
|
+
break;
|
|
146
|
+
default:
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
return results;
|
|
150
|
+
}));
|
|
151
|
+
return results.flat();
|
|
77
152
|
}
|
|
78
153
|
validateArgs();
|
|
79
|
-
validateFlags();
|
|
154
|
+
await validateFlags();
|
|
80
155
|
}
|
|
81
156
|
exports.validate = validate;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oclif/core",
|
|
3
3
|
"description": "base library for oclif CLIs",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.16.1",
|
|
5
5
|
"author": "Salesforce",
|
|
6
6
|
"bugs": "https://github.com/oclif/core/issues",
|
|
7
7
|
"dependencies": {
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"shx": "^0.3.4",
|
|
75
75
|
"sinon": "^11.1.2",
|
|
76
76
|
"ts-node": "^9.1.1",
|
|
77
|
+
"tsd": "^0.22.0",
|
|
77
78
|
"typescript": "4.5.5"
|
|
78
79
|
},
|
|
79
80
|
"engines": {
|