286 lines
9.1 KiB
JavaScript
286 lines
9.1 KiB
JavaScript
/*
|
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
|
Author Tobias Koppers @sokra
|
|
*/
|
|
"use strict";
|
|
const NullDependency = require("./NullDependency");
|
|
|
|
class HarmonyExportImportedSpecifierDependency extends NullDependency {
|
|
constructor(originModule, importDependency, importedVar, id, name, activeExports, otherStarExports) {
|
|
super();
|
|
this.originModule = originModule;
|
|
this.importDependency = importDependency;
|
|
this.importedVar = importedVar;
|
|
this.id = id;
|
|
this.name = name;
|
|
this.activeExports = activeExports;
|
|
this.otherStarExports = otherStarExports;
|
|
}
|
|
|
|
get type() {
|
|
return "harmony export imported specifier";
|
|
}
|
|
|
|
getReference() {
|
|
const name = this.name;
|
|
const used = this.originModule.isUsed(name);
|
|
const importedModule = this.importDependency.module;
|
|
|
|
if(!importedModule || !used || !this.originModule.usedExports) return null;
|
|
|
|
const hasUsedExports = Array.isArray(this.originModule.usedExports);
|
|
|
|
if(name) {
|
|
const nameIsNotInUsedExports = hasUsedExports && this.originModule.usedExports.indexOf(name) < 0;
|
|
if(nameIsNotInUsedExports) return null;
|
|
|
|
// export { name as name }
|
|
if(this.id) {
|
|
return {
|
|
module: importedModule,
|
|
importedNames: [this.id]
|
|
};
|
|
}
|
|
|
|
// export { * as name }
|
|
return {
|
|
module: importedModule,
|
|
importedNames: true
|
|
};
|
|
}
|
|
|
|
const hasProvidedExports = Array.isArray(importedModule.providedExports);
|
|
const activeFromOtherStarExports = this._discoverActiveExportsFromOtherStartExports();
|
|
|
|
// export *
|
|
if(hasUsedExports) {
|
|
// reexport * with known used exports
|
|
const importedNames = this.originModule.usedExports.filter(id => {
|
|
if(id === "default") return false;
|
|
if(this.activeExports.has(id)) return false;
|
|
if(activeFromOtherStarExports.has(id)) return false;
|
|
if(hasProvidedExports && importedModule.providedExports.indexOf(id) < 0) return false;
|
|
|
|
return true;
|
|
});
|
|
|
|
return {
|
|
module: importedModule,
|
|
importedNames
|
|
};
|
|
}
|
|
|
|
if(hasProvidedExports) {
|
|
return {
|
|
module: importedModule,
|
|
importedNames: importedModule.providedExports.filter(id => {
|
|
if(id === "default") return false;
|
|
if(this.activeExports.has(id)) return false;
|
|
if(activeFromOtherStarExports.has(id)) return false;
|
|
|
|
return true;
|
|
})
|
|
};
|
|
}
|
|
|
|
return {
|
|
module: importedModule,
|
|
importedNames: true,
|
|
};
|
|
}
|
|
|
|
_discoverActiveExportsFromOtherStartExports() {
|
|
if(!this.otherStarExports)
|
|
return new Set();
|
|
const result = new Set();
|
|
// try to learn impossible exports from other star exports with provided exports
|
|
for(const otherStarExport of this.otherStarExports) {
|
|
const otherImportedModule = otherStarExport.importDependency.module;
|
|
if(otherImportedModule && Array.isArray(otherImportedModule.providedExports)) {
|
|
for(const exportName of otherImportedModule.providedExports)
|
|
result.add(exportName);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
getExports() {
|
|
if(this.name) {
|
|
return {
|
|
exports: [this.name]
|
|
};
|
|
}
|
|
|
|
const importedModule = this.importDependency.module;
|
|
|
|
if(!importedModule) {
|
|
// no imported module available
|
|
return {
|
|
exports: null
|
|
};
|
|
}
|
|
|
|
if(Array.isArray(importedModule.providedExports)) {
|
|
return {
|
|
exports: importedModule.providedExports.filter(id => id !== "default"),
|
|
dependencies: [importedModule]
|
|
};
|
|
}
|
|
|
|
if(importedModule.providedExports) {
|
|
return {
|
|
exports: true
|
|
};
|
|
}
|
|
|
|
return {
|
|
exports: null,
|
|
dependencies: [importedModule]
|
|
};
|
|
}
|
|
|
|
updateHash(hash) {
|
|
super.updateHash(hash);
|
|
const hashValue = this.getHashValue(this.importDependency.module);
|
|
hash.update(hashValue);
|
|
}
|
|
|
|
getHashValue(importedModule) {
|
|
if(!importedModule) {
|
|
return "";
|
|
}
|
|
|
|
const stringifiedUsedExport = JSON.stringify(importedModule.usedExports);
|
|
const stringifiedProvidedExport = JSON.stringify(importedModule.providedExports);
|
|
return importedModule.used + stringifiedUsedExport + stringifiedProvidedExport;
|
|
}
|
|
}
|
|
|
|
module.exports = HarmonyExportImportedSpecifierDependency;
|
|
|
|
HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedSpecifierDependencyTemplate {
|
|
apply(dep, source, outputOptions, requestShortener) {
|
|
const content = this.getContent(dep);
|
|
source.insert(-1, content);
|
|
}
|
|
|
|
getContent(dep) {
|
|
const name = dep.importedVar;
|
|
const used = dep.originModule.isUsed(dep.name);
|
|
const importedModule = dep.importDependency.module;
|
|
const importsExportsUnknown = !importedModule || !Array.isArray(importedModule.providedExports);
|
|
|
|
const getReexportStatement = this.reexportStatementCreator(dep.originModule, importsExportsUnknown, name);
|
|
|
|
// we want to rexport something, but the export isn't used
|
|
if(!used) {
|
|
return "/* unused harmony reexport " + dep.name + " */\n";
|
|
}
|
|
|
|
// we want to reexport the default export from a non-hamory module
|
|
const isNotAHarmonyModule = !(importedModule && (!importedModule.meta || importedModule.meta.harmonyModule));
|
|
if(dep.name && dep.id === "default" && isNotAHarmonyModule) {
|
|
return "/* harmony reexport (default from non-hamory) */ " + getReexportStatement(JSON.stringify(used), null);
|
|
}
|
|
|
|
// we want to reexport a key as new key
|
|
if(dep.name && dep.id) {
|
|
var idUsed = importedModule && importedModule.isUsed(dep.id);
|
|
return "/* harmony reexport (binding) */ " + getReexportStatement(JSON.stringify(used), JSON.stringify(idUsed));
|
|
}
|
|
|
|
// we want to reexport the module object as named export
|
|
if(dep.name) {
|
|
return "/* harmony reexport (module object) */ " + getReexportStatement(JSON.stringify(used), "");
|
|
}
|
|
|
|
const hasProvidedExports = importedModule && Array.isArray(importedModule.providedExports);
|
|
|
|
const activeFromOtherStarExports = dep._discoverActiveExportsFromOtherStartExports();
|
|
|
|
// we know which exports are used
|
|
if(Array.isArray(dep.originModule.usedExports)) {
|
|
const items = dep.originModule.usedExports.map(id => {
|
|
if(id === "default") return;
|
|
if(dep.activeExports.has(id)) return;
|
|
if(importedModule.isProvided(id) === false) return;
|
|
if(activeFromOtherStarExports.has(id)) return;
|
|
var exportUsed = dep.originModule.isUsed(id);
|
|
var idUsed = importedModule && importedModule.isUsed(id);
|
|
return [exportUsed, idUsed];
|
|
}).filter(Boolean);
|
|
|
|
if(items.length === 0) {
|
|
return "/* unused harmony namespace reexport */\n";
|
|
}
|
|
|
|
return items.map(function(item) {
|
|
return "/* harmony namespace reexport (by used) */ " + getReexportStatement(JSON.stringify(item[0]), JSON.stringify(item[1]));
|
|
}).join("");
|
|
}
|
|
|
|
// not sure which exports are used, but we know which are provided
|
|
if(dep.originModule.usedExports && importedModule && hasProvidedExports) {
|
|
const items = importedModule.providedExports.map(id => {
|
|
if(id === "default") return;
|
|
if(dep.activeExports.has(id)) return;
|
|
if(activeFromOtherStarExports.has(id)) return;
|
|
var exportUsed = dep.originModule.isUsed(id);
|
|
var idUsed = importedModule && importedModule.isUsed(id);
|
|
return [exportUsed, idUsed];
|
|
}).filter(Boolean);
|
|
|
|
if(items.length === 0) {
|
|
return "/* empty harmony namespace reexport */\n";
|
|
}
|
|
|
|
return items.map(function(item) {
|
|
return "/* harmony namespace reexport (by provided) */ " + getReexportStatement(JSON.stringify(item[0]), JSON.stringify(item[1]));
|
|
}).join("");
|
|
}
|
|
|
|
// not sure which exports are used and provided
|
|
if(dep.originModule.usedExports) {
|
|
const activeExports = Array.from(dep.activeExports).concat(Array.from(activeFromOtherStarExports));
|
|
let content = "/* harmony namespace reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in " + name + ") ";
|
|
|
|
// Filter out exports which are defined by other exports
|
|
// and filter out default export because it cannot be reexported with *
|
|
if(activeExports.length > 0)
|
|
content += "if(" + JSON.stringify(activeExports.concat("default")) + ".indexOf(__WEBPACK_IMPORT_KEY__) < 0) ";
|
|
else
|
|
content += "if(__WEBPACK_IMPORT_KEY__ !== 'default') ";
|
|
const exportsName = dep.originModule.exportsArgument || "exports";
|
|
return content + `(function(key) { __webpack_require__.d(${exportsName}, key, function() { return ${name}[key]; }) }(__WEBPACK_IMPORT_KEY__));\n`;
|
|
}
|
|
|
|
return "/* unused harmony reexport namespace */\n";
|
|
}
|
|
|
|
reexportStatementCreator(module, importsExportsUnknown, name) {
|
|
const exportsName = module.exportsArgument || "exports";
|
|
const getReexportStatement = (key, valueKey) => {
|
|
const conditional = this.getConditional(importsExportsUnknown, valueKey, name);
|
|
const returnValue = this.getReturnValue(valueKey);
|
|
return `${conditional}__webpack_require__.d(${exportsName}, ${key}, function() { return ${name}${returnValue}; });\n`;
|
|
};
|
|
return getReexportStatement;
|
|
}
|
|
|
|
getConditional(importsExportsUnknown, valueKey, name) {
|
|
if(!importsExportsUnknown || !valueKey) {
|
|
return "";
|
|
}
|
|
|
|
return `if(__webpack_require__.o(${name}, ${valueKey})) `;
|
|
}
|
|
|
|
getReturnValue(valueKey) {
|
|
if(valueKey === null) {
|
|
return "_default.a";
|
|
}
|
|
|
|
return valueKey && "[" + valueKey + "]";
|
|
}
|
|
};
|