UNPKG

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