Giter Club home page Giter Club logo

madge's Introduction

madge

Last version Donate

Madge is a developer tool for generating a visual graph of your module dependencies, finding circular dependencies, and giving you other useful info. Joel Kemp's awesome dependency-tree is used for extracting the dependency tree.

  • Works for JavaScript (AMD, CommonJS, and ES6 modules)
  • Also works for CSS preprocessors (Sass, Stylus, and Less)
  • NPM installed dependencies are excluded by default (can be enabled)
  • All core Node.js modules (assert, path, fs, etc) are excluded
  • Will traverse child dependencies automatically

Read the changelog for latest changes.

I've worked with Madge on my free time for the last couple of years and it's been a great experience. It started as an experiment but turned out to be a very useful tool for many developers. I have many ideas for the project and it would definitely be easier to dedicate more time to it with some financial support 🙏

Regardless of your contribution, thanks for your support!

Examples

Graph generated from madge's own code and dependencies.

graph

A graph with circular dependencies. Blue has dependencies, green has no dependencies, and red has circular dependencies.

graph-circular

See it in action

in-action

Installation

npm -g install madge

Graphviz (optional)

Graphviz is only required if you want to generate visual graphs (e.g. in SVG or DOT format).

Mac OS X

brew install graphviz || port install graphviz

Ubuntu

apt-get install graphviz

API

madge(path: string|array|object, config: object)

path is a single file or directory, or an array of files/directories to read. A predefined tree can also be passed in as an object.

config is optional and should be the configuration to use.

Returns a Promise resolved with the Madge instance object.

Functions

.obj()

Returns an Object with all dependencies.

const madge = require('madge');

madge('path/to/app.js').then((res) => {
	console.log(res.obj());
});

.warnings()

Returns an Object of warnings.

const madge = require('madge');

madge('path/to/app.js').then((res) => {
	console.log(res.warnings());
});

.circular()

Returns an Array of all modules that have circular dependencies.

const madge = require('madge');

madge('path/to/app.js').then((res) => {
	console.log(res.circular());
});

.circularGraph()

Returns an Object with only circular dependencies.

const madge = require('madge');

madge('path/to/app.js').then((res) => {
	console.log(res.circularGraph());
});

.depends()

Returns an Array of all modules that depend on a given module.

const madge = require('madge');

madge('path/to/app.js').then((res) => {
	console.log(res.depends('lib/log.js'));
});

.orphans()

Return an Array of all modules that no one is depending on.

const madge = require('madge');

madge('path/to/app.js').then((res) => {
	console.log(res.orphans());
});

.leaves()

Return an Array of all modules that have no dependencies.

const madge = require('madge');

madge('path/to/app.js').then((res) => {
	console.log(res.leaves());
});

.dot([circularOnly: boolean])

Returns a Promise resolved with a DOT representation of the module dependency graph. Set circularOnly to only include circular dependencies.

const madge = require('madge');

madge('path/to/app.js')
	.then((res) => res.dot())
	.then((output) => {
		console.log(output);
	});

.image(imagePath: string, [circularOnly: boolean])

Write the graph as an image to the given image path. Set circularOnly to only include circular dependencies. The image format to use is determined from the file extension. Returns a Promise resolved with a full path to the written image.

const madge = require('madge');

madge('path/to/app.js')
	.then((res) => res.image('path/to/image.svg'))
	.then((writtenImagePath) => {
		console.log('Image written to ' + writtenImagePath);
	});

.svg()

Return a Promise resolved with the XML SVG representation of the dependency graph as a Buffer.

const madge = require('madge');

madge('path/to/app.js')
	.then((res) => res.svg())
	.then((output) => {
		console.log(output.toString());
	});

Configuration

Property Type Default Description
baseDir String null Base directory to use instead of the default
includeNpm Boolean false If shallow NPM modules should be included
fileExtensions Array ['js'] Valid file extensions used to find files in directories
excludeRegExp Array false An array of RegExp for excluding modules
requireConfig String null RequireJS config for resolving aliased modules
webpackConfig String null Webpack config for resolving aliased modules
tsConfig String|Object null TypeScript config for resolving aliased modules - Either a path to a tsconfig file or an object containing the config
layout String  dot Layout to use in the graph
rankdir String  LR Sets the direction of the graph layout
fontName String Arial Font name to use in the graph
fontSize String 14px Font size to use in the graph
backgroundColor String #000000 Background color for the graph
nodeShape String box A string specifying the shape of a node in the graph
nodeStyle String rounded A string specifying the style of a node in the graph
nodeColor String #c6c5fe Default node color to use in the graph
noDependencyColor String #cfffac Color to use for nodes with no dependencies
cyclicNodeColor String #ff6c60 Color to use for circular dependencies
edgeColor String #757575 Edge color to use in the graph
graphVizOptions Object false Custom Graphviz options
graphVizPath String null Custom Graphviz path
detectiveOptions Object false Custom detective options for dependency-tree and precinct
dependencyFilter Function false Function called with a dependency filepath (exclude subtrees by returning false)

