config-builder.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. var path = require('path'),
  2. url = require('url'),
  3. _ = require('lodash'),
  4. findit = require('findit2'),
  5. fs = require('fs');
  6. function eachConfigFile (root, callback) {
  7. var files = {};
  8. var dirs = {};
  9. var dirNames = {};
  10. var find = findit(root, {followSymlinks: true});
  11. var loopingOn = null;
  12. find.on('file', function (file, stat, linkPath) {
  13. if (file.match(/\.amd\.json$/)) {
  14. files[linkPath || file] = stat;
  15. }
  16. });
  17. find.on('error', function (err) {
  18. if (err.code === 'ELOOP') loopingOn = err.path;
  19. else {
  20. console.log(err);
  21. find.stop();
  22. }
  23. });
  24. find.on('directory', function (dir, stat, stop, linkPath) {
  25. var name = linkPath || dir;
  26. if (dir === loopingOn && !isLessDeep(name, dirNames[dir])) {
  27. stop();
  28. name = dirNames[dir];
  29. }
  30. loopingOn = null;
  31. dirNames[dir] = name;
  32. dirs[name] = stat;
  33. });
  34. find.on('end', function () {
  35. callback(null, {files: files, dirs: dirs});
  36. });
  37. }
  38. function transformShimDeps (json) {
  39. var shimmedList = json.shim && Object.keys(json.shim);
  40. if (!shimmedList) return;
  41. for (var i = 0; i < shimmedList.length; i++) {
  42. var shim = json.shim[shimmedList[i]];
  43. if (Array.isArray(shim)) {
  44. json.shim[shimmedList[i]] = {deps: shim};
  45. }
  46. }
  47. }
  48. function transformPaths (json, root, file, dirs) {
  49. if (json.paths) {
  50. var specifier = path.basename(file).replace(/\.amd\.json$/, "");
  51. var modulePath = specifier === "local" ? path.dirname(file) : dirs[specifier];
  52. var dir = (path.relative(root, modulePath).split(path.sep).join('/') || ".") + '/';
  53. transformPathArray(json.paths);
  54. }
  55. function transformPathArray (array) {
  56. var paths = Object.keys(array);
  57. for (var i = 0; i < paths.length; i++) {
  58. var key = paths[i];
  59. var pathValue = array[key];
  60. switch (typeof pathValue) {
  61. case "string":
  62. array[key] = url.resolve(dir, pathValue) || ".";
  63. if (array[key].slice(-1) === "/") array[key] = array[key].slice(0, -1);
  64. break;
  65. case "object":
  66. Array.isArray(pathValue) && transformPathArray(pathValue);
  67. break;
  68. }
  69. }
  70. }
  71. }
  72. function isLessDeep (a, b) {
  73. var bDepth = b ? b.split(path.sep).length : Infinity;
  74. var aDepth = a ? a.split(path.sep).length : Infinity;
  75. return aDepth < bDepth;
  76. }
  77. function constructDirMap (dirs) {
  78. var result = {};
  79. for (var i = 0; i < dirs.length; i++) {
  80. var dir = dirs[i];
  81. var basename = path.basename(dir);
  82. if (isLessDeep(dir, result[basename])) {
  83. result[basename] = dir;
  84. }
  85. }
  86. return result;
  87. }
  88. function queoeOfFilesToProcess (files, dirMap) {
  89. var firstPass = [], secondPass = [];
  90. for (var i = 0; i < files.length; i++) {
  91. var file = files[i];
  92. var basename = path.basename(file);
  93. var specifier = basename.replace(/\.amd\.json$/, "");
  94. if (specifier == "" || specifier[0] == ".") {
  95. continue;
  96. } else if (specifier == "local") {
  97. firstPass.push(file);
  98. } else if (dirMap[specifier]) {
  99. secondPass.push(file);
  100. } else {
  101. throw new Error("No location for " + file);
  102. }
  103. }
  104. return firstPass.concat(secondPass).reverse();
  105. }
  106. exports.produceConfigObject = function (root, callback) {
  107. root = path.resolve(root);
  108. eachConfigFile(root, function (err, filesAndDirs) {
  109. if (err) {
  110. callback(err);
  111. return;
  112. }
  113. var dirMap = constructDirMap(Object.keys(filesAndDirs.dirs));
  114. var queue;
  115. try {
  116. queue = queoeOfFilesToProcess(Object.keys(filesAndDirs.files), dirMap);
  117. } catch (e) {
  118. callback(e);
  119. return;
  120. }
  121. if (!queue.length) {
  122. callback(new Error("No .amd.json-type file found"));
  123. return;
  124. }
  125. var result = {};
  126. for (var i = 0; i < queue.length; i++) {
  127. var file = queue[i];
  128. var json = JSON.parse(JSON.stringify(require(file)));
  129. transformShimDeps(json);
  130. transformPaths(json, root, file, dirMap);
  131. _.mergeWith(result, json, function (a, b) {
  132. return _.isArray(a) ? b.concat(a) : undefined;
  133. });
  134. }
  135. callback(null, result);
  136. })
  137. };