-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
/
validateCLIOptions.ts
125 lines (111 loc) · 3.55 KB
/
validateCLIOptions.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import camelcase = require('camelcase');
import chalk = require('chalk');
import type {Options} from 'yargs';
import type {Config} from '@jest/types';
import type {
DeprecatedOptionFunc,
DeprecatedOptions,
DeprecationItem,
} from './types';
import {
ValidationError,
createDidYouMeanMessage,
format,
logValidationWarning,
} from './utils';
const BULLET: string = chalk.bold('\u25CF');
export const DOCUMENTATION_NOTE = ` ${chalk.bold('CLI Options Documentation:')}
https://jestjs.io/docs/cli
`;
const createCLIValidationError = (
unrecognizedOptions: Array<string>,
allowedOptions: Set<string>,
) => {
let title = `${BULLET} Unrecognized CLI Parameter`;
let message;
const comment =
` ${chalk.bold('CLI Options Documentation')}:\n` +
' https://jestjs.io/docs/cli\n';
if (unrecognizedOptions.length === 1) {
const unrecognized = unrecognizedOptions[0];
const didYouMeanMessage =
unrecognized.length > 1
? createDidYouMeanMessage(unrecognized, [...allowedOptions])
: '';
message = ` Unrecognized option ${chalk.bold(format(unrecognized))}.${
didYouMeanMessage ? ` ${didYouMeanMessage}` : ''
}`;
} else {
title += 's';
message =
' Following options were not recognized:\n' +
` ${chalk.bold(format(unrecognizedOptions))}`;
}
return new ValidationError(title, message, comment);
};
const validateDeprecatedOptions = (
deprecatedOptions: Array<DeprecationItem>,
deprecationEntries: DeprecatedOptions,
argv: Config.Argv,
) => {
for (const opt of deprecatedOptions) {
const name = opt.name;
const message = deprecationEntries[name](argv);
const comment = DOCUMENTATION_NOTE;
if (opt.fatal) {
throw new ValidationError(name, message, comment);
} else {
logValidationWarning(name, message, comment);
}
}
};
export default function validateCLIOptions(
argv: Config.Argv,
options: Record<string, Options> & {
deprecationEntries?: DeprecatedOptions;
} = {},
rawArgv: Array<string> = [],
): boolean {
const yargsSpecialOptions = ['$0', '_', 'help', 'h'];
const allowedOptions = Object.keys(options).reduce(
(acc, option) =>
acc.add(option).add((options[option].alias as string) || option),
new Set(yargsSpecialOptions),
);
const deprecationEntries = options.deprecationEntries ?? {};
const CLIDeprecations = Object.keys(deprecationEntries).reduce<
Record<string, DeprecatedOptionFunc>
>((acc, entry) => {
acc[entry] = deprecationEntries[entry];
if (options[entry]) {
const alias = options[entry].alias as string;
if (alias) {
acc[alias] = deprecationEntries[entry];
}
}
return acc;
}, {});
const deprecations = new Set(Object.keys(CLIDeprecations));
const deprecatedOptions = Object.keys(argv)
.filter(arg => deprecations.has(arg) && argv[arg] != null)
.map(arg => ({fatal: !allowedOptions.has(arg), name: arg}));
if (deprecatedOptions.length > 0) {
validateDeprecatedOptions(deprecatedOptions, CLIDeprecations, argv);
}
const unrecognizedOptions = Object.keys(argv).filter(
arg =>
!allowedOptions.has(camelcase(arg, {locale: 'en-US'})) &&
!allowedOptions.has(arg) &&
(rawArgv.length === 0 || rawArgv.includes(arg)),
);
if (unrecognizedOptions.length > 0) {
throw createCLIValidationError(unrecognizedOptions, allowedOptions);
}
return true;
}