You can use configuration file either in .madgerc in your project or home folder or directly in package.json. Look here for alternative locations for the file.

.madgerc

{
  "fontSize": "10px",
  "graphVizOptions": {
    "G": {
      "rankdir": "LR"
    }
  }
}

package.json

{
  "name": "foo",
  "version": "0.0.1",
  ...
  "madge": {
    "fontSize": "10px",
    "graphVizOptions": {
      "G": {
        "rankdir": "LR"
      }
    }
  }
}

CLI

Examples

List dependencies from a single file

madge path/src/app.js

List dependencies from multiple files

madge path/src/foo.js path/src/bar.js

List dependencies from all *.js files found in a directory

madge path/src

List dependencies from multiple directories

madge path/src/foo path/src/bar

List dependencies from all *.js and *.jsx files found in a directory

madge --extensions js,jsx path/src

Finding circular dependencies

madge --circular path/src/app.js

Show modules that depends on a given module

madge --depends wheels.js path/src/app.js

Show modules that no one is depending on

madge --orphans path/src/

Show modules that have no dependencies

madge --leaves path/src/

Excluding modules

madge --exclude '^(foo|bar)\.js$' path/src/app.js

Save graph as a SVG image (requires Graphviz)

madge --image graph.svg path/src/app.js

Save graph with only circular dependencies

madge --circular --image graph.svg path/src/app.js

Save graph as a DOT file for further processing (requires Graphviz)

madge --dot path/src/app.js > graph.gv

Using pipe to transform tree (this example will uppercase all paths)

madge --json path/src/app.js | tr '[a-z]' '[A-Z]' | madge --stdin

Debugging

To enable debugging output if you encounter problems, run madge with the --debug option then throw the result in a gist when creating issues on GitHub.

madge --debug path/src/app.js

Running tests

npm install
npm test

Creating a release

npm run release

FAQ

Missing dependencies?

It could happen that the files you're not seeing have been skipped due to errors or that they can't be resolved. Run madge with the --warning option to see skipped files. If you need even more info run with the --debug option.

Using both Javascript and Typescript in your project?

Madge uses dependency-tree which uses filing-cabinet to resolve modules. However it requires configurations for each file type (js/jsx) and (ts/tsx). So provide both webpackConfig and tsConfig options to madge.

Using mixed import syntax in the same file?

Only one syntax is used by default. You can use both though if you're willing to take the degraded performance. Put this in your madge config to enable mixed imports.

For ES6 + CommonJS:

{
  "detectiveOptions": {
    "es6": {
      "mixedImports": true
    }
  }
}

For TypeScript + CommonJS:

{
  "detectiveOptions": {
    "ts": {
      "mixedImports": true
    }
  }
}

How to ignore import type statements in ES6 + Flow?

Put this in your madge config.

{
  "detectiveOptions": {
    "es6": {
      "skipTypeImports": true
    }
  }
}

How to ignore import in type annotations in TypeScript?

Put this in your madge config.

{
  "detectiveOptions": {
    "ts": {
      "skipTypeImports": true
    }
  }
}

How to ignore dynamic imports in Typescript?

Put this in your madge config.

{
  "detectiveOptions": {
    "ts": {
      "skipAsyncImports": true
    },
    "tsx": {
      "skipAsyncImports": true
    }
  }
}

Note: tsx is optional, use this when working with JSX.

Mixing TypesScript and Javascript imports?

Ensure you have this in your .tsconfig file.

{
  "compilerOptions": {
    "module": "commonjs",
    "allowJs": true
  }
}

What's the "Error: write EPIPE" when exporting graph to image?

Ensure you have installed Graphviz. If you're running Windows, note that Graphviz is not added to the PATH variable during install. You should add the folder of gvpr.exe (typically %Graphviz_folder%/bin) to the PATH variable manually.

How do I fix the "Graphviz not built with triangulation library" error when using sfdp layout?

Homebrew doesn't include GTS by default. Fix this by doing:

brew uninstall graphviz
brew install gts
brew install graphviz

The image produced by madge is very hard to read, what's wrong?

