static async gatherFilesFromDir(startPath, customConfig = {}) {
    const allowlistModes = ['npm', 'git', 'all', 'export-map'];
    if (customConfig.allowlistMode && !allowlistModes.includes(customConfig.allowlistMode)) {
      throw new Error(
        `[gatherFilesConfig] Please provide a valid allowListMode like "${allowlistModes.join(
          '|',
        )}". Found: "${customConfig.allowlistMode}"`,
      );
    }

    const cfg = {
      ...this.defaultGatherFilesConfig,
      ...customConfig,
    };
    if (!customConfig.omitDefaultAllowlist) {
      cfg.allowlist = [
        ...this.defaultGatherFilesConfig.allowlist,
        ...(customConfig.allowlist || []),
      ];
    }

    if (cfg.allowlistMode === 'export-map') {
      const pkgJson = getPackageJson(startPath);
      if (!pkgJson?.exports) {
        LogService.error(`No exports found in package.json of ${startPath}`);
      }
      if (pkgJson?.exports) {
        const exposedAndInternalPaths = await this.getPathsFromExportMap(pkgJson?.exports, {
          packageRootPath: startPath,
        });
        return /** @type {PathFromSystemRoot[]} */ (
          exposedAndInternalPaths
            // TODO: path.resolve(startPath, p.internal)?
            .map(p => p.internal)
            .filter(p =>
              cfg.extensions.includes(/** @type {`.${string}`} */ (`${path.extname(p)}`)),
            )
        );
      }
    }

    /** @type {string[]} */
    const negativeGitGlobs = [];
    /** @type {string[]} */
    const npmGlobs = [];
    const allowlistMode = cfg.allowlistMode || this._determineAllowListMode(startPath);

    if (allowlistMode === 'git') {
      negativeGitGlobs.push(
        ...getGitIgnorePaths(startPath).map(gitIgnorePath => `!${gitIgnorePath}`),
      );
    } else if (allowlistMode === 'npm') {
      npmGlobs.push(...getNpmPackagePaths(startPath));
    }

    const combinedGlobs = Array.from(new Set([...cfg.allowlist, ...npmGlobs, ...negativeGitGlobs]));
    const hasProvidedPositiveGlob = cfg.allowlist.some(glob => !glob.startsWith('!'));

    // We need to expand
    const shouldLookForAllFilesInProject =
      allowlistMode === 'all' || (!npmGlobs.length && !hasProvidedPositiveGlob);
    if (shouldLookForAllFilesInProject) {
      combinedGlobs.push(this._getDefaultGlobDepthPattern(cfg.depth, cfg.extensions));
    }

    const globbyCfg = {
      expandDirectories: false,
      fs: fsAdapter.fs,
      onlyFiles: true,
      absolute: true,
      cwd: startPath,
    };
    let filteredGlobRes = await globby(combinedGlobs, globbyCfg);

    // Unfortunatly, globby does not correctly remove the negated globs,
    // so we have to do it manually
    const negatedGlobs = combinedGlobs.filter(p => p.startsWith('!'));
    if (negatedGlobs.length) {
      const subtract = await globby(
        negatedGlobs.map(p => p.slice(1)),
        globbyCfg,
      );
      // eslint-disable-next-line no-shadow
      filteredGlobRes = filteredGlobRes.filter(file => !subtract.includes(file));
    }

    // Make sure we don't delete to much by giving customConfig.allowlist priority
    if (customConfig.allowlist?.length) {
      const customResults = await globby(customConfig.allowlist, globbyCfg);
      filteredGlobRes = Array.from(new Set([...filteredGlobRes, ...customResults]));
    }

    // Filter by extension (in the future: use globs exclusively for this?)
    if (cfg.extensions.length) {
      filteredGlobRes = filteredGlobRes.filter(glob =>
        cfg.extensions.some(ext => glob.endsWith(ext)),
      );
    }

    if (!filteredGlobRes?.length) {
      LogService.warn(`No files found for path '${startPath}'`);
      return [];
    }

    return /** @type {PathFromSystemRoot[]} */ (filteredGlobRes.map(toPosixPath));
  }
Gets an array of files for given extension
@param {PathFromSystemRoot} startPath - local filesystem path
@param {Partial<GatherFilesConfig>} customConfig - configuration object
@returns {Promise<PathFromSystemRoot[]>} result list of file paths