inital
This commit is contained in:
517
node_modules/@11ty/eleventy/src/EleventyFiles.js
generated
vendored
Normal file
517
node_modules/@11ty/eleventy/src/EleventyFiles.js
generated
vendored
Normal file
@@ -0,0 +1,517 @@
|
||||
import fs from "node:fs";
|
||||
|
||||
import { TemplatePath, isPlainObject } from "@11ty/eleventy-utils";
|
||||
import debugUtil from "debug";
|
||||
|
||||
import EleventyExtensionMap from "./EleventyExtensionMap.js";
|
||||
import TemplateData from "./Data/TemplateData.js";
|
||||
import TemplateGlob from "./TemplateGlob.js";
|
||||
import TemplatePassthroughManager from "./TemplatePassthroughManager.js";
|
||||
import EleventyBaseError from "./Errors/EleventyBaseError.js";
|
||||
import checkPassthroughCopyBehavior from "./Util/PassthroughCopyBehaviorCheck.js";
|
||||
|
||||
const debug = debugUtil("Eleventy:EleventyFiles");
|
||||
|
||||
class EleventyFilesError extends EleventyBaseError {}
|
||||
|
||||
class EleventyFiles {
|
||||
constructor(formats, eleventyConfig) {
|
||||
if (!eleventyConfig) {
|
||||
throw new EleventyFilesError("Missing `eleventyConfig`` argument.");
|
||||
}
|
||||
|
||||
this.eleventyConfig = eleventyConfig;
|
||||
this.config = eleventyConfig.getConfig();
|
||||
this.aggregateBench = this.config.benchmarkManager.get("Aggregate");
|
||||
|
||||
this.formats = formats;
|
||||
this.eleventyIgnoreContent = false;
|
||||
}
|
||||
|
||||
get dirs() {
|
||||
return this.eleventyConfig.directories;
|
||||
}
|
||||
|
||||
get inputDir() {
|
||||
return this.dirs.input;
|
||||
}
|
||||
|
||||
get outputDir() {
|
||||
return this.dirs.output;
|
||||
}
|
||||
|
||||
get includesDir() {
|
||||
return this.dirs.includes;
|
||||
}
|
||||
|
||||
get layoutsDir() {
|
||||
return this.dirs.layouts;
|
||||
}
|
||||
|
||||
get dataDir() {
|
||||
return this.dirs.data;
|
||||
}
|
||||
|
||||
// Backwards compat
|
||||
getDataDir() {
|
||||
return this.dataDir;
|
||||
}
|
||||
|
||||
setFileSystemSearch(fileSystemSearch) {
|
||||
this.fileSystemSearch = fileSystemSearch;
|
||||
}
|
||||
|
||||
init() {
|
||||
if (this.dirs.inputFile || this.dirs.inputGlob) {
|
||||
this.templateGlobs = TemplateGlob.map([this.dirs.inputFile || this.dirs.inputGlob]);
|
||||
} else {
|
||||
// Input is a directory
|
||||
this.templateGlobs = this.extensionMap.getGlobs(this.inputDir);
|
||||
}
|
||||
|
||||
this.initPassthroughManager();
|
||||
this.setupGlobs();
|
||||
}
|
||||
|
||||
get validTemplateGlobs() {
|
||||
if (!this._validTemplateGlobs) {
|
||||
let globs;
|
||||
// Input is a file
|
||||
if (this.inputFile) {
|
||||
globs = this.templateGlobs;
|
||||
} else {
|
||||
// input is a directory
|
||||
globs = this.extensionMap.getValidGlobs(this.inputDir);
|
||||
}
|
||||
this._validTemplateGlobs = globs;
|
||||
}
|
||||
return this._validTemplateGlobs;
|
||||
}
|
||||
|
||||
get passthroughGlobs() {
|
||||
let paths = new Set();
|
||||
// stuff added in addPassthroughCopy()
|
||||
for (let path of this.passthroughManager.getConfigPathGlobs()) {
|
||||
paths.add(path);
|
||||
}
|
||||
// non-template language extensions
|
||||
for (let path of this.extensionMap.getPassthroughCopyGlobs(this.inputDir)) {
|
||||
paths.add(path);
|
||||
}
|
||||
return Array.from(paths);
|
||||
}
|
||||
|
||||
restart() {
|
||||
this.passthroughManager.reset();
|
||||
this.setupGlobs();
|
||||
this._glob = null;
|
||||
}
|
||||
|
||||
/* For testing */
|
||||
_setConfig(config) {
|
||||
if (!config.ignores) {
|
||||
config.ignores = new Set();
|
||||
config.ignores.add("**/node_modules/**");
|
||||
}
|
||||
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/* Set command root for local project paths */
|
||||
// This is only used by tests
|
||||
_setLocalPathRoot(dir) {
|
||||
this.localPathRoot = dir;
|
||||
}
|
||||
|
||||
set extensionMap(extensionMap) {
|
||||
this._extensionMap = extensionMap;
|
||||
}
|
||||
|
||||
get extensionMap() {
|
||||
// for tests
|
||||
if (!this._extensionMap) {
|
||||
this._extensionMap = new EleventyExtensionMap(this.eleventyConfig);
|
||||
this._extensionMap.setFormats(this.formats);
|
||||
this._extensionMap.config = this.eleventyConfig;
|
||||
}
|
||||
return this._extensionMap;
|
||||
}
|
||||
|
||||
setRunMode(runMode) {
|
||||
this.runMode = runMode;
|
||||
}
|
||||
|
||||
initPassthroughManager() {
|
||||
let mgr = new TemplatePassthroughManager(this.eleventyConfig);
|
||||
mgr.setRunMode(this.runMode);
|
||||
mgr.extensionMap = this.extensionMap;
|
||||
mgr.setFileSystemSearch(this.fileSystemSearch);
|
||||
this.passthroughManager = mgr;
|
||||
}
|
||||
|
||||
getPassthroughManager() {
|
||||
return this.passthroughManager;
|
||||
}
|
||||
|
||||
setPassthroughManager(mgr) {
|
||||
mgr.extensionMap = this.extensionMap;
|
||||
this.passthroughManager = mgr;
|
||||
}
|
||||
|
||||
set templateData(templateData) {
|
||||
this._templateData = templateData;
|
||||
}
|
||||
|
||||
get templateData() {
|
||||
if (!this._templateData) {
|
||||
this._templateData = new TemplateData(this.eleventyConfig);
|
||||
}
|
||||
|
||||
return this._templateData;
|
||||
}
|
||||
|
||||
setupGlobs() {
|
||||
this.fileIgnores = this.getIgnores();
|
||||
this.extraIgnores = this._getIncludesAndDataDirs();
|
||||
this.uniqueIgnores = this.getIgnoreGlobs();
|
||||
|
||||
// Conditional added for tests that don’t have a config
|
||||
if (this.config?.events) {
|
||||
this.config.events.emit("eleventy.ignores", this.uniqueIgnores);
|
||||
}
|
||||
|
||||
this.normalizedTemplateGlobs = this.templateGlobs;
|
||||
}
|
||||
|
||||
getIgnoreGlobs() {
|
||||
let uniqueIgnores = new Set();
|
||||
for (let ignore of this.fileIgnores) {
|
||||
uniqueIgnores.add(ignore);
|
||||
}
|
||||
for (let ignore of this.extraIgnores) {
|
||||
uniqueIgnores.add(ignore);
|
||||
}
|
||||
// Placing the config ignores last here is important to the tests
|
||||
for (let ignore of this.config.ignores) {
|
||||
uniqueIgnores.add(TemplateGlob.normalizePath(this.localPathRoot || ".", ignore));
|
||||
}
|
||||
return Array.from(uniqueIgnores);
|
||||
}
|
||||
|
||||
static getFileIgnores(ignoreFiles) {
|
||||
if (!Array.isArray(ignoreFiles)) {
|
||||
ignoreFiles = [ignoreFiles];
|
||||
}
|
||||
|
||||
let ignores = [];
|
||||
for (let ignorePath of ignoreFiles) {
|
||||
ignorePath = TemplatePath.normalize(ignorePath);
|
||||
|
||||
let dir = TemplatePath.getDirFromFilePath(ignorePath);
|
||||
|
||||
if (fs.existsSync(ignorePath) && fs.statSync(ignorePath).size > 0) {
|
||||
let ignoreContent = fs.readFileSync(ignorePath, "utf8");
|
||||
|
||||
ignores = ignores.concat(EleventyFiles.normalizeIgnoreContent(dir, ignoreContent));
|
||||
}
|
||||
}
|
||||
|
||||
ignores.forEach((path) => debug(`${ignoreFiles} ignoring: ${path}`));
|
||||
|
||||
return ignores;
|
||||
}
|
||||
|
||||
static normalizeIgnoreContent(dir, ignoreContent) {
|
||||
let ignores = [];
|
||||
|
||||
if (ignoreContent) {
|
||||
ignores = ignoreContent
|
||||
.split("\n")
|
||||
.map((line) => {
|
||||
return line.trim();
|
||||
})
|
||||
.filter((line) => {
|
||||
if (line.charAt(0) === "!") {
|
||||
debug(
|
||||
">>> When processing .gitignore/.eleventyignore, Eleventy does not currently support negative patterns but encountered one:",
|
||||
);
|
||||
debug(">>>", line);
|
||||
debug("Follow along at https://github.com/11ty/eleventy/issues/693 to track support.");
|
||||
}
|
||||
|
||||
// empty lines or comments get filtered out
|
||||
return line.length > 0 && line.charAt(0) !== "#" && line.charAt(0) !== "!";
|
||||
})
|
||||
.map((line) => {
|
||||
let path = TemplateGlob.normalizePath(dir, "/", line);
|
||||
path = TemplatePath.addLeadingDotSlash(TemplatePath.relativePath(path));
|
||||
|
||||
try {
|
||||
// Note these folders must exist to get /** suffix
|
||||
let stat = fs.statSync(path);
|
||||
if (stat.isDirectory()) {
|
||||
return path + "/**";
|
||||
}
|
||||
return path;
|
||||
} catch (e) {
|
||||
return path;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return ignores;
|
||||
}
|
||||
|
||||
setEleventyIgnoreContent(content) {
|
||||
this.eleventyIgnoreContent = content;
|
||||
}
|
||||
|
||||
getIgnores() {
|
||||
let files = new Set();
|
||||
|
||||
for (let ignore of EleventyFiles.getFileIgnores(this.getIgnoreFiles())) {
|
||||
files.add(ignore);
|
||||
}
|
||||
|
||||
// testing API
|
||||
if (this.eleventyIgnoreContent !== false) {
|
||||
files.add(this.eleventyIgnoreContent);
|
||||
}
|
||||
|
||||
// ignore output dir (unless this excludes all input)
|
||||
// input: . and output: . (skip)
|
||||
// input: ./content and output . (skip)
|
||||
// input: . and output: ./_site (add)
|
||||
if (!this.inputDir.startsWith(this.outputDir)) {
|
||||
// both are already normalized in 3.0
|
||||
files.add(TemplateGlob.map(this.outputDir + "/**"));
|
||||
}
|
||||
|
||||
return Array.from(files);
|
||||
}
|
||||
|
||||
getIgnoreFiles() {
|
||||
let ignoreFiles = new Set();
|
||||
let rootDirectory = this.localPathRoot || ".";
|
||||
|
||||
if (this.config.useGitIgnore) {
|
||||
ignoreFiles.add(TemplatePath.join(rootDirectory, ".gitignore"));
|
||||
}
|
||||
|
||||
if (this.eleventyIgnoreContent === false) {
|
||||
let absoluteInputDir = TemplatePath.absolutePath(this.inputDir);
|
||||
ignoreFiles.add(TemplatePath.join(rootDirectory, ".eleventyignore"));
|
||||
if (rootDirectory !== absoluteInputDir) {
|
||||
ignoreFiles.add(TemplatePath.join(this.inputDir, ".eleventyignore"));
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(ignoreFiles);
|
||||
}
|
||||
|
||||
/* Backwards compat */
|
||||
getIncludesDir() {
|
||||
return this.includesDir;
|
||||
}
|
||||
|
||||
/* Backwards compat */
|
||||
getLayoutsDir() {
|
||||
return this.layoutsDir;
|
||||
}
|
||||
|
||||
getFileGlobs() {
|
||||
return this.normalizedTemplateGlobs;
|
||||
}
|
||||
|
||||
getRawFiles() {
|
||||
return this.templateGlobs;
|
||||
}
|
||||
|
||||
async getWatchPathCache() {
|
||||
// Issue #1325: make sure passthrough copy files are not included here
|
||||
if (!this.pathCache) {
|
||||
throw new Error("Watching requires `.getFiles()` to be called first in EleventyFiles");
|
||||
}
|
||||
|
||||
let ret = [];
|
||||
// Filter out the passthrough copy paths.
|
||||
for (let path of this.pathCache) {
|
||||
if (
|
||||
this.extensionMap.isFullTemplateFilePath(path) &&
|
||||
(await this.extensionMap.shouldSpiderJavaScriptDependencies(path))
|
||||
) {
|
||||
ret.push(path);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
_globSearch() {
|
||||
let globs = this.getFileGlobs();
|
||||
|
||||
// returns a promise
|
||||
debug("Searching for: %o", globs);
|
||||
return this.fileSystemSearch.search("templates", globs, {
|
||||
ignore: this.uniqueIgnores,
|
||||
});
|
||||
}
|
||||
|
||||
getPathsWithVirtualTemplates(paths) {
|
||||
// Support for virtual templates added in 3.0
|
||||
if (this.config.virtualTemplates && isPlainObject(this.config.virtualTemplates)) {
|
||||
let virtualTemplates = Object.keys(this.config.virtualTemplates)
|
||||
.filter((path) => {
|
||||
// Filter out includes/layouts
|
||||
return this.dirs.isTemplateFile(path);
|
||||
})
|
||||
.map((path) => {
|
||||
let fullVirtualPath = this.dirs.getInputPath(path);
|
||||
if (!this.extensionMap.getKey(fullVirtualPath)) {
|
||||
this.eleventyConfig.logger.warn(
|
||||
`The virtual template at ${fullVirtualPath} is using a template format that’s not valid for your project. Your project is using: "${this.formats}". Read more about formats: https://v3.11ty.dev/docs/config/#template-formats`,
|
||||
);
|
||||
}
|
||||
return fullVirtualPath;
|
||||
});
|
||||
|
||||
paths = paths.concat(virtualTemplates);
|
||||
|
||||
// Virtual templates can not live at the same place as files on the file system!
|
||||
if (paths.length !== new Set(paths).size) {
|
||||
let conflicts = {};
|
||||
for (let path of paths) {
|
||||
if (conflicts[path]) {
|
||||
throw new Error(
|
||||
`A virtual template had the same path as a file on the file system: "${path}"`,
|
||||
);
|
||||
}
|
||||
|
||||
conflicts[path] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
async getFiles() {
|
||||
let bench = this.aggregateBench.get("Searching the file system (templates)");
|
||||
bench.before();
|
||||
let globResults = await this._globSearch();
|
||||
let paths = TemplatePath.addLeadingDotSlashArray(globResults);
|
||||
bench.after();
|
||||
|
||||
// Note 2.0.0-canary.19 removed a `filter` option for custom template syntax here that was unpublished and unused.
|
||||
|
||||
paths = this.getPathsWithVirtualTemplates(paths);
|
||||
|
||||
this.pathCache = paths;
|
||||
return paths;
|
||||
}
|
||||
|
||||
getFileShape(paths, filePath) {
|
||||
if (!filePath) {
|
||||
return;
|
||||
}
|
||||
if (this.isPassthroughCopyFile(paths, filePath)) {
|
||||
return "copy";
|
||||
}
|
||||
if (this.isFullTemplateFile(paths, filePath)) {
|
||||
return "template";
|
||||
}
|
||||
// include/layout/unknown
|
||||
}
|
||||
|
||||
isPassthroughCopyFile(paths, filePath) {
|
||||
return this.passthroughManager.isPassthroughCopyFile(paths, filePath);
|
||||
}
|
||||
|
||||
// Assumption here that filePath is not a passthrough copy file
|
||||
isFullTemplateFile(paths, filePath) {
|
||||
if (!filePath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let path of paths) {
|
||||
if (path === filePath) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* For `eleventy --watch` */
|
||||
getGlobWatcherFiles() {
|
||||
// TODO improvement: tie the includes and data to specific file extensions (currently using `**`)
|
||||
let directoryGlobs = this._getIncludesAndDataDirs();
|
||||
|
||||
if (checkPassthroughCopyBehavior(this.config, this.runMode)) {
|
||||
return this.validTemplateGlobs.concat(directoryGlobs);
|
||||
}
|
||||
|
||||
// Revert to old passthroughcopy copy files behavior
|
||||
return this.validTemplateGlobs.concat(this.passthroughGlobs).concat(directoryGlobs);
|
||||
}
|
||||
|
||||
/* For `eleventy --watch` */
|
||||
getGlobWatcherFilesForPassthroughCopy() {
|
||||
return this.passthroughGlobs;
|
||||
}
|
||||
|
||||
/* For `eleventy --watch` */
|
||||
async getGlobWatcherTemplateDataFiles() {
|
||||
let templateData = this.templateData;
|
||||
return await templateData.getTemplateDataFileGlob();
|
||||
}
|
||||
|
||||
/* For `eleventy --watch` */
|
||||
// TODO this isn’t great but reduces complexity avoiding using TemplateData:getLocalDataPaths for each template in the cache
|
||||
async getWatcherTemplateJavaScriptDataFiles() {
|
||||
let globs = this.templateData.getTemplateJavaScriptDataFileGlob();
|
||||
let bench = this.aggregateBench.get("Searching the file system (watching)");
|
||||
bench.before();
|
||||
let results = TemplatePath.addLeadingDotSlashArray(
|
||||
await this.fileSystemSearch.search("js-dependencies", globs, {
|
||||
ignore: ["**/node_modules/**"],
|
||||
}),
|
||||
);
|
||||
bench.after();
|
||||
return results;
|
||||
}
|
||||
|
||||
/* Ignored by `eleventy --watch` */
|
||||
getGlobWatcherIgnores() {
|
||||
// convert to format without ! since they are passed in as a separate argument to glob watcher
|
||||
let entries = new Set(
|
||||
this.fileIgnores.map((ignore) => TemplatePath.stripLeadingDotSlash(ignore)),
|
||||
);
|
||||
|
||||
for (let ignore of this.config.watchIgnores) {
|
||||
entries.add(TemplateGlob.normalizePath(this.localPathRoot || ".", ignore));
|
||||
}
|
||||
|
||||
// de-duplicated
|
||||
return Array.from(entries);
|
||||
}
|
||||
|
||||
_getIncludesAndDataDirs() {
|
||||
let rawPaths = new Set();
|
||||
rawPaths.add(this.includesDir);
|
||||
if (this.layoutsDir) {
|
||||
rawPaths.add(this.layoutsDir);
|
||||
}
|
||||
rawPaths.add(this.dataDir);
|
||||
|
||||
return Array.from(rawPaths)
|
||||
.filter((entry) => {
|
||||
// never ignore the input directory (even if config file returns "" for these)
|
||||
return entry && entry !== this.inputDir;
|
||||
})
|
||||
.map((entry) => {
|
||||
return TemplateGlob.map(entry + "**");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default EleventyFiles;
|
Reference in New Issue
Block a user