Skip to content

Commit

Permalink
feat: add help style support (#164)
Browse files Browse the repository at this point in the history
* WIP: Help Style configuration to eliminate excessively long help output

* WIP: trying to solve these testing issues

* WIP: tests passing but missing cli flags

* WIP: added tests for CLI flags

* WIP: change help-style alias to 'y' to maintain single char flag/dash pattern

* docs: Utils documentation fix (#163)

* Update concurrently => concurrent in examples

* Add myself as a contributer

* Add myself as a contributer properly, this time :)

* wIP: started on readme docs

* WIP: updated a couple files based on feedback in the pull request

* WIP: added myself as a contributor

* WIP: moved help-style defaults to function calls

* WIP: added check for undefined to helpstyle, almost 100% code coverage

* feat: implemented configuration options for Help Style

* fix: making sure tests/validations run properly
  • Loading branch information
K3TH3R authored and Kent C. Dodds committed Nov 9, 2017
1 parent fc7e660 commit 9338d72
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 22 deletions.
10 changes: 10 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,16 @@
"contributions": [
"doc"
]
},
{
"login": "iamkether",
"name": "Kether Saturnius",
"avatar_url": "https://avatars2.githubusercontent.com/u/11901111?v=4",
"profile": "http://www.k3th3r.com",
"contributions": [
"code",
"doc"
]
}
]
}
42 changes: 32 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ All the benefits of npm scripts without the cost of a bloated package.json and l
[![downloads][downloads-badge]][npm-stat]
[![MIT License][license-badge]][LICENSE]

