join-function.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.defaultJoin = void 0;
  6. var _path = _interopRequireDefault(require("path"));
  7. var _fs = _interopRequireDefault(require("fs"));
  8. function _interopRequireDefault(obj) {
  9. return obj && obj.__esModule ? obj : {
  10. default: obj
  11. };
  12. }
  13. const compose = (f, g)=>(...args)=>f(g(...args));
  14. const simpleJoin = compose(_path.default.normalize, _path.default.join);
  15. const defaultJoin = createJoinForPredicate(function predicate(_, uri, base, i, next) {
  16. const absolute = simpleJoin(base, uri);
  17. return _fs.default.existsSync(absolute) ? absolute : next(i === 0 ? absolute : null);
  18. }, "defaultJoin");
  19. exports.defaultJoin = defaultJoin;
  20. function* createIterator(arr) {
  21. for (const i of arr){
  22. yield i;
  23. }
  24. }
  25. /**
  26. * Define a join function by a predicate that tests possible base paths from an iterator.
  27. *
  28. * The `predicate` is of the form:
  29. *
  30. * ```
  31. * function(filename, uri, base, i, next):string|null
  32. * ```
  33. *
  34. * Given the uri and base it should either return:
  35. * - an absolute path success
  36. * - a call to `next(null)` as failure
  37. * - a call to `next(absolute)` where absolute is placeholder and the iterator continues
  38. *
  39. * The value given to `next(...)` is only used if success does not eventually occur.
  40. *
  41. * The `file` value is typically unused but useful if you would like to differentiate behaviour.
  42. *
  43. * You can write a much simpler function than this if you have specific requirements.
  44. *
  45. * @param {function} predicate A function that tests values
  46. * @param {string} [name] Optional name for the resulting join function
  47. */ function createJoinForPredicate(predicate, name) {
  48. /**
  49. * A factory for a join function with logging.
  50. *
  51. * @param {string} filename The current file being processed
  52. * @param {{debug:function|boolean,root:string}} options An options hash
  53. */ function join(filename, options) {
  54. const log = createDebugLogger(options.debug);
  55. /**
  56. * Join function proper.
  57. *
  58. * For absolute uri only `uri` will be provided. In this case we substitute any `root` given in options.
  59. *
  60. * @param {string} uri A uri path, relative or absolute
  61. * @param {string|Iterator.<string>} [baseOrIteratorOrAbsent] Optional absolute base path or iterator thereof
  62. * @return {string} Just the uri where base is empty or the uri appended to the base
  63. */ return function joinProper(uri, baseOrIteratorOrAbsent) {
  64. const iterator = typeof baseOrIteratorOrAbsent === "undefined" && createIterator([
  65. options.root
  66. ]) || typeof baseOrIteratorOrAbsent === "string" && createIterator([
  67. baseOrIteratorOrAbsent
  68. ]) || baseOrIteratorOrAbsent;
  69. const result = runIterator([]);
  70. log(createJoinMsg, [
  71. filename,
  72. uri,
  73. result,
  74. result.isFound
  75. ]);
  76. return typeof result.absolute === "string" ? result.absolute : uri;
  77. function runIterator(accumulator) {
  78. const nextItem = iterator.next();
  79. var base = !nextItem.done && nextItem.value;
  80. if (typeof base === "string") {
  81. const element = predicate(filename, uri, base, accumulator.length, next);
  82. if (typeof element === "string" && _path.default.isAbsolute(element)) {
  83. return Object.assign(accumulator.concat(base), {
  84. isFound: true,
  85. absolute: element
  86. });
  87. } else if (Array.isArray(element)) {
  88. return element;
  89. } else {
  90. throw new Error("predicate must return an absolute path or the result of calling next()");
  91. }
  92. } else {
  93. return accumulator;
  94. }
  95. function next(fallback) {
  96. return runIterator(Object.assign(accumulator.concat(base), typeof fallback === "string" && {
  97. absolute: fallback
  98. }));
  99. }
  100. }
  101. };
  102. }
  103. function toString() {
  104. return "[Function: " + name + "]";
  105. }
  106. return Object.assign(join, name && {
  107. valueOf: toString,
  108. toString: toString
  109. });
  110. }
  111. /**
  112. * Format a debug message.
  113. *
  114. * @param {string} file The file being processed by webpack
  115. * @param {string} uri A uri path, relative or absolute
  116. * @param {Array.<string>} bases Absolute base paths up to and including the found one
  117. * @param {boolean} isFound Indicates the last base was correct
  118. * @return {string} Formatted message
  119. */ function createJoinMsg(file, uri, bases, isFound) {
  120. return [
  121. "resolve-url-loader: " + pathToString(file) + ": " + uri
  122. ].concat(bases.map(pathToString).filter(Boolean)).concat(isFound ? "FOUND" : "NOT FOUND").join("\n ");
  123. /**
  124. * If given path is within `process.cwd()` then show relative posix path, otherwise show absolute posix path.
  125. *
  126. * @param {string} absolute An absolute path
  127. * @return {string} A relative or absolute path
  128. */ function pathToString(absolute) {
  129. if (!absolute) {
  130. return null;
  131. } else {
  132. const relative = _path.default.relative(process.cwd(), absolute).split(_path.default.sep);
  133. return (relative[0] === ".." ? absolute.split(_path.default.sep) : [
  134. "."
  135. ].concat(relative).filter(Boolean)).join("/");
  136. }
  137. }
  138. }
  139. exports.createJoinMsg = createJoinMsg;
  140. /**
  141. * A factory for a log function predicated on the given debug parameter.
  142. *
  143. * The logging function created accepts a function that formats a message and parameters that the function utilises.
  144. * Presuming the message function may be expensive we only call it if logging is enabled.
  145. *
  146. * The log messages are de-duplicated based on the parameters, so it is assumed they are simple types that stringify
  147. * well.
  148. *
  149. * @param {function|boolean} debug A boolean or debug function
  150. * @return {function(function, array)} A logging function possibly degenerate
  151. */ function createDebugLogger(debug) {
  152. const log = !!debug && (typeof debug === "function" ? debug : console.log);
  153. const cache = {};
  154. return log ? actuallyLog : noop;
  155. function noop() {}
  156. function actuallyLog(msgFn, params) {
  157. const key = JSON.stringify(params);
  158. if (!cache[key]) {
  159. cache[key] = true;
  160. log(msgFn.apply(null, params));
  161. }
  162. }
  163. }
  164. exports.createDebugLogger = createDebugLogger;
  165. //# sourceMappingURL=join-function.js.map