config-builder.js 3.9 KB

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