406 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			406 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/*
 | 
						|
	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
						|
	Author Tobias Koppers @sokra
 | 
						|
*/
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
const Dependency = require("../Dependency");
 | 
						|
const { UsageState } = require("../ExportsInfo");
 | 
						|
const Template = require("../Template");
 | 
						|
const { equals } = require("../util/ArrayHelpers");
 | 
						|
const makeSerializable = require("../util/makeSerializable");
 | 
						|
const propertyAccess = require("../util/propertyAccess");
 | 
						|
const { handleDependencyBase } = require("./CommonJsDependencyHelpers");
 | 
						|
const ModuleDependency = require("./ModuleDependency");
 | 
						|
const processExportInfo = require("./processExportInfo");
 | 
						|
 | 
						|
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
 | 
						|
/** @typedef {import("../Dependency").ExportsSpec} ExportsSpec */
 | 
						|
/** @typedef {import("../Dependency").ReferencedExport} ReferencedExport */
 | 
						|
/** @typedef {import("../Dependency").TRANSITIVE} TRANSITIVE */
 | 
						|
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
 | 
						|
/** @typedef {import("../ExportsInfo")} ExportsInfo */
 | 
						|
/** @typedef {import("../ExportsInfo").ExportInfo} ExportInfo */
 | 
						|
/** @typedef {import("../Module")} Module */
 | 
						|
/** @typedef {import("../ModuleGraph")} ModuleGraph */
 | 
						|
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
 | 
						|
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
 | 
						|
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
 | 
						|
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
 | 
						|
/** @typedef {import("./CommonJsDependencyHelpers").CommonJSDependencyBaseKeywords} CommonJSDependencyBaseKeywords */
 | 
						|
 | 
						|
const idsSymbol = Symbol("CommonJsExportRequireDependency.ids");
 | 
						|
 | 
						|
const EMPTY_OBJECT = {};
 | 
						|
 | 
						|
