| [9af201e] | 1 | /*
|
|---|
| 2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
|---|
| 3 | Author Tobias Koppers @sokra
|
|---|
| 4 | */
|
|---|
| 5 |
|
|---|
| 6 | "use strict";
|
|---|
| 7 |
|
|---|
| 8 | const {
|
|---|
| 9 | DEFAULT_EXPORT,
|
|---|
| 10 | NAMESPACE_OBJECT_EXPORT
|
|---|
| 11 | } = require("./util/concatenate");
|
|---|
| 12 |
|
|---|
| 13 | /** @typedef {import("./Chunk")} Chunk */
|
|---|
| 14 | /** @typedef {import("./Module")} Module */
|
|---|
| 15 | /** @typedef {import("./optimize/ConcatenatedModule").ConcatenatedModuleInfo} ConcatenatedModuleInfo */
|
|---|
| 16 | /** @typedef {import("./optimize/ConcatenatedModule").ModuleInfo} ModuleInfo */
|
|---|
| 17 | /** @typedef {import("./optimize/ConcatenatedModule").ExportName} Ids */
|
|---|
| 18 |
|
|---|
| 19 | const MODULE_REFERENCE_REGEXP =
|
|---|
| 20 | /^__WEBPACK_MODULE_REFERENCE__(\d+)_([\da-f]+|ns)(_call)?(_directImport)?(_deferredImport)?(?:_asiSafe(\d))?__$/;
|
|---|
| 21 |
|
|---|
| 22 | /**
|
|---|
| 23 | * Encodes how a concatenated module reference should be interpreted when it is
|
|---|
| 24 | * later reconstructed from its placeholder identifier.
|
|---|
| 25 | * @typedef {object} ModuleReferenceOptions
|
|---|
| 26 | * @property {Ids} ids the properties or exports selected from the referenced module
|
|---|
| 27 | * @property {boolean} call true, when this referenced export is called
|
|---|
| 28 | * @property {boolean} directImport true, when this referenced export is directly imported (not via property access)
|
|---|
| 29 | * @property {boolean} deferredImport true, when this referenced export is deferred
|
|---|
| 30 | * @property {boolean | undefined} asiSafe if the position is ASI safe or unknown
|
|---|
| 31 | */
|
|---|
| 32 |
|
|---|
| 33 | /**
|
|---|
| 34 | * Tracks the symbols and cross-module references needed while rendering a
|
|---|
| 35 | * concatenated module.
|
|---|
| 36 | */
|
|---|
| 37 | class ConcatenationScope {
|
|---|
| 38 | /**
|
|---|
| 39 | * Creates the mutable scope object used while rendering a concatenated
|
|---|
| 40 | * module and its cross-module references.
|
|---|
| 41 | * @param {ModuleInfo[] | Map<Module, ModuleInfo>} modulesMap all module info by module
|
|---|
| 42 | * @param {ConcatenatedModuleInfo} currentModule the current module info
|
|---|
| 43 | * @param {Set<string>} usedNames all used names
|
|---|
| 44 | */
|
|---|
| 45 | constructor(modulesMap, currentModule, usedNames) {
|
|---|
| 46 | this._currentModule = currentModule;
|
|---|
| 47 | if (Array.isArray(modulesMap)) {
|
|---|
| 48 | /** @type {Map<Module, ConcatenatedModuleInfo>} */
|
|---|
| 49 | const map = new Map();
|
|---|
| 50 | for (const info of modulesMap) {
|
|---|
| 51 | map.set(info.module, /** @type {ConcatenatedModuleInfo} */ (info));
|
|---|
| 52 | }
|
|---|
| 53 | modulesMap = map;
|
|---|
| 54 | }
|
|---|
| 55 | this.usedNames = usedNames;
|
|---|
| 56 | this._modulesMap = modulesMap;
|
|---|
| 57 | }
|
|---|
| 58 |
|
|---|
| 59 | /**
|
|---|
| 60 | * Checks whether a module participates in the current concatenation scope.
|
|---|
| 61 | * @param {Module} module the referenced module
|
|---|
| 62 | * @returns {boolean} true, when it's in the scope
|
|---|
| 63 | */
|
|---|
| 64 | isModuleInScope(module) {
|
|---|
| 65 | return this._modulesMap.has(module);
|
|---|
| 66 | }
|
|---|
| 67 |
|
|---|
| 68 | /**
|
|---|
| 69 | * Records the symbol that should be used when the current module exports a
|
|---|
| 70 | * named binding.
|
|---|
| 71 | * @param {string} exportName name of the export
|
|---|
| 72 | * @param {string} symbol identifier of the export in source code
|
|---|
| 73 | */
|
|---|
| 74 | registerExport(exportName, symbol) {
|
|---|
| 75 | if (!this._currentModule.exportMap) {
|
|---|
| 76 | this._currentModule.exportMap = new Map();
|
|---|
| 77 | }
|
|---|
| 78 | if (!this._currentModule.exportMap.has(exportName)) {
|
|---|
| 79 | this._currentModule.exportMap.set(exportName, symbol);
|
|---|
| 80 | }
|
|---|
| 81 | }
|
|---|
| 82 |
|
|---|
| 83 | /**
|
|---|
| 84 | * Records a raw expression that can be used to reference an export without
|
|---|
| 85 | * going through the normal symbol map.
|
|---|
| 86 | * @param {string} exportName name of the export
|
|---|
| 87 | * @param {string} expression expression to be used
|
|---|
| 88 | */
|
|---|
| 89 | registerRawExport(exportName, expression) {
|
|---|
| 90 | if (!this._currentModule.rawExportMap) {
|
|---|
| 91 | this._currentModule.rawExportMap = new Map();
|
|---|
| 92 | }
|
|---|
| 93 | if (!this._currentModule.rawExportMap.has(exportName)) {
|
|---|
| 94 | this._currentModule.rawExportMap.set(exportName, expression);
|
|---|
| 95 | }
|
|---|
| 96 | }
|
|---|
| 97 |
|
|---|
| 98 | /**
|
|---|
| 99 | * Returns the raw expression registered for an export, if one exists.
|
|---|
| 100 | * @param {string} exportName name of the export
|
|---|
| 101 | * @returns {string | undefined} the expression of the export
|
|---|
| 102 | */
|
|---|
| 103 | getRawExport(exportName) {
|
|---|
| 104 | if (!this._currentModule.rawExportMap) {
|
|---|
| 105 | return undefined;
|
|---|
| 106 | }
|
|---|
| 107 | return this._currentModule.rawExportMap.get(exportName);
|
|---|
| 108 | }
|
|---|
| 109 |
|
|---|
| 110 | /**
|
|---|
| 111 | * Replaces the raw expression for an export only when that export already
|
|---|
| 112 | * has an entry in the raw export map.
|
|---|
| 113 | * @param {string} exportName name of the export
|
|---|
| 114 | * @param {string} expression expression to be used
|
|---|
| 115 | */
|
|---|
| 116 | setRawExportMap(exportName, expression) {
|
|---|
| 117 | if (!this._currentModule.rawExportMap) {
|
|---|
| 118 | this._currentModule.rawExportMap = new Map();
|
|---|
| 119 | }
|
|---|
| 120 | if (this._currentModule.rawExportMap.has(exportName)) {
|
|---|
| 121 | this._currentModule.rawExportMap.set(exportName, expression);
|
|---|
| 122 | }
|
|---|
| 123 | }
|
|---|
| 124 |
|
|---|
| 125 | /**
|
|---|
| 126 | * Records the symbol that should be used for the synthetic namespace export.
|
|---|
| 127 | * @param {string} symbol identifier of the export in source code
|
|---|
| 128 | */
|
|---|
| 129 | registerNamespaceExport(symbol) {
|
|---|
| 130 | this._currentModule.namespaceExportSymbol = symbol;
|
|---|
| 131 | }
|
|---|
| 132 |
|
|---|
| 133 | /**
|
|---|
| 134 | * Encodes a reference to another concatenated module as a placeholder
|
|---|
| 135 | * identifier that can be parsed later during code generation.
|
|---|
| 136 | * @param {Module} module the referenced module
|
|---|
| 137 | * @param {Partial<ModuleReferenceOptions>} options options
|
|---|
| 138 | * @returns {string} the reference as identifier
|
|---|
| 139 | */
|
|---|
| 140 | createModuleReference(
|
|---|
| 141 | module,
|
|---|
| 142 | {
|
|---|
| 143 | ids = undefined,
|
|---|
| 144 | call = false,
|
|---|
| 145 | directImport = false,
|
|---|
| 146 | deferredImport = false,
|
|---|
| 147 | asiSafe = false
|
|---|
| 148 | }
|
|---|
| 149 | ) {
|
|---|
| 150 | const info = /** @type {ModuleInfo} */ (this._modulesMap.get(module));
|
|---|
| 151 | const callFlag = call ? "_call" : "";
|
|---|
| 152 | const directImportFlag = directImport ? "_directImport" : "";
|
|---|
| 153 | const deferredImportFlag = deferredImport ? "_deferredImport" : "";
|
|---|
| 154 | const asiSafeFlag = asiSafe
|
|---|
| 155 | ? "_asiSafe1"
|
|---|
| 156 | : asiSafe === false
|
|---|
| 157 | ? "_asiSafe0"
|
|---|
| 158 | : "";
|
|---|
| 159 | const exportData = ids
|
|---|
| 160 | ? Buffer.from(JSON.stringify(ids), "utf8").toString("hex")
|
|---|
| 161 | : "ns";
|
|---|
| 162 | // a "._" is appended to allow "delete ...", which would cause a SyntaxError in strict mode
|
|---|
| 163 | return `__WEBPACK_MODULE_REFERENCE__${info.index}_${exportData}${callFlag}${directImportFlag}${deferredImportFlag}${asiSafeFlag}__._`;
|
|---|
| 164 | }
|
|---|
| 165 |
|
|---|
| 166 | /**
|
|---|
| 167 | * Checks whether an identifier is one of webpack's encoded concatenation
|
|---|
| 168 | * module references.
|
|---|
| 169 | * @param {string} name the identifier
|
|---|
| 170 | * @returns {boolean} true, when it's an module reference
|
|---|
| 171 | */
|
|---|
| 172 | static isModuleReference(name) {
|
|---|
| 173 | return MODULE_REFERENCE_REGEXP.test(name);
|
|---|
| 174 | }
|
|---|
| 175 |
|
|---|
| 176 | /**
|
|---|
| 177 | * Parses an encoded module reference back into its module index and
|
|---|
| 178 | * reference flags.
|
|---|
| 179 | * @param {string} name the identifier
|
|---|
| 180 | * @returns {ModuleReferenceOptions & { index: number } | null} parsed options and index
|
|---|
| 181 | */
|
|---|
| 182 | static matchModuleReference(name) {
|
|---|
| 183 | const match = MODULE_REFERENCE_REGEXP.exec(name);
|
|---|
| 184 | if (!match) return null;
|
|---|
| 185 | const index = Number(match[1]);
|
|---|
| 186 | const asiSafe = match[6];
|
|---|
| 187 | return {
|
|---|
| 188 | index,
|
|---|
| 189 | ids:
|
|---|
| 190 | match[2] === "ns"
|
|---|
| 191 | ? []
|
|---|
| 192 | : JSON.parse(Buffer.from(match[2], "hex").toString("utf8")),
|
|---|
| 193 | call: Boolean(match[3]),
|
|---|
| 194 | directImport: Boolean(match[4]),
|
|---|
| 195 | deferredImport: Boolean(match[5]),
|
|---|
| 196 | asiSafe: asiSafe ? asiSafe === "1" : undefined
|
|---|
| 197 | };
|
|---|
| 198 | }
|
|---|
| 199 | }
|
|---|
| 200 |
|
|---|
| 201 | ConcatenationScope.DEFAULT_EXPORT = DEFAULT_EXPORT;
|
|---|
| 202 | ConcatenationScope.NAMESPACE_OBJECT_EXPORT = NAMESPACE_OBJECT_EXPORT;
|
|---|
| 203 |
|
|---|
| 204 | module.exports = ConcatenationScope;
|
|---|