-
-
Notifications
You must be signed in to change notification settings - Fork 63
/
_utils.ts
143 lines (129 loc) 路 3.25 KB
/
_utils.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import type { FlagOptions } from "./types.ts";
import { distance } from "../_utils/distance.ts";
/** Convert param case string to camel case. */
export function paramCaseToCamelCase(str: string): string {
return str.replace(
/-([a-z])/g,
(g) => g[1].toUpperCase(),
);
}
/** Convert underscore case string to camel case. */
export function underscoreToCamelCase(str: string): string {
return str
.replace(/([a-z])([A-Z])/g, "$1_$2")
.toLowerCase()
.replace(
/_([a-z])/g,
(g) => g[1].toUpperCase(),
);
}
/**
* Find option by flag, name or alias.
*
* @param flags Source options array.
* @param name Name of the option.
*/
export function getOption<O extends FlagOptions>(
flags: Array<O>,
name: string,
): O | undefined {
while (name[0] === "-") {
name = name.slice(1);
}
for (const flag of flags) {
if (isOption(flag, name)) {
return flag;
}
}
return;
}
export function didYouMeanOption(
option: string,
options: Array<FlagOptions>,
): string {
const optionNames = options
.map((option) => [option.name, ...(option.aliases ?? [])])
.flat()
.map((option) => getFlag(option));
return didYouMean(" Did you mean option", getFlag(option), optionNames);
}
export function didYouMeanType(type: string, types: Array<string>): string {
return didYouMean(" Did you mean type", type, types);
}
export function didYouMean(
message: string,
type: string,
types: Array<string>,
): string {
const match: string | undefined = closest(type, types);
return match ? `${message} "${match}"?` : "";
}
export function getFlag(name: string) {
if (name.startsWith("-")) {
return name;
}
if (name.length > 1) {
return `--${name}`;
}
return `-${name}`;
}
/**
* Check if option has name or alias.
*
* @param option The option to check.
* @param name The option name or alias.
*/
function isOption(option: FlagOptions, name: string) {
return option.name === name ||
(option.aliases && option.aliases.indexOf(name) !== -1);
}
export function matchWildCardOptions(
name: string,
flags: Array<FlagOptions>,
): FlagOptions | undefined {
for (const option of flags) {
if (option.name.indexOf("*") === -1) {
continue;
}
let matched = matchWildCardOption(name, option);
if (matched) {
matched = { ...matched, name };
flags.push(matched);
return matched;
}
}
}
function matchWildCardOption(
name: string,
option: FlagOptions,
): FlagOptions | false {
const parts = option.name.split(".");
const parts2 = name.split(".");
if (parts.length !== parts2.length) {
return false;
}
const count = Math.max(parts.length, parts2.length);
for (let i = 0; i < count; i++) {
if (parts[i] !== parts2[i] && parts[i] !== "*") {
return false;
}
}
return option;
}
function closest(str: string, arr: string[]): string | undefined {
let minDistance = Infinity;
let minIndex = 0;
for (let i = 0; i < arr.length; i++) {
const dist = distance(str, arr[i]);
if (dist < minDistance) {
minDistance = dist;
minIndex = i;
}
}
return arr[minIndex];
}
export function getDefaultValue(option: FlagOptions): unknown {
return typeof option.default === "function"
? option.default()
: option.default;
}