Template.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const Tapable = require("tapable");
  7. const ConcatSource = require("webpack-sources").ConcatSource;
  8. const START_LOWERCASE_ALPHABET_CODE = "a".charCodeAt(0);
  9. const START_UPPERCASE_ALPHABET_CODE = "A".charCodeAt(0);
  10. const DELTA_A_TO_Z = "z".charCodeAt(0) - START_LOWERCASE_ALPHABET_CODE + 1;
  11. module.exports = class Template extends Tapable {
  12. constructor(outputOptions) {
  13. super();
  14. this.outputOptions = outputOptions || {};
  15. }
  16. static getFunctionContent(fn) {
  17. return fn.toString().replace(/^function\s?\(\)\s?\{\n?|\n?\}$/g, "").replace(/^\t/mg, "");
  18. }
  19. static toIdentifier(str) {
  20. if(typeof str !== "string") return "";
  21. return str.replace(/^[^a-zA-Z$_]/, "_").replace(/[^a-zA-Z0-9$_]/g, "_");
  22. }
  23. static toPath(str) {
  24. if(typeof str !== "string") return "";
  25. return str.replace(/[^a-zA-Z0-9_!§$()=\-\^°]+/g, "-").replace(/^-|-$/, "");
  26. }
  27. // map number to a single character a-z, A-Z or <_ + number> if number is too big
  28. static numberToIdentifer(n) {
  29. // lower case
  30. if(n < DELTA_A_TO_Z) return String.fromCharCode(START_LOWERCASE_ALPHABET_CODE + n);
  31. // upper case
  32. n -= DELTA_A_TO_Z;
  33. if(n < DELTA_A_TO_Z) return String.fromCharCode(START_UPPERCASE_ALPHABET_CODE + n);
  34. // fall back to _ + number
  35. n -= DELTA_A_TO_Z;
  36. return "_" + n;
  37. }
  38. indent(str) {
  39. if(Array.isArray(str)) {
  40. return str.map(this.indent.bind(this)).join("\n");
  41. } else {
  42. str = str.trimRight();
  43. if(!str) return "";
  44. var ind = (str[0] === "\n" ? "" : "\t");
  45. return ind + str.replace(/\n([^\n])/g, "\n\t$1");
  46. }
  47. }
  48. prefix(str, prefix) {
  49. if(Array.isArray(str)) {
  50. str = str.join("\n");
  51. }
  52. str = str.trim();
  53. if(!str) return "";
  54. const ind = (str[0] === "\n" ? "" : prefix);
  55. return ind + str.replace(/\n([^\n])/g, "\n" + prefix + "$1");
  56. }
  57. asString(str) {
  58. if(Array.isArray(str)) {
  59. return str.join("\n");
  60. }
  61. return str;
  62. }
  63. getModulesArrayBounds(modules) {
  64. if(!modules.every(moduleIdIsNumber))
  65. return false;
  66. var maxId = -Infinity;
  67. var minId = Infinity;
  68. modules.forEach(function(module) {
  69. if(maxId < module.id) maxId = module.id;
  70. if(minId > module.id) minId = module.id;
  71. });
  72. if(minId < 16 + ("" + minId).length) {
  73. // add minId x ',' instead of 'Array(minId).concat(...)'
  74. minId = 0;
  75. }
  76. var objectOverhead = modules.map(function(module) {
  77. var idLength = (module.id + "").length;
  78. return idLength + 2;
  79. }).reduce(function(a, b) {
  80. return a + b;
  81. }, -1);
  82. var arrayOverhead = minId === 0 ? maxId : 16 + ("" + minId).length + maxId;
  83. return arrayOverhead < objectOverhead ? [minId, maxId] : false;
  84. }
  85. renderChunkModules(chunk, moduleTemplate, dependencyTemplates, prefix) {
  86. if(!prefix) prefix = "";
  87. var source = new ConcatSource();
  88. if(chunk.modules.length === 0) {
  89. source.add("[]");
  90. return source;
  91. }
  92. var removedModules = chunk.removedModules;
  93. var allModules = chunk.modules.map(function(module) {
  94. return {
  95. id: module.id,
  96. source: moduleTemplate.render(module, dependencyTemplates, chunk)
  97. };
  98. });
  99. if(removedModules && removedModules.length > 0) {
  100. removedModules.forEach(function(id) {
  101. allModules.push({
  102. id: id,
  103. source: "false"
  104. });
  105. });
  106. }
  107. var bounds = this.getModulesArrayBounds(chunk.modules);
  108. if(bounds) {
  109. // Render a spare array
  110. var minId = bounds[0];
  111. var maxId = bounds[1];
  112. if(minId !== 0) source.add("Array(" + minId + ").concat(");
  113. source.add("[\n");
  114. var modules = {};
  115. allModules.forEach(function(module) {
  116. modules[module.id] = module;
  117. });
  118. for(var idx = minId; idx <= maxId; idx++) {
  119. var module = modules[idx];
  120. if(idx !== minId) source.add(",\n");
  121. source.add("/* " + idx + " */");
  122. if(module) {
  123. source.add("\n");
  124. source.add(module.source);
  125. }
  126. }
  127. source.add("\n" + prefix + "]");
  128. if(minId !== 0) source.add(")");
  129. } else {
  130. // Render an object
  131. source.add("{\n");
  132. allModules.sort(function(a, b) {
  133. var aId = a.id + "";
  134. var bId = b.id + "";
  135. if(aId < bId) return -1;
  136. if(aId > bId) return 1;
  137. return 0;
  138. }).forEach(function(module, idx) {
  139. if(idx !== 0) source.add(",\n");
  140. source.add("\n/***/ " + JSON.stringify(module.id) + ":\n");
  141. source.add(module.source);
  142. });
  143. source.add("\n\n" + prefix + "}");
  144. }
  145. return source;
  146. }
  147. };
  148. function moduleIdIsNumber(module) {
  149. return typeof module.id === "number";
  150. }