UNPKG

3.39 kBJavaScriptView Raw
1'use strict';
2
3const tree = require('./tree');
4const cyclic = require('./cyclic');
5const graph = require('./graph');
6const log = require('./log');
7
8const defaultConfig = {
9 baseDir: null,
10 excludeRegExp: false,
11 fileExtensions: ['js'],
12 includeNpm: false,
13 requireConfig: null,
14 webpackConfig: null,
15 tsConfig: null,
16 rankdir: 'LR',
17 layout: 'dot',
18 fontName: 'Arial',
19 fontSize: '14px',
20 backgroundColor: '#111111',
21 nodeColor: '#c6c5fe',
22 nodeShape: 'box',
23 nodeStyle: 'rounded',
24 noDependencyColor: '#cfffac',
25 cyclicNodeColor: '#ff6c60',
26 edgeColor: '#757575',
27 graphVizOptions: false,
28 graphVizPath: false,
29 dependencyFilter: false
30};
31
32class Madge {
33 /**
34 * Class constructor.
35 * @constructor
36 * @api public
37 * @param {String|Array|Object} path
38 * @param {Object} config
39 * @return {Promise}
40 */
41 constructor(path, config) {
42 this.skipped = [];
43
44 if (!path) {
45 throw new Error('path argument not provided');
46 }
47
48 this.config = Object.assign({}, defaultConfig, config);
49
50 if (typeof path === 'object' && !Array.isArray(path)) {
51 this.tree = path;
52 log('using predefined tree %o', path);
53 return Promise.resolve(this);
54 }
55
56 if (typeof path === 'string') {
57 path = [path];
58 }
59
60 return tree(path, this.config).then((res) => {
61 this.tree = res.tree;
62 this.skipped = res.skipped;
63 return this;
64 });
65 }
66
67 /**
68 * Return the module dependency graph as an object.
69 * @api public
70 * @return {Object}
71 */
72 obj() {
73 return this.tree;
74 }
75
76 /**
77 * Return produced warnings.
78 * @api public
79 * @return {Array}
80 */
81 warnings() {
82 return {
83 skipped: this.skipped
84 };
85 }
86
87 /**
88 * Return the modules that has circular dependencies.
89 * @api public
90 * @return {Object}
91 */
92 circular() {
93 return cyclic(this.tree);
94 }
95
96 /**
97 * Return a list of modules that depends on the given module.
98 * @api public
99 * @param {String} id
100 * @return {Array}
101 */
102 depends(id) {
103 const tree = this.obj();
104
105 return Object
106 .keys(tree)
107 .filter((dep) => tree[dep].indexOf(id) >= 0);
108 }
109
110 /**
111 * Return a list of modules that no one is depending on.
112 * @api public
113 * @return {Array}
114 */
115 orphans() {
116 const tree = this.obj();
117 const map = {};
118
119 Object
120 .keys(tree)
121 .forEach((dep) => {
122 tree[dep].forEach((id) => {
123 map[id] = true;
124 });
125 });
126
127 return Object
128 .keys(tree)
129 .filter((dep) => !map[dep]);
130 }
131
132 /**
133 * Return a list of modules that have no dependencies.
134 * @api public
135 * @return {Array}
136 */
137 leaves() {
138 const tree = this.obj();
139 return Object.keys(tree).filter((key) => !tree[key].length);
140 }
141
142 /**
143 * Return the module dependency graph as DOT output.
144 * @api public
145 * @return {Promise}
146 */
147 dot() {
148 return graph.dot(this.obj(), this.circular(), this.config);
149 }
150
151 /**
152 * Write dependency graph to image.
153 * @api public
154 * @param {String} imagePath
155 * @return {Promise}
156 */
157 image(imagePath) {
158 if (!imagePath) {
159 return Promise.reject(new Error('imagePath not provided'));
160 }
161
162 return graph.image(this.obj(), this.circular(), imagePath, this.config);
163 }
164
165 /**
166 * Return Buffer with XML SVG representation of the dependency graph.
167 * @api public
168 * @return {Promise}
169 */
170 svg() {
171 return graph.svg(this.obj(), this.circular(), this.config);
172 }
173}
174
175/**
176 * Expose API.
177 * @param {String|Array} path
178 * @param {Object} config
179 * @return {Promise}
180 */
181module.exports = (path, config) => new Madge(path, config);