class CommonJsExportRequireDependency extends ModuleDependency {
 | 
						|
	/**
 | 
						|
	 * @param {Range} range range
 | 
						|
	 * @param {Range | null} valueRange value range
 | 
						|
	 * @param {CommonJSDependencyBaseKeywords} base base
 | 
						|
	 * @param {string[]} names names
 | 
						|
	 * @param {string} request request
 | 
						|
	 * @param {string[]} ids ids
 | 
						|
	 * @param {boolean} resultUsed true, when the result is used
 | 
						|
	 */
 | 
						|
	constructor(range, valueRange, base, names, request, ids, resultUsed) {
 | 
						|
		super(request);
 | 
						|
		this.range = range;
 | 
						|
		this.valueRange = valueRange;
 | 
						|
		this.base = base;
 | 
						|
		this.names = names;
 | 
						|
		this.ids = ids;
 | 
						|
		this.resultUsed = resultUsed;
 | 
						|
		this.asiSafe = undefined;
 | 
						|
	}
 | 
						|
 | 
						|
	get type() {
 | 
						|
		return "cjs export require";
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @returns {boolean | TRANSITIVE} true, when changes to the referenced module could affect the referencing module; TRANSITIVE, when changes to the referenced module could affect referencing modules of the referencing module
 | 
						|
	 */
 | 
						|
	couldAffectReferencingModule() {
 | 
						|
		return Dependency.TRANSITIVE;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @param {ModuleGraph} moduleGraph the module graph
 | 
						|
	 * @returns {string[]} the imported id
 | 
						|
	 */
 | 
						|
	getIds(moduleGraph) {
 | 
						|
		return moduleGraph.getMeta(this)[idsSymbol] || this.ids;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @param {ModuleGraph} moduleGraph the module graph
 | 
						|
	 * @param {string[]} ids the imported ids
 | 
						|
	 * @returns {void}
 | 
						|
	 */
 | 
						|
	setIds(moduleGraph, ids) {
 | 
						|
		moduleGraph.getMeta(this)[idsSymbol] = ids;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Returns list of exports referenced by this dependency
 | 
						|
	 * @param {ModuleGraph} moduleGraph module graph
 | 
						|
	 * @param {RuntimeSpec} runtime the runtime for which the module is analysed
 | 
						|
	 * @returns {(string[] | ReferencedExport)[]} referenced exports
 | 
						|
	 */
 | 
						|
	getReferencedExports(moduleGraph, runtime) {
 | 
						|
		const ids = this.getIds(moduleGraph);
 | 
						|
		const getFullResult = () => {
 | 
						|
			if (ids.length === 0) {
 | 
						|
				return Dependency.EXPORTS_OBJECT_REFERENCED;
 | 
						|
			}
 | 
						|
			return [
 | 
						|
				{
 | 
						|
					name: ids,
 | 
						|
					canMangle: false
 | 
						|
				}
 | 
						|
			];
 | 
						|
		};
 | 
						|
		if (this.resultUsed) return getFullResult();
 | 
						|
		/** @type {ExportsInfo | undefined} */
 | 
						|
		let exportsInfo = moduleGraph.getExportsInfo(
 | 
						|
			/** @type {Module} */ (moduleGraph.getParentModule(this))
 | 
						|
		);
 | 
						|
		for (const name of this.names) {
 | 
						|
			const exportInfo = /** @type {ExportInfo} */ (
 | 
						|
				exportsInfo.getReadOnlyExportInfo(name)
 | 
						|
			);
 | 
						|
			const used = exportInfo.getUsed(runtime);
 | 
						|
			if (used === UsageState.Unused) return Dependency.NO_EXPORTS_REFERENCED;
 | 
						|
			if (used !== UsageState.OnlyPropertiesUsed) return getFullResult();
 | 
						|
			exportsInfo = exportInfo.exportsInfo;
 | 
						|
			if (!exportsInfo) return getFullResult();
 | 
						|
		}
 | 
						|
		if (exportsInfo.otherExportsInfo.getUsed(runtime) !== UsageState.Unused) {
 | 
						|
			return getFullResult();
 | 
						|
		}
 | 
						|
		/** @type {string[][]} */
 | 
						|
		const referencedExports = [];
 | 
						|
		for (const exportInfo of exportsInfo.orderedExports) {
 | 
						|
			processExportInfo(
 | 
						|
				runtime,
 | 
						|
				referencedExports,
 | 
						|
				[...ids, exportInfo.name],
 | 
						|
				exportInfo,
 | 
						|
				false
 | 
						|
			);
 | 
						|
		}
 | 
						|
		return referencedExports.map((name) => ({
 | 
						|
			name,
 | 
						|
			canMangle: false
 | 
						|
		}));
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Returns the exported names
 | 
						|
	 * @param {ModuleGraph} moduleGraph module graph
 | 
						|
	 * @returns {ExportsSpec | undefined} export names
 | 
						|
	 */
 | 
						|
	getExports(moduleGraph) {
 | 
						|
		if (this.names.length === 1) {
 | 
						|
			const ids = this.getIds(moduleGraph);
 | 
						|
			const name = this.names[0];
 | 
						|
			const from = moduleGraph.getConnection(this);
 | 
						|
			if (!from) return;
 | 
						|
			return {
 | 
						|
				exports: [
 | 
						|
					{
 | 
						|
						name,
 | 
						|
						from,
 | 
						|
						export: ids.length === 0 ? null : ids,
 | 
						|
						// we can't mangle names that are in an empty object
 | 
						|
						// because one could access the prototype property
 | 
						|
						// when export isn't set yet
 | 
						|
						canMangle: !(name in EMPTY_OBJECT) && false
 | 
						|
					}
 | 
						|
				],
 | 
						|
				dependencies: [from.module]
 | 
						|
			};
 | 
						|
		} else if (this.names.length > 0) {
 | 
						|
			const name = this.names[0];
 | 
						|
			return {
 | 
						|
				exports: [
 | 
						|
					{
 | 
						|
						name,
 | 
						|
						// we can't mangle names that are in an empty object
 | 
						|
						// because one could access the prototype property
 | 
						|
						// when export isn't set yet
 | 
						|
						canMangle: !(name in EMPTY_OBJECT) && false
 | 
						|
					}
 | 
						|
				],
 | 
						|
				dependencies: undefined
 | 
						|
			};
 | 
						|
		}
 | 
						|
		const from = moduleGraph.getConnection(this);
 | 
						|
		if (!from) return;
 | 
						|
		const reexportInfo = this.getStarReexports(
 | 
						|
			moduleGraph,
 | 
						|
			undefined,
 | 
						|
			from.module
 | 
						|
		);
 | 
						|
		const ids = this.getIds(moduleGraph);
 | 
						|
		if (reexportInfo) {
 | 
						|
			return {
 | 
						|
				exports: Array.from(
 | 
						|
					/** @type {Set<string>} */
 | 
						|
					(reexportInfo.exports),
 | 
						|
					(name) => ({
 | 
						|
						name,
 | 
						|
						from,
 | 
						|
						export: [...ids, name],
 | 
						|
						canMangle: !(name in EMPTY_OBJECT) && false
 | 
						|
					})
 | 
						|
				),
 | 
						|
				// TODO handle deep reexports
 | 
						|
				dependencies: [from.module]
 | 
						|
			};
 | 
						|
		}
 | 
						|
		return {
 | 
						|
			exports: true,
 | 
						|
			from: ids.length === 0 ? from : undefined,
 | 
						|
			canMangle: false,
 | 
						|
			dependencies: [from.module]
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @param {ModuleGraph} moduleGraph the module graph
 | 
						|
	 * @param {RuntimeSpec} runtime the runtime
 | 
						|
	 * @param {Module} importedModule the imported module (optional)
 | 
						|
	 * @returns {{exports?: Set<string>, checked?: Set<string>} | undefined} information
 | 
						|
	 */
 | 
						|
	getStarReexports(
 | 
						|
		moduleGraph,
 | 
						|
		runtime,
 | 
						|
		importedModule = /** @type {Module} */ (moduleGraph.getModule(this))
 | 
						|
	) {
 | 
						|
		/** @type {ExportsInfo | undefined} */
 | 
						|
		let importedExportsInfo = moduleGraph.getExportsInfo(importedModule);
 | 
						|
		const ids = this.getIds(moduleGraph);
 | 
						|
		if (ids.length > 0) {
 | 
						|
			importedExportsInfo = importedExportsInfo.getNestedExportsInfo(ids);
 | 
						|
		}
 | 
						|
		/** @type {ExportsInfo | undefined} */
 | 
						|
		let exportsInfo = moduleGraph.getExportsInfo(
 | 
						|
			/** @type {Module} */ (moduleGraph.getParentModule(this))
 | 
						|
		);
 | 
						|
		if (this.names.length > 0) {
 | 
						|
			exportsInfo = exportsInfo.getNestedExportsInfo(this.names);
 | 
						|
		}
 | 
						|
 | 
						|
		const noExtraExports =
 | 
						|
			importedExportsInfo &&
 | 
						|
			importedExportsInfo.otherExportsInfo.provided === false;
 | 
						|
		const noExtraImports =
 | 
						|
			exportsInfo &&
 | 
						|
			exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused;
 | 
						|
 | 
						|
		if (!noExtraExports && !noExtraImports) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		const isNamespaceImport =
 | 
						|
			importedModule.getExportsType(moduleGraph, false) === "namespace";
 | 
						|
 | 
						|
		/** @type {Set<string>} */
 | 
						|
		const exports = new Set();
 | 
						|
		/** @type {Set<string>} */
 | 
						|
		const checked = new Set();
 | 
						|
 | 
						|
		if (noExtraImports) {
 | 
						|
			for (const exportInfo of /** @type {ExportsInfo} */ (exportsInfo)
 | 
						|
				.orderedExports) {
 | 
						|
				const name = exportInfo.name;
 | 
						|
				if (exportInfo.getUsed(runtime) === UsageState.Unused) continue;
 | 
						|
				if (name === "__esModule" && isNamespaceImport) {
 | 
						|
					exports.add(name);
 | 
						|
				} else if (importedExportsInfo) {
 | 
						|
					const importedExportInfo =
 | 
						|
						importedExportsInfo.getReadOnlyExportInfo(name);
 | 
						|
					if (importedExportInfo.provided === false) continue;
 | 
						|
					exports.add(name);
 | 
						|
					if (importedExportInfo.provided === true) continue;
 | 
						|
					checked.add(name);
 | 
						|
				} else {
 | 
						|
					exports.add(name);
 | 
						|
					checked.add(name);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		} else if (noExtraExports) {
 | 
						|
			for (const importedExportInfo of /** @type {ExportsInfo} */ (
 | 
						|
				importedExportsInfo
 | 
						|
			).orderedExports) {
 | 
						|
				const name = importedExportInfo.name;
 | 
						|
				if (importedExportInfo.provided === false) continue;
 | 
						|
				if (exportsInfo) {
 | 
						|
					const exportInfo = exportsInfo.getReadOnlyExportInfo(name);
 | 
						|
					if (exportInfo.getUsed(runtime) === UsageState.Unused) continue;
 | 
						|
				}
 | 
						|
				exports.add(name);
 | 
						|
				if (importedExportInfo.provided === true) continue;
 | 
						|
				checked.add(name);
 | 
						|
			}
 | 
						|
			if (isNamespaceImport) {
 | 
						|
				exports.add("__esModule");
 | 
						|
				checked.delete("__esModule");
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return { exports, checked };
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @param {ObjectSerializerContext} context context
 | 
						|
	 */
 | 
						|
	serialize(context) {
 | 
						|
		const { write } = context;
 | 
						|
		write(this.asiSafe);
 | 
						|
		write(this.range);
 | 
						|
		write(this.valueRange);
 | 
						|
		write(this.base);
 | 
						|
		write(this.names);
 | 
						|
		write(this.ids);
 | 
						|
		write(this.resultUsed);
 | 
						|
		super.serialize(context);
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @param {ObjectDeserializerContext} context context
 | 
						|
	 */
 | 
						|
	deserialize(context) {
 | 
						|
		const { read } = context;
 | 
						|
		this.asiSafe = read();
 | 
						|
		this.range = read();
 | 
						|
		this.valueRange = read();
 | 
						|
		this.base = read();
 | 
						|
		this.names = read();
 | 
						|
		this.ids = read();
 | 
						|
		this.resultUsed = read();
 | 
						|
		super.deserialize(context);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
makeSerializable(
 | 
						|
	CommonJsExportRequireDependency,
 | 
						|
	"webpack/lib/dependencies/CommonJsExportRequireDependency"
 | 
						|
);
 | 
						|
 | 
						|
CommonJsExportRequireDependency.Template = class CommonJsExportRequireDependencyTemplate extends (
 | 
						|
	ModuleDependency.Template
 | 
						|
) {
 | 
						|
	/**
 | 
						|
	 * @param {Dependency} dependency the dependency for which the template should be applied
 | 
						|
	 * @param {ReplaceSource} source the current replace source which can be modified
 | 
						|
	 * @param {DependencyTemplateContext} templateContext the context object
 | 
						|
	 * @returns {void}
 | 
						|
	 */
 | 
						|
	apply(
 | 
						|
		dependency,
 | 
						|
		source,
 | 
						|
		{
 | 
						|
			module,
 | 
						|
			runtimeTemplate,
 | 
						|
			chunkGraph,
 | 
						|
			moduleGraph,
 | 
						|
			runtimeRequirements,
 | 
						|
			runtime
 | 
						|
		}
 | 
						|
	) {
 | 
						|
		const dep = /** @type {CommonJsExportRequireDependency} */ (dependency);
 | 
						|
		const used = moduleGraph
 | 
						|
			.getExportsInfo(module)
 | 
						|
			.getUsedName(dep.names, runtime);
 | 
						|
 | 
						|
		const [type, base] = handleDependencyBase(
 | 
						|
			dep.base,
 | 
						|
			module,
 | 
						|
			runtimeRequirements
 | 
						|
		);
 | 
						|
 | 
						|
		const importedModule = moduleGraph.getModule(dep);
 | 
						|
		let requireExpr = runtimeTemplate.moduleExports({
 | 
						|
			module: importedModule,
 | 
						|
			chunkGraph,
 | 
						|
			request: dep.request,
 | 
						|
			weak: dep.weak,
 | 
						|
			runtimeRequirements
 | 
						|
		});
 | 
						|
		if (importedModule) {
 | 
						|
			const ids = dep.getIds(moduleGraph);
 | 
						|
			const usedImported = moduleGraph
 | 
						|
				.getExportsInfo(importedModule)
 | 
						|
				.getUsedName(ids, runtime);
 | 
						|
			if (usedImported) {
 | 
						|
				const comment = equals(usedImported, ids)
 | 
						|
					? ""
 | 
						|
					: `${Template.toNormalComment(propertyAccess(ids))} `;
 | 
						|
				requireExpr += `${comment}${propertyAccess(usedImported)}`;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		switch (type) {
 | 
						|
			case "expression":
 | 
						|
				source.replace(
 | 
						|
					dep.range[0],
 | 
						|
					dep.range[1] - 1,
 | 
						|
					used
 | 
						|
						? `${base}${propertyAccess(used)} = ${requireExpr}`
 | 
						|
						: `/* unused reexport */ ${requireExpr}`
 | 
						|
				);
 | 
						|
				return;
 | 
						|
			case "Object.defineProperty":
 | 
						|
				throw new Error("TODO");
 | 
						|
			default:
 | 
						|
				throw new Error("Unexpected type");
 | 
						|
		}
 | 
						|
	}
 | 
						|
};
 | 
						|
 | 
						|
module.exports = CommonJsExportRequireDependency;
 |