import { glob } from "tinyglobby"; import { TemplatePath } from "@11ty/eleventy-utils"; import debugUtil from "debug"; import FileSystemRemap from "./Util/GlobRemap.js"; import { isGlobMatch } from "./Util/GlobMatcher.js"; const debug = debugUtil("Eleventy:FileSystemSearch"); class FileSystemSearch { constructor() { this.inputs = {}; this.outputs = {}; this.promises = {}; this.count = 0; } getCacheKey(key, globs, options) { if (Array.isArray(globs)) { globs = globs.sort(); } return key + JSON.stringify(globs) + JSON.stringify(options); } // returns a promise search(key, globs, options = {}) { debug("Glob search (%o) searching for: %o", key, globs); if (!Array.isArray(globs)) { globs = [globs]; } // Strip leading slashes from everything! globs = globs.map((entry) => TemplatePath.stripLeadingDotSlash(entry)); let cwd = FileSystemRemap.getCwd(globs); if (cwd) { options.cwd = cwd; } if (options.ignore && Array.isArray(options.ignore)) { options.ignore = options.ignore.map((entry) => { entry = TemplatePath.stripLeadingDotSlash(entry); return FileSystemRemap.remapInput(entry, cwd); }); debug("Glob search (%o) ignoring: %o", key, options.ignore); } let cacheKey = this.getCacheKey(key, globs, options); // Only after the promise has resolved if (this.outputs[cacheKey]) { return Array.from(this.outputs[cacheKey]); } if (!this.promises[cacheKey]) { this.inputs[cacheKey] = { input: globs, options, }; this.count++; globs = globs.map((entry) => { if (cwd && entry.startsWith(cwd)) { return FileSystemRemap.remapInput(entry, cwd); } return entry; }); this.promises[cacheKey] = glob( globs, Object.assign( { caseSensitiveMatch: false, // insensitive dot: true, }, options, ), ).then((results) => { this.outputs[cacheKey] = new Set( results.map((entry) => { let remapped = FileSystemRemap.remapOutput(entry, options.cwd); return TemplatePath.standardizeFilePath(remapped); }), ); return Array.from(this.outputs[cacheKey]); }); } // may be an unresolved promise return this.promises[cacheKey]; } _modify(path, setOperation) { path = TemplatePath.stripLeadingDotSlash(path); let normalized = TemplatePath.standardizeFilePath(path); for (let key in this.inputs) { let { input, options } = this.inputs[key]; if ( isGlobMatch(path, input, { ignore: options.ignore, }) ) { this.outputs[key][setOperation](normalized); } } } add(path) { this._modify(path, "add"); } delete(path) { this._modify(path, "delete"); } // Issue #3859 get rid of chokidar globs // getAllOutputFiles() { // return Object.values(this.outputs).map(set => Array.from(set)).flat(); // } } export default FileSystemSearch;