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