ConcatenationScope.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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)?(_deferredImport)?(?:_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} deferredImport true, when this referenced export is deferred
  21. * @property {boolean | undefined} asiSafe if the position is ASI safe or unknown
  22. */
  23. class ConcatenationScope {
  24. /**
  25. * @param {ModuleInfo[] | Map<Module, ModuleInfo>} modulesMap all module info by module
  26. * @param {ConcatenatedModuleInfo} currentModule the current module info
  27. */
  28. constructor(modulesMap, currentModule) {
  29. this._currentModule = currentModule;
  30. if (Array.isArray(modulesMap)) {
  31. const map = new Map();
  32. for (const info of modulesMap) {
  33. map.set(info.module, info);
  34. }
  35. modulesMap = map;
  36. }
  37. this._modulesMap = modulesMap;
  38. }
  39. /**
  40. * @param {Module} module the referenced module
  41. * @returns {boolean} true, when it's in the scope
  42. */
  43. isModuleInScope(module) {
  44. return this._modulesMap.has(module);
  45. }
  46. /**
  47. * @param {string} exportName name of the export
  48. * @param {string} symbol identifier of the export in source code
  49. */
  50. registerExport(exportName, symbol) {
  51. if (!this._currentModule.exportMap) {
  52. this._currentModule.exportMap = new Map();
  53. }
  54. if (!this._currentModule.exportMap.has(exportName)) {
  55. this._currentModule.exportMap.set(exportName, symbol);
  56. }
  57. }
  58. /**
  59. * @param {string} exportName name of the export
  60. * @param {string} expression expression to be used
  61. */
  62. registerRawExport(exportName, expression) {
  63. if (!this._currentModule.rawExportMap) {
  64. this._currentModule.rawExportMap = new Map();
  65. }
  66. if (!this._currentModule.rawExportMap.has(exportName)) {
  67. this._currentModule.rawExportMap.set(exportName, expression);
  68. }
  69. }
  70. /**
  71. * @param {string} symbol identifier of the export in source code
  72. */
  73. registerNamespaceExport(symbol) {
  74. this._currentModule.namespaceExportSymbol = symbol;
  75. }
  76. /**
  77. * @param {Module} module the referenced module
  78. * @param {Partial<ModuleReferenceOptions>} options options
  79. * @returns {string} the reference as identifier
  80. */
  81. createModuleReference(
  82. module,
  83. {
  84. ids = undefined,
  85. call = false,
  86. directImport = false,
  87. deferredImport = false,
  88. asiSafe = false
  89. }
  90. ) {
  91. const info = /** @type {ModuleInfo} */ (this._modulesMap.get(module));
  92. const callFlag = call ? "_call" : "";
  93. const directImportFlag = directImport ? "_directImport" : "";
  94. const deferredImportFlag = deferredImport ? "_deferredImport" : "";
  95. const asiSafeFlag = asiSafe
  96. ? "_asiSafe1"
  97. : asiSafe === false
  98. ? "_asiSafe0"
  99. : "";
  100. const exportData = ids
  101. ? Buffer.from(JSON.stringify(ids), "utf8").toString("hex")
  102. : "ns";
  103. // a "._" is appended to allow "delete ...", which would cause a SyntaxError in strict mode
  104. return `__WEBPACK_MODULE_REFERENCE__${info.index}_${exportData}${callFlag}${directImportFlag}${deferredImportFlag}${asiSafeFlag}__._`;
  105. }
  106. /**
  107. * @param {string} name the identifier
  108. * @returns {boolean} true, when it's an module reference
  109. */
  110. static isModuleReference(name) {
  111. return MODULE_REFERENCE_REGEXP.test(name);
  112. }
  113. /**
  114. * @param {string} name the identifier
  115. * @returns {ModuleReferenceOptions & { index: number } | null} parsed options and index
  116. */
  117. static matchModuleReference(name) {
  118. const match = MODULE_REFERENCE_REGEXP.exec(name);
  119. if (!match) return null;
  120. const index = Number(match[1]);
  121. const asiSafe = match[6];
  122. return {
  123. index,
  124. ids:
  125. match[2] === "ns"
  126. ? []
  127. : JSON.parse(Buffer.from(match[2], "hex").toString("utf8")),
  128. call: Boolean(match[3]),
  129. directImport: Boolean(match[4]),
  130. deferredImport: Boolean(match[5]),
  131. asiSafe: asiSafe ? asiSafe === "1" : undefined
  132. };
  133. }
  134. }
  135. ConcatenationScope.DEFAULT_EXPORT = DEFAULT_EXPORT;
  136. ConcatenationScope.NAMESPACE_OBJECT_EXPORT = NAMESPACE_OBJECT_EXPORT;
  137. module.exports = ConcatenationScope;