├── CHANGELOG.md ├── .npmignore ├── doc ├── debug.png ├── express.dev.png ├── oneapmfed@npm2.png ├── oneapmfed@npm3.png └── express.production.png ├── .travis.yml ├── .editorconfig ├── bin └── npm2dot ├── test ├── test.json └── test.main.js ├── .gitignore ├── package.json ├── LICENSE ├── index.js └── README.md /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 2015/07/09 0.0.1 2 | 3 | - init -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | doc -------------------------------------------------------------------------------- /doc/debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longtian/npm2dot/HEAD/doc/debug.png -------------------------------------------------------------------------------- /doc/express.dev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longtian/npm2dot/HEAD/doc/express.dev.png -------------------------------------------------------------------------------- /doc/oneapmfed@npm2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longtian/npm2dot/HEAD/doc/oneapmfed@npm2.png -------------------------------------------------------------------------------- /doc/oneapmfed@npm3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longtian/npm2dot/HEAD/doc/oneapmfed@npm3.png -------------------------------------------------------------------------------- /doc/express.production.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longtian/npm2dot/HEAD/doc/express.production.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | - "0.12" 5 | - "6" 6 | - "8" 7 | script: "npm test" 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://editorconfig.org/#example-file 2 | # top-most EditorConfig file 3 | root = true 4 | 5 | [Makefile] 6 | indent_style = tab 7 | 8 | [*.{js,md}] 9 | charset = utf-8 10 | indent_style = space 11 | indent_size = 2 -------------------------------------------------------------------------------- /bin/npm2dot: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var buffer = ""; 3 | 4 | process.stdin.on('data', function (newData) { 5 | buffer += newData; 6 | }); 7 | 8 | process.stdin.on('close', function () { 9 | // collect all data from stdin pipeline 10 | require('../')(buffer, process.stdout); 11 | }); 12 | -------------------------------------------------------------------------------- /test/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "a", 3 | "version": "1.2.3", 4 | "dependencies": { 5 | "b": { 6 | "version": "2" 7 | }, 8 | "c": { 9 | "version": "2" 10 | }, 11 | "d": { 12 | "version": "2", 13 | "dependencies": { 14 | "f": { 15 | "version": 1 16 | } 17 | } 18 | }, 19 | "e": { 20 | "version": "2", 21 | "dependencies": { 22 | "f": { 23 | "version": 1 24 | } 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | .idea -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm2dot", 3 | "version": "2.0.0", 4 | "description": "convert npm dependency list to graphviz format", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node_modules/.bin/mocha ./test", 8 | "publish-patch": "mocha && npm version patch && git push && git push --tags && npm publish" 9 | }, 10 | "bin": { 11 | "npm2dot": "./bin/npm2dot" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/longtian/npm2dot.git" 16 | }, 17 | "keywords": [ 18 | "graphviz" 19 | ], 20 | "author": "longtian", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/longtian/npm2dot/issues" 24 | }, 25 | "homepage": "https://github.com/longtian/npm2dot#readme", 26 | "devDependencies": { 27 | "mocha": "^2.2.5" 28 | }, 29 | "preferGlobal": true 30 | } 31 | -------------------------------------------------------------------------------- /test/test.main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var assert = require('assert'); 4 | var path = require('path'); 5 | var fs = require('fs'); 6 | var convertFunc = require('../'); 7 | 8 | var MockStream = function () { 9 | this.buffer = ""; 10 | }; 11 | 12 | MockStream.prototype.write = function (data) { 13 | this.buffer += data; 14 | }; 15 | 16 | describe('npm2dot', function () { 17 | it('should be defined', function () { 18 | assert.ok(convertFunc); 19 | }); 20 | 21 | it('should throw if passed object', function () { 22 | assert.throws(function () { 23 | convertFunc({}); 24 | }); 25 | }); 26 | 27 | it('should parse the test.json', function () { 28 | var mockStream = new MockStream(); 29 | convertFunc(fs.readFileSync(path.join(__dirname, 'test.json')).toString(), mockStream); 30 | assert.ok(mockStream.buffer.length > 10); 31 | }); 32 | }) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 龙天 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var format = require('util').format; 3 | var EOL = require('os').EOL; 4 | var NODE_NAME_PREFIX = "N_"; 5 | 6 | /** 7 | * 8 | * @param textContent {String} 9 | * @param outputStream {WritableStream} 10 | */ 11 | module.exports = function (textContent, outputStream) { 12 | 13 | if (typeof textContent !== "string") { 14 | throw new Error('Param jsonTree must be a string'); 15 | } 16 | 17 | if (!outputStream) { 18 | outputStream = process.stdout; 19 | } 20 | 21 | // generate id for each module 22 | var id = 0; 23 | var tree = JSON.parse(textContent); 24 | 25 | 26 | /** 27 | * recursive 28 | * 29 | * @param tree {Object} 30 | * @param prev {String} 31 | * @param level {Number} 32 | * 33 | */ 34 | function show(tree, prev, level) { 35 | level = level + 1; 36 | 37 | if (tree) { 38 | //FIXME: prototype check 39 | for (var i in tree.dependencies) { 40 | if (tree.dependencies.hasOwnProperty(i)) { 41 | id++; 42 | var nodeName = NODE_NAME_PREFIX + id; 43 | var child = i + '@' + tree.dependencies[i].version; 44 | 45 | outputStream.write(format(' "%s" -> "%s"%s', prev, nodeName, EOL)); 46 | outputStream.write(format(' "%s"[label="%s",style="filled",fillcolor="%d 1 1"]%s', nodeName, child, level / 15, EOL)); 47 | 48 | show(tree.dependencies[i], nodeName, level); 49 | } 50 | 51 | } 52 | } 53 | } 54 | 55 | outputStream.write(format('digraph{%s', EOL)); 56 | outputStream.write(format(' root="%s@%s"%s', tree.name, tree.version, EOL)); 57 | show(tree, tree.name + "@" + tree.version, 0); 58 | outputStream.write(format('}%s', EOL)); 59 | }; 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # npm2dot 2 | ![NPM](https://david-dm.org/wyvernnot/npm2dot.svg) 3 | [![Build Status](https://travis-ci.org/longtian/npm2dot.svg?branch=master)](https://travis-ci.org/longtian/npm2dot) 4 | 5 | Convert npm dependency list to dot file which can be visualized using graphviz 6 | 7 | [![NPM](https://nodei.co/npm/npm2dot.png)](https://nodei.co/npm/npm2dot/) 8 | 9 | **Install** 10 | 11 | ```sh 12 | npm install npm2dot -g 13 | ``` 14 | 15 | **Usage** 16 | 17 | 1\. In a `Node.js` package folder, type in console: 18 | 19 | ```sh 20 | npm ls --json | npm2dot 21 | ``` 22 | 23 | 2\. By default `npm2dot` will write following content to stdout: 24 | 25 | ``` 26 | digraph{ 27 | root="debug@2.2.0" 28 | "debug@2.2.0" -> "N_1" 29 | "N_1"[label="ms@0.7.1",style="filled",fillcolor="0.06666666666666667 1 1"] 30 | } 31 | ``` 32 | 33 | 3\. This output can be piped to `Graphviz` to generate a picture: 34 | 35 | ```sh 36 | npm ls --json | npm2dot | dot -Tpng -o debug.png -Grankdir=LR 37 | ``` 38 | 39 | Picture `debug.png` is very simple because [`debug`](https://www.npmjs.com/package/debug) has only one dependency: 40 | 41 | ![debug.png](doc/debug.png) 42 | 43 | That's how `npm2dot` interacts with `npm ls` and `Graphviz`. More complicated use cases are: 44 | 45 | ## Use Case 1 : Comparison of folder structure installed separately using NPM2 and NPM3 46 | 47 | NPM3 is currently in beta, one of the most expected feature is [flatten structure](http://www.infoq.com/news/2015/06/npm) : 48 | 49 | > Dependencies will now be installed maximally flat. Insofar as is possible, all of your dependencies, 50 | > and their dependencies, and THEIR dependencies will be installed in your project's node_modules folder with no nesting. 51 | > You'll only see modules nested underneath one another when two (or more) modules have conflicting dependencies. 52 | 53 | Using `npm2dot` and `Graphviz` will help you clearly understand this change: 54 | 55 | ```sh 56 | npm ls --json | npm2dot | twopi -Tsvg -o /tmp/twopi.svg -Granksep=4 57 | ``` 58 | 59 | **Result:** 60 | 61 | Before, the dependencies is install with npm@2.x 62 | 63 | ![npm2](doc/oneapmfed@npm2.png) 64 | 65 | If we use npm@3.x (`npm install npm@3.x-next -g`) to install dependencies, there are less nodes in the structure 66 | 67 | ![npm3](doc/oneapmfed@npm3.png) 68 | 69 | ## Use Case 2 : Comparison of Express Production and Development environment 70 | 71 | In express folder, execute 72 | 73 | ```sh 74 | npm ls --json | npm2dot | dot -Grankdir=LR -Tpng -O 75 | ``` 76 | 77 | **Result:** 78 | 79 | Express Production Environment 80 | 81 | ![express#production](doc/express.production.png) 82 | 83 | Express Development Environment 84 | 85 | ![express#development](doc/express.dev.png) 86 | 87 | ## About 88 | 89 | 1\. `Graphviz` can be downloaded at [http://www.graphviz.org/Download.php](http://www.graphviz.org/Download.php). 90 | 91 | 2\. Anyone can fork this repo to provide more interesting use cases. 92 | 93 | 3\. Please include a link to original [github repo](https://github.com/longtian/npm2dot), if you want to use any pictures on this page. 94 | 95 | 96 | --------------------------------------------------------------------------------