Repository: rollup/rollup
File: src/utils/options/normalizeInputOptions.ts (TypeScript)

Code before:
} {
	// These are options that may trigger special warnings or behaviour later
	// if the user did not select an explicit value
	const unsetOptions = new Set<string>();

	const context = config.context ?? 'undefined';
	const onwarn = getOnwarn(config);
	const strictDeprecations = config.strictDeprecations || false;
	const maxParallelFileOps = getmaxParallelFileOps(config, onwarn, strictDeprecations);
	const options: NormalizedInputOptions & InputOptions = {
		acorn: getAcorn(config) as unknown as NormalizedInputOptions['acorn'],
		acornInjectPlugins: getAcornInjectPlugins(config),
		cache: getCache(config),
		context,
		experimentalCacheExpiry: config.experimentalCacheExpiry ?? 10,
		external: getIdMatcher(config.external),
		inlineDynamicImports: getInlineDynamicImports(config, onwarn, strictDeprecations),
		input: getInput(config),
		makeAbsoluteExternalsRelative: config.makeAbsoluteExternalsRelative ?? 'ifRelativeSource',
		manualChunks: getManualChunks(config, onwarn, strictDeprecations),
		maxParallelFileOps,
		maxParallelFileReads: maxParallelFileOps,
		moduleContext: getModuleContext(config, context),
		onwarn,
		perf: config.perf || false,
		plugins: flatten(ensureArray(config.plugins)),
		preserveEntrySignatures: config.preserveEntrySignatures ?? 'exports-only',
		preserveModules: getPreserveModules(config, onwarn, strictDeprecations),
		preserveSymlinks: config.preserveSymlinks || false,
		shimMissingExports: config.shimMissingExports || false,
		strictDeprecations,
		treeshake: getTreeshake(config)
	};

	warnUnknownOptions(
		config as GenericConfigObject,
		[...Object.keys(options), 'watch'],
		'input options',
		options.onwarn,
		/^(output)$/
	);
	return { options, unsetOptions };
}

const getOnwarn = (config: InputOptions): NormalizedInputOptions['onwarn'] => {
	const { onwarn } = config;
	return onwarn
		? warning => {
				warning.toString = () => {
					let str = '';


Review comment (suggestion):
Two things:
 - In the end, `flatten` just reimplements `[].flat(Infinity)`, which I would prefer to use
 - `ensureArray` is only called on the original array. However, it also filters falsy plugins, which should also happen in nested arrays.

```suggestion
		plugins: ensureArray(config.plugins).flat(Infinity).filter(Boolean),
```

Code after:
} {
	// These are options that may trigger special warnings or behaviour later
	// if the user did not select an explicit value
	const unsetOptions = new Set<string>();

	const context = config.context ?? 'undefined';
	const onwarn = getOnwarn(config);
	const strictDeprecations = config.strictDeprecations || false;
	const maxParallelFileOps = getmaxParallelFileOps(config, onwarn, strictDeprecations);
	const options: NormalizedInputOptions & InputOptions = {
		acorn: getAcorn(config) as unknown as NormalizedInputOptions['acorn'],
		acornInjectPlugins: getAcornInjectPlugins(config),
		cache: getCache(config),
		context,
		experimentalCacheExpiry: config.experimentalCacheExpiry ?? 10,
		external: getIdMatcher(config.external),
		inlineDynamicImports: getInlineDynamicImports(config, onwarn, strictDeprecations),
		input: getInput(config),
		makeAbsoluteExternalsRelative: config.makeAbsoluteExternalsRelative ?? 'ifRelativeSource',
		manualChunks: getManualChunks(config, onwarn, strictDeprecations),
		maxParallelFileOps,
		maxParallelFileReads: maxParallelFileOps,
		moduleContext: getModuleContext(config, context),
		onwarn,
		perf: config.perf || false,
		plugins: normalizePluginOption(config.plugins),
		preserveEntrySignatures: config.preserveEntrySignatures ?? 'exports-only',
		preserveModules: getPreserveModules(config, onwarn, strictDeprecations),
		preserveSymlinks: config.preserveSymlinks || false,
		shimMissingExports: config.shimMissingExports || false,
		strictDeprecations,
		treeshake: getTreeshake(config)
	};

	warnUnknownOptions(
		config as GenericConfigObject,
		[...Object.keys(options), 'watch'],
		'input options',
		options.onwarn,
		/^(output)$/
	);
	return { options, unsetOptions };
}

const getOnwarn = (config: InputOptions): NormalizedInputOptions['onwarn'] => {
	const { onwarn } = config;
	return onwarn
		? warning => {
				warning.toString = () => {
					let str = '';