src/vs/platform/diagnostics/node/diagnosticsService.ts/collect
export async function collectWorkspaceStats(folder: string, filter: string[]): Promise<WorkspaceStats> {
	const configFilePatterns: ConfigFilePatterns[] = [
		{ tag: 'grunt.js', filePattern: /^gruntfile\.js$/i },
		{ tag: 'gulp.js', filePattern: /^gulpfile\.js$/i },
		{ tag: 'tsconfig.json', filePattern: /^tsconfig\.json$/i },
		{ tag: 'package.json', filePattern: /^package\.json$/i },
		{ tag: 'jsconfig.json', filePattern: /^jsconfig\.json$/i },
		{ tag: 'tslint.json', filePattern: /^tslint\.json$/i },
		{ tag: 'eslint.json', filePattern: /^eslint\.json$/i },
		{ tag: 'tasks.json', filePattern: /^tasks\.json$/i },
		{ tag: 'launch.json', filePattern: /^launch\.json$/i },
		{ tag: 'settings.json', filePattern: /^settings\.json$/i },
		{ tag: 'webpack.config.js', filePattern: /^webpack\.config\.js$/i },
		{ tag: 'project.json', filePattern: /^project\.json$/i },
		{ tag: 'makefile', filePattern: /^makefile$/i },
		{ tag: 'sln', filePattern: /^.+\.sln$/i },
		{ tag: 'csproj', filePattern: /^.+\.csproj$/i },
		{ tag: 'cmake', filePattern: /^.+\.cmake$/i },
		{ tag: 'github-actions', filePattern: /^.+\.yml$/i, relativePathPattern: /^\.github(?:\/|\\)workflows$/i }
	];

	const fileTypes = new Map<string, number>();
	const configFiles = new Map<string, number>();

	const MAX_FILES = 20000;

	function collect(root: string, dir: string, filter: string[], token: { count: number, maxReached: boolean }): Promise<void> {
		const relativePath = dir.substring(root.length + 1);

		return new Promise(async resolve => {
			let files: IDirent[];
			try {
				files = await Promises.readdir(dir, { withFileTypes: true });
			} catch (error) {
				// Ignore folders that can't be read
				resolve();
				return;
			}

			if (token.count >= MAX_FILES) {
				token.count += files.length;
				token.maxReached = true;
				resolve();
				return;
			}

			let pending = files.length;
			if (pending === 0) {
				resolve();
				return;
			}

			let filesToRead = files;
			if (token.count + files.length > MAX_FILES) {
				token.maxReached = true;
				pending = MAX_FILES - token.count;
				filesToRead = files.slice(0, pending);
			}

			token.count += files.length;

			for (const file of filesToRead) {
				if (file.isDirectory()) {
					if (!filter.includes(file.name)) {
						await collect(root, join(dir, file.name), filter, token);
					}

					if (--pending === 0) {
						resolve();
						return;
					}
				} else {
					const index = file.name.lastIndexOf('.');
					if (index >= 0) {
						const fileType = file.name.substring(index + 1);
						if (fileType) {
							fileTypes.set(fileType, (fileTypes.get(fileType) ?? 0) + 1);
						}
					}

					for (const configFile of configFilePatterns) {
						if (configFile.relativePathPattern?.test(relativePath) !== false && configFile.filePattern.test(file.name)) {
							configFiles.set(configFile.tag, (configFiles.get(configFile.tag) ?? 0) + 1);
						}
					}

					if (--pending === 0) {
						resolve();
						return;
					}
				}
			}
		});
	}

	const token: { count: number, maxReached: boolean } = { count: 0, maxReached: false };

	await collect(folder, folder, filter, token);
	const launchConfigs = await collectLaunchConfigs(folder);
	return {
		configFiles: asSortedItems(configFiles),
		fileTypes: asSortedItems(fileTypes),
		fileCount: token.count,
		maxFilesReached: token.maxReached,
		launchConfigFiles: launchConfigs
	};
}