From b406cc0ecfbf0bb9cb0c7384c1a17adc4924236a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 20 Jan 2018 02:52:47 -0800 Subject: [PATCH] feat: implemented not found hook --- .eslintignore | 1 + package.json | 13 +++++-- src/commands/hello.ts | 13 ------- src/hooks/not_found.ts | 28 ++++++++++++++ test/commands/hello.test.ts | 14 ------- test/fixtures/test/package.json | 15 ++++++++ test/fixtures/test/src/commands/hello.js | 15 ++++++++ test/hooks/not_found.test.ts | 15 ++++++++ yarn.lock | 47 +++++++++++++++++++++--- 9 files changed, 126 insertions(+), 35 deletions(-) delete mode 100644 src/commands/hello.ts create mode 100644 src/hooks/not_found.ts delete mode 100644 test/commands/hello.test.ts create mode 100644 test/fixtures/test/package.json create mode 100644 test/fixtures/test/src/commands/hello.js create mode 100644 test/hooks/not_found.test.ts diff --git a/.eslintignore b/.eslintignore index 502167fa..c6ddca41 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,2 @@ /lib +/test/fixtures diff --git a/package.json b/package.json index 06c603f2..8067802e 100644 --- a/package.json +++ b/package.json @@ -6,14 +6,19 @@ "bugs": "https://github.com/jdxcode/not-found/issues", "dependencies": { "@dxcli/command": "^0.1.13", - "cli-ux": "^3.1.3" + "@dxcli/config": "^0.1.21", + "@heroku-cli/color": "^1.1.1", + "cli-ux": "^3.1.3", + "string-similarity": "^1.2.0" }, "devDependencies": { "@dxcli/dev-semantic-release": "^0.0.3", - "@dxcli/dev-test": "^0.5.2", + "@dxcli/dev-test": "^0.7.0", "@dxcli/dev-tslint": "^0.0.15", + "@dxcli/version": "^0.1.4", "@types/node": "^9.3.0", "@types/read-pkg": "^3.0.0", + "@types/supports-color": "^3.1.0", "eslint": "^4.16.0", "eslint-config-dxcli": "^1.1.4", "husky": "^0.14.3", @@ -25,7 +30,9 @@ "typescript": "^2.6.2" }, "dxcli": { - "commands": "./lib/commands" + "hooks": { + "command_not_found": "./lib/hooks/not_found" + } }, "engines": { "node": ">=8.0.0" diff --git a/src/commands/hello.ts b/src/commands/hello.ts deleted file mode 100644 index 8e4dfc7b..00000000 --- a/src/commands/hello.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Command, {flags} from '@dxcli/command' -import cli from 'cli-ux' - -export default class CLI extends Command { - static flags = { - name: flags.string({char: 'n', description: 'name to print'}) - } - - async run() { - const name = this.flags.name || 'world' - cli.log(`hello ${name}!`) - } -} diff --git a/src/hooks/not_found.ts b/src/hooks/not_found.ts new file mode 100644 index 00000000..246a286a --- /dev/null +++ b/src/hooks/not_found.ts @@ -0,0 +1,28 @@ +import {Hooks, IHook} from '@dxcli/config' +import {color} from '@heroku-cli/color' +import cli from 'cli-ux' + +const hook: IHook = async opts => { + function closest(cmd: string) { + const DCE = require('string-similarity') + return DCE.findBestMatch(cmd, opts.config.engine.commandIDs).bestMatch.target + } + + let binHelp = `${opts.config.bin} help` + let idSplit = opts.id.split(':') + if (await opts.config.engine.findTopic(idSplit[0])) { + // if valid topic, update binHelp with topic + binHelp = `${binHelp} ${idSplit[0]}` + // if topic:COMMAND present, try closest for id + // if (idSplit[1]) closest = this.closest(id) + } + + let perhaps = closest ? `Perhaps you meant ${color.yellow(closest(opts.id))}\n` : '' + cli.error( + `${color.yellow(opts.id)} is not a ${opts.config.bin} command. + ${perhaps}Run ${color.cmd(binHelp)} for a list of available commands.`, + {exit: 127}, + ) +} + +export default hook diff --git a/test/commands/hello.test.ts b/test/commands/hello.test.ts deleted file mode 100644 index b5346758..00000000 --- a/test/commands/hello.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {describe, expect, it, output} from '@dxcli/dev-test' - -import cmd from '../../src/commands/hello' - -describe.stdout('command', () => { - it('says hello world!', async () => { - await cmd.run([]) - expect(output.stdout).to.equal('hello world!\n') - }) - it('says hello jeff!', async () => { - await cmd.run(['--name', 'jeff']) - expect(output.stdout).to.equal('hello jeff!\n') - }) -}) diff --git a/test/fixtures/test/package.json b/test/fixtures/test/package.json new file mode 100644 index 00000000..21b697bd --- /dev/null +++ b/test/fixtures/test/package.json @@ -0,0 +1,15 @@ +{ + "name": "@dxcli/test-not-found", + "version": "0.0.0", + "dxcli": { + "bin": "mycli", + "plugins": ["../.."], + "commands": "./src/commands" + }, + "engines": { + "node": ">=8.0.0" + }, + "files": [ + "/src" + ] +} diff --git a/test/fixtures/test/src/commands/hello.js b/test/fixtures/test/src/commands/hello.js new file mode 100644 index 00000000..1a762c0b --- /dev/null +++ b/test/fixtures/test/src/commands/hello.js @@ -0,0 +1,15 @@ +const {Command, flags} = require('@dxcli/command') +const {cli} = require('cli-ux') + +class CLI extends Command { + async run() { + const name = this.flags.name || 'world' + cli.log(`hello ${name}!`) + } +} + +CLI.flags = { + name: flags.string({char: 'n', description: 'name to print'}), +} + +module.exports = CLI diff --git a/test/hooks/not_found.test.ts b/test/hooks/not_found.test.ts new file mode 100644 index 00000000..ef81fade --- /dev/null +++ b/test/hooks/not_found.test.ts @@ -0,0 +1,15 @@ +import {describe, expect, testHook} from '@dxcli/dev-test' +import color from '@heroku-cli/color' +import * as path from 'path' + +color.enabled = false + +const root = path.join(__dirname, '../fixtures/test') + +describe('command', () => { + testHook('command_not_found', {id: 'hel'}, {root, stderr: true, exit: 127}, ({error}) => { + expect(error!.message).to.equal(`hel is not a mycli command. + Perhaps you meant hello +Run mycli help for a list of available commands.`) + }) +}) diff --git a/yarn.lock b/yarn.lock index 4c1fc0c7..7c0a2936 100644 --- a/yarn.lock +++ b/yarn.lock @@ -102,7 +102,7 @@ dependencies: find-up "^2.1.0" -"@dxcli/command@^0.1.13": +"@dxcli/command@^0.1.11", "@dxcli/command@^0.1.13": version "0.1.13" resolved "https://registry.yarnpkg.com/@dxcli/command/-/command-0.1.13.tgz#b4dec2e629076c2b50f4cf43c9324dd6ccb98382" dependencies: @@ -122,6 +122,16 @@ lodash "^4.17.4" read-pkg "^3.0.0" +"@dxcli/config@^0.1.21": + version "0.1.21" + resolved "https://registry.yarnpkg.com/@dxcli/config/-/config-0.1.21.tgz#d3cf65e672c5d0e36ba64982199021ede4b7a11a" + dependencies: + debug "^3.1.0" + fs-extra "^5.0.0" + load-json-file "^4.0.0" + lodash "^4.17.4" + read-pkg "^3.0.0" + "@dxcli/dev-commitmsg@^0.0.3": version "0.0.3" resolved "https://registry.yarnpkg.com/@dxcli/dev-commitmsg/-/dev-commitmsg-0.0.3.tgz#8941971c9778b675dd14c407c1123b8bef397757" @@ -146,9 +156,9 @@ "@semantic-release/npm" "^2.6.1" semantic-release "^12.2.0" -"@dxcli/dev-test@^0.5.2": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@dxcli/dev-test/-/dev-test-0.5.2.tgz#102e1f9a8922264a5050f6c16a8060ea26493152" +"@dxcli/dev-test@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@dxcli/dev-test/-/dev-test-0.7.0.tgz#bdbed14ed36cf94d3a5956643535b607611333f9" dependencies: "@dxcli/dev-nyc-config" "^0.0.3" "@dxcli/engine" "^0.1.5" @@ -221,6 +231,23 @@ version "0.0.1" resolved "https://registry.yarnpkg.com/@dxcli/screen/-/screen-0.0.1.tgz#9af4e8d0e5a9475e9e4b5f2da775b0447ff72fc2" +"@dxcli/version@^0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@dxcli/version/-/version-0.1.4.tgz#6f4da6fb9e8dbb58afcc3cb73974ba32abd573d6" + dependencies: + "@dxcli/command" "^0.1.11" + "@dxcli/config" "^0.1.20" + cli-ux "^3.1.3" + +"@heroku-cli/color@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@heroku-cli/color/-/color-1.1.1.tgz#a2c25239ff1196733a79cabc7a750cd46b96dc30" + dependencies: + ansi-styles "^3.2.0" + chalk "^2.3.0" + strip-ansi "^4.0.0" + supports-color "^5.1.0" + "@heroku/linewrap@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@heroku/linewrap/-/linewrap-1.0.0.tgz#a9d4e99f0a3e423a899b775f5f3d6747a1ff15c6" @@ -377,6 +404,10 @@ version "0.0.30" resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" +"@types/supports-color@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/supports-color/-/supports-color-3.1.0.tgz#3584b6b54f45333e988da2c29e6797eff5a20f8c" + JSONStream@^1.0.4: version "1.3.2" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.2.tgz#c102371b6ec3a7cf3b847ca00c20bb0fce4c6dea" @@ -2837,7 +2868,7 @@ lodash@4.17.2: version "4.17.2" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42" -lodash@^4.0.0, lodash@^4.11.1, lodash@^4.17.4, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1: +lodash@^4.0.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.17.4, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -4229,6 +4260,12 @@ strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" +string-similarity@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-1.2.0.tgz#d75153cb383846318b7a39a8d9292bb4db4e9c30" + dependencies: + lodash "^4.13.1" + string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"