Browse Source

produceConfigObject deals correctly with paths

Herbert Vojčík 10 years ago
parent
commit
4a4cba3879

+ 64 - 27
lib/config-builder.js

@@ -1,4 +1,5 @@
 var path = require('path'),
+    url = require('url'),
     _ = require('lodash'),
     findit = require('findit'),
     fs = require('fs');
@@ -30,6 +31,56 @@ function transformShimDeps(json) {
     }
 }
 
+function transformPaths(json, root, file, dirs) {
+    if (json.paths) {
+        var specifier = path.basename(file).replace(/\.amd\.json$/, "");
+        var modulePath = specifier === "local" ? path.dirname(file) : dirs[specifier];
+        var dir = (path.relative(root, modulePath).split(path.sep).join('/') || ".") + '/';
+        var paths = Object.keys(json.paths);
+        for (var i = 0; i < paths.length; i++) {
+            var key = paths[i];
+            json.paths[key] = url.resolve(dir, json.paths[key]) || ".";
+        }
+    }
+}
+
+function isLessDeep(a, b) {
+    var bDepth = b ? b.split(path.sep).length : Infinity;
+    var aDepth = a ? a.split(path.sep).length : Infinity;
+    return aDepth < bDepth;
+}
+
+function constructDirMap(dirs) {
+    var result = {};
+    for (var i = 0; i < dirs.length; i++) {
+        var dir = dirs[i];
+        var basename = path.basename(dir);
+        if (isLessDeep(dir, result[basename])) {
+            result[basename] = dir;
+        }
+    }
+    return result;
+}
+
+function queoeOfFilesToProcess(files, dirMap) {
+    var firstPass = [], secondPass = [];
+    for (var i = 0; i < files.length; i++) {
+        var file = files[i];
+        var basename = path.basename(file);
+        var specifier = basename.replace(/\.amd\.json$/, "");
+        if (specifier == "" || specifier[0] == ".") {
+            continue;
+        } else if (specifier == "local") {
+            firstPass.push(file);
+        } else if (dirMap[specifier]) {
+            secondPass.push(file);
+        } else {
+            throw new Error("No location for " + file);
+        }
+    }
+    return  firstPass.concat(secondPass);
+}
+
 exports.produceConfigObject = function (root, callback) {
     eachConfigFile(root, function (err, filesAndDirs) {
         if (err) {
@@ -37,39 +88,25 @@ exports.produceConfigObject = function (root, callback) {
             return;
         }
 
-        var dirExists = {};
-        var dirs = Object.keys(filesAndDirs.dirs);
-        for (var i = 0; i < dirs.length; i++) {
-            dirExists[path.basename(dirs[i])] = true;
-        }
-
-        var files = Object.keys(filesAndDirs.files);
-        var firstPass = [], secondPass = [];
-        for (var i = 0; i < files.length; i++) {
-            var file = files[i];
-            var basename = path.basename(file);
-            var specifier = basename.replace(/\.amd\.json$/, "");
-            if (specifier == "" || specifier[0] == ".") {
-                continue;
-            } else if (specifier == "local") {
-                firstPass.push(file);
-            } else if (dirExists[specifier]) {
-                secondPass.push(file);
-            } else {
-                callback(new Error("No location for " + file));
-                return;
-            }
+        var dirMap = constructDirMap(Object.keys(filesAndDirs.dirs));
+        var queue;
+        try {
+            queue = queoeOfFilesToProcess(Object.keys(filesAndDirs.files), dirMap);
+        } catch (e) {
+            callback(e);
+            return;
         }
-        var bothPasses = [].concat(firstPass).concat(secondPass);
-        if (!bothPasses.length) {
+        if (!queue.length) {
             callback(new Error("No .amd.json-type file found"));
             return;
         }
         var result = {};
-        for (var i = 0; i < bothPasses.length; i++) {
-            var json = require(bothPasses[i]);
+        for (var i = 0; i < queue.length; i++) {
+            var file = queue[i];
+            var json = require(file);
             transformShimDeps(json);
-            _.merge(result, json, function(a, b) {
+            transformPaths(json, root, file, dirMap);
+            _.merge(result, json, function (a, b) {
                 return _.isArray(a) ? a.concat(b) : undefined;
             });
         }

+ 33 - 0
test/produce.js

@@ -93,3 +93,36 @@ describe('#produceConfigObject knows to deal with shims', function () {
     });
 
 });
+
+describe('#produceConfigObject paths', function () {
+    it('should leave root local.amd.json paths unchanged', function (done) {
+        builder.produceConfigObject(fixture('single-local-paths'), function (err, result) {
+            assert.ifError(err);
+            assert.deepEqual(result, {
+                paths: {dot: ".", rel: "relative", sibling: "../sibling", abs: "/absolute", uri: "http://example.com/uri"}
+            });
+            done();
+        });
+    });
+
+    it('should make deep local.amd.json paths relative to deep', function (done) {
+        builder.produceConfigObject(fixture('single-deep-local-paths'), function (err, result) {
+            assert.ifError(err);
+            assert.deepEqual(result, {
+                paths: {dot: "deep", rel: "deep/relative", sibling: "sibling", abs: "/absolute", uri: "http://example.com/uri"}
+            });
+            done();
+        });
+    });
+
+    it('should make foo.amd.json paths relative to foo that is least deep', function (done) {
+        builder.produceConfigObject(fixture('single-other-paths'), function (err, result) {
+            assert.ifError(err);
+            assert.deepEqual(result, {
+                paths: {dot: "z2/other", rel: "z2/other/relative", sibling: "z2/sibling", abs: "/absolute", uri: "http://example.com/uri"}
+            });
+            done();
+        });
+    });
+
+});

+ 9 - 0
test/single-deep-local-paths/deep/local.amd.json

@@ -0,0 +1,9 @@
+{
+    "paths": {
+        "dot": ".",
+        "rel": "relative",
+        "sibling": "../sibling",
+        "abs": "/absolute",
+        "uri": "http://example.com/uri"
+    }
+}

+ 5 - 0
test/single-local-paths/.amd.json

@@ -0,0 +1,5 @@
+{
+    "paths": {
+        "fooDot": "fooDot"
+    }
+}

+ 5 - 0
test/single-local-paths/amd.json

@@ -0,0 +1,5 @@
+{
+    "paths": {
+        "fooStripped": "fooStripped"
+    }
+}

+ 9 - 0
test/single-local-paths/local.amd.json

@@ -0,0 +1,9 @@
+{
+    "paths": {
+        "dot": ".",
+        "rel": "relative",
+        "sibling": "../sibling",
+        "abs": "/absolute",
+        "uri": "http://example.com/uri"
+    }
+}

+ 1 - 0
test/single-other-paths/a3/3/other/local.amd.json

@@ -0,0 +1 @@
+{}

+ 9 - 0
test/single-other-paths/other.amd.json

@@ -0,0 +1,9 @@
+{
+    "paths": {
+        "dot": ".",
+        "rel": "relative",
+        "sibling": "../sibling",
+        "abs": "/absolute",
+        "uri": "http://example.com/uri"
+    }
+}

+ 1 - 0
test/single-other-paths/z2/other/local.amd.json

@@ -0,0 +1 @@
+{}