You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
168 lines
4.4 KiB
168 lines
4.4 KiB
/* |
|
MIT License http://www.opensource.org/licenses/mit-license.php |
|
Author Tobias Koppers @sokra |
|
*/ |
|
|
|
"use strict"; |
|
|
|
const InitFragment = require("../InitFragment"); |
|
const RuntimeGlobals = require("../RuntimeGlobals"); |
|
const { first } = require("../util/SetHelpers"); |
|
|
|
/** @typedef {import("webpack-sources").Source} Source */ |
|
/** @typedef {import("../Generator").GenerateContext} GenerateContext */ |
|
|
|
const joinIterableWithComma = iterable => { |
|
// This is more performant than Array.from().join(", ") |
|
// as it doesn't create an array |
|
let str = ""; |
|
let first = true; |
|
for (const item of iterable) { |
|
if (first) { |
|
first = false; |
|
} else { |
|
str += ", "; |
|
} |
|
str += item; |
|
} |
|
return str; |
|
}; |
|
|
|
const EMPTY_MAP = new Map(); |
|
const EMPTY_SET = new Set(); |
|
|
|
/** |
|
* @typedef {GenerateContext} Context |
|
*/ |
|
class HarmonyExportInitFragment extends InitFragment { |
|
/** |
|
* @param {string} exportsArgument the exports identifier |
|
* @param {Map<string, string>} exportMap mapping from used name to exposed variable name |
|
* @param {Set<string>} unusedExports list of unused export names |
|
*/ |
|
constructor( |
|
exportsArgument, |
|
exportMap = EMPTY_MAP, |
|
unusedExports = EMPTY_SET |
|
) { |
|
super(undefined, InitFragment.STAGE_HARMONY_EXPORTS, 1, "harmony-exports"); |
|
this.exportsArgument = exportsArgument; |
|
this.exportMap = exportMap; |
|
this.unusedExports = unusedExports; |
|
} |
|
|
|
/** |
|
* @param {HarmonyExportInitFragment[]} fragments all fragments to merge |
|
* @returns {HarmonyExportInitFragment} merged fragment |
|
*/ |
|
mergeAll(fragments) { |
|
let exportMap; |
|
let exportMapOwned = false; |
|
let unusedExports; |
|
let unusedExportsOwned = false; |
|
|
|
for (const fragment of fragments) { |
|
if (fragment.exportMap.size !== 0) { |
|
if (exportMap === undefined) { |
|
exportMap = fragment.exportMap; |
|
exportMapOwned = false; |
|
} else { |
|
if (!exportMapOwned) { |
|
exportMap = new Map(exportMap); |
|
exportMapOwned = true; |
|
} |
|
for (const [key, value] of fragment.exportMap) { |
|
if (!exportMap.has(key)) exportMap.set(key, value); |
|
} |
|
} |
|
} |
|
if (fragment.unusedExports.size !== 0) { |
|
if (unusedExports === undefined) { |
|
unusedExports = fragment.unusedExports; |
|
unusedExportsOwned = false; |
|
} else { |
|
if (!unusedExportsOwned) { |
|
unusedExports = new Set(unusedExports); |
|
unusedExportsOwned = true; |
|
} |
|
for (const value of fragment.unusedExports) { |
|
unusedExports.add(value); |
|
} |
|
} |
|
} |
|
} |
|
return new HarmonyExportInitFragment( |
|
this.exportsArgument, |
|
exportMap, |
|
unusedExports |
|
); |
|
} |
|
|
|
merge(other) { |
|
let exportMap; |
|
if (this.exportMap.size === 0) { |
|
exportMap = other.exportMap; |
|
} else if (other.exportMap.size === 0) { |
|
exportMap = this.exportMap; |
|
} else { |
|
exportMap = new Map(other.exportMap); |
|
for (const [key, value] of this.exportMap) { |
|
if (!exportMap.has(key)) exportMap.set(key, value); |
|
} |
|
} |
|
let unusedExports; |
|
if (this.unusedExports.size === 0) { |
|
unusedExports = other.unusedExports; |
|
} else if (other.unusedExports.size === 0) { |
|
unusedExports = this.unusedExports; |
|
} else { |
|
unusedExports = new Set(other.unusedExports); |
|
for (const value of this.unusedExports) { |
|
unusedExports.add(value); |
|
} |
|
} |
|
return new HarmonyExportInitFragment( |
|
this.exportsArgument, |
|
exportMap, |
|
unusedExports |
|
); |
|
} |
|
|
|
/** |
|
* @param {Context} context context |
|
* @returns {string|Source} the source code that will be included as initialization code |
|
*/ |
|
getContent({ runtimeTemplate, runtimeRequirements }) { |
|
runtimeRequirements.add(RuntimeGlobals.exports); |
|
runtimeRequirements.add(RuntimeGlobals.definePropertyGetters); |
|
|
|
const unusedPart = |
|
this.unusedExports.size > 1 |
|
? `/* unused harmony exports ${joinIterableWithComma( |
|
this.unusedExports |
|
)} */\n` |
|
: this.unusedExports.size > 0 |
|
? `/* unused harmony export ${first(this.unusedExports)} */\n` |
|
: ""; |
|
const definitions = []; |
|
const orderedExportMap = Array.from(this.exportMap).sort(([a], [b]) => |
|
a < b ? -1 : 1 |
|
); |
|
for (const [key, value] of orderedExportMap) { |
|
definitions.push( |
|
`\n/* harmony export */ ${JSON.stringify( |
|
key |
|
)}: ${runtimeTemplate.returningFunction(value)}` |
|
); |
|
} |
|
const definePart = |
|
this.exportMap.size > 0 |
|
? `/* harmony export */ ${RuntimeGlobals.definePropertyGetters}(${ |
|
this.exportsArgument |
|
}, {${definitions.join(",")}\n/* harmony export */ });\n` |
|
: ""; |
|
return `${definePart}${unusedPart}`; |
|
} |
|
} |
|
|
|
module.exports = HarmonyExportInitFragment;
|
|
|