[![All Contributors](https://img.shields.io/badge/all_contributors-35-orange.svg?style=flat-square)](#contributors)
[![All Contributors](https://img.shields.io/badge/all_contributors-36-orange.svg?style=flat-square)](#contributors)
[![PRs Welcome][prs-badge]][prs]
[![Donate][donate-badge]][donate]
[![Code of Conduct][coc-badge]][coc]
Expand Down Expand Up @@ -106,15 +106,17 @@ Commands:
completion generate bash completion script

Options:
--config, -c Config file to use (defaults to nearest package-scripts.yml
or package-scripts.js)
[default: "<path-to-your-project>/package-scripts.js"]
--silent, -s Silent nps output [boolean] [default: false]
--log-level, -l The log level to use
[choices: "error", "warn", "info", "debug"] [default: "info"]
--require, -r Module to preload
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
--config, -c Config file to use (defaults to nearest package-scripts.yml
or package-scripts.js)
[default: "<path-to-your-project>/package-scripts.js"]
--silent, -s Silent nps output [boolean] [default: false]
--log-level, -l The log level to use
[choices: "error", "warn", "info", "debug"] [default: "info"]
--require, -r Module to preload
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
--help-style, -y Style of help to use
[choices: "all", "scripts", "basic"] [default: "all"]

Examples:
nps.js test build Runs the `test` script then the
Expand Down Expand Up @@ -310,6 +312,25 @@ And you can pass arguments to scripts by putting the scripts in quotes:
nps "test --cover" check-coverage
```

##### -y, --help-style

By default, `nps` will dump a very long help documentation to the screen based on your package-scripts.js file. You can modify this output with one of three help-style options:

`all` gives you the normal default output:
```console
nps help "--help-style all"
```

`scripts` will give you only the help information built from your package-scripts.js file
```console
nps help "--help-style scripts"
```

`basic` will give you only the name and description of the scripts from your package-scripts.js file
```console
nps help "--help-style basic"
```

That's all for the CLI.

### package-scripts.js
Expand Down Expand Up @@ -470,6 +491,7 @@ Thanks goes to these people ([emoji key][emojis]):
| [<img src="https://avatars.githubusercontent.com/u/1155589?v=3" width="100px;"/><br /><sub>Sorin Muntean</sub>](https://github.com/sxn)<br />[💻](https://github.com/kentcdodds/p-s/commits?author=sxn "Code") [⚠️](https://github.com/kentcdodds/p-s/commits?author=sxn "Tests") [📖](https://github.com/kentcdodds/p-s/commits?author=sxn "Documentation") | [<img src="https://avatars.githubusercontent.com/u/1970063?v=3" width="100px;"/><br /><sub>Keith Gunn</sub>](https://github.com/gunnx)<br />[🐛](https://github.com/kentcdodds/p-s/issues?q=author%3Agunnx "Bug reports") [💻](https://github.com/kentcdodds/p-s/commits?author=gunnx "Code") [⚠️](https://github.com/kentcdodds/p-s/commits?author=gunnx "Tests") | [<img src="https://avatars.githubusercontent.com/u/1019478?v=3" width="100px;"/><br /><sub>Joe Martella</sub>](http://martellaj.github.io)<br />[🐛](https://github.com/kentcdodds/p-s/issues?q=author%3Amartellaj "Bug reports") [💻](https://github.com/kentcdodds/p-s/commits?author=martellaj "Code") [⚠️](https://github.com/kentcdodds/p-s/commits?author=martellaj "Tests") | [<img src="https://avatars.githubusercontent.com/u/1887854?v=3" width="100px;"/><br /><sub>Martin Segado</sub>](https://github.com/msegado)<br />[📖](https://github.com/kentcdodds/p-s/commits?author=msegado "Documentation") | [<img src="https://avatars.githubusercontent.com/u/36491?v=3" width="100px;"/><br /><sub>Bram Borggreve</sub>](http://colmena.io/)<br />[🐛](https://github.com/kentcdodds/p-s/issues?q=author%3Abeeman "Bug reports") [💻](https://github.com/kentcdodds/p-s/commits?author=beeman "Code") | [<img src="https://avatars.githubusercontent.com/u/86454?v=3" width="100px;"/><br /><sub>Elijah Manor</sub>](http://elijahmanor.com)<br />[📹](#video-elijahmanor "Videos") | [<img src="https://avatars.githubusercontent.com/u/10691183?v=3" width="100px;"/><br /><sub>Ragu Ramaswamy</sub>](https://github.com/rrag)<br />[💻](https://github.com/kentcdodds/p-s/commits?author=rrag "Code") [⚠️](https://github.com/kentcdodds/p-s/commits?author=rrag "Tests") [🐛](https://github.com/kentcdodds/p-s/issues?q=author%3Arrag "Bug reports") |
| [<img src="https://avatars.githubusercontent.com/u/2915616?v=3" width="100px;"/><br /><sub>Erik Fox</sub>](http://www.erikfox.co/)<br />[🐛](https://github.com/kentcdodds/p-s/issues?q=author%3Aerikfox "Bug reports") [💻](https://github.com/kentcdodds/p-s/commits?author=erikfox "Code") [📖](https://github.com/kentcdodds/p-s/commits?author=erikfox "Documentation") [⚠️](https://github.com/kentcdodds/p-s/commits?author=erikfox "Tests") | [<img src="https://avatars.githubusercontent.com/u/5351262?v=3" width="100px;"/><br /><sub>Aditya Pratap Singh</sub>](http://blog.adityapsingh.com)<br />[👀](#review-addityasingh "Reviewed Pull Requests") | [<img src="https://avatars.githubusercontent.com/u/7687132?v=3" width="100px;"/><br /><sub>bumbleblym</sub>](https://github.com/bumbleblym)<br />[💻](https://github.com/kentcdodds/p-s/commits?author=bumbleblym "Code") [📖](https://github.com/kentcdodds/p-s/commits?author=bumbleblym "Documentation") | [<img src="https://avatars.githubusercontent.com/u/7091543?v=3" width="100px;"/><br /><sub>Islam Attrash</sub>](https://twitter.com/IslamAttrash)<br />[💻](https://github.com/kentcdodds/p-s/commits?author=Attrash-Islam "Code") | [<img src="https://avatars.githubusercontent.com/u/7215306?v=3" width="100px;"/><br /><sub>JasonSooter</sub>](https://github.com/JasonSooter)<br />[📖](https://github.com/kentcdodds/p-s/commits?author=JasonSooter "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/116871?v=3" width="100px;"/><br /><sub>Nate Cavanaugh</sub>](http://alterform.com)<br />[💻](https://github.com/kentcdodds/p-s/commits?author=natecavanaugh "Code") | [<img src="https://avatars2.githubusercontent.com/u/3534924?v=3" width="100px;"/><br /><sub>Wissam Abirached</sub>](https://designingforscale.com)<br />[💻](https://github.com/kentcdodds/p-s/commits?author=wabirached "Code") [⚠️](https://github.com/kentcdodds/p-s/commits?author=wabirached "Tests") |
| [<img src="https://avatars1.githubusercontent.com/u/12592677?v=3" width="100px;"/><br /><sub>Paweł Mikołajczyk</sub>](https://github.com/Miklet)<br />[💻](https://github.com/kentcdodds/p-s/commits?author=Miklet "Code") [⚠️](https://github.com/kentcdodds/p-s/commits?author=Miklet "Tests") | [<img src="https://avatars0.githubusercontent.com/u/1295580?v=3" width="100px;"/><br /><sub>Kyle Welch</sub>](http://www.krwelch.com)<br />[💻](https://github.com/kentcdodds/p-s/commits?author=kwelch "Code") [⚠️](https://github.com/kentcdodds/p-s/commits?author=kwelch "Tests") | [<img src="https://avatars3.githubusercontent.com/u/22868432?v=3" width="100px;"/><br /><sub>Lufty Wiranda</sub>](http://instagram.com/luftywiranda13)<br />[💻](https://github.com/kentcdodds/p-s/commits?author=luftywiranda13 "Code") | [<img src="https://avatars6.githubusercontent.com/u/2936644?v=4" width="100px;"/><br /><sub>Bhargav Ponnapalli</sub>](http://imbhargav5.com)<br />[💻](https://github.com/kentcdodds/p-s/commits?author=imbhargav5 "Code") | [<img src="https://avatars0.githubusercontent.com/u/1538572?v=4" width="100px;"/><br /><sub>falieson</sub>](https://github.com/Falieson)<br />[📖](https://github.com/kentcdodds/p-s/commits?author=Falieson "Documentation") [🔧](#tool-Falieson "Tools") | [<img src="https://avatars2.githubusercontent.com/u/22251956?v=4" width="100px;"/><br /><sub>Suhas Karanth</sub>](https://github.com/sudo-suhas)<br />[🐛](https://github.com/kentcdodds/p-s/issues?q=author%3Asudo-suhas "Bug reports") [💻](https://github.com/kentcdodds/p-s/commits?author=sudo-suhas "Code") | [<img src="https://avatars3.githubusercontent.com/u/1228867?v=4" width="100px;"/><br /><sub>Eric Skram</sub>](http://www.ericskram.com)<br />[📖](https://github.com/kentcdodds/p-s/commits?author=Vpr99 "Documentation") |
| [<img src="https://avatars2.githubusercontent.com/u/11901111?v=4" width="100px;"/><br /><sub>Kether Saturnius</sub>](http://www.k3th3r.com)<br />[💻](https://github.com/kentcdodds/p-s/commits?author=iamkether "Code") [📖](https://github.com/kentcdodds/p-s/commits?author=iamkether "Documentation") |
<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors][all-contributors] specification.
Expand Down
133 changes: 133 additions & 0 deletions src/bin-utils/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ test('loadConfig: calls the config function if it is a function', () => {
scripts: {
functionConfig: 'echo worked!',
},
options: {
'help-style': 'all',
},
})
})

Expand Down Expand Up @@ -375,6 +378,136 @@ test('specificHelpScript : help: shows script not found when no match found', ()
expect(actual).toBe(expected)
})

test('helpStyle: output help with trailing scripts', () => {
const config = {
options: {
'help-style': 'scripts',
},
scripts: {
default: {
description: 'the default script',
script: 'echo "default"',
},
foo: {
description: 'the foo script',
script: 'echo "foo"',
},
bar: {
default: {
description: 'stuff',
script: 'echo "bar default"',
},
baz: 'echo "baz"',
barBub: {
script: 'echo "barBub"',
},
},
build: {
default: 'webpack',
x: {
default: {
script: 'webpack --env.x',
description: 'webpack with x env',
},
y: {
description: 'build X-Y',
script: 'echo "build x-y"',
},
},
},
foobar: 'echo "foobar"',
extra: 42,
},
}

const message = help(config)
const expected = `
Available scripts (camel or kebab case accepted)
${chalk.green('default')} - ${chalk.white('the default script')} - ${chalk.gray(
'echo "default"',
)}
${chalk.green('foo')} - ${chalk.white('the foo script')} - ${chalk.gray(
'echo "foo"',
)}
${chalk.green('bar')} - ${chalk.white('stuff')} - ${chalk.gray(
'echo "bar default"',
)}
${chalk.green('bar.baz')} - ${chalk.gray('echo "baz"')}
${chalk.green('bar.barBub')} - ${chalk.gray('echo "barBub"')}
${chalk.green('build')} - ${chalk.gray('webpack')}
${chalk.green('build.x')} - ${chalk.white('webpack with x env')} - ${chalk.gray(
'webpack --env.x',
)}
${chalk.green('build.x.y')} - ${chalk.white('build X-Y')} - ${chalk.gray(
'echo "build x-y"',
)}
${chalk.green('foobar')} - ${chalk.gray('echo "foobar"')}
`.trim()

expect(message).toBe(expected)
})

test('helpStyle: output help without trailing scripts', () => {
const config = {
options: {
'help-style': 'basic',
},
scripts: {
default: {
description: 'the default script',
script: 'echo "default"',
},
foo: {
description: 'the foo script',
script: 'echo "foo"',
},
bar: {
default: {
description: 'stuff',
script: 'echo "bar default"',
},
baz: 'echo "baz"',
barBub: {
script: 'echo "barBub"',
},
},
build: {
default: 'webpack',
x: {
default: {
script: 'webpack --env.x',
description: 'webpack with x env',
},
y: {
description: 'build X-Y',
script: 'echo "build x-y"',
},
},
},
foobar: 'echo "foobar"',
extra: 42,
},
}

const message = help(config)
const expected = `
Available scripts (camel or kebab case accepted)
${chalk.green('default')} - ${chalk.white('the default script')}
${chalk.green('foo')} - ${chalk.white('the foo script')}
${chalk.green('bar')} - ${chalk.white('stuff')}
${chalk.green('bar.baz')}
${chalk.green('bar.barBub')}
${chalk.green('build')}
${chalk.green('build.x')} - ${chalk.white('webpack with x env')}
${chalk.green('build.x.y')} - ${chalk.white('build X-Y')}
${chalk.green('foobar')}
`.trim()

expect(message).toBe(expected)
})

function getAbsoluteFixturePath(fixture) {
return path.join(__dirname, 'fixtures', fixture)
}
5 changes: 4 additions & 1 deletion src/bin-utils/__tests__/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ const valid = [
'',
'--help',
'-h',
'--help-style scripts',
'-y basic',
'--version',
'-v',
'--silent',
Expand Down Expand Up @@ -195,7 +197,7 @@ test('init without an existing config will initialize package-scripts.js', () =>
})

test('if there is a help script in the psConfig, does not show the help', () => {
mockBinUtils.mock.psConfig = {scripts: {help: 'hi'}}
mockBinUtils.mock.psConfig = {scripts: {help: 'hi'}, options: {}}
expect(parse('help')).not.toBe(undefined)
expect(mockGetLogger.mock.info).toHaveBeenCalledTimes(0)
})
Expand All @@ -208,6 +210,7 @@ test('if help is called with a script, it shows the help for that script', () =>
script: 'echo "specific"',
},
},
options: {},
}
expect(parse('help specific')).toBe(undefined)
expect(mockBinUtils.specificHelpScript).toHaveBeenCalledTimes(1)
Expand Down
34 changes: 24 additions & 10 deletions src/bin-utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,14 @@ function loadConfig(configPath, input) {
})
throw new Error(typeMessage)
}
return config

const defaultConfig = {
options: {
'help-style': 'all',
},
}

return {...defaultConfig, ...config}
}

export {
Expand Down Expand Up @@ -171,25 +178,32 @@ function requireDefaultFromModule(modulePath) {
}
}

function scriptObjectToChalk({name, description, script}) {
function scriptObjectToChalk(options, {name, description, script}) {
const coloredName = chalk.green(name)
const coloredScript = chalk.gray(script)
let line
const line = [coloredName]
let showScript = true
if (typeof options !== 'undefined' && options['help-style'] === 'basic') {
showScript = false
}
if (description) {
line = [coloredName, chalk.white(description), coloredScript]
} else {
line = [coloredName, coloredScript]
line.push(chalk.white(description))
}
if (showScript) {
line.push(coloredScript)
}
return line.join(' - ').trim()
}

function help({scripts}) {
function help({scripts, options}) {
const availableScripts = getAvailableScripts(scripts)
const filteredScripts = availableScripts.filter(
script => !script.hiddenFromHelp,
)
const scriptLines = filteredScripts.map(scriptObjectToChalk)
if (scriptLines.length) {
if (filteredScripts.length > 0) {
const scriptLines = filteredScripts.map(
scriptObjectToChalk.bind(null, options || {'help-style': 'all'}),
)
const topMessage = 'Available scripts (camel or kebab case accepted)'
const message = `${topMessage}\n\n${scriptLines.join('\n')}`
return message
Expand All @@ -203,7 +217,7 @@ function specificHelpScript(config, scriptName) {
if (isNull(script)) {
return chalk.yellow(`Script matching name ${scriptName} was not found.`)
} else {
return scriptObjectToChalk(script)
return scriptObjectToChalk({'help-style': 'all'}, script)
}
}

Expand Down
15 changes: 14 additions & 1 deletion src/bin-utils/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ function parse(rawArgv) {
type: 'boolean',
default: true,
},
'help-style': {
describe: 'Choose the level of detail displayed by the help command',
choices: ['all', 'scripts', 'basic'],
alias: 'y',
default: 'all',
},
}

const yargsInstance = yargs(rawArgv)
Expand Down Expand Up @@ -117,6 +123,7 @@ function parse(rawArgv) {
log.info(help(psConfig))
return true
}
const helpStyle = String(psConfig.options['help-style'])
const hasDefaultScript = Boolean(psConfig.scripts.default)
const noScriptSpecifiedAndNoDefault =
!specifiedScripts.length && !hasDefaultScript
Expand All @@ -129,7 +136,13 @@ function parse(rawArgv) {
log.info(specificHelpScript(psConfig, specifiedScripts[1]))
return true
} else if (commandIsHelp || noScriptSpecifiedAndNoDefault) {
parser.showHelp('log')
// Can't achieve 100% branch coverage without refactoring this showHelp()
// function into ./index.js and re-working existing tests and such. Branch
// options aren't relevant here either, so telling Istanbul to ignore.
/* istanbul ignore next */
if (helpStyle === 'all') {
parser.showHelp('log')
}
log.info(help(psConfig))
return true
}
Expand Down

0 comments on commit 9338d72

Please sign in to comment.