Try running madge with a different layout, here's a list of the ones you can try:

  • dot "hierarchical" or layered drawings of directed graphs. This is the default tool to use if edges have directionality.

  • neato "spring model'' layouts. This is the default tool to use if the graph is not too large (about 100 nodes) and you don't know anything else about it. Neato attempts to minimize a global energy function, which is equivalent to statistical multi-dimensional scaling.

  • fdp "spring model'' layouts similar to those of neato, but does this by reducing forces rather than working with energy.

  • sfdp multiscale version of fdp for the layout of large graphs.

  • twopi radial layouts, after Graham Wills 97. Nodes are placed on concentric circles depending their distance from a given root node.

  • circo circular layout, after Six and Tollis 99, Kauffman and Wiese 02. This is suitable for certain diagrams of multiple cyclic structures, such as certain telecommunications networks.

Credits

Contributors

This project exists thanks to all the people who contribute. Contributors

Donations ❤️

Thanks to the awesome people below for making donations! 🙏Donate

Bernard Stojanović (24 Mars, 2021)

BeroBurny

Ole Jørgen Brønner (Oct 8, 2020)

olejorgenb

RxDB (Apr 1, 2020)

RxDB

Peter Verswyvelen (Feb 24, 2020)

Ziriax

Landon Alder (Mar 19, 2019)

landonalder

License

MIT License

madge's People

Contributors

andersdjohnson avatar cammytown avatar fdc-viktor-luft avatar fizker avatar havunen avatar hulkish avatar kamiazya avatar legobeat avatar lleaff avatar meister avatar mlostekk avatar mrjoelkemp avatar mwhite avatar neelance avatar oliverjash avatar osamie avatar pablolion avatar pahen avatar paulirish avatar pixeldrew avatar realityking avatar rmi7 avatar russaa avatar sethdavenport avatar todor-a avatar waldyrious avatar wayofthefuture avatar wheresrhys avatar zekth avatar zubb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

madge's Issues

--read Option does not work under Windows

http://stackoverflow.com/questions/8452957/synchronously-reading-stdin-in-windows

In bin/madge, line 39:

src = JSON.parse(fs.readFileSync('/dev/stdin').toString());

Fails with

fs.js:427
return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
^
Error: ENOENT, no such file or directory 'C:\dev\stdin'
at Object.fs.openSync (fs.js:427:18)
at Object.fs.readFileSync (fs.js:284:15)
at Object. (C:\Users\jdl\AppData\Roaming\npm\node_modules\madge\bin\madge:39:22)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:901:3

Similar issue for chaplinjs was fixed here:

chaplinjs/chaplin@b0d5b6b

Please assist. Thanks!

Differences between dot and image output - intentional or undesired?

Right now, the ouput as dot and the output as image are very different. One of the reasons appears, to be that ...image() will call g.output() with a lot of options that's missing from ...dot()'s call to g.to_dot().

This is probably due to the fact that to_dot doesn't accept options in the first place. If i were unifying this behaviour, would this be a valuable patch for you? I guess, what i'm asking is: would you prefer the way it is now (dot being very clean, image being called with more options) or would you consider a patch that creates a dot-file that will contain all the attributes that would lead to the very same image?

Number of graph node lines increase with each render

When rendering with .image multiple times, the generated graph's nodes do not clear, leading to doubled, tripled, ... lines in the resulting image.

