You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

interpolateName.js 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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. if (typeof name === 'function') {
  29. filename = name(loaderContext.resourcePath);
  30. } else {
  31. filename = name || '[hash].[ext]';
  32. }
  33. const context = options.context;
  34. const content = options.content;
  35. const regExp = options.regExp;
  36. let ext = 'bin';
  37. let basename = 'file';
  38. let directory = '';
  39. let folder = '';
  40. if (loaderContext.resourcePath) {
  41. const parsed = path.parse(loaderContext.resourcePath);
  42. let resourcePath = loaderContext.resourcePath;
  43. if (parsed.ext) {
  44. ext = parsed.ext.substr(1);
  45. }
  46. if (parsed.dir) {
  47. basename = parsed.name;
  48. resourcePath = parsed.dir + path.sep;
  49. }
  50. if (typeof context !== 'undefined') {
  51. directory = path
  52. .relative(context, resourcePath + '_')
  53. .replace(/\\/g, '/')
  54. .replace(/\.\.(\/)?/g, '_$1');
  55. directory = directory.substr(0, directory.length - 1);
  56. } else {
  57. directory = resourcePath.replace(/\\/g, '/').replace(/\.\.(\/)?/g, '_$1');
  58. }
  59. if (directory.length === 1) {
  60. directory = '';
  61. } else if (directory.length > 1) {
  62. folder = path.basename(directory);
  63. }
  64. }
  65. let url = filename;
  66. if (content) {
  67. // Match hash template
  68. url = url
  69. // `hash` and `contenthash` are same in `loader-utils` context
  70. // let's keep `hash` for backward compatibility
  71. .replace(
  72. /\[(?:([^:\]]+):)?(?:hash|contenthash)(?::([a-z]+\d*))?(?::(\d+))?\]/gi,
  73. (all, hashType, digestType, maxLength) =>
  74. getHashDigest(content, hashType, digestType, parseInt(maxLength, 10))
  75. )
  76. .replace(/\[emoji(?::(\d+))?\]/gi, (all, length) =>
  77. encodeStringToEmoji(content, parseInt(length, 10))
  78. );
  79. }
  80. url = url
  81. .replace(/\[ext\]/gi, () => ext)
  82. .replace(/\[name\]/gi, () => basename)
  83. .replace(/\[path\]/gi, () => directory)
  84. .replace(/\[folder\]/gi, () => folder);
  85. if (regExp && loaderContext.resourcePath) {
  86. const match = loaderContext.resourcePath.match(new RegExp(regExp));
  87. match &&
  88. match.forEach((matched, i) => {
  89. url = url.replace(new RegExp('\\[' + i + '\\]', 'ig'), matched);
  90. });
  91. }
  92. if (
  93. typeof loaderContext.options === 'object' &&
  94. typeof loaderContext.options.customInterpolateName === 'function'
  95. ) {
  96. url = loaderContext.options.customInterpolateName.call(
  97. loaderContext,
  98. url,
  99. name,
  100. options
  101. );
  102. }
  103. return url;
  104. }
  105. module.exports = interpolateName;