| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";const { UsageState } = require("../ExportsInfo");const {	numberToIdentifier,	NUMBER_OF_IDENTIFIER_START_CHARS,	NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS} = require("../Template");const { assignDeterministicIds } = require("../ids/IdHelpers");const { compareSelect, compareStringsNumeric } = require("../util/comparators");/** @typedef {import("../Compiler")} Compiler *//** @typedef {import("../ExportsInfo")} ExportsInfo *//** @typedef {import("../ExportsInfo").ExportInfo} ExportInfo *//** * @param {ExportsInfo} exportsInfo exports info * @returns {boolean} mangle is possible */const canMangle = exportsInfo => {	if (exportsInfo.otherExportsInfo.getUsed(undefined) !== UsageState.Unused)		return false;	let hasSomethingToMangle = false;	for (const exportInfo of exportsInfo.exports) {		if (exportInfo.canMangle === true) {			hasSomethingToMangle = true;		}	}	return hasSomethingToMangle;};// Sort by nameconst comparator = compareSelect(e => e.name, compareStringsNumeric);/** * @param {boolean} deterministic use deterministic names * @param {ExportsInfo} exportsInfo exports info * @param {boolean} isNamespace is namespace object * @returns {void} */const mangleExportsInfo = (deterministic, exportsInfo, isNamespace) => {	if (!canMangle(exportsInfo)) return;	const usedNames = new Set();	/** @type {ExportInfo[]} */	const mangleableExports = [];	// Avoid to renamed exports that are not provided when	// 1. it's not a namespace export: non-provided exports can be found in prototype chain	// 2. there are other provided exports and deterministic mode is chosen:	//    non-provided exports would break the determinism	let avoidMangleNonProvided = !isNamespace;	if (!avoidMangleNonProvided && deterministic) {		for (const exportInfo of exportsInfo.ownedExports) {			if (exportInfo.provided !== false) {				avoidMangleNonProvided = true;				break;			}		}	}	for (const exportInfo of exportsInfo.ownedExports) {		const name = exportInfo.name;		if (!exportInfo.hasUsedName()) {			if (				// Can the export be mangled?				exportInfo.canMangle !== true ||				// Never rename 1 char exports				(name.length === 1 && /^[a-zA-Z0-9_$]/.test(name)) ||				// Don't rename 2 char exports in deterministic mode				(deterministic &&					name.length === 2 &&					/^[a-zA-Z_$][a-zA-Z0-9_$]|^[1-9][0-9]/.test(name)) ||				// Don't rename exports that are not provided				(avoidMangleNonProvided && exportInfo.provided !== true)			) {				exportInfo.setUsedName(name);				usedNames.add(name);			} else {				mangleableExports.push(exportInfo);			}		}		if (exportInfo.exportsInfoOwned) {			const used = exportInfo.getUsed(undefined);			if (				used === UsageState.OnlyPropertiesUsed ||				used === UsageState.Unused			) {				mangleExportsInfo(deterministic, exportInfo.exportsInfo, false);			}		}	}	if (deterministic) {		assignDeterministicIds(			mangleableExports,			e => e.name,			comparator,			(e, id) => {				const name = numberToIdentifier(id);				const size = usedNames.size;				usedNames.add(name);				if (size === usedNames.size) return false;				e.setUsedName(name);				return true;			},			[				NUMBER_OF_IDENTIFIER_START_CHARS,				NUMBER_OF_IDENTIFIER_START_CHARS *					NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS			],			NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS,			usedNames.size		);	} else {		const usedExports = [];		const unusedExports = [];		for (const exportInfo of mangleableExports) {			if (exportInfo.getUsed(undefined) === UsageState.Unused) {				unusedExports.push(exportInfo);			} else {				usedExports.push(exportInfo);			}		}		usedExports.sort(comparator);		unusedExports.sort(comparator);		let i = 0;		for (const list of [usedExports, unusedExports]) {			for (const exportInfo of list) {				let name;				do {					name = numberToIdentifier(i++);				} while (usedNames.has(name));				exportInfo.setUsedName(name);			}		}	}};class MangleExportsPlugin {	/**	 * @param {boolean} deterministic use deterministic names	 */	constructor(deterministic) {		this._deterministic = deterministic;	}	/**	 * Apply the plugin	 * @param {Compiler} compiler the compiler instance	 * @returns {void}	 */	apply(compiler) {		const { _deterministic: deterministic } = this;		compiler.hooks.compilation.tap("MangleExportsPlugin", compilation => {			const moduleGraph = compilation.moduleGraph;			compilation.hooks.optimizeCodeGeneration.tap(				"MangleExportsPlugin",				modules => {					if (compilation.moduleMemCaches) {						throw new Error(							"optimization.mangleExports can't be used with cacheUnaffected as export mangling is a global effect"						);					}					for (const module of modules) {						const isNamespace =							module.buildMeta && module.buildMeta.exportsType === "namespace";						const exportsInfo = moduleGraph.getExportsInfo(module);						mangleExportsInfo(deterministic, exportsInfo, isNamespace);					}				}			);		});	}}module.exports = MangleExportsPlugin;
 |