ConcatenationScope.js 4.6 KB

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