It's a simple fix:
module.exports.image = function (modules, opts, callback) {
checkGraphvizInstalled();
/* patched by adding this here */
g = graphviz.digraph('G');

Nested AMD/RequireJS modules not found because baseUrl not honoured

madge doesn't find deep nested modules because it either doesn't honour the baseUrl from require.config, or because the baseUrl doesn't necessarily reflect the local directory structure.

When using AMD (RequireJS) modules, the module paths may not reflect file system paths. It would help if madge honoured the baseUrl in require.config object, however that won't solve all (or my) cases.
Consider this:
directory structure:

/resources
 └─── /js
      ├─── main.js              // entry point for RequireJS
      └─── /js_modules
            └─── /map
                  ├─── map.js
                  └─── tiles.js

main.js

require.config({
    baseUrl: '/application_context/resources/js/js_modules/
});
define(['map/map'], function(map) {
    console.log('application loaded');
});

map.js

define(['map/tiles'], function(tiles) {
    return {
        mapTiles: tiles
    }
});

Honouring the baseUrl won't be enough in this case, because it's purpose is for the deployed context, not necessarily the directory structure where main.js is found.

I would suggest adding a configurable property, such as --require-base-url which madge can use to evaluate AMD module paths

--circular does not work on Windows

  1. Clone the Brackets project (https://github.com/adobe/brackets) on both a Mac and a Windows machine
  2. Run madge --format cjs --exclude "/node_modules/|/extensions/|/nls/|/node/|/jquery-ui/|/tests/|/test/|/spec/" --circular <<cloned repo>>/src

Result:
Windows: "No circular dependencies found!"
Mac: Lists about 30 circular dependency chains

If I do --depends instead, it seems to work except it prints absolute paths for everything instead of module names (relative paths without ".js"). Maybe a clue as to what's breaking --circular?

Doesn't detect circular dependency when ./ is in module path

Problem:

It says no circular dependencies even though there is one.

To reproduce:

Directory structure

a.coffee
foo/b.coffee

a.coffee:

define 'a', ['./foo/b'], ->

b.coffee:

define 'foo/b', ['a'], ->

Now run madge --circular --format amd ./ and notice that it doesn't detect the circular dependency.

If you remove the ./ from a.coffee it detects the circularity.

I noticed this on Windows. I didn't have time yet to try on *nix.

Use one file as entry (instead of a directory)

In a senario like RequireJS, it's more like there's only one entry in the HTML, the optimizer of RequireJS analyses the main file, then all dependencies are figured out, instead of scanning a whole directory to figure out the depencies.

I can't find a parameter for scanning file like that? How about it, can we add that?

New feature: modfiy file contents before parsing

I do not know, if this should be part of the master branch, but I found it extremely helpful:
the possibility to modify file contents before they are parsed.

I used the onParseFile callback functions for this (see this commit here):
the passed in argument {src: ..., filename: ...} can be modified within the callback and these --possibly modified-- data are then used in the further processing (i.e. parsing the file contents etc).

This has the possible drawback that an unsuspecting programmer may produce unintentional side effects when modifying the argument of onParseFile without knowing that these modified data will be used in the further processing ...

However this could be rectified by requiring that an additional property is set on the argument, if it should be used in further processing, e.g. something like

{
    src: "....",
    filename: "....",
    useModified: true
}

and if useModified is missing or not true, then the passed in argument for onParseFile will be ignored during further processing.

Comprehend Sugared AMD Modules

With require.js, you can write AMD modules using the sugared syntax:

define(function(require){
var mod1 = require('mod1') ;
});

I've run madge over a project which uses this, but it only seems to detect the top most module dependencies and not the rest.

Ignores require statements that use `path.join(`

For all of our require statements, we use this form:

require(path.join(__dirname, '..', 'config', 'config.js'))

I tested removing path.join, so that it's simply

require('../config/config.js')

And that works. But as it is, it's only finding our external dependencies and none of our own code.

excluding more than one directory

Hi there

this one works well

$ madge --exclude node_modules --image source_map.png .

however, if I try to exclude more than 1 directory, it seems to really slow down and choke

 $ madge --exclude node_modules doc test artifiacts --image source_map.png .

am I doing something wrong?

Error with graph generation

Hi, I just installed it on Windows 7, 64 bit, Using Node 0.10.24

F:\dev\www\SnapClip\frontend\api\public\assets\js>madge --image graph.png app.js

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: This socket is closed.
    at Socket._write (net.js:635:19)
    at doWrite (_stream_writable.js:221:10)
    at writeOrBuffer (_stream_writable.js:211:5)
    at Socket.Writable.write (_stream_writable.js:180:11)
    at Socket.write (net.js:613:40)
    at Graph.render (C:\Users\Kow\AppData\Roaming\npm\node_modules\madge\node_modules\graphviz\lib\deps\graph.js:380:18)
    at Graph.output (C:\Users\Kow\AppData\Roaming\npm\node_modules\madge\node_modules\graphviz\lib\deps\graph.js:385:8)
    at Object.module.exports.image (C:\Users\Kow\AppData\Roaming\npm\node_modules\madge\lib\graph.js:110:4)
    at Madge.image (C:\Users\Kow\AppData\Roaming\npm\node_modules\madge\lib\madge.js:211:8)
    at run (C:\Users\Kow\AppData\Roaming\npm\node_modules\madge\bin\madge:110:7)

Is there some dependency I miss?

fails to install on node 8: node-commander 0.6

Anyway to update the package.json to use node-commander 1.0?

Otherwise, npm install madge on node 0.8 fails to install, with node-commander 0.6 not supporting node 0.8

npm ERR! notsup Not compatible with your version of node/npm: [email protected]
npm ERR! notsup Required: {"node":">= 0.4.x < 0.7.0"}
npm ERR! notsup Actual: {"npm":"1.1.32","node":"0.8.0"}

Thanks

Circular.js resolver function defect

In the madge ...circular.js the resolver function parameter modules is a dependences tree with the structure like: { 'lib\A' : ['lib/B'], 'lib\B' : ['lib/C'] }, so for the id = 'lib\A' modules[id] is ['lib/B']. In the first call to the recursion we have id = 'lib\A', and the second call will be with dependences array first element 'lib/B', but in the modules there is no key 'lib/B' - it has key 'lib\B' - the slashes are in the wrong direction. Fixed it as below, in order all slashes will have the same direction. Please review and update the circular.js.
function resolver(id, modules, circular, resolved, unresolved) {
id = id.replace(///g, '');
unresolved[id] = true;
if (modules[id]) {
modules[id].forEach(function (dependency) {
dependency = dependency.replace(///g, '');
if (!resolved[dependency]) {
if (unresolved[dependency]) {
circular.push(getPath(dependency, unresolved));
return;
}
resolver(dependency, modules, circular, resolved, unresolved);
}
});
}
resolved[id] = true;
unresolved[id] = false;
}

AMD not finding nested depedencies

Given:

// app.js
define(['a'], function (a) {
    console.log('a');
});
// a.js
define(['b'], function (b) {
    console.log('a');
});
// b.js
define([], function () {
    return {};
});

When I run:

// api.js
var madge = require('madge');
var dependencyObject = madge('app.js', {
    format: 'amd',
    findNestedDependencies: true
});
console.log(dependencyObject.tree);

The output is:

$ node api.js
{ app: [ 'a' ] }

How come madge is not finding the nested AMD dependencies?

output of --circular is incomplete

The output of --circular only prints two modules of the circuit. The two that are printed are not always the problem spot. It can be a chore to sort out the complete circuit. It would be much more helpful if --circular printed the whole circuit.

Recognition of require.js configuration

require.js lets you use an extensive config, that may contain dependencies as well. This is quite common, if you use libraries that were not written amd-style themselves. This is, what shim is for. In this example, we're using three jQuery-plugins, that depend on jquery being loaded first.

require.config({
    shim: {
        'jquery.animate-enhanced': {deps: ['jquery']},
        'jquery.imagesloaded': {deps: ['jquery']},
    },
    paths: {
        jquery: 'lib/jquery-2.0.3',
        less: 'lib/less-1.6.1',
        "jquery.animate-enhanced": 'lib/jquery.animate-enhanced-1.08',
        "jquery.imagesloaded": 'lib/jquery.imagesloaded-2.1.2',
    }
});

also: with paths you can define paths independent from the require-strings. It would be awesome if madge would use these, too.

Thank you.

Dude, this project is money in the bank. Thank you.

PNG generation fails on Windows 7 x64

Command line dump:

>madge --version
0.3.1
>madge --image graph.png --format amd scripts

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: This socket is closed.
    at Socket._write (net.js:637:19)
    at doWrite (_stream_writable.js:226:10)
    at writeOrBuffer (_stream_writable.js:216:5)
    at Socket.Writable.write (_stream_writable.js:183:11)
    at Socket.write (net.js:615:40)
    at Graph.render (C:\Users\Felix\AppData\Roaming\npm\node_modules\madge\node_modules\graphviz\lib\deps\graph.js:380:18)
    at Graph.output (C:\Users\Felix\AppData\Roaming\npm\node_modules\madge\node_modules\graphviz\lib\deps\graph.js:385:8)
    at Object.module.exports.image (C:\Users\Felix\AppData\Roaming\npm\node_modules\madge\lib\graph.js:109:4)
    at Madge.image (C:\Users\Felix\AppData\Roaming\npm\node_modules\madge\lib\madge.js:135:8)
    at run (C:\Users\Felix\AppData\Roaming\npm\node_modules\madge\bin\madge:102:7)

using requireConfig with paths

Currently madge does not seem to resolve the module IDs from the RequireJS paths-config:

if I use madge with the requireConfig option and the config-file contains path-settings, then madge will create 2 entries in the dependency graph, e.g. for the paths entry

{paths: {
   "someModuleA": "some/module/at/location/a"
}}

the resulting tree object will have the entries

  • one entry for the path-style ID (e.g. some/module/at/location/a)
  • and one entry for the ID as specified in the path-config (e.g. someModuleA)

where the first one seems to be created, when madge evaluates the file of "module a", and the second one is created if/when "module a" is require by its ID from somewhere else (i.e. form a module other than "module a"), e.g. something like this:

{
   ...
   "someModuleA": [/* list of dependencies for module a */],
   ...
    "some/module/at/location/a": [/* list of dependencies of module a */],
   ...
}

This issue is not resolved by convertAliases since the problem manifests in the ID entries themselves, and not in their dependency-lists (which are processed by convertAliases), i.e.

{
   ...
   "moduleId":   //<- this is NOT processed by convertAliases()
      [/* list of dependencies of moduleId */]   //<- these entries ARE processed by convertAliases()
   ...
}

I patched this behavior in this fork/commit, with the following changes:

  • added an alternate processing (instead of convertAliases) which will
    • use IDs from config-paths definition (instead of path-styled IDs as in convertAliases)
    • for each path-definition in the RequireJS config-paths: merge the 2 corresponding entries (as mentioned above, i.e. the "ID-entry" and the "path-entry")
    • FIX: resolve the paths from the RequireJS config against its baseUrl property, if one is set (otherwise the paths may not get matched against the module IDs correctly) this may also be necessary for convertAliases ... I did not check
  • added option useModuleIds (boolean): if omitted or false will use the old default behavior, if true will use this new alternative instead of convertAliases

NOTE:
I did not make a pull request, since the npm test did not execute on my machine without failures -- but this is also true for the current master branch.
I am running the tests on a Windows 64bit machine ... is there some special setting/configuration I have to use, to get the tests running?
For instance I noticed, that the files are referenced by absolute paths, but the test-values expect relative paths... also in some tests, there is an unexpected "dangling-symlink": [], entry which causes the test to fail...

inverting tree, subset-ing tree, deep dependencies...

I need the following for my work... and I'm prepared to do this as a pull request if it is welcome, but want to check first. If you feel it makes more sense to do outside of madge, then I'm fine with that. If potential use cases don't pop out at you, I'd be happy to discuss them. But in short, I have at least two goals:

  1. support for unit testing where the unit tests depend on the modules under test, and thus if I change a module, I can quickly and easily identify (as part of the build process) which unit tests to run; and
  2. quick diagrams of portions of an apps dependency tree that relate to a given module.

inverted tree with hash object instead of array
In addition to being able to browse by module with an array of the modules on which each depends, I need the inversion with a hash instead of an array. So, where .tree now gives me:

{
  "moduleA": ["moduleB", "moduleC"],
  "moduleD": ["moduleB"],
  "moduleE": ["moduleA"]
}

I need, if I called something like .invertedHash(), something like:

{
  "moduleA": {
    "moduleE": true
  },
  "moduleB": {
    "moduleA": true,
    "moduleD": true
  },
  "moduleC": {
   "moduleA": true
  },

subsetting the tree/deep dependencies
There is currently a depends(moduleId) function that gives you a shallow list of dependencies. I need a way to get a set of deep dependencies expressed in two forms:

A) as the .tree property currently expresses them such that I can draw graphs of the subset. If this were to be implemented as an overload of .tree, and I gave it .tree('moduleB'), I'd expect the example above to return

{
  "moduleA": ["moduleB"],
  "moduleD": ["moduleB"],
  "moduleE": ["moduleA"]
}

Note the absence of moduleC. What remains is the part of the graph of modules that depend on moduleB.

B) as the .depends(moduleId) function currently expresses them, but deep instead of shallow. So in the example, if I called deepDepends('moduleB') I'd get:

[
  "moduleA",
  "moduleD",
  "moduleE"
]

As I said above, I can do this outside of madge if you don't think it fits into the madge use cases sufficiently, but wanted to offer to do it as a PR, as that would be my preference. If you'd like to discuss alternatives which might be (a) sufficient for my needs and (b) more in line with the vision, please let me know! I've implemented this in the past for Google Closure Library dependencies and it makes for a great on-the-fly testing environment for developers, as well as for new developers when they're trying to get a handle on the structure of an app (the subsetted graphs use case).

madge --depends doesn't seem to include --require-config

Hi,

I'm attempting to find orphaned modules, using the --depends option, but it doesn't seem to consider paths in the require config.

madge --require-config modules/main.js --depends underscore modules yields no results even though underscore is one of my most common dependencies.

modules/main.js

require.config({
    paths: {
        underscore: '../bower_components/underscore/underscore'
        // (etc)
    }
});

modules/app.js

define(function (require) {
    'use strict';
    var $ = require('jquery'),
        _ = require('underscore');
   //...etc
});

image colors param

using nodejs, in a simple program, i trid to change bgcolor.
i use an object in parameters named colors like in docs.

var graph = dependencyObject.image({
'layout': 'sfdp',
'colors': {
'bgcolor': '#ffffff',
'edge' : '#666666',
'dependencies' : '#00ff00',
'fontColor' : '#bada55',
'fontFace' : 'Arial'
}
}, function(data){
require("fs").writeFile("out.jpg", data, 'binary', function(err) {
console.log(err);
});
});

but line 53 of graph.js

colors = opts.imageColors || {};

and not colors = opts.colors || {};

Bigger project does not fit in image

Hi. Tahnks very much for your tool! I found me cycle :)

I tried to generate a dependency map with madge --image graph.png --format amd .
The output is an image where I cant see the project because it is "scalled down".

when i only draw the map with a part of my project like madge --image graph.png --format amd common/
everything works fine. any idea?

no transitive dependencies

When I have a simple file with the dependency e.g. to react

require("react");

the madge only finds

{ index: [ '../node_modules/react/react' ] }

and does not recurse any further.

I must be missing something. I want to get all transitive dependencies, too.

resolve relative module IDs

If I have multiple references to the same module but they use different paths (relative / absolute) the graph won't show the proper connections.

string/trim, ./trim and ../string/trim doesn't resolve to same module (I think it should).

PS: I saw that behavior on AMD.

Delegate the generation of the dependency tree to an external module?

Big fan of madge! Thanks for the great work.

Semantically, it seems like madge is a visualization layer of an app's dependency tree. The generation of the tree is also done within madge though.

I wrote https://github.com/mrjoelkemp/node-dependency-tree as a way to generate the dependency tree of any JS codebase (amd, cjs, es6). It outputs a nested JSON structure (or a list of visited files) representing the tree of a file. Is there any interest in using that to power madge?

  1. It would allow madge to avoid the need to maintain the various syntaxes – reducing the size and surface area of the codebase.
  2. node-dependency-tree is actively maintained and I'm open to any of the needs of madge moving forward
  3. Madge would gain the ability to traverse SASS/Stylus (and soon Less) codebases
  4. Webpack loading support is planned shortly – which madge would get with a version bump

Thanks for your time.

Need a way to know which requires couldn't be parsed

detective.find returns a list of "expressions" which are requires which essentially couldn't be analyzed because it doesn't know which files they were. Madge should have an option to return the expressions, or better yet, should always return them.

These are important for a dependency package builder I'm making, since if a dependency is missing from the package, things are broken. I need a way to know at least if some requires weren't able to be analyzed, so I can throw an exception.

Backslashes in dot-output

This may be related to windows, i am getting a lot of nodes duplicated. In one instance, they have their "regular" forward slash, in one instance, they'll have the backslash (probably from the filesystem).

this also happens, if i run madge from a cygwin-bash on windows.

Right now, i can mitigate the problem like this:

 madge('www', {format: "amd"}).dot().replace(/\\/g, '/')

But it also means that i can't just use the commandline tool to generate an image.

Squashed image output

@pahen just started to play around madge and have encountered a strange issue with the image output.

The image generated is squashed and a fixed height. When I zoom in I can see the dependencies. Is this likely caused by too many files to process?

What is the purpose of convertAliases()?

I just discovered madge today. It's great!

I'm attempting to generate a diagram of a fairly large RequireJS-based codebase, with a big mix of AMD modules and shim'd non-AMD dependencies.

The diagram I'm getting is pretty huge, partly because the codebase is huge, but also because the module id's are being replaced with their relative file paths.

I added this line inside converAliases's inner forEach:

console.log("replacing " + array[i] + " with " + aliases[moduleName]);

And sure enough, many lines to the effect of replacing jquery with j/lib/jquery.min.

I find looking at the module id's more pleasant, so I've commented out convertAliases. What's the reasoning behind displaying file paths instead of module id's?

thanks!

(also, sorry about opening this issue with a title of "cd" and no content... I thought focus was on my terminal :) )

"EPIPE" error exporting to graph

Hello; I'm trying to export a graph of my CoffeeScript/Webpack application to PNG on Windows. I installed GraphWiz from http://www.graphviz.org/Download_windows.php. When I run "madge --image dep.png desktop/influx/parser/src" I see:

events.js:141
throw er; // Unhandled 'error' event
^

Error: write EPIPE
at exports._errnoException (util.js:870:11)
at Socket._writeGeneric (net.js:675:26)
at Socket._write (net.js:694:8)
at doWrite (_stream_writable.js:292:12)
at writeOrBuffer (_stream_writable.js:278:5)
at Socket.Writable.write (_stream_writable.js:207:11)
at Socket.write (net.js:618:40)
at Graph.render (C:\Users\james\AppData\Roaming\npm\node_modules\madge\node_modules\graphviz\lib\deps\graph.js:380:18)
at Graph.output (C:\Users\james\AppData\Roaming\npm\node_modules\madge\node_modules\graphviz\lib\deps\graph.js:385:8)
at Object.module.exports.image (C:\Users\james\AppData\Roaming\npm\node_modules\madge\lib\graph.js:110:4)

Have I installed the wrong package, or installed it incorrectly?

Thanks, James.

Support TypeScript

We use madge to find circular deps in Angular. We had been outputting to ES6, which lets us do a symbol-level graph (instead of file-level like commonjs)
But we no longer use the ES6 output for anything else, so I'd like to remove it.

I tried pointing madge at our sources

 {
    format: 'es6',
    paths: ['modules/angular2'],
    extensions: ['.ts']
  }

but I get an empty set of deps for each module, so I think node-detective-es6 or node-source-walk are getting confused parsing the TS files (even though we use ES6 module syntax).

ES6 tests failing

I was trying to analyse dependencies written in es6 syntax and had some trouble and then discovered that the es6 related tests are failing. This is on master sha 3b4957b

after checkout out the repo I ran npm install and npm test and got the following output.

  module format (ES6)
    1) should behave as expected on ok files
    ✓ should tackle errors in files 
    2) should be able to exclude modules
    3) should find circular dependencies
    4) should find absolute imports from the root

