diff --git a/ghost/pretty-cli/.eslintrc.js b/ghost/pretty-cli/.eslintrc.js new file mode 100644 index 0000000000..6a5eab530d --- /dev/null +++ b/ghost/pretty-cli/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: ['ghost'], + extends: [ + 'plugin:ghost/node', + ] +}; diff --git a/ghost/pretty-cli/LICENSE b/ghost/pretty-cli/LICENSE new file mode 100644 index 0000000000..e511320823 --- /dev/null +++ b/ghost/pretty-cli/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018-2019 Ghost Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ghost/pretty-cli/README.md b/ghost/pretty-cli/README.md new file mode 100644 index 0000000000..060c09d506 --- /dev/null +++ b/ghost/pretty-cli/README.md @@ -0,0 +1,46 @@ +# Pretty CLI + +A mini-module to style a [sywac](http://sywac.io/) instance in a standard way + +## Install + +Either: `npm install @tryghost/pretty-cli --save` + +Or: `yarn add @tryghost/pretty-cli` + +## Usage + +E.g. `const prettyCLI = require('@tryghost/pretty-cli');` + +`prettyCLI` is a pre-styled instance of the [sywac](http://sywac.io/) API. + +See the [sywac quickstart](http://sywac.io/docs/) and [config guide](http://sywac.io/docs/sync-config.html) for full usage. + +Example: + +``` +#!/usr/bin/env node +const prettyCLI = require('@tryghost/pretty-cli'); + + +prettyCLI + .command({ + flags: 'myTask [option]', + desc: 'Run myTask', + run: (argv) => { ... do something here } + }) + .parseAndExit(); +``` + +You can also grab a fresh instance of the api with `prettyCLI.Api.get()`. + +The style rules used are available at `prettyCLI.styles`. + +## Test + +- `yarn lint` run just eslint +- `yarn test` run lint && tests + +# Copyright & License + +Copyright (c) 2018-2019 Ghost Foundation - Released under the [MIT license](LICENSE). diff --git a/ghost/pretty-cli/index.js b/ghost/pretty-cli/index.js new file mode 100644 index 0000000000..e9fd56a9f9 --- /dev/null +++ b/ghost/pretty-cli/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/pretty-cli'); diff --git a/ghost/pretty-cli/lib/pretty-cli.js b/ghost/pretty-cli/lib/pretty-cli.js new file mode 100644 index 0000000000..7811943277 --- /dev/null +++ b/ghost/pretty-cli/lib/pretty-cli.js @@ -0,0 +1,30 @@ +const Api = require('sywac/api'); +const styles = require('./styles'); +const ui = require('./ui'); +/** + * Pretty CLI + * + * A mini-module to style a sywac instance in a standard way + */ + +// Exports a pre-configured version of sywac +module.exports = Api.get() +// Use help & version with short forms AND +// group them into a Global Options group to keep them separate from per-command options + .help('-h, --help', {group: 'Global Options:'}) + .version('-v, --version', {group: 'Global Options:'}) + // Load our style rules + .style(styles) + // Add some padding at the end + .epilogue(' ') + // If no command is passed, output the help menu + .showHelpByDefault(); + +// Expose a clean version, just in case +module.exports.Api = Api; + +// Export the styles +module.exports.styles = styles; + +// Export our ui tools +module.exports.ui = ui; diff --git a/ghost/pretty-cli/lib/styles.js b/ghost/pretty-cli/lib/styles.js new file mode 100644 index 0000000000..f7204c5e88 --- /dev/null +++ b/ghost/pretty-cli/lib/styles.js @@ -0,0 +1,21 @@ +const chalk = require('chalk'); + +module.exports = { + // Usage: script [options] etc + usagePrefix: (str) => { + return chalk.yellow(str.slice(0, 6)) + '\n ' + str.slice(7); + }, + // Options: Arguments: etc + group: str => chalk.yellow(str), + // --help etc + flags: str => chalk.green(str), + // [required] [boolean] etc + hints: str => chalk.dim(str), + // Use different style when a type is invalid + groupError: str => chalk.red(str), + flagsError: str => chalk.red(str), + descError: str => chalk.yellow(str), + hintsError: str => chalk.red(str), + // style error messages + messages: str => chalk.red(str) +}; diff --git a/ghost/pretty-cli/lib/ui.js b/ghost/pretty-cli/lib/ui.js new file mode 100644 index 0000000000..90014a225d --- /dev/null +++ b/ghost/pretty-cli/lib/ui.js @@ -0,0 +1,15 @@ +const chalk = require('chalk'); +const log = (...args) => console.log(...args); // eslint-disable-line no-console + +module.exports.log = log; +module.exports.log.error = (...args) => { + log(chalk.red('error'), ...args); +}; + +module.exports.log.info = (...args) => { + log(chalk.cyan('info'), ...args); +}; + +module.exports.log.ok = (...args) => { + log(chalk.green('ok'), ...args); +}; diff --git a/ghost/pretty-cli/package.json b/ghost/pretty-cli/package.json new file mode 100644 index 0000000000..21db9ef0b2 --- /dev/null +++ b/ghost/pretty-cli/package.json @@ -0,0 +1,31 @@ +{ + "name": "@tryghost/pretty-cli", + "version": "1.1.4", + "description": "A mini-module to style a sywac instance in a standard way", + "repository": "https://github.com/TryGhost/slimer/tree/master/packages/pretty-cli", + "author": "Ghost Foundation", + "license": "MIT", + "main": "index.js", + "scripts": { + "dev": "echo \"Implement me!\"", + "test": "NODE_ENV=testing mocha ./test/**/*.test.js", + "lint": "eslint . --ext .js --cache", + "posttest": "yarn lint" + }, + "files": [ + "index.js", + "lib" + ], + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "mocha": "6.0.2", + "should": "13.2.3", + "sinon": "7.2.7" + }, + "dependencies": { + "chalk": "^2.4.1", + "sywac": "^1.2.1" + } +} diff --git a/ghost/pretty-cli/test/.eslintrc.js b/ghost/pretty-cli/test/.eslintrc.js new file mode 100644 index 0000000000..edb3308632 --- /dev/null +++ b/ghost/pretty-cli/test/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: ['ghost'], + extends: [ + 'plugin:ghost/test', + ] +}; diff --git a/ghost/pretty-cli/test/pretty-cli.test.js b/ghost/pretty-cli/test/pretty-cli.test.js new file mode 100644 index 0000000000..e303cde15a --- /dev/null +++ b/ghost/pretty-cli/test/pretty-cli.test.js @@ -0,0 +1,32 @@ +// Switch these lines once there are useful utils +// const testUtils = require('./utils'); +require('./utils'); + +const prettyCLI = require('../lib/pretty-cli'); + +// Check the API is as we depend on in other modules; +describe('API', function () { + it('Exposes styled-sywac, styles & the sywac API', function () { + // Detect a basic prestyled sywac instance + prettyCLI.should.be.an.Object().with.property('types'); + prettyCLI.parseAndExit.should.be.a.Function(); + + // Detect the basic sywac Api + prettyCLI.Api.should.be.a.Function(); + prettyCLI.Api.get.should.be.a.Function(); + + // Detect style rules + prettyCLI.styles.should.be.an.Object(); + prettyCLI.styles.should.have.properties([ + 'usagePrefix', + 'group', + 'flags', + 'hints', + 'groupError', + 'flagsError', + 'descError', + 'hintsError', + 'messages' + ]); + }); +}); diff --git a/ghost/pretty-cli/test/utils/assertions.js b/ghost/pretty-cli/test/utils/assertions.js new file mode 100644 index 0000000000..7364ee8aa1 --- /dev/null +++ b/ghost/pretty-cli/test/utils/assertions.js @@ -0,0 +1,11 @@ +/** + * Custom Should Assertions + * + * Add any custom assertions to this file. + */ + +// Example Assertion +// should.Assertion.add('ExampleAssertion', function () { +// this.params = {operator: 'to be a valid Example Assertion'}; +// this.obj.should.be.an.Object; +// }); diff --git a/ghost/pretty-cli/test/utils/index.js b/ghost/pretty-cli/test/utils/index.js new file mode 100644 index 0000000000..0d67d86ff8 --- /dev/null +++ b/ghost/pretty-cli/test/utils/index.js @@ -0,0 +1,11 @@ +/** + * Test Utilities + * + * Shared utils for writing tests + */ + +// Require overrides - these add globals for tests +require('./overrides'); + +// Require assertions - adds custom should assertions +require('./assertions'); diff --git a/ghost/pretty-cli/test/utils/overrides.js b/ghost/pretty-cli/test/utils/overrides.js new file mode 100644 index 0000000000..90203424ee --- /dev/null +++ b/ghost/pretty-cli/test/utils/overrides.js @@ -0,0 +1,10 @@ +// This file is required before any test is run + +// Taken from the should wiki, this is how to make should global +// Should is a global in our eslint test config +global.should = require('should').noConflict(); +should.extend(); + +// Sinon is a simple case +// Sinon is a global in our eslint test config +global.sinon = require('sinon');