@applicvision/js-toolbox
Version:
A collection of tools for modern JavaScript development
60 lines (52 loc) • 1.87 kB
JavaScript
import fs from 'node:fs/promises'
import path from 'node:path'
import { pathToFileURL } from 'node:url'
async function readGitignore() {
try {
const gitIgnore = `${await fs.readFile('.gitignore')}`
return gitIgnore.split('\n').filter(file => file)
} catch (e) {
if (e.code !== 'ENOENT') {
throw e
}
return []
}
}
/**
* @template {boolean} [T = false]
* @param {string} directory
* @param {Set<string>} ignoreSet
* @param {(filename: string) => boolean} fileMatcher
* @param {T} useFileUrls
* @returns {Promise<T extends true ? URL[] : string[]>}
*/
async function scanDirectory(directory, ignoreSet, fileMatcher, useFileUrls) {
const entries = await fs.readdir(directory, { withFileTypes: true })
const filtered = entries
.filter(entry => !entry.name.startsWith('.'))
.filter(entry => !ignoreSet.has(entry.name))
const found = await Promise.all(filtered.map(async entry => {
if (entry.isDirectory()) {
const directoryPath = path.join(directory, entry.name)
return ignoreSet.has(directoryPath) ? [] : scanDirectory(directoryPath, ignoreSet, fileMatcher, useFileUrls)
}
if (fileMatcher(entry.name)) {
const filePath = path.join(directory, entry.name)
return useFileUrls ? pathToFileURL(filePath) : filePath
}
return []
}))
// @ts-ignore
return found.flat()
}
/**
* @template {boolean} [T=false]
* @param {string} directory
* @param {{ignoreSet?: Set<string>, fileMatcher?: (filename: string) => boolean, useFileUrls?: T}} options
* @returns {Promise<T extends true ? URL[] : string[]>}
*/
export async function findFiles(directory = '.', { ignoreSet = new Set(), fileMatcher = () => true, useFileUrls } = {}) {
const gitIgnoreEntries = await readGitignore()
gitIgnoreEntries.forEach(ignoreEntry => ignoreSet.add(ignoreEntry))
return scanDirectory(directory, ignoreSet, fileMatcher, useFileUrls)
}