addDirectory = (ctx, directory, addSubDirectory, callback) => {
			fs.readdir(directory, (err, files) => {
				if (err) return callback(err);
				const processedFiles = cmf.hooks.contextModuleFiles.call(
					/** @type {string[]} */ (files).map(file => file.normalize("NFC"))
				);
				if (!processedFiles || processedFiles.length === 0)
					return callback(null, []);
				asyncLib.map(
					processedFiles.filter(p => p.indexOf(".") !== 0),
					(segment, callback) => {
						const subResource = join(fs, directory, segment);

						if (!exclude || !subResource.match(exclude)) {
							fs.stat(subResource, (err, _stat) => {
								if (err) {
									if (err.code === "ENOENT") {
										// ENOENT is ok here because the file may have been deleted between
										// the readdir and stat calls.
										return callback();
									}
									return callback(err);
								}

								const stat = /** @type {IStats} */ (_stat);

								if (stat.isDirectory()) {
									if (!recursive) return callback();
									addSubDirectory(ctx, subResource, callback);
								} else if (
									stat.isFile() &&
									(!include || subResource.match(include))
								) {
									/** @type {{ context: string, request: string }} */
									const obj = {
										context: ctx,
										request: `.${subResource.slice(ctx.length).replace(/\\/g, "/")}`
									};

									this.hooks.alternativeRequests.callAsync(
										[obj],
										options,
										(err, alternatives) => {
											if (err) return callback(err);
											callback(
												null,
												/** @type {ContextAlternativeRequest[]} */
												(alternatives)
													.filter(obj =>
														regExp.test(/** @type {string} */ (obj.request))
													)
													.map(obj => {
														const dep = new ContextElementDependency(
															`${obj.request}${resourceQuery}${resourceFragment}`,
															obj.request,
															typePrefix,
															/** @type {string} */
															(category),
															referencedExports,
															obj.context,
															attributes
														);
														dep.optional = true;
														return dep;
													})
											);
										}
									);
								} else {
									callback();
								}
							});
						} else {
							callback();
						}
					},
					(err, result) => {
						if (err) return callback(err);

						if (!result) return callback(null, []);

						const flattenedResult = [];

						for (const item of result) {
							if (item) flattenedResult.push(...item);
						}

						callback(null, flattenedResult);
					}
				);
			});
		}
@param {string} ctx context
@param {string} directory directory
@param {(context: string, subResource: string, callback: () => void) => void} addSubDirectory addSubDirectoryFn
@param {ResolveDependenciesCallback} callback callback