├── .babelrc ├── .npmignore ├── .gitignore ├── test ├── mockData │ └── messages.js ├── stream.js ├── 02-unstyled.js ├── 06-builtin-template.js ├── 07-advanced-titles.js ├── 05-custom-template.js ├── 09-context.js └── 08-stack.js ├── src ├── utils.js ├── templates │ ├── basic.js │ └── advanced.js ├── index.js └── Pretty.js ├── examples └── build-result.js ├── package.json └── README.md /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | /src/ 3 | node_modules 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /lib/ 2 | /node_modules/ 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /test/mockData/messages.js: -------------------------------------------------------------------------------- 1 | const warnings = [ 2 | { 3 | type: 'title', 4 | name: 'WARNING', 5 | message: "This is a warning title\n" 6 | }, 7 | { 8 | message: "This is a warning message with description", 9 | description: 'You can add very long descriptions, also pieces of code' 10 | }, 11 | "This is a warning message\n" 12 | ]; 13 | 14 | module.exports = { 15 | warnings 16 | }; 17 | -------------------------------------------------------------------------------- /test/stream.js: -------------------------------------------------------------------------------- 1 | module.exports = function captureStream(stream){ 2 | var oldWrite = stream.write; 3 | var buf = ''; 4 | stream.write = function(chunk, encoding, callback){ 5 | buf += chunk.toString(); // chunk is a String or Buffer 6 | oldWrite.apply(stream, arguments); 7 | } 8 | 9 | return { 10 | unhook: function unhook(){ 11 | stream.write = oldWrite; 12 | }, 13 | captured: function(){ 14 | return buf; 15 | } 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | 2 | const UTILS = (template, pretty)=>{ 3 | return { 4 | /** 5 | * Indent add a number of spaces before the text in order to put in in the same line 6 | * 7 | * @param {string|array} content if content is a string the function tries to split it 8 | * @return {[type]} [description] 9 | */ 10 | indent:(content)=>{ 11 | return pretty._output(content, 'line'); 12 | } 13 | } 14 | } 15 | export default UTILS; 16 | -------------------------------------------------------------------------------- /src/templates/basic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Inspired by 3 | * https://twitter.com/andreypopp/status/758251557100064768 4 | */ 5 | var colors = require('colors'); 6 | 7 | module.exports = { 8 | 'info': function(message){return ' I '.bgBlue.black +" " + message}, 9 | 'error': function(message){return ' E '.bgRed.white +" " + message}, 10 | 'log': function(message){return ' L '.bgWhite.black +" " + message}, 11 | 'warning': function(message){return ' W '.bgYellow.black +" " + message} 12 | } 13 | -------------------------------------------------------------------------------- /test/02-unstyled.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert; 2 | var captureStream = require('./stream.js'); 3 | var pretty = require('../src/pretty.js')(); 4 | 5 | 6 | describe("Unstyled output", function(){ 7 | var hook; 8 | beforeEach(function(){ 9 | hook = captureStream(process.stdout); 10 | }); 11 | 12 | afterEach(function(){ 13 | hook.unhook(); 14 | }); 15 | 16 | it("Should print some unstyled log output", function(){ 17 | pretty.log('hi'); 18 | assert.equal(hook.captured(),'hi\n'); 19 | }) 20 | 21 | it("Should print some unstyled info", function(){ 22 | pretty.info('info message'); 23 | assert.equal(hook.captured(),'info message\n'); 24 | }) 25 | it("Should print some unstyled error", function(){ 26 | pretty.error('error message'); 27 | assert.equal(hook.captured(),'error message\n'); 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /test/06-builtin-template.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert; 2 | var captureStream = require('./stream.js'); 3 | var colors = require('colors') 4 | 5 | const TEMPLATE = require('../src/templates/basic'); 6 | 7 | var pretty = require('../src/pretty.js')({ 8 | template: TEMPLATE 9 | }); 10 | 11 | 12 | 13 | describe("Built-in Template", function(){ 14 | var hook; 15 | beforeEach(function(){ 16 | hook = captureStream(process.stdout); 17 | }); 18 | afterEach(function(){ 19 | hook.unhook(); 20 | }); 21 | var tests = { 22 | warning: 'Warning Message', 23 | log: 'Log Message', 24 | error: 'Error Message', 25 | info: 'Info Message' 26 | }; 27 | 28 | Object.keys(tests) 29 | .map(function(key, i){ 30 | it("Should print some "+ key, function(){ 31 | var msg = tests[key] 32 | pretty[key](msg); 33 | assert.equal(hook.captured(),TEMPLATE[key](msg)+'\n'); 34 | }) 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /test/07-advanced-titles.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert; 2 | var captureStream = require('./stream.js'); 3 | var colors = require('colors') 4 | 5 | const TEMPLATE = require('../src/templates/advanced'); 6 | 7 | var pretty = require('../src/pretty.js')({ 8 | template: TEMPLATE 9 | }); 10 | 11 | 12 | describe("Titles", function(){ 13 | var hook; 14 | beforeEach(function(){ 15 | hook = captureStream(process.stdout); 16 | }); 17 | afterEach(function(){ 18 | hook.unhook(); 19 | }); 20 | 21 | var tests = { 22 | warning: {type:'title', name:'WARNING', message:"This is a warning title"}, 23 | log: {type:'title', name:'MODULE', message:"Log Title"} , 24 | error: {type:'title', name:'ERROR', message:"Error Title"}, 25 | info: {type:'title', name:'MODULE', message:"Info Title"} 26 | } 27 | 28 | Object.keys(tests) 29 | .map(function(key, i){ 30 | it("Should print a title of "+ key, function(){ 31 | var msg = tests[key] 32 | pretty[key](msg); 33 | assert.equal(hook.captured(),TEMPLATE[key](msg)+'\n'); 34 | }) 35 | }) 36 | 37 | }) 38 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | Copyright (c) 2016 Michael Cereda 4 | http://michaelcereda.com 5 | 6 | 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: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | 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. 11 | */ 12 | 13 | import Pretty from './Pretty'; 14 | 15 | module.exports = Pretty; 16 | -------------------------------------------------------------------------------- /test/05-custom-template.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert; 2 | var captureStream = require('./stream.js'); 3 | var colors = require('colors'); 4 | 5 | const TEMPLATE = { 6 | 'info': function(message){return ' I '.bgBlue.black +" " + message}, 7 | 'error': function(message){return ' E '.bgRed.white +" " + message}, 8 | 'log': function(message){return ' L '.bgWhite.black +" " + message}, 9 | 'warning': function(message){return ' W '.bgYellow.black +" " + message} 10 | } 11 | var pretty = require('../src/pretty.js')({ 12 | template: TEMPLATE 13 | }); 14 | 15 | 16 | describe("Custom Template", function(){ 17 | var hook; 18 | beforeEach(function(){ 19 | hook = captureStream(process.stdout); 20 | }); 21 | afterEach(function(){ 22 | hook.unhook(); 23 | }); 24 | var tests = { 25 | warning: 'Warning Message', 26 | log: 'Log Message', 27 | error: 'Error Message', 28 | info: 'Info Message'}; 29 | 30 | Object.keys(tests) 31 | .map(function(key, i){ 32 | it("Should print some "+ key, function(){ 33 | var msg = tests[key] 34 | pretty[key](msg); 35 | assert.equal(hook.captured(),TEMPLATE[key](msg)+'\n'); 36 | }) 37 | }) 38 | 39 | }) 40 | -------------------------------------------------------------------------------- /examples/build-result.js: -------------------------------------------------------------------------------- 1 | var pretty = require('../lib')({ 2 | template: require('../lib/templates/advanced') 3 | }) 4 | pretty.addCustomMethod('stats', function(content){ 5 | return pretty.error({ 6 | type:'title', 7 | name:'STATS', 8 | message: "time: "+ content.time+', errors:'+ content.errors+', warnings:'+content.warnings}) 9 | }) 10 | 11 | pretty.error({type:'title', name:'BUILD', message:'complete with errors'}) 12 | // pretty.error({type:'title', name:'STATS', message:'time: 45ms, errors: 1, warnings:3\n'}) 13 | pretty.stats({time:'30ms', errors:12, warnings:3}) 14 | console.log('') 15 | pretty.error({message:'../files/test.js\n',name:'MODULE', type:'title'}) 16 | var description = 17 | "[00:00:19] Failed to load external module babel-core/register\n" 18 | +"[00:00:19] Failed to load external module babel/register\n" 19 | +"\n" 20 | +"module, __filename, __dirname) { import ...\n" 21 | +" ^^^^^^\n" 22 | +"\n" 23 | +"SyntaxError: Unexpected reserved word\n" 24 | +" at exports.runInThisContext (vm.js:53:16)\n" 25 | 26 | 27 | 28 | pretty.error({message:'Test', description:description}) 29 | console.log('') 30 | pretty.warning({message:'../files/test.js\n',name:'MODULE', type:'title'}) 31 | pretty.warning({message:'Test', description:description}) 32 | -------------------------------------------------------------------------------- /test/09-context.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert; 2 | var captureStream = require('./stream.js'); 3 | var colors = require('colors') 4 | 5 | const TEMPLATE = require('../src/templates/advanced'); 6 | 7 | var pretty = require('../src/pretty.js')({ 8 | template: TEMPLATE 9 | }); 10 | 11 | 12 | describe("Context", function(){ 13 | var hook; 14 | beforeEach(function(){ 15 | hook = captureStream(process.stdout); 16 | }); 17 | afterEach(function(){ 18 | hook.unhook(); 19 | }); 20 | 21 | it("Should add field from context", function(){ 22 | var title = {type:'title', name:'WARNING', message:"This is a warning title\n"}; 23 | var message = "This is a warning message\n" 24 | var message_obj = {message:"This is a warning message with description"} 25 | pretty.context({description:'You can add very long descriptions, also pieces of code'}); 26 | pretty.warning(title); 27 | pretty.warning(message); 28 | pretty.warning(message_obj); 29 | 30 | var checkMessage = TEMPLATE.warning(title)+'\n' + 31 | TEMPLATE.warning(message)+'\n' + 32 | TEMPLATE.warning(message_obj)+'\n' 33 | ; 34 | assert.equal(hook.captured(), checkMessage); 35 | assert.property(message_obj,'description'); 36 | }); 37 | }) 38 | -------------------------------------------------------------------------------- /test/08-stack.js: -------------------------------------------------------------------------------- 1 | const assert = require('chai').assert; 2 | const captureStream = require('./stream.js'); 3 | const colors = require('colors'); 4 | const prettyInit = require('../src/pretty.js'); 5 | 6 | const msg = require('./mockData/messages').warnings; 7 | const template = require('../src/templates/advanced'); 8 | const pretty = require('../src/pretty.js')({ 9 | template 10 | }); 11 | 12 | function buildStack(stack, msg) { 13 | return msg.forEach(item => stack.warning(item)); 14 | } 15 | 16 | describe('Stack', () => { 17 | let hook; 18 | let stack; 19 | 20 | beforeEach(() => { 21 | hook = captureStream(process.stdout); 22 | stack = pretty.stack('build'); 23 | }); 24 | 25 | afterEach(() => { 26 | hook.unhook(); 27 | }); 28 | 29 | it('Should print title and message from the stack', () => { 30 | buildStack(stack, msg); 31 | stack.print(); 32 | 33 | const expected = msg.map(title => template.warning(title)).join('\n'); 34 | assert.deepEqual(hook.captured(), expected); 35 | }); 36 | 37 | it('Should handle multiple stacks independently', () => { 38 | buildStack(stack, msg); 39 | buildStack(stack, msg); 40 | 41 | stack.print(); 42 | 43 | let expected = msg.map(title => template.warning(title)).join('\n'); 44 | expected = expected + expected; 45 | assert.deepEqual(hook.captured(), expected); 46 | }); 47 | }) 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pretty-cli", 3 | "version": "0.0.13", 4 | "description": "Pretty-cli is a lightweight utility that helps you to create nice looking command line interfaces. It forces a well structured output and gives unimited flexibility with its templating system without adding any overhead.", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "test": "mocha --compilers js:babel-core/register --watch", 8 | "test-dbg": "mocha --debug --compilers js:babel-core/register --watch", 9 | "dev": "./node_modules/.bin/babel-watch index.js", 10 | "compile": "./node_modules/.bin/babel src --optional runtime -d lib", 11 | "compile-watch": "./node_modules/.bin/babel src --watch --optional runtime -d lib", 12 | "prepublish": "npm run compile" 13 | }, 14 | "keywords": [ 15 | "console", 16 | "pretty-cli", 17 | "prettify", 18 | "cli", 19 | "output", 20 | "print", 21 | "console.log", 22 | "log" 23 | ], 24 | "author": "Michael Cereda", 25 | "license": "MIT", 26 | "devDependencies": { 27 | "babel-cli": "^6.14.0", 28 | "babel-preset-es2015": "^6.14.0", 29 | "chai": "^3.5.0", 30 | "mocha": "^3.0.2" 31 | }, 32 | "repository": { 33 | "type": "git", 34 | "url": "https://github.com/MichaelCereda/pretty-cli.git" 35 | }, 36 | "dependencies": { 37 | "colors": "^1.1.2", 38 | "lodash": "^4.15.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/templates/advanced.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Inspired by 3 | * https://twitter.com/andreypopp/status/758251557100064768 4 | */ 5 | var colors = require('colors/safe'); 6 | 7 | /** 8 | * Creating advanced themes is very easy. 9 | * _content_ can be a string or a JSON object, you have total control over the 10 | * formatting. 11 | * 12 | * Here I'm building the template using a loop, you can do as you 13 | * prefer. Loops help you to keep your style intact even if you add a lot of 14 | * elements. 15 | */ 16 | 17 | 18 | function block(msg){ 19 | return ' '+msg+' '; 20 | } 21 | 22 | var types = { 23 | 'info': {initial: 'I', blockBg:['bgBlue','black'], titleColor:'blue'}, 24 | 'error': {initial: 'E', blockBg:['bgRed','white'], titleColor:'red'}, 25 | 'log': {initial: 'L', blockBg:['bgWhite','black'], titleColor:'white'}, 26 | 'warning': {initial: 'W', blockBg:['bgYellow','black'], titleColor:'yellow'}, 27 | } 28 | 29 | var template = {}; 30 | Object.keys(types).map(function(type){ 31 | var _specs = types[type]; 32 | 33 | template[type] = function(content){ 34 | var line = colors[_specs.blockBg[0]][_specs.blockBg[1]](block(_specs.initial)) 35 | +" " + content; 36 | if(typeof content !== 'string'){ 37 | line = colors[_specs.blockBg[0]][_specs.blockBg[1]](block(_specs.initial)) 38 | +" " + content.message; 39 | if(content.type=='title'){ 40 | line = colors[_specs.blockBg[0]][_specs.blockBg[1]](block(content.name)) 41 | + " " + colors[_specs.titleColor](content.message); 42 | } 43 | if(content.description){ 44 | line +='\n'+ content.description; 45 | } 46 | } 47 | return line; 48 | } 49 | }) 50 | module.exports = template; 51 | -------------------------------------------------------------------------------- /src/Pretty.js: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | Copyright (c) 2016 Michael Cereda 4 | http://michaelcereda.com 5 | 6 | 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: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | 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. 11 | */ 12 | 13 | import {union} from 'lodash'; 14 | 15 | class ExternalInterface { 16 | constructor(opts) { 17 | this.settings = {}; 18 | 19 | Object.assign(this.settings, this.settings, opts || {}); 20 | 21 | this._output = opts.output || console.log; 22 | this._context = opts.context || {}; 23 | this._stack = opts.stack || {}; 24 | this._parent_key = opts.parent_key || ""; 25 | this._printFn = opts.print; 26 | this._cached_messages = []; 27 | 28 | let methods = ['log', 'info', 'warning', 'success', 'error']; 29 | 30 | if (opts.template) { 31 | methods = union(methods, Object.keys(opts.template)); 32 | } 33 | 34 | methods.map((method, i) => { 35 | this[method] = ((contentType) => { 36 | var _ct = contentType; 37 | return (content) => { 38 | if (typeof content !== 'string') { 39 | Object.assign(content, this._context, content); 40 | } 41 | this._output(content, _ct); 42 | } 43 | })(method) 44 | }) 45 | 46 | if (this._parent_key !== '') { 47 | this['clear'] = () => { 48 | this._stack = {}; 49 | } 50 | this['get'] = () => { 51 | return this._stack; 52 | } 53 | this['print'] = () => { 54 | this._printFn() 55 | } 56 | } 57 | } 58 | 59 | stack(key) { 60 | const newSettings = Object.assign({}, this.settings, { 61 | stack: {}, 62 | parent_key: key 63 | }); 64 | 65 | this.stack[key] = new ExternalInterface(newSettings); 66 | return this.stack[key]; 67 | } 68 | 69 | context(ctx) { 70 | this._context = ctx; 71 | return this; 72 | } 73 | addCustomMethod(name, fn) { 74 | this[name] = fn; 75 | } 76 | } 77 | 78 | module.exports = function (opts) { 79 | opts = opts || {} 80 | 81 | let output = opts => { 82 | var _opts = opts; 83 | 84 | return (content, contentType) => { 85 | var tmpl; 86 | if (!_opts || !_opts.template || !_opts.template[contentType]) { 87 | tmpl = x => x; 88 | } else { 89 | tmpl = _opts.template[contentType] 90 | } 91 | if (!content) content = ''; 92 | 93 | let str = tmpl(content); 94 | 95 | if (_opts.printOutput === false) { 96 | return str; 97 | } 98 | console.log(str) 99 | } 100 | } 101 | Object.assign(opts, { 102 | output: output 103 | }, opts) 104 | // Inizializing output function 105 | opts.output = opts.output(opts) 106 | opts.print = opts.output 107 | return new ExternalInterface(opts) 108 | } 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pretty-cli 2 | 3 | Pretty-cli is a lightweight utility that helps you to create nice looking command line interfaces. It forces a well structured output and gives unimited flexibility with its templating system without adding any overhead. 4 | Freely inspired by my experience with bunyan 5 | Check the code examples. 6 | 7 | ![out](https://cloud.githubusercontent.com/assets/107390/17268513/0be770fa-55fa-11e6-87cb-b07f70864fc7.gif) 8 | 9 | ## Installation 10 | 11 | Just use NPM and you're ready to go 12 | ``` 13 | npm install pretty-cli --save 14 | ``` 15 | 16 | ## Code Example 17 | 18 | Instead of using console.log to output your messages: 19 | ```javascript 20 | console.log("First error message"); 21 | console.log("Other unformatted error message"); 22 | ``` 23 | 24 | with __pretty-cli__ you can 25 | - Use different type of output 26 | 27 | ```javascript 28 | pretty = require('pretty-cli')(); 29 | 30 | pretty.log("Log Message"); 31 | pretty.error("Error Message"); 32 | pretty.warning("Warning Message"); 33 | pretty.info("Info Message"); 34 | ``` 35 | 36 | Use templates that unify your design 37 | 38 | ```javascript 39 | pretty = require('pretty-cli')({ 40 | template: 41 | }) 42 | pretty.log("Log Message"); 43 | pretty.error("Error Message"); 44 | pretty.warning("Warning Message"); 45 | pretty.info("Info Message"); 46 | 47 | ``` 48 | 49 | With custom templates you can unify your styles and use complex objects. 50 | 51 | ```javascript 52 | pretty = require('pretty-cli')({ 53 | template: require('myTemplate') 54 | }) 55 | pretty.error({message:'../files/test.js\n',name:'MODULE', type:'title'}) 56 | pretty.error({message:'Test', description:"Long description message or code sample"}) 57 | 58 | ``` 59 | 60 | Create custom templates in a breeze, they are pure javascript! 61 | In this example I'm using colors, but you can use everything you prefer. 62 | There are no limitations. 63 | 64 | ```javascript 65 | var colors = require('colors'); 66 | 67 | var MY_TEMPLATE = { 68 | 'info': function(message){return ' I '.bgBlue.black +" " + message}, 69 | 'error': function(message){return ' E '.bgRed.white +" " + message}, 70 | 'log': function(message){return ' L '.bgWhite.black +" " + message}, 71 | 'warning': function(message){return ' W '.bgYellow.black +" " + message} 72 | } 73 | 74 | ``` 75 | 76 | 77 | ### Advanced Use 78 | 79 | Create custom print methods to automate special tasks 80 | 81 | ```javascript 82 | pretty = require('pretty-cli')({ 83 | template: require('myTemplate') 84 | }) 85 | 86 | pretty.addCustomMethod('stats', function(content){ 87 | return pretty.error({ 88 | type:'title', 89 | name:'STATS', 90 | message: "time: "+ content.time+', errors:'+ content.errors+', warnings:'+content.warnings}) 91 | }) 92 | 93 | pretty.error({type:'title', name:'BUILD', message:'complete with errors'}) 94 | pretty.stats({time:'30ms', errors:12, warnings:3}) 95 | ``` 96 | ![pretty-cli](https://cloud.githubusercontent.com/assets/107390/17260213/15b804da-559d-11e6-8f3c-22149b5b1fcd.jpg) 97 | 98 | You can also define custom methods using the template itself. 99 | This feature is very useful when you have to define a new message type (by default pretty-cli ships log, error, success, info). 100 | 101 | ```javascript 102 | const TEMPLATE = { 103 | //... 104 | note: (message)=>{return 'NOTE:'+message} 105 | } 106 | 107 | pretty = require('pretty-cli')({ 108 | template: TEMPLATE 109 | }) 110 | 111 | pretty.note('my note') 112 | ``` 113 | 114 | #### Context 115 | Pretty-cli focuses on semplicity and reusability. You don't have to repeat yourself. 116 | 117 | When you're looping through items sometimes happens that you want to mantain a similar context while changing just specific parts. 118 | For this purpose you can use __.context()__ to achieve that functionality. 119 | 120 | ```javascript 121 | var cli = require('pretty-cli')(); 122 | 123 | cli.context({ 124 | type:'looped item' 125 | }); 126 | //Shows current context 127 | console.log(cli.context()); 128 | // { type:'looped item' } 129 | for(var i=0;i<10;i++){ 130 | cli.log({message:'Item '+i}) 131 | } 132 | 133 | ``` 134 | Context is automatically merged for every following message. 135 | To clean the context you can simply set it to an empty object. 136 | 137 | ```javascript 138 | cli.context({ 139 | }); 140 | //Shows current context 141 | console.log(cli.context()); 142 | // {} 143 | ``` 144 | 145 | 151 | 152 | ### Utils 153 | 154 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | ## Motivation 175 | 176 | This library has been created to help the js community in creating nice looking command line interfaces with the objective of improving current practices and standardize the output. 177 | 178 | ## Tests 179 | 180 | Tests can be run with mocha 181 | 182 | ``` 183 | mocha test 184 | ``` 185 | 186 | ## Contributors 187 | 188 | Contributors are very very welcome. 189 | The project needs: 190 | - People who can create nice looking templates 191 | - New ideas to help the workflow of developers 192 | - Pull requests 193 | 194 | ## License 195 | 196 | 197 | The MIT License (MIT) 198 | Copyright (c) 2016 Michael Cereda 199 | http://michaelcereda.com 200 | 201 | 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: 202 | 203 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 204 | 205 | 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. 206 | --------------------------------------------------------------------------------