...

  1) module format (ES6) should behave as expected on ok files:

      AssertionError: expected Object {
  a: Array [],
  d: Array [],
  'fancy-main/not-index': Array [],
  'sub/b': Array [],
  'sub/c': Array []
} to equal Object {
  a: Array [ 'sub/b' ],
  d: Array [],
  'fancy-main/not-index': Array [],
  'sub/b': Array [ 'sub/c' ],
  'sub/c': Array [ 'd' ]
} (at a -> length, A has 0 and B has 1)
      + expected - actual

       {
      +  "a": [
      +    "sub/b"
      +  ],
      -  "a": [],
         "d": [],
         "fancy-main/not-index": [],
      +  "sub/b": [
      +    "sub/c"
      +  ],
      +  "sub/c": [
      +    "d"
      +  ]
      -  "sub/b": [],
      -  "sub/c": []
       }

(there is more output, but i figure this should be easy to reproduce).
Thanks

--image and --depends used together

How can I plot a graph of a single module and its dependencies?

When I tried the following command it did not generate a graph, but rather print the dependencies. Is in that case only one --option used?

madge --image graph.png --depends 'module' project/src/

does included graph.js file incorrectly reference opts.colors instead of opts.imageColors?

I was having trouble to get my generated image to render with any of my custom colors passed using API:

