Skip to content

Commit 7012f47

Browse files
committed
chore: command suggestions enhancements
1 parent a9452d7 commit 7012f47

File tree

5 files changed

+65
-11
lines changed

5 files changed

+65
-11
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
"is-ci": "~4.1.0",
9494
"istextorbinary": "~9.5.0",
9595
"jju": "~1.4.0",
96+
"js-levenshtein": "^1.1.6",
9697
"lodash.clonedeep": "^4.5.0",
9798
"mime": "~4.0.4",
9899
"mixpanel": "~0.18.0",
@@ -126,6 +127,7 @@
126127
"@types/inquirer": "^9.0.7",
127128
"@types/is-ci": "^3.0.4",
128129
"@types/jju": "^1.4.5",
130+
"@types/js-levenshtein": "^1",
129131
"@types/lodash.clonedeep": "^4",
130132
"@types/mime": "^4.0.0",
131133
"@types/node": "^22.0.0",

src/commands/help.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { jaroWinkler } from '@skyra/jaro-winkler';
21
import chalk from 'chalk';
32

43
import { ApifyCommand, commandRegistry } from '../lib/command-framework/apify-command.js';
54
import { Args } from '../lib/command-framework/args.js';
65
import { renderHelpForCommand, renderMainHelpMenu } from '../lib/command-framework/help.js';
6+
import { useCommandSuggestions } from '../lib/hooks/useCommandSuggestions.js';
77
import { error } from '../lib/outputs.js';
88

99
export class HelpCommand extends ApifyCommand<typeof HelpCommand> {
@@ -37,13 +37,7 @@ export class HelpCommand extends ApifyCommand<typeof HelpCommand> {
3737
const command = commandRegistry.get(lowercasedCommandString);
3838

3939
if (!command) {
40-
const allCommands = [...commandRegistry.keys()];
41-
42-
const closestMatches = allCommands.filter((cmd) => {
43-
const lowercased = cmd.toLowerCase();
44-
45-
return jaroWinkler(lowercasedCommandString, lowercased) >= 0.95;
46-
});
40+
const closestMatches = useCommandSuggestions(lowercasedCommandString);
4741

4842
let message = chalk.gray(`Command ${chalk.whiteBright(commandString)} not found`);
4943

src/entrypoints/_shared.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { renderMainHelpMenu, selectiveRenderHelpForCommand } from '../lib/comman
1616
import { readStdin } from '../lib/commands/read-stdin.js';
1717
import { useCLIMetadata } from '../lib/hooks/useCLIMetadata.js';
1818
import { shouldSkipVersionCheck } from '../lib/hooks/useCLIVersionCheck.js';
19+
import { useCommandSuggestions } from '../lib/hooks/useCommandSuggestions.js';
1920
import { error } from '../lib/outputs.js';
2021
import { cliDebugPrint } from '../lib/utils/cliDebugPrint.js';
2122

@@ -129,9 +130,18 @@ export async function runCLI(entrypoint: string) {
129130
const command = commandRegistry.get(possibleCommands.find((cmd) => commandRegistry.has(cmd)) ?? '');
130131

131132
if (!command) {
132-
error({
133-
message: `Command ${parsed._[0]} not found`,
134-
});
133+
const closestMatches = useCommandSuggestions(String(parsed._[0]));
134+
135+
let message = chalk.gray(`Command ${chalk.whiteBright(parsed._[0])} not found`);
136+
137+
if (closestMatches.length) {
138+
message += '\n ';
139+
message += chalk.gray(
140+
`Did you mean: ${closestMatches.map((cmd) => chalk.whiteBright(cmd)).join(', ')}?`,
141+
);
142+
}
143+
144+
error({ message });
135145

136146
return;
137147
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { jaroWinkler } from '@skyra/jaro-winkler';
2+
import levenshtein from 'js-levenshtein';
3+
4+
import { commandRegistry } from '../command-framework/apify-command.js';
5+
6+
export function useCommandSuggestions(inputString: string) {
7+
const allCommands = [...commandRegistry.entries()];
8+
9+
const lowercasedCommandString = inputString.toLowerCase();
10+
11+
const closestMatches = allCommands
12+
.map(([cmdString, cmdClass]) => {
13+
const lowercased = cmdString.toLowerCase();
14+
15+
const matches =
16+
levenshtein(lowercasedCommandString, lowercased) <= 2 ||
17+
jaroWinkler(lowercasedCommandString, lowercased) >= 0.95;
18+
19+
if (matches) {
20+
if (cmdString === cmdClass.name) {
21+
return cmdString;
22+
}
23+
24+
return `${cmdString} (alias for ${cmdClass.name})`;
25+
}
26+
27+
return null;
28+
})
29+
.filter((item) => item !== null);
30+
31+
return closestMatches;
32+
}

yarn.lock

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1638,6 +1638,13 @@ __metadata:
16381638
languageName: node
16391639
linkType: hard
16401640

1641+
"@types/js-levenshtein@npm:^1":
1642+
version: 1.1.3
1643+
resolution: "@types/js-levenshtein@npm:1.1.3"
1644+
checksum: 10c0/025f2bd8d865cfa7a996799a1a2f2a77fa2fc74a28971aa035a103de35d7c1e3d949721a88f57fdb532815bbcb2bf7019196a608ed0a8bbd1023d64c52bb251b
1645+
languageName: node
1646+
linkType: hard
1647+
16411648
"@types/json-schema@npm:^7.0.15":
16421649
version: 7.0.15
16431650
resolution: "@types/json-schema@npm:7.0.15"
@@ -2384,6 +2391,7 @@ __metadata:
23842391
"@types/inquirer": "npm:^9.0.7"
23852392
"@types/is-ci": "npm:^3.0.4"
23862393
"@types/jju": "npm:^1.4.5"
2394+
"@types/js-levenshtein": "npm:^1"
23872395
"@types/lodash.clonedeep": "npm:^4"
23882396
"@types/mime": "npm:^4.0.0"
23892397
"@types/node": "npm:^22.0.0"
@@ -2417,6 +2425,7 @@ __metadata:
24172425
is-ci: "npm:~4.1.0"
24182426
istextorbinary: "npm:~9.5.0"
24192427
jju: "npm:~1.4.0"
2428+
js-levenshtein: "npm:^1.1.6"
24202429
lint-staged: "npm:^16.0.0"
24212430
lodash.clonedeep: "npm:^4.5.0"
24222431
mdast-util-from-markdown: "npm:^2.0.2"
@@ -5941,6 +5950,13 @@ __metadata:
59415950
languageName: node
59425951
linkType: hard
59435952

5953+
"js-levenshtein@npm:^1.1.6":
5954+
version: 1.1.6
5955+
resolution: "js-levenshtein@npm:1.1.6"
5956+
checksum: 10c0/14045735325ea1fd87f434a74b11d8a14380f090f154747e613529c7cff68b5ee607f5230fa40665d5fb6125a3791f4c223f73b9feca754f989b059f5c05864f
5957+
languageName: node
5958+
linkType: hard
5959+
59445960
"js-tokens@npm:^4.0.0":
59455961
version: 4.0.0
59465962
resolution: "js-tokens@npm:4.0.0"

0 commit comments

Comments
 (0)