10
0

ConcatenationScope.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const {
  7. DEFAULT_EXPORT,
  8. NAMESPACE_OBJECT_EXPORT
  9. } = require("./util/concatenate");
  10. /** @typedef {import("./Module")} Module */
  11. /** @typedef {import("./optimize/ConcatenatedModule").ConcatenatedModuleInfo} ConcatenatedModuleInfo */
  12. /** @typedef {import("./optimize/ConcatenatedModule").ModuleInfo} ModuleInfo */
  13. const MODULE_REFERENCE_REGEXP =
  14. /^__WEBPACK_MODULE_REFERENCE__(\d+)_([\da-f]+|ns)(_call)?(_directImport)?(?:_asiSafe(\d))?__$/;
  15. /**
  16. * @typedef {object} ModuleReferenceOptions
  17. * @property {string[]} ids the properties/exports of the module
  18. * @property {boolean} call true, when this referenced export is called
  19. * @property {boolean} directImport true, when this referenced export is directly imported (not via property access)
  20. * @property {boolean | undefined} asiSafe if the position is ASI safe or unknown
  21. */
  22. class ConcatenationScope {
  23. /**
  24. * @param {ModuleInfo[] | Map<Module, ModuleInfo>} modulesMap all module info by module
  25. * @param {ConcatenatedModuleInfo} currentModule the current module info
  26. */
  27. constructor(modulesMap, currentModule) {
  28. this._currentModule = currentModule;
  29. if (Array.isArray(modulesMap)) {
  30. const map = new Map();
  31. for (const info of modulesMap) {
  32. map.set(info.module, info);
  33. }
  34. modulesMap = map;
  35. }
  36. this._modulesMap = modulesMap;
  37. }
  38. /**
  39. * @param {Module} module the referenced module
  40. * @returns {boolean} true, when it's in the scope
  41. */
  42. isModuleInScope(module) {
  43. return this._modulesMap.has(module);
  44. }
  45. /**
  46. * @param {string} exportName name of the export
  47. * @param {string} symbol identifier of the export in source code
  48. */
  49. registerExport(exportName, symbol) {
  50. if (!this._currentModule.exportMap) {
  51. this._currentModule.exportMap = new Map();
  52. }
  53. if (!this._currentModule.exportMap.has(exportName)) {
  54. this._currentModule.exportMap.set(exportName, symbol);
  55. }
  56. }
  57. /**
  58. * @param {string} exportName name of the export
  59. * @param {string} expression expression to be used
  60. */
  61. registerRawExport(exportName, expression) {
  62. if (!this._currentModule.rawExportMap) {
  63. this._currentModule.rawExportMap = new Map();
  64. }
  65. if (!this._currentModule.rawExportMap.has(exportName)) {
  66. this._currentModule.rawExportMap.set(exportName, expression);
  67. }
  68. }
  69. /**
  70. * @param {string} symbol identifier of the export in source code
  71. */
  72. registerNamespaceExport(symbol) {
  73. this._currentModule.namespaceExportSymbol = symbol;
  74. }
  75. /**
  76. * @param {Module} module the referenced module
  77. * @param {Partial<ModuleReferenceOptions>} options options
  78. * @returns {string} the reference as identifier
  79. */
  80. createModuleReference(
  81. module,
  82. { ids = undefined, call = false, directImport = false, asiSafe = false }
  83. ) {
  84. const info = /** @type {ModuleInfo} */ (this._modulesMap.get(module));
  85. const callFlag = call ? "_call" : "";
  86. const directImportFlag = directImport ? "_directImport" : "";
  87. const asiSafeFlag = asiSafe
  88. ? "_asiSafe1"
  89. : asiSafe === false
  90. ? "_asiSafe0"
  91. : "";
  92. const exportData = ids
  93. ? Buffer.from(JSON.stringify(ids), "utf-8").toString("hex")
  94. : "ns";
  95. // a "._" is appended to allow "delete ...", which would cause a SyntaxError in strict mode
  96. return `__WEBPACK_MODULE_REFERENCE__${info.index}_${exportData}${callFlag}${directImportFlag}${asiSafeFlag}__._`;
  97. }
  98. /**
  99. * @param {string} name the identifier
  100. * @returns {boolean} true, when it's an module reference
  101. */
  102. static isModuleReference(name) {
  103. return MODULE_REFERENCE_REGEXP.test(name);
  104. }
  105. /**
  106. * @param {string} name the identifier
  107. * @returns {ModuleReferenceOptions & { index: number } | null} parsed options and index
  108. */
  109. static matchModuleReference(name) {
  110. const match = MODULE_REFERENCE_REGEXP.exec(name);
  111. if (!match) return null;
  112. const index = Number(match[1]);
  113. const asiSafe = match[5];
  114. return {
  115. index,
  116. ids:
  117. match[2] === "ns"
  118. ? []
  119. : JSON.parse(Buffer.from(match[2], "hex").toString("utf-8")),
  120. call: Boolean(match[3]),
  121. directImport: Boolean(match[4]),
  122. asiSafe: asiSafe ? asiSafe === "1" : undefined
  123. };
  124. }
  125. }
  126. ConcatenationScope.DEFAULT_EXPORT = DEFAULT_EXPORT;
  127. ConcatenationScope.NAMESPACE_OBJECT_EXPORT = NAMESPACE_OBJECT_EXPORT;
  128. module.exports = ConcatenationScope;