├── .eslintrc ├── .gitignore ├── README.md ├── bin └── cmd.js ├── example.json ├── example.md ├── index.js └── package.json /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true 4 | }, 5 | "rules": { 6 | "strict": 0, 7 | "quotes": 0 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # npm-dep-info 2 | 3 | Generates a glimpse of descriptions for your dependencies in the package.json 4 | 5 | ## Install 6 | 7 | ``` 8 | npm install npm-dep-info -g 9 | ``` 10 | 11 | ## Example 12 | 13 | Have you ever got confused of what your NPM packages do? Sometimes it just can't 14 | be told by their names. 15 | 16 | Example taken from [exorcist](https://github.com/thlorenz/exorcist)'s 17 | package.json 18 | 19 | ``` 20 | { 21 | "name": "exorcist", 22 | "dependencies": { 23 | "minimist": "0.0.5", 24 | "mold-source-map": "~0.3.0", 25 | "nave": "~0.5.1" 26 | }, 27 | "devDependencies": { 28 | "tap": "~0.4.3", 29 | "browserify": "~3.20.0", 30 | "through2": "~0.4.0" 31 | } 32 | } 33 | ``` 34 | 35 | With npm-dep-info, you get a nice description of these packages: 36 | 37 | ``` 38 | { 39 | "dependencies": { 40 | "minimist": "parse argument options", 41 | "mold-source-map": "Mold a source map that is almost perfect for you into one that is.", 42 | "nave": "Virtual Environments for Node" 43 | }, 44 | "devDependencies": { 45 | "tap": "A Test-Anything-Protocol library", 46 | "browserify": "browser-side require() the node way", 47 | "through2": "A tiny wrapper around Node streams2 Transform to avoid explicit subclassing noise" 48 | } 49 | } 50 | ``` 51 | 52 | It can generate a 53 | [Markdown file](https://github.com/pH200/npm-dep-info/blob/master/example.md) 54 | for you, too. 55 | 56 | And a table output: 57 | 58 | ``` 59 | dependencies 60 | ┌─────────────────┬───────────────────────────────────────────────────────┐ 61 | │ name │ description │ 62 | ├─────────────────┼───────────────────────────────────────────────────────┤ 63 | │ minimist │ parse argument options │ 64 | ├─────────────────┼───────────────────────────────────────────────────────┤ 65 | │ mold-source-map │ Mold a source map that is almost perfect for you into │ 66 | │ │ one that is. │ 67 | ├─────────────────┼───────────────────────────────────────────────────────┤ 68 | │ nave │ Virtual Environments for Node │ 69 | └─────────────────┴───────────────────────────────────────────────────────┘ 70 | ... 71 | ``` 72 | 73 | ## Usage 74 | 75 | ``` 76 | Usage: 77 | npm-dep-info [OPTIONS] [ARGS] 78 | 79 | Options: 80 | -M, --markdown Output as Markdown 81 | -T, --table Output as table 82 | -I, --include STRING Include extra properties from package.json of the 83 | dependency (e.g. --include version,homepage) 84 | -o, --output PATH Write output to file 85 | -i, --input PATH Location of package.json (default ./) 86 | ``` 87 | 88 | Output a description from the current directory: 89 | 90 | ``` 91 | npm-dep-info 92 | npm-dep-info -M # markdown 93 | npm-dep-info -T # table 94 | ``` 95 | 96 | Output to file: 97 | 98 | ``` 99 | npm-dep-info -o dependencies.json 100 | npm-dep-info > dependencies.json # pipe 101 | ``` 102 | 103 | Include extra info 104 | 105 | ``` 106 | npm-dep-info --include version,homepage # split by "," 107 | ``` 108 | -------------------------------------------------------------------------------- /bin/cmd.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var cli = require('cli').enable('version', 'status'); 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | var depInfo = require('../'); 6 | 7 | cli.setApp('npm-dep-info', '1.4.0'); 8 | 9 | cli.parse({ 10 | markdown: ['M', 'Output as Markdown'], 11 | table: ['T', 'Output as table'], 12 | include: [ 13 | 'I', 14 | 'Include extra properties from package.json of the dependency' + 15 | ' (e.g. --include version,homepage)', 16 | 'string' 17 | ], 18 | output: ['o', 'Write output to file', 'path'], 19 | input: ['i', 'Location of package.json (default ./)', 'path'] 20 | }); 21 | 22 | function readPkg(dirPath){ 23 | var pjPath = path.join(dirPath || './', 'package.json'); 24 | try { 25 | var pj = fs.readFileSync(pjPath, { encoding: 'utf8' }); 26 | } catch (e) { 27 | cli.fatal('Cannot read package.json'); 28 | return -1; 29 | } 30 | 31 | try { 32 | return JSON.parse(pj); 33 | } catch (e) { 34 | cli.fatal('Cannot parse package.json'); 35 | return -1; 36 | } 37 | } 38 | 39 | cli.main(function (args, options) { 40 | var pkg = readPkg(options.input); 41 | 42 | if (pkg === -1) { 43 | return; 44 | } 45 | 46 | var includes = options.include ? options.include.split(',') : null; 47 | var result; 48 | try { 49 | if (options.markdown) { 50 | result = depInfo.markdownOutput(pkg, options.input, includes); 51 | } else if (options.table) { 52 | result = depInfo.tableOutput(pkg, options.input, includes); 53 | } else { 54 | var depObj = depInfo.defaultOutput(pkg, options.input, includes); 55 | result = JSON.stringify(depObj, null, 2); 56 | } 57 | } catch (e) { 58 | cli.fatal(e.message); 59 | } 60 | 61 | if (options.output) { 62 | try { 63 | fs.writeFileSync(options.output, result); 64 | } catch (e) { 65 | cli.fatal('Cannot write file to ' + options.output); 66 | } 67 | return; 68 | } 69 | 70 | cli.output(result); 71 | }); 72 | -------------------------------------------------------------------------------- /example.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "minimist": "parse argument options", 4 | "mold-source-map": "Mold a source map that is almost perfect for you into one that is.", 5 | "nave": "Virtual Environments for Node" 6 | }, 7 | "devDependencies": { 8 | "tap": "A Test-Anything-Protocol library", 9 | "browserify": "browser-side require() the node way", 10 | "through2": "A tiny wrapper around Node streams2 Transform to avoid explicit subclassing noise" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /example.md: -------------------------------------------------------------------------------- 1 | # exorcist 2 | 3 | ## dependencies 4 | 5 | ### minimist 6 | 7 | parse argument options 8 | 9 | https://github.com/substack/minimist 10 | 11 | ### mold-source-map 12 | 13 | Mold a source map that is almost perfect for you into one that is. 14 | 15 | https://github.com/thlorenz/mold-source-map 16 | 17 | ### nave 18 | 19 | Virtual Environments for Node 20 | 21 | ## devDependencies 22 | 23 | ### tap 24 | 25 | A Test-Anything-Protocol library 26 | 27 | https://github.com/isaacs/node-tap 28 | 29 | ### browserify 30 | 31 | browser-side require() the node way 32 | 33 | https://github.com/substack/node-browserify 34 | 35 | ### through2 36 | 37 | A tiny wrapper around Node streams2 Transform to avoid explicit subclassing noise 38 | 39 | https://github.com/rvagg/through2 40 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var Table = require('cli-table'); 4 | 5 | function eachValue(obj, iterator) { 6 | var keys = Object.keys(obj); 7 | for (var i = 0; i < keys.length; i++) { 8 | iterator(obj[keys[i]]); 9 | } 10 | } 11 | 12 | function generateMeta(moduleNames, relPath, moduleSeletor) { 13 | return moduleNames.reduce(function (seed, moduleName) { 14 | var modulePjPath = path.join( 15 | relPath || './', 16 | 'node_modules', 17 | moduleName, 18 | 'package.json'); 19 | var modulePkg; 20 | try { 21 | var modulePj = fs.readFileSync(modulePjPath, { encoding: 'utf8' }); 22 | modulePkg = JSON.parse(modulePj); 23 | } catch (e) { 24 | modulePkg = { 25 | name: moduleName, 26 | description: 27 | "Package not found. " + 28 | "Make sure you have run npm install." 29 | }; 30 | } 31 | if (moduleSeletor) { 32 | seed[moduleName] = moduleSeletor(modulePkg); 33 | } else { 34 | seed[moduleName] = modulePkg; 35 | } 36 | return seed; 37 | }, {}); 38 | } 39 | 40 | function defaultOutput(pkg, relPath, includes) { 41 | function moduleSeletor(m) { 42 | return m.description || ''; 43 | } 44 | function includesSeletor(m) { 45 | var modulePkg = { description: m.description }; 46 | includes.forEach(function (propName) { 47 | modulePkg[propName] = m[propName]; 48 | }); 49 | return modulePkg; 50 | } 51 | 52 | var result = {}; 53 | if (typeof pkg.dependencies === 'object') { 54 | result.dependencies = generateMeta( 55 | Object.keys(pkg.dependencies), 56 | relPath, 57 | includes ? includesSeletor : moduleSeletor); 58 | } 59 | if (typeof pkg.devDependencies === 'object') { 60 | result.devDependencies = generateMeta( 61 | Object.keys(pkg.devDependencies), 62 | relPath, 63 | includes ? includesSeletor : moduleSeletor); 64 | } 65 | 66 | return result; 67 | } 68 | 69 | function markdownOutput(pkg, relPath, includes) { 70 | var result = '# ' + pkg.name + '\n\n'; 71 | 72 | function depWriter(dep) { 73 | result += '### ' + dep.name + '\n\n'; 74 | if (dep.description) { 75 | result += dep.description + '\n\n'; 76 | } 77 | if (dep.homepage) { 78 | result += dep.homepage + '\n\n'; 79 | } 80 | if (includes) { 81 | includes.forEach(function (propName) { 82 | var prop = dep[propName]; 83 | if (!prop) { 84 | return; 85 | } 86 | if (typeof prop === 'string') { 87 | result += '#### ' + propName + '\n\n'; 88 | result += prop + '\n\n'; 89 | } else { 90 | result += '#### ' + propName + '\n\n'; 91 | result += '```\n' + JSON.stringify(prop, null, 2) + '\n```\n\n'; 92 | } 93 | }); 94 | } 95 | } 96 | 97 | if (typeof pkg.dependencies === 'object') { 98 | var dependencies = generateMeta( 99 | Object.keys(pkg.dependencies), 100 | relPath); 101 | result += "## dependencies\n\n"; 102 | eachValue(dependencies, depWriter); 103 | } 104 | if (typeof pkg.devDependencies === 'object') { 105 | var devDependencies = generateMeta( 106 | Object.keys(pkg.devDependencies), 107 | relPath); 108 | result += "## devDependencies\n\n"; 109 | eachValue(devDependencies, depWriter); 110 | } 111 | 112 | if (result === "") { 113 | return "No dependencies"; 114 | } 115 | // trim linebreaks 116 | return result.replace(/\n?\n$/m, ''); 117 | } 118 | 119 | function tableOutput(pkg, relPath, includes) { 120 | function stringifyObject(obj) { 121 | if (typeof obj === 'string') { 122 | return obj; 123 | } 124 | if (obj && typeof obj === 'object') { 125 | for (var propName in obj) { 126 | var prop = obj[propName]; 127 | if (typeof prop === 'string') { 128 | return prop + '...'; 129 | } 130 | } 131 | } 132 | return ''; 133 | } 134 | function ellipsis(str, len) { 135 | if (str.length > len) { 136 | return str.substr(0, len - 2) + '..'; 137 | } 138 | return str; 139 | } 140 | function wrap(str, len) { 141 | var words = str.split(' '); 142 | var output = [""]; 143 | while (words.length > 0) { 144 | var word = words.shift(); 145 | if (word.length > len) { 146 | word = ellipsis(word, len); 147 | } 148 | var lastIndex = output.length - 1; 149 | var line = output[lastIndex]; 150 | if ((line + word).length > len) { 151 | output.push(word); 152 | } else { 153 | output[lastIndex] = line + ' ' + word; 154 | } 155 | } 156 | return output.join('\n').replace(/^\s/, ''); 157 | } 158 | function tableWriter(deps) { 159 | var head = ['name', 'description']; 160 | if (includes) { 161 | head = head.concat(includes); 162 | } 163 | var table = new Table({ 164 | head: head 165 | }); 166 | 167 | eachValue(deps, function (dep) { 168 | var row = [ 169 | ellipsis(dep.name, 18), 170 | wrap(dep.description, 54) 171 | ]; 172 | 173 | if (includes) { 174 | includes.forEach(function (propName) { 175 | row.push(stringifyObject(dep[propName])); 176 | }); 177 | } 178 | 179 | table.push(row); 180 | }); 181 | 182 | return table.toString(); 183 | } 184 | 185 | var result = ""; 186 | if (typeof pkg.dependencies === 'object') { 187 | var dependencies = generateMeta( 188 | Object.keys(pkg.dependencies), 189 | relPath); 190 | result += 'dependencies\n'; 191 | result += tableWriter(dependencies) + '\n'; 192 | } 193 | if (typeof pkg.devDependencies === 'object') { 194 | var devDependencies = generateMeta( 195 | Object.keys(pkg.devDependencies), 196 | relPath); 197 | result += 'devDependencies\n'; 198 | result += tableWriter(devDependencies) + '\n'; 199 | } 200 | 201 | return result; 202 | } 203 | 204 | module.exports = { 205 | defaultOutput: defaultOutput, 206 | markdownOutput: markdownOutput, 207 | tableOutput: tableOutput 208 | }; 209 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm-dep-info", 3 | "version": "1.4.0", 4 | "description": "Generates a glimpse of descriptions for your dependencies in the package.json", 5 | "bin": { 6 | "npm-dep-info": "bin/cmd.js" 7 | }, 8 | "main": "index.js", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/pH200/npm-dep-info.git" 12 | }, 13 | "homepage": "https://github.com/pH200/npm-dep-info", 14 | "scripts": { 15 | "example-json": "node bin/cmd.js -i node_modules/exorcist/ > example.json", 16 | "example-md": "node bin/cmd.js -i node_modules/exorcist/ -M > example.md", 17 | "test-json": "node bin/cmd.js -i node_modules/exorcist/ -I keywords,license", 18 | "test-md": "node bin/cmd.js -i node_modules/exorcist/ -M -I keywords,license" 19 | }, 20 | "keywords": [ 21 | "npm", 22 | "dependencies", 23 | "package.json", 24 | "analyze", 25 | "modules" 26 | ], 27 | "author": "pH200 ", 28 | "license": "BSD", 29 | "dependencies": { 30 | "cli": "^0.6.6", 31 | "cli-table": "^0.3.1" 32 | } 33 | } 34 | --------------------------------------------------------------------------------