Skip to content

Commit

Permalink
feat: support spaced commands (#166)
Browse files Browse the repository at this point in the history
* feat: support spaced commands

* fix: do not suggest hidden commands

* chore: prepare for v2

* chore: update core

* chore: update circle config

* chore: remove github actions

* chore: regenerate lock file
  • Loading branch information
mdonnalley committed Jun 7, 2021
1 parent d7f5ae8 commit 4222d2d
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 113 deletions.
84 changes: 24 additions & 60 deletions .circleci/config.yml
@@ -1,65 +1,29 @@
---
version: 2
jobs:
node-latest: &test
docker:
- image: node:latest
working_directory: ~/cli
steps:
- checkout
- restore_cache: &restore_cache
keys:
- v1-npm-{{checksum ".circleci/config.yml"}}-{{checksum "yarn.lock"}}
- v1-npm-{{checksum ".circleci/config.yml"}}
- run:
name: Install dependencies
command: yarn
- run:
name: Run tests
command: yarn test
node-12:
<<: *test
docker:
- image: node:12
node-10:
<<: *test
docker:
- image: node:10
release:
<<: *test
steps:
- add_ssh_keys
- checkout
- restore_cache: *restore_cache
- run:
name: Install release dependencies
command: |
yarn global add @oclif/semantic-release@3 semantic-release@17
yarn --frozen-lockfile
- run:
name: Cut release
command: |
export PATH=/usr/local/share/.config/yarn/global/node_modules/.bin:$PATH
semantic-release -e @oclif/semantic-release
- save_cache:
key: v1-yarn-{{checksum ".circleci/config.yml"}}-{{checksum "yarn.lock"}}
paths:
- ~/cli/node_modules
- /usr/local/share/.cache/yarn
- /usr/local/share/.config/yarn
version: 2.1

orbs:
release-management: salesforce/npm-release-management@4

workflows:
version: 2
"@oclif/plugin-not-found":
test-and-release:
jobs:
- node-latest
- node-12
- node-10
- release:
context: org-global
filters:
branches: {only: master}
- release-management/test-package:
matrix:
parameters:
os:
- linux
- windows
node_version:
- latest
- lts
exclude:
- os: windows
node_version: lts
- release-management/release-package:
github-release: true
tag: core-v1
requires:
- node-latest
- node-12
- node-10
- release-management/test-package
filters:
branches:
only: main
1 change: 0 additions & 1 deletion .github/dependabot.yml
Expand Up @@ -10,5 +10,4 @@ updates:
pull-request-branch-name:
separator: "-"
ignore:
- dependency-name: "typescript"
- dependency-name: "fs-extra"
26 changes: 0 additions & 26 deletions .github/workflows/ci.yml

This file was deleted.

16 changes: 8 additions & 8 deletions package.json
@@ -1,7 +1,7 @@
{
"name": "@oclif/plugin-not-found",
"description": "\"did you mean\" for oclif",
"version": "1.2.4",
"version": "2.0.0",
"author": "Jeff Dickey @jdxcode",
"oclif": {
"hooks": {
Expand All @@ -15,7 +15,7 @@
"bugs": "https://github.com/oclif/plugin-not-found/issues",
"dependencies": {
"@oclif/color": "^0.x",
"@oclif/command": "^1.6.0",
"@oclif/core": "0.5.3",
"cli-ux": "^5.5.1",
"fast-levenshtein": "^3.0.0",
"lodash": "^4.17.21"
Expand All @@ -30,19 +30,19 @@
"@types/chai": "^4.2.18",
"@types/fast-levenshtein": "^0.0.1",
"@types/lodash": "^4.14.170",
"@types/mocha": "^8.2.0",
"@types/mocha": "^8.2.2",
"@types/node": "^15.6.1",
"@types/supports-color": "^8.1.0",
"chai": "^4.2.0",
"eslint": "^7.27.0",
"eslint-config-oclif": "^3.1.0",
"chai": "^4.3.4",
"eslint-config-oclif-typescript": "^0.2.0",
"eslint-config-oclif": "^3.1.0",
"eslint": "^7.27.0",
"mocha": "^8.4.0",
"ts-node": "^9.1.1",
"typescript": "3.8.3"
"typescript": "^4.2.4"
},
"engines": {
"node": ">=8.0.0"
"node": ">=14.0.0"
},
"files": [
"/oclif.manifest.json",
Expand Down
24 changes: 14 additions & 10 deletions src/index.ts
@@ -1,41 +1,45 @@
import {color} from '@oclif/color'
import {Hook} from '@oclif/config'
import {Hook, toConfiguredId} from '@oclif/core'
import {cli} from 'cli-ux'
import * as Levenshtein from 'fast-levenshtein'
import * as _ from 'lodash'

const hook: Hook.CommandNotFound = async function (opts) {
const hiddenCommandIds = opts.config.commands.filter(c => c.hidden).map(c => c.id)
const commandIDs = [
...opts.config.commandIDs,
..._.flatten(opts.config.commands.map(c => c.aliases)),
'version',
]
].filter(c => !hiddenCommandIds.includes(c))

if (commandIDs.length === 0) return
function closest(cmd: string) {
function closest(cmd: string): string {
return _.minBy(commandIDs, c => Levenshtein.get(cmd, c))!
}

let binHelp = `${opts.config.bin} help`
const idSplit = opts.id.split(':')
if (await opts.config.findTopic(idSplit[0])) {
if (opts.config.findTopic(idSplit[0])) {
// if valid topic, update binHelp with topic
binHelp = `${binHelp} ${idSplit[0]}`
}

const suggestion: string = closest(opts.id)
this.warn(`${color.yellow(opts.id)} is not a ${opts.config.bin} command.`)
const suggestion = closest(opts.id)
const readableSuggestion = toConfiguredId(suggestion, this.config)
const originalCmd = toConfiguredId(opts.id, this.config)
this.warn(`${color.yellow(originalCmd)} is not a ${opts.config.bin} command.`)

let response
let response = ''
try {
response = await cli.prompt(`Did you mean ${color.blueBright(suggestion)}? [y/n]`, {timeout: 4900})
response = await cli.prompt(`Did you mean ${color.blueBright(readableSuggestion)}? [y/n]`, {timeout: 4900})
} catch (error) {
this.log('')
this.debug(error)
}

if (response === 'y') {
const argv = process.argv
await this.config.runCommand(suggestion, argv.slice(3, argv.length))
const argv = opts.argv || process.argv.slice(3, process.argv.length)
await this.config.runCommand(suggestion, argv)
this.exit(0)
}

Expand Down
10 changes: 10 additions & 0 deletions test/hooks/not-found.test.ts
Expand Up @@ -17,6 +17,16 @@ describe('command_not_found', () => {
expect(ctx.stdout).to.be.contain('commands\nhelp')
})

test
.stderr()
.stub(cli, 'prompt', () => async () => 'y')
.stub(process, 'argv', [])
.hook('command_not_found', {id: 'commans', argv: ['foo', '--bar', 'baz']})
.catch('Unexpected arguments: foo, --bar, baz\nSee more help with --help')
.end('runs hook with suggested command and provided args on yes', (ctx: any) => {
expect(ctx.stderr).to.contain('Warning: commans is not a @oclif/plugin-not-found command.\n')
})

test
.stderr()
.stub(cli, 'prompt', () => async () => 'n')
Expand Down
67 changes: 59 additions & 8 deletions yarn.lock
Expand Up @@ -107,6 +107,28 @@
is-wsl "^2.1.1"
tslib "^2.0.0"

"@oclif/core@0.5.3":
version "0.5.3"
resolved "https://registry.npmjs.org/@oclif/core/-/core-0.5.3.tgz#ac360e9a37aa8d57c93081906292a13d2c41bd52"
integrity sha512-MtaSCv6O3NagFPHPHYssYSHZ/K2BExI/zB6exaWA9kjycTYgnLABwUjw5kaHmX9WkXDNGOyjaHBhqmoRSozfOA==
dependencies:
"@oclif/linewrap" "^1.0.0"
chalk "^4.1.0"
clean-stack "^3.0.0"
cli-ux "^5.1.0"
debug "^4.1.1"
fs-extra "^9.0.1"
globby "^11.0.1"
indent-string "^4.0.0"
is-wsl "^2.1.1"
lodash.template "^4.4.0"
semver "^7.3.2"
string-width "^4.2.0"
strip-ansi "^6.0.0"
tslib "^2.0.0"
widest-line "^3.1.0"
wrap-ansi "^7.0.0"

"@oclif/dev-cli@^1.26.0":
version "1.26.0"
resolved "https://registry.yarnpkg.com/@oclif/dev-cli/-/dev-cli-1.26.0.tgz#e3ec294b362c010ffc8948003d3770955c7951fd"
Expand Down Expand Up @@ -225,7 +247,7 @@
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.5.tgz#8a4accfc403c124a0bafe8a9fc61a05ec1032073"
integrity sha512-lAVp+Kj54ui/vLUFxsJTMtWvZraZxum3w3Nwkble2dNuV5VnPA+Mi2oGX9XYJAaIvZi3tn3cbjS/qcJXRb6Bww==

"@types/mocha@^8.2.0":
"@types/mocha@^8.2.2":
version "8.2.2"
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.2.tgz#91daa226eb8c2ff261e6a8cbf8c7304641e095e0"
integrity sha512-Lwh0lzzqT5Pqh6z61P3c3P5nm6fzQK/MMHl9UKeneAeInVflBSz1O2EkX6gM6xfJd7FBXBY5purtLx7fUiZ7Hw==
Expand Down Expand Up @@ -468,6 +490,11 @@ astral-regex@^2.0.0:
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==

at-least-node@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==

atob@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
Expand Down Expand Up @@ -601,7 +628,7 @@ cardinal@^2.1.1:
ansicolors "~0.3.2"
redeyed "~2.1.0"

chai@^4.2.0:
chai@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49"
integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==
Expand Down Expand Up @@ -718,9 +745,9 @@ cli-ux@^4.8.2:
supports-hyperlinks "^1.0.1"
treeify "^1.1.0"

cli-ux@^5.2.1, cli-ux@^5.5.1:
cli-ux@^5.1.0, cli-ux@^5.2.1, cli-ux@^5.5.1:
version "5.5.1"
resolved "https://registry.yarnpkg.com/cli-ux/-/cli-ux-5.5.1.tgz#99d28dae0c3ef7845fa2ea56e066a1d5fcceca9e"
resolved "https://registry.npmjs.org/cli-ux/-/cli-ux-5.5.1.tgz#99d28dae0c3ef7845fa2ea56e066a1d5fcceca9e"
integrity sha512-t3DT1U1C3rArLGYLpKa3m9dr/8uKZRI8HRm/rXKL7UTjm4c+Yd9zHNWg1tP8uaJkUbhmvx5SQHwb3VWpPUVdHQ==
dependencies:
"@oclif/command" "^1.6.0"
Expand Down Expand Up @@ -1448,6 +1475,16 @@ fs-extra@^8.1:
jsonfile "^4.0.0"
universalify "^0.1.0"

fs-extra@^9.0.1:
version "9.1.0"
resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
dependencies:
at-least-node "^1.0.0"
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"

fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
Expand Down Expand Up @@ -1964,6 +2001,15 @@ jsonfile@^4.0.0:
optionalDependencies:
graceful-fs "^4.1.6"

jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
dependencies:
universalify "^2.0.0"
optionalDependencies:
graceful-fs "^4.1.6"

kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
version "3.2.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
Expand Down Expand Up @@ -3154,10 +3200,10 @@ type-fest@^0.8.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==

typescript@3.8.3:
version "3.8.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==
typescript@^4.2.4:
version "4.2.4"
resolved "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961"
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==

union-value@^1.0.0:
version "1.0.0"
Expand All @@ -3174,6 +3220,11 @@ universalify@^0.1.0:
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==

universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==

unset-value@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
Expand Down

0 comments on commit 4222d2d

Please sign in to comment.