summaryrefslogtreecommitdiff
path: root/node_modules/@11ty/eleventy/src/FileSystemSearch.js
blob: 972e80ba3d8196a067e53154117dc6861bd794ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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;