Skip to content

Commit

Permalink
Resolve the module IDs from the RequireJS paths-config properly.
Browse files Browse the repository at this point in the history
  • Loading branch information
pahen committed Dec 19, 2014
1 parent 9bf15c9 commit 41b54e2
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 20 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ minimize a global energy function, which is equivalent to statistical multi-dime
## v0.4.0 (December 19, 2014)
Add support for JSX (React) and additional module paths (Thanks to Ben Lowery).
Fix for detecting presence of AMD or CommonJS modules (Thanks to Aaron Russ).
Now resolves the module IDs from the RequireJS paths-config properly (Thanks to russaa).
Added support for option findNestedDependencies to find nested dependencies in AMD modules.

## v0.3.5 (Septemper 22, 2014)
Expand Down
69 changes: 59 additions & 10 deletions lib/madge.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,63 @@ function mergeTrees(a, b) {
});
});
}

/**
* Replace alias found inside tree with alias
* @param {Object} tree
* @param {Object} alias list
*/
function convertAliases(tree, aliases) {
Object.keys(tree).forEach(function (id) {
tree[id].forEach(function (moduleName, i, array) {
if (aliases[moduleName]) {
array[i] = aliases[moduleName];
* Helper for re-mapping path-refs to id-refs that are specified in RequireJS' path config.
* @param {Object} deps (dependency-list)
* @param {Object} pathDefs (path-definitions from requirejs-config)
* @param {String} baseDir (base directory of source files)
*/
function convertPathsToIds(deps, pathDefs, baseDir) {
var path, pathDeps, i1, len1, i2, len2, isContained;

if (baseDir){
baseDir += '/';
} else {
baseDir = '';
}

Object.keys(pathDefs).forEach(function (id) {
path = pathDefs[id];

//if path does not start with / or a protocol: prepend with baseDir
if (!/^[^\/]+:\/\/|^\//m.test(path) ){
path = baseDir + path;
}

if (path !== id && deps[path]) {
if (deps[id] && deps[id].length > 0){
pathDeps = deps[path].slice(0, deps[path].length-1);

//remove entries from <path-ref>, if already contained in <id-ref>
for (i1=0, len1 = pathDeps.length; i1 < len1; ++i1){
for (i2=0, len2 = deps[id].length; i2 < len2; ++i2){
if (pathDeps[i1] === deps[id][i2]){
pathDeps.splice(i1--, 1);
break;
}
}
}
deps[id] = deps[id].concat(pathDeps);
} else {
deps[id] = deps[path];
}

delete deps[path];
} else if (!deps[id]) {
deps[id] = [];
}

//normalize entries within deps-arrays (i.e. replace path-refs with id-refs)
Object.keys(pathDefs).forEach(function (id) {
path = baseDir + pathDefs[id];
if (deps[id]){
for (i1=0, len1 = deps[id].length; i1 < len1; ++i1){
//replace path-ref with id-ref (if necessary)
if (deps[id][i1] === path){
deps[id][i1] = id;
}
}
}
});
});
Expand Down Expand Up @@ -87,8 +134,10 @@ function Madge(src, opts) {
}

if (this.opts.requireConfig) {
var baseDir = src.length ? src[0].replace(/\\/g, '/') : '';
baseDir = requirejs.getBaseUrlFromConfig(this.opts.requireConfig, baseDir);
convertPathsToIds(tree, requirejs.getPathsFromConfig(this.opts.requireConfig, this.opts.exclude), baseDir);
mergeTrees(tree, requirejs.getShimDepsFromConfig(this.opts.requireConfig, this.opts.exclude));
convertAliases(tree, requirejs.getPathsFromConfig(this.opts.requireConfig, this.opts.exclude));
}

this.tree = tree;
Expand Down
15 changes: 14 additions & 1 deletion lib/requirejs.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
* Module dependencies.
*/
var fs = require('fs'),
parse = require('./parse/parse');
parse = require('./parse/parse'),
path = require('path');

/**
* Read shim dependencies from RequireJS config.
* @param {String} filename
* @param {String} [exclude]
* @return {Object}
*/
module.exports.getShimDepsFromConfig = function (filename, exclude) {
var deps = {},
Expand All @@ -36,6 +38,7 @@ module.exports.getShimDepsFromConfig = function (filename, exclude) {
* Read path definitions from RequireJS config.
* @param {String} filename
* @param {String} [exclude]
* @return {Object}
*/
module.exports.getPathsFromConfig = function (filename, exclude) {
var paths = {},
Expand All @@ -53,3 +56,13 @@ module.exports.getPathsFromConfig = function (filename, exclude) {

return paths;
};

/**
* Read baseUrl from RequireJS config.
* @param {String} filename
* @param {String} srcBaseDir
*/
module.exports.getBaseUrlFromConfig = function (filename, srcBaseDir) {
var config = parse.findConfig(filename, fs.readFileSync(filename, 'utf8'));
return config.baseUrl ? path.relative(srcBaseDir, config.baseUrl) : '';
};
12 changes: 3 additions & 9 deletions test/amd.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('module format (AMD)', function () {
madge([__dirname + '/files/amd/requirejs/a.js'], {
format: 'amd',
requireConfig: __dirname + '/files/amd/requirejs/config.js'
}).obj().should.eql({ a: [ 'vendor/jquery-2.0.3' ], 'jquery': [], 'jquery.foo': [ 'vendor/jquery-2.0.3' ], 'jquery.bar': [ 'vendor/jquery-2.0.3' ], 'baz': [ 'vendor/quux' ], 'quux': [] });
}).obj().should.eql({ 'a': [ 'jquery' ], 'jquery': [], 'jquery.foo': [ 'jquery' ], 'jquery.bar': [ 'jquery' ], 'baz': [ 'quux' ], 'quux': [] });
});

it('should be able to exclude modules', function () {
Expand All @@ -53,7 +53,7 @@ describe('module format (AMD)', function () {
format: 'amd',
requireConfig: __dirname + '/files/amd/requirejs/config.js',
exclude: '^jquery.foo|quux$'
}).obj().should.eql({ a: [ 'vendor/jquery-2.0.3' ], 'jquery': [], 'jquery.bar': [ 'vendor/jquery-2.0.3' ] , 'baz': []});
}).obj().should.eql({ a: [ 'jquery' ], 'jquery': [], 'jquery.bar': [ 'jquery' ] , 'baz': []});
});

it('should tackle errors in files', function () {
Expand All @@ -62,12 +62,6 @@ describe('module format (AMD)', function () {
}).obj().should.eql({ error: [] });
});

// it('should handle id different than file', function () {
// madge([__dirname + '/files/amd/namedWrapped/diff.js'], {
// format: 'amd'
// }).obj().should.eql({ 'ffid': [] });
// });

it('should handle named modules', function () {
madge([__dirname + '/files/amd/namedWrapped/car.js'], {
format: 'amd'
Expand All @@ -90,7 +84,7 @@ describe('module format (AMD)', function () {
madge([__dirname + '/files/amd/circularAlias'], {
format: 'amd',
requireConfig: __dirname + '/files/amd/circularAlias/config.js'
}).circular().getArray().should.eql([ [ 'dos', 'x86' ] ]);
}).circular().getArray().should.eql([ [ 'cpu', 'jsdos' ] ]);
});

it('should find modules that depends on another', function () {
Expand Down

0 comments on commit 41b54e2

Please sign in to comment.