interpolateName.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. 'use strict';
  2. const path = require('path');
  3. const emojisList = require('emojis-list');
  4. const getHashDigest = require('./getHashDigest');
  5. const emojiRegex = /[\uD800-\uDFFF]./;
  6. const emojiList = emojisList.filter((emoji) => emojiRegex.test(emoji));
  7. const emojiCache = {};
  8. function encodeStringToEmoji(content, length) {
  9. if (emojiCache[content]) {
  10. return emojiCache[content];
  11. }
  12. length = length || 1;
  13. const emojis = [];
  14. do {
  15. if (!emojiList.length) {
  16. throw new Error('Ran out of emoji');
  17. }
  18. const index = Math.floor(Math.random() * emojiList.length);
  19. emojis.push(emojiList[index]);
  20. emojiList.splice(index, 1);
  21. } while (--length > 0);
  22. const emojiEncoding = emojis.join('');
  23. emojiCache[content] = emojiEncoding;
  24. return emojiEncoding;
  25. }
  26. function interpolateName(loaderContext, name, options) {
  27. let filename;
  28. const hasQuery =
  29. loaderContext.resourceQuery && loaderContext.resourceQuery.length > 1;
  30. if (typeof name === 'function') {
  31. filename = name(
  32. loaderContext.resourcePath,
  33. hasQuery ? loaderContext.resourceQuery : undefined
  34. );
  35. } else {
  36. filename = name || '[hash].[ext]';
  37. }
  38. const context = options.context;
  39. const content = options.content;
  40. const regExp = options.regExp;
  41. let ext = 'bin';
  42. let basename = 'file';
  43. let directory = '';
  44. let folder = '';
  45. let query = '';
  46. if (loaderContext.resourcePath) {
  47. const parsed = path.parse(loaderContext.resourcePath);
  48. let resourcePath = loaderContext.resourcePath;
  49. if (parsed.ext) {
  50. ext = parsed.ext.substr(1);
  51. }
  52. if (parsed.dir) {
  53. basename = parsed.name;
  54. resourcePath = parsed.dir + path.sep;
  55. }
  56. if (typeof context !== 'undefined') {
  57. directory = path
  58. .relative(context, resourcePath + '_')
  59. .replace(/\\/g, '/')
  60. .replace(/\.\.(\/)?/g, '_$1');
  61. directory = directory.substr(0, directory.length - 1);
  62. } else {
  63. directory = resourcePath.replace(/\\/g, '/').replace(/\.\.(\/)?/g, '_$1');
  64. }
  65. if (directory.length === 1) {
  66. directory = '';
  67. } else if (directory.length > 1) {
  68. folder = path.basename(directory);
  69. }
  70. }
  71. if (loaderContext.resourceQuery && loaderContext.resourceQuery.length > 1) {
  72. query = loaderContext.resourceQuery;
  73. const hashIdx = query.indexOf('#');
  74. if (hashIdx >= 0) {
  75. query = query.substr(0, hashIdx);
  76. }
  77. }
  78. let url = filename;
  79. if (content) {
  80. // Match hash template
  81. url = url
  82. // `hash` and `contenthash` are same in `loader-utils` context
  83. // let's keep `hash` for backward compatibility
  84. .replace(
  85. /\[(?:([^[:\]]+):)?(?:hash|contenthash)(?::([a-z]+\d*))?(?::(\d+))?\]/gi,
  86. (all, hashType, digestType, maxLength) =>
  87. getHashDigest(content, hashType, digestType, parseInt(maxLength, 10))
  88. )
  89. .replace(/\[emoji(?::(\d+))?\]/gi, (all, length) =>
  90. encodeStringToEmoji(content, parseInt(length, 10))
  91. );
  92. }
  93. url = url
  94. .replace(/\[ext\]/gi, () => ext)
  95. .replace(/\[name\]/gi, () => basename)
  96. .replace(/\[path\]/gi, () => directory)
  97. .replace(/\[folder\]/gi, () => folder)
  98. .replace(/\[query\]/gi, () => query);
  99. if (regExp && loaderContext.resourcePath) {
  100. const match = loaderContext.resourcePath.match(new RegExp(regExp));
  101. match &&
  102. match.forEach((matched, i) => {
  103. url = url.replace(new RegExp('\\[' + i + '\\]', 'ig'), matched);
  104. });
  105. }
  106. if (
  107. typeof loaderContext.options === 'object' &&
  108. typeof loaderContext.options.customInterpolateName === 'function'
  109. ) {
  110. url = loaderContext.options.customInterpolateName.call(
  111. loaderContext,
  112. url,
  113. name,
  114. options
  115. );
  116. }
  117. return url;
  118. }
  119. module.exports = interpolateName;