applyOutputDefaults = (
	output,
	{
		context,
		targetProperties: tp,
		isAffectedByBrowserslist,
		outputModule,
		development,
		entry,
		futureDefaults,
		asyncWebAssembly
	}
) => {
	/**
	 * @param {Library=} library the library option
	 * @returns {string} a readable library name
	 */
	const getLibraryName = library => {
		const libraryName =
			typeof library === "object" &&
			library &&
			!Array.isArray(library) &&
			"type" in library
				? library.name
				: /** @type {LibraryName} */ (library);
		if (Array.isArray(libraryName)) {
			return libraryName.join(".");
		} else if (typeof libraryName === "object") {
			return getLibraryName(libraryName.root);
		} else if (typeof libraryName === "string") {
			return libraryName;
		}
		return "";
	};

	F(output, "uniqueName", () => {
		const libraryName = getLibraryName(output.library).replace(
			/^\[(\\*[\w:]+\\*)\](\.)|(\.)\[(\\*[\w:]+\\*)\](?=\.|$)|\[(\\*[\w:]+\\*)\]/g,
			(m, a, d1, d2, b, c) => {
				const content = a || b || c;
				return content.startsWith("\\") && content.endsWith("\\")
					? `${d2 || ""}[${content.slice(1, -1)}]${d1 || ""}`
					: "";
			}
		);
		if (libraryName) return libraryName;
		const pkgPath = path.resolve(context, "package.json");
		try {
			const packageInfo = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
			return packageInfo.name || "";
		} catch (err) {
			if (/** @type {Error & { code: string }} */ (err).code !== "ENOENT") {
				/** @type {Error & { code: string }} */
				(err).message +=
					`\nwhile determining default 'output.uniqueName' from 'name' in ${pkgPath}`;
				throw err;
			}
			return "";
		}
	});

	F(output, "module", () => Boolean(outputModule));

	const environment = /** @type {Environment} */ (output.environment);
	/**
	 * @param {boolean | undefined} v value
	 * @returns {boolean} true, when v is truthy or undefined
	 */
	const optimistic = v => v || v === undefined;
	/**
	 * @param {boolean | undefined} v value
	 * @param {boolean | undefined} c condition
	 * @returns {boolean | undefined} true, when v is truthy or undefined, or c is truthy
	 */
	const conditionallyOptimistic = (v, c) => (v === undefined && c) || v;

	F(
		environment,
		"globalThis",
		() => /** @type {boolean | undefined} */ (tp && tp.globalThis)
	);
	F(
		environment,
		"bigIntLiteral",
		() =>
			tp && optimistic(/** @type {boolean | undefined} */ (tp.bigIntLiteral))
	);
	F(
		environment,
		"const",
		() => tp && optimistic(/** @type {boolean | undefined} */ (tp.const))
	);
	F(
		environment,
		"arrowFunction",
		() =>
			tp && optimistic(/** @type {boolean | undefined} */ (tp.arrowFunction))
	);
	F(
		environment,
		"asyncFunction",
		() =>
			tp && optimistic(/** @type {boolean | undefined} */ (tp.asyncFunction))
	);
	F(
		environment,
		"forOf",
		() => tp && optimistic(/** @type {boolean | undefined} */ (tp.forOf))
	);
	F(
		environment,
		"destructuring",
		() =>
			tp && optimistic(/** @type {boolean | undefined} */ (tp.destructuring))
	);
	F(
		environment,
		"optionalChaining",
		() =>
			tp && optimistic(/** @type {boolean | undefined} */ (tp.optionalChaining))
	);
	F(
		environment,
		"nodePrefixForCoreModules",
		() =>
			tp &&
			optimistic(
				/** @type {boolean | undefined} */ (tp.nodePrefixForCoreModules)
			)
	);
	F(
		environment,
		"templateLiteral",
		() =>
			tp && optimistic(/** @type {boolean | undefined} */ (tp.templateLiteral))
	);
	F(environment, "dynamicImport", () =>
		conditionallyOptimistic(
			/** @type {boolean | undefined} */ (tp && tp.dynamicImport),
			output.module
		)
	);
	F(environment, "dynamicImportInWorker", () =>
		conditionallyOptimistic(
			/** @type {boolean | undefined} */ (tp && tp.dynamicImportInWorker),
			output.module
		)
	);
	F(environment, "module", () =>
		conditionallyOptimistic(
			/** @type {boolean | undefined} */ (tp && tp.module),
			output.module
		)
	);
	F(
		environment,
		"document",
		() => tp && optimistic(/** @type {boolean | undefined} */ (tp.document))
	);

	D(output, "filename", output.module ? "[name].mjs" : "[name].js");
	F(output, "iife", () => !output.module);
	D(output, "importFunctionName", "import");
	D(output, "importMetaName", "import.meta");
	F(output, "chunkFilename", () => {
		const filename =
			/** @type {NonNullable<Output["chunkFilename"]>} */
			(output.filename);
		if (typeof filename !== "function") {
			const hasName = filename.includes("[name]");
			const hasId = filename.includes("[id]");
			const hasChunkHash = filename.includes("[chunkhash]");
			const hasContentHash = filename.includes("[contenthash]");
			// Anything changing depending on chunk is fine
			if (hasChunkHash || hasContentHash || hasName || hasId) return filename;
			// Otherwise prefix "[id]." in front of the basename to make it changing
			return filename.replace(/(^|\/)([^/]*(?:\?|$))/, "$1[id].$2");
		}
		return output.module ? "[id].mjs" : "[id].js";
	});
	F(output, "cssFilename", () => {
		const filename =
			/** @type {NonNullable<Output["cssFilename"]>} */
			(output.filename);
		if (typeof filename !== "function") {
			return filename.replace(/\.[mc]?js(\?|$)/, ".css$1");
		}
		return "[id].css";
	});
	F(output, "cssChunkFilename", () => {
		const chunkFilename =
			/** @type {NonNullable<Output["cssChunkFilename"]>} */
			(output.chunkFilename);
		if (typeof chunkFilename !== "function") {
			return chunkFilename.replace(/\.[mc]?js(\?|$)/, ".css$1");
		}
		return "[id].css";
	});
	D(output, "assetModuleFilename", "[hash][ext][query]");
	D(output, "webassemblyModuleFilename", "[hash].module.wasm");
	D(output, "compareBeforeEmit", true);
	D(output, "charset", !futureDefaults);
	const uniqueNameId = Template.toIdentifier(
		/** @type {NonNullable<Output["uniqueName"]>} */ (output.uniqueName)
	);
	F(output, "hotUpdateGlobal", () => `webpackHotUpdate${uniqueNameId}`);
	F(output, "chunkLoadingGlobal", () => `webpackChunk${uniqueNameId}`);
	F(output, "globalObject", () => {
		if (tp) {
			if (tp.global) return "global";
			if (tp.globalThis) return "globalThis";
		}
		return "self";
	});
	F(output, "chunkFormat", () => {
		if (tp) {
			const helpMessage = isAffectedByBrowserslist
				? "Make sure that your 'browserslist' includes only platforms that support these features or select an appropriate 'target' to allow selecting a chunk format by default. Alternatively specify the 'output.chunkFormat' directly."
				: "Select an appropriate 'target' to allow selecting one by default, or specify the 'output.chunkFormat' directly.";
			if (output.module) {
				if (environment.dynamicImport) return "module";
				if (tp.document) return "array-push";
				throw new Error(
					"For the selected environment is no default ESM chunk format available:\n" +
						"ESM exports can be chosen when 'import()' is available.\n" +
						`JSONP Array push can be chosen when 'document' is available.\n${
							helpMessage
						}`
				);
			} else {
				if (tp.document) return "array-push";
				if (tp.require) return "commonjs";
				if (tp.nodeBuiltins) return "commonjs";
				if (tp.importScripts) return "array-push";
				throw new Error(
					"For the selected environment is no default script chunk format available:\n" +
						"JSONP Array push can be chosen when 'document' or 'importScripts' is available.\n" +
						`CommonJs exports can be chosen when 'require' or node builtins are available.\n${
							helpMessage
						}`
				);
			}
		}
		throw new Error(
			"Chunk format can't be selected by default when no target is specified"
		);
	});
	D(output, "asyncChunks", true);
	F(output, "chunkLoading", () => {
		if (tp) {
			switch (output.chunkFormat) {
				case "array-push":
					if (tp.document) return "jsonp";
					if (tp.importScripts) return "import-scripts";
					break;
				case "commonjs":
					if (tp.require) return "require";
					if (tp.nodeBuiltins) return "async-node";
					break;
				case "module":
					if (environment.dynamicImport) return "import";
					break;
			}
			if (
				(tp.require === null ||
					tp.nodeBuiltins === null ||
					tp.document === null ||
					tp.importScripts === null) &&
				output.module &&
				environment.dynamicImport
			) {
				return "universal";
			}
		}
		return false;
	});
	F(output, "workerChunkLoading", () => {
		if (tp) {
			switch (output.chunkFormat) {
				case "array-push":
					if (tp.importScriptsInWorker) return "import-scripts";
					break;
				case "commonjs":
					if (tp.require) return "require";
					if (tp.nodeBuiltins) return "async-node";
					break;
				case "module":
					if (environment.dynamicImportInWorker) return "import";
					break;
			}
			if (
				(tp.require === null ||
					tp.nodeBuiltins === null ||
					tp.importScriptsInWorker === null) &&
				output.module &&
				environment.dynamicImport
			) {
				return "universal";
			}
		}
		return false;
	});
	F(output, "wasmLoading", () => {
		if (tp) {
			if (tp.fetchWasm) return "fetch";
			if (tp.nodeBuiltins) return "async-node";
			if (
				(tp.nodeBuiltins === null || tp.fetchWasm === null) &&
				asyncWebAssembly &&
				output.module &&
				environment.dynamicImport
			) {
				return "universal";
			}
		}
		return false;
	});
	F(output, "workerWasmLoading", () => output.wasmLoading);
	F(output, "devtoolNamespace", () => output.uniqueName);
	if (output.library) {
		F(output.library, "type", () => (output.module ? "module" : "var"));
	}
	F(output, "path", () => path.join(process.cwd(), "dist"));
	F(output, "pathinfo", () => development);
	D(output, "sourceMapFilename", "[file].map[query]");
	D(
		output,
		"hotUpdateChunkFilename",
		`[id].[fullhash].hot-update.${output.module ? "mjs" : "js"}`
	);
	D(output, "hotUpdateMainFilename", "[runtime].[fullhash].hot-update.json");
	D(output, "crossOriginLoading", false);
	F(output, "scriptType", () => (output.module ? "module" : false));
	D(
		output,
		"publicPath",
		(tp && (tp.document || tp.importScripts)) || output.scriptType === "module"
			? "auto"
			: ""
	);
	D(output, "workerPublicPath", "");
	D(output, "chunkLoadTimeout", 120000);
	F(output, "hashFunction", () => {
		if (futureDefaults) {
			DEFAULTS.HASH_FUNCTION = "xxhash64";
			return "xxhash64";
		}

		return "md4";
	});
	D(output, "hashDigest", "hex");
	D(output, "hashDigestLength", futureDefaults ? 16 : 20);
	D(output, "strictModuleErrorHandling", false);
	D(output, "strictModuleExceptionHandling", false);

	const { trustedTypes } = output;
	if (trustedTypes) {
		F(
			trustedTypes,
			"policyName",
			() =>
				/** @type {NonNullable<Output["uniqueName"]>} */
				(output.uniqueName).replace(/[^a-zA-Z0-9\-#=_/@.%]+/g, "_") || "webpack"
		);
		D(trustedTypes, "onPolicyCreationFailure", "stop");
	}

	/**
	 * @param {(entryDescription: EntryDescription) => void} fn iterator
	 * @returns {void}
	 */
	const forEachEntry = fn => {
		for (const name of Object.keys(entry)) {
			fn(/** @type {{[k: string] : EntryDescription}} */ (entry)[name]);
		}
	};
	A(output, "enabledLibraryTypes", () => {
		/** @type {LibraryType[]} */
		const enabledLibraryTypes = [];
		if (output.library) {
			enabledLibraryTypes.push(output.library.type);
		}
		forEachEntry(desc => {
			if (desc.library) {
				enabledLibraryTypes.push(desc.library.type);
			}
		});
		return enabledLibraryTypes;
	});

	A(output, "enabledChunkLoadingTypes", () => {
		const enabledChunkLoadingTypes = new Set();
		if (output.chunkLoading) {
			enabledChunkLoadingTypes.add(output.chunkLoading);
		}
		if (output.workerChunkLoading) {
			enabledChunkLoadingTypes.add(output.workerChunkLoading);
		}
		forEachEntry(desc => {
			if (desc.chunkLoading) {
				enabledChunkLoadingTypes.add(desc.chunkLoading);
			}
		});
		return Array.from(enabledChunkLoadingTypes);
	});

	A(output, "enabledWasmLoadingTypes", () => {
		const enabledWasmLoadingTypes = new Set();
		if (output.wasmLoading) {
			enabledWasmLoadingTypes.add(output.wasmLoading);
		}
		if (output.workerWasmLoading) {
			enabledWasmLoadingTypes.add(output.workerWasmLoading);
		}
		forEachEntry(desc => {
			if (desc.wasmLoading) {
				enabledWasmLoadingTypes.add(desc.wasmLoading);
			}
		});
		return Array.from(enabledWasmLoadingTypes);
	});
}
@param {Output} output options
@param {object} options options
@param {string} options.context context
@param {TargetProperties | false} options.targetProperties target properties
@param {boolean} options.isAffectedByBrowserslist is affected by browserslist
@param {boolean} options.outputModule is outputModule experiment enabled
@param {boolean} options.development is development mode
@param {Entry} options.entry entry option
@param {boolean} options.futureDefaults is future defaults enabled
@param {boolean} options.asyncWebAssembly is asyncWebAssembly enabled
@returns {void}