UNPKG

@jsenv/util

Version:

Set of functions often needed when using Node.js.

103 lines (89 loc) 3.56 kB
import { createCancellationToken, createOperation } from "@jsenv/cancellation" import { normalizeStructuredMetaMap, urlCanContainsMetaMatching, urlToMeta } from "@jsenv/url-meta" import { ensureUrlTrailingSlash } from "./internal/ensureUrlTrailingSlash.js" import { assertAndNormalizeDirectoryUrl } from "./assertAndNormalizeDirectoryUrl.js" import { readDirectory } from "./readDirectory.js" import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js" import { urlToRelativeUrl } from "./urlToRelativeUrl.js" import { comparePathnames } from "./comparePathnames.js" export const collectDirectoryMatchReport = async ({ cancellationToken = createCancellationToken(), directoryUrl, structuredMetaMap, predicate, }) => { const matchingArray = [] const ignoredArray = [] const rootDirectoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl) if (typeof predicate !== "function") { throw new TypeError(`predicate must be a function, got ${predicate}`) } const structuredMetaMapNormalized = normalizeStructuredMetaMap( structuredMetaMap, rootDirectoryUrl, ) const visitDirectory = async (directoryUrl) => { const directoryItems = await createOperation({ cancellationToken, start: () => readDirectory(directoryUrl), }) await Promise.all( directoryItems.map(async (directoryItem) => { const directoryChildNodeUrl = `${directoryUrl}${directoryItem}` const relativeUrl = urlToRelativeUrl(directoryChildNodeUrl, rootDirectoryUrl) const directoryChildNodeStats = await createOperation({ cancellationToken, start: () => readFileSystemNodeStat(directoryChildNodeUrl, { // we ignore symlink because recursively traversed // so symlinked file will be discovered. // Moreover if they lead outside of directoryPath it can become a problem // like infinite recursion of whatever. // that we could handle using an object of pathname already seen but it will be useless // because directoryPath is recursively traversed followLink: false, }), }) if (directoryChildNodeStats.isDirectory()) { const subDirectoryUrl = `${directoryChildNodeUrl}/` if ( !urlCanContainsMetaMatching({ url: subDirectoryUrl, structuredMetaMap: structuredMetaMapNormalized, predicate, }) ) { ignoredArray.push({ relativeUrl: ensureUrlTrailingSlash(relativeUrl), fileStats: directoryChildNodeStats, }) return } await visitDirectory(subDirectoryUrl) return } if (directoryChildNodeStats.isFile()) { const meta = urlToMeta({ url: directoryChildNodeUrl, structuredMetaMap: structuredMetaMapNormalized, }) if (!predicate(meta)) { ignoredArray.push({ relativeUrl, meta, fileStats: directoryChildNodeStats }) return } matchingArray.push({ relativeUrl, meta, fileStats: directoryChildNodeStats }) return } }), ) } await visitDirectory(rootDirectoryUrl) return { matchingArray: sortByRelativeUrl(matchingArray), ignoredArray: sortByRelativeUrl(ignoredArray), } } const sortByRelativeUrl = (array) => array.sort((left, right) => { return comparePathnames(left.relativeUrl, right.relativeUrl) })