applyWebpackOptionsDefaults = (options, compilerIndex) => {
	F(options, "context", () => process.cwd());
	F(options, "target", () =>
		getDefaultTarget(/** @type {string} */ (options.context))
	);

	const { mode, name, target } = options;

	const targetProperties =
		target === false
			? /** @type {false} */ (false)
			: typeof target === "string"
				? getTargetProperties(target, /** @type {Context} */ (options.context))
				: getTargetsProperties(
						/** @type {string[]} */ (target),
						/** @type {Context} */ (options.context)
					);

	const development = mode === "development";
	const production = mode === "production" || !mode;

	if (typeof options.entry !== "function") {
		for (const key of Object.keys(options.entry)) {
			F(
				options.entry[key],
				"import",
				() => /** @type {[string]} */ (["./src"])
			);
		}
	}

	F(options, "devtool", () => (development ? "eval" : false));
	D(options, "watch", false);
	D(options, "profile", false);
	D(options, "parallelism", 100);
	D(options, "recordsInputPath", false);
	D(options, "recordsOutputPath", false);

	applyExperimentsDefaults(options.experiments, {
		production,
		development,
		targetProperties
	});

	const futureDefaults =
		/** @type {NonNullable<ExperimentsNormalized["futureDefaults"]>} */
		(options.experiments.futureDefaults);

	F(options, "cache", () =>
		development ? { type: /** @type {"memory"} */ ("memory") } : false
	);
	applyCacheDefaults(options.cache, {
		name: name || DEFAULT_CACHE_NAME,
		mode: mode || "production",
		development,
		cacheUnaffected: options.experiments.cacheUnaffected,
		futureDefaults,
		compilerIndex
	});
	const cache = Boolean(options.cache);

	applySnapshotDefaults(options.snapshot, {
		production,
		futureDefaults
	});

	applyOutputDefaults(options.output, {
		context: /** @type {Context} */ (options.context),
		targetProperties,
		isAffectedByBrowserslist:
			target === undefined ||
			(typeof target === "string" && target.startsWith("browserslist")) ||
			(Array.isArray(target) &&
				target.some(target => target.startsWith("browserslist"))),
		outputModule:
			/** @type {NonNullable<ExperimentsNormalized["outputModule"]>} */
			(options.experiments.outputModule),
		development,
		entry: options.entry,
		futureDefaults,
		asyncWebAssembly:
			/** @type {NonNullable<ExperimentsNormalized["asyncWebAssembly"]>} */
			(options.experiments.asyncWebAssembly)
	});

	applyModuleDefaults(options.module, {
		cache,
		syncWebAssembly:
			/** @type {NonNullable<ExperimentsNormalized["syncWebAssembly"]>} */
			(options.experiments.syncWebAssembly),
		asyncWebAssembly:
			/** @type {NonNullable<ExperimentsNormalized["asyncWebAssembly"]>} */
			(options.experiments.asyncWebAssembly),
		css:
			/** @type {NonNullable<ExperimentsNormalized["css"]>} */
			(options.experiments.css),
		futureDefaults,
		isNode: targetProperties && targetProperties.node === true,
		uniqueName: /** @type {string} */ (options.output.uniqueName),
		targetProperties,
		mode: options.mode
	});

	applyExternalsPresetsDefaults(options.externalsPresets, {
		targetProperties,
		buildHttp: Boolean(options.experiments.buildHttp)
	});

	applyLoaderDefaults(
		/** @type {NonNullable<WebpackOptionsNormalized["loader"]>} */ (
			options.loader
		),
		{ targetProperties, environment: options.output.environment }
	);

	F(options, "externalsType", () => {
		const validExternalTypes = require("../../schemas/WebpackOptions.json")
			.definitions.ExternalsType.enum;
		return options.output.library &&
			validExternalTypes.includes(options.output.library.type)
			? /** @type {ExternalsType} */ (options.output.library.type)
			: options.output.module
				? "module-import"
				: "var";
	});

	applyNodeDefaults(options.node, {
		futureDefaults:
			/** @type {NonNullable<WebpackOptionsNormalized["experiments"]["futureDefaults"]>} */
			(options.experiments.futureDefaults),
		outputModule:
			/** @type {NonNullable<WebpackOptionsNormalized["output"]["module"]>} */
			(options.output.module),
		targetProperties
	});

	F(options, "performance", () =>
		production &&
		targetProperties &&
		(targetProperties.browser || targetProperties.browser === null)
			? {}
			: false
	);
	applyPerformanceDefaults(
		/** @type {NonNullable<WebpackOptionsNormalized["performance"]>} */
		(options.performance),
		{
			production
		}
	);

	applyOptimizationDefaults(options.optimization, {
		development,
		production,
		css:
			/** @type {NonNullable<ExperimentsNormalized["css"]>} */
			(options.experiments.css),
		records: Boolean(options.recordsInputPath || options.recordsOutputPath)
	});

	options.resolve = cleverMerge(
		getResolveDefaults({
			cache,
			context: /** @type {Context} */ (options.context),
			targetProperties,
			mode: /** @type {Mode} */ (options.mode),
			css:
				/** @type {NonNullable<ExperimentsNormalized["css"]>} */
				(options.experiments.css)
		}),
		options.resolve
	);

	options.resolveLoader = cleverMerge(
		getResolveLoaderDefaults({ cache }),
		options.resolveLoader
	);

	return {
		platform:
			targetProperties === false
				? targetProperties
				: {
						web: targetProperties.web,
						browser: targetProperties.browser,
						webworker: targetProperties.webworker,
						node: targetProperties.node,
						nwjs: targetProperties.nwjs,
						electron: targetProperties.electron
					}
	};
}
@param {WebpackOptionsNormalized} options options to be modified
@param {number=} compilerIndex index of compiler
@returns {ResolvedOptions} Resolved options after apply defaults