normalizeCacheGroups = (cacheGroups, defaultSizeTypes) => {
	if (typeof cacheGroups === "function") {
		return cacheGroups;
	}
	if (typeof cacheGroups === "object" && cacheGroups !== null) {
		/** @type {((module: Module, context: CacheGroupsContext, results: CacheGroupSource[]) => void)[]} */
		const handlers = [];
		for (const key of Object.keys(cacheGroups)) {
			const option = cacheGroups[key];
			if (option === false) {
				continue;
			}
			if (typeof option === "string" || option instanceof RegExp) {
				const source = createCacheGroupSource({}, key, defaultSizeTypes);
				handlers.push((module, context, results) => {
					if (checkTest(option, module, context)) {
						results.push(source);
					}
				});
			} else if (typeof option === "function") {
				const cache = new WeakMap();
				handlers.push((module, context, results) => {
					const result = option(module);
					if (result) {
						const groups = Array.isArray(result) ? result : [result];
						for (const group of groups) {
							const cachedSource = cache.get(group);
							if (cachedSource !== undefined) {
								results.push(cachedSource);
							} else {
								const source = createCacheGroupSource(
									group,
									key,
									defaultSizeTypes
								);
								cache.set(group, source);
								results.push(source);
							}
						}
					}
				});
			} else {
				const source = createCacheGroupSource(option, key, defaultSizeTypes);
				handlers.push((module, context, results) => {
					if (
						checkTest(option.test, module, context) &&
						checkModuleType(option.type, module) &&
						checkModuleLayer(option.layer, module)
					) {
						results.push(source);
					}
				});
			}
		}
		/**
		 * @param {Module} module the current module
		 * @param {CacheGroupsContext} context the current context
		 * @returns {CacheGroupSource[]} the matching cache groups
		 */
		const fn = (module, context) => {
			/** @type {CacheGroupSource[]} */
			const results = [];
			for (const fn of handlers) {
				fn(module, context, results);
			}
			return results;
		};
		return fn;
	}
	return () => null;
}
@param {undefined | GetCacheGroups | Record<string, false | string | RegExp | OptimizationSplitChunksGetCacheGroups | OptimizationSplitChunksCacheGroup>} cacheGroups the cache group options
@param {string[]} defaultSizeTypes the default size types
@returns {GetCacheGroups} a function to get the cache groups