Looking thru the code, I found in lib/graph.js some code where reference was made to an opts.colors variable, however the API uses the imageColors property instead.

For example:

if (opts.colors) {
        G.bgcolor = opts.imageColors.bgcolor || '#000000';
        E.color = opts.imageColors.edge || '#757575';
        N.color =  opts.imageColors.dependencies || '#c6c5fe';
        N.fontcolor = opts.imageColors.fontColor || opts.imageColors.dependencies || '#c6c5fe';
    }

should be:

    if (opts.imageColors) {
        G.bgcolor = opts.imageColors.bgcolor || '#000000';
        E.color = opts.imageColors.edge || '#757575';
        N.color =  opts.imageColors.dependencies || '#c6c5fe';
        N.fontcolor = opts.imageColors.fontColor || opts.imageColors.dependencies || '#c6c5fe';
    }

When I did a search and replace on this file alone, my images rendered based on my customized colors as expected ;)

If i was good enough with Git, i would create a pull, patch, or whatever to try and contribute... but if you do search/replace on this one file.. that is the only change.

ES6 Module Support

Hello,

Fantastic tool you've got here. Just wondering if you would considered supporting ES6 modules? I know the final spec wasn't out for a while but it seems like it has stabilized and might be worth considering. There is actually a project called node-detective-e6 as well: https://www.npmjs.com/package/detective-es6

Thanks much!

Show version numbers of each external/vendor dependencies

My app contains dependencies to the internal component/app and external JS libraries. For each external/vendor (like backbone/underscore/etc.), I hope the tree could show that I use which version of it. This is great as when I run Madge across all my sites I can detect different versions of the same library and so on.

Also, it seems like when I use cjs instead of amd, some vendors are shown by name (jquery), but some are shown by the full path. Any advice? Thanks a lot!

How do you map actual required strings to paths?

In cjs.js, madge is mapping some parameters to require such that they're fullly resolved paths. I need a way to map these back to what they were originally required as.

How can I do that? Does this need to be an added feature?

coffee

support for coffeescript ?

PS: superb tool!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.