Files
fedilearns/node_modules/@11ty/eleventy/src/Util/TemplateDepGraph.js
2026-04-29 08:30:52 -07:00

161 lines
4.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { DepGraph as DependencyGraph } from "dependency-graph";
import debugUtil from "debug";
const debug = debugUtil("Eleventy:TemplateDepGraph");
const COLLECTION_PREFIX = "__collection:";
export class TemplateDepGraph extends DependencyGraph {
static STAGES = ["[basic]", "[userconfig]", "[keys]", "all"];
#configCollectionNames = new Set();
constructor() {
// BREAKING TODO move this back to non-circular with errors
super({ circular: true });
let previous;
// establish stage relationships, all uses keys, keys uses userconfig, userconfig uses tags
for (let stageName of TemplateDepGraph.STAGES.filter(Boolean).reverse()) {
let stageKey = `${COLLECTION_PREFIX}${stageName}`;
if (previous) {
this.uses(previous, stageKey);
}
previous = stageKey;
}
}
uses(from, to) {
this.addDependency(from, to);
}
addTag(tagName, type) {
if (
tagName === "all" ||
(tagName.startsWith("[") && tagName.endsWith("]")) ||
this.#configCollectionNames.has(tagName)
) {
return;
}
if (!type) {
throw new Error(
`Missing tag type for addTag. Expecting one of ${TemplateDepGraph.STAGES.map((entry) => entry.slice(1, -1)).join(" or ")}. Received: ${type}`,
);
}
debug("collection type %o uses tag %o", tagName, type);
this.uses(`${COLLECTION_PREFIX}[${type}]`, `${COLLECTION_PREFIX}${tagName}`);
}
addConfigCollectionName(collectionName) {
if (collectionName === "all") {
return;
}
this.#configCollectionNames.add(collectionName);
// Collection relationships to `[userconfig]` are added last, in unfilteredOrder()
}
cleanupCollectionNames(collectionNames = []) {
let s = new Set(collectionNames);
if (s.has("[userconfig]")) {
return collectionNames;
}
let hasAnyConfigCollections = collectionNames.find((name) => {
if (this.#configCollectionNames.has(name)) {
return true;
}
return false;
});
if (hasAnyConfigCollections) {
s.add("[userconfig]");
}
return Array.from(s);
}
addTemplate(filePath, consumes = [], publishesTo = []) {
// Move to the beginning if it doesnt consume anything
if (consumes.length === 0) {
this.uses(`${COLLECTION_PREFIX}[basic]`, filePath);
}
consumes = this.cleanupCollectionNames(consumes);
publishesTo = this.cleanupCollectionNames(publishesTo);
// Cant consume AND publish to `all` simultaneously
let consumesAll = consumes.includes("all");
if (consumesAll) {
publishesTo = publishesTo.filter((entry) => entry !== "all");
}
debug("%o consumes %o and publishes to %o", filePath, consumes, publishesTo);
for (let collectionName of publishesTo) {
if (!consumesAll) {
let tagType = "basic";
let consumesUserConfigCollection = consumes.includes("[userconfig]");
if (consumesUserConfigCollection) {
// must finish before [keys]
tagType = "keys";
}
this.addTag(collectionName, tagType);
}
this.uses(`${COLLECTION_PREFIX}${collectionName}`, filePath);
}
for (let collectionName of consumes) {
this.uses(filePath, `${COLLECTION_PREFIX}${collectionName}`);
let stageIndex = TemplateDepGraph.STAGES.indexOf(collectionName);
let nextStage = stageIndex > 0 ? TemplateDepGraph.STAGES[stageIndex + 1] : undefined;
if (nextStage) {
this.uses(`${COLLECTION_PREFIX}${nextStage}`, filePath);
}
}
}
addDependency(from, to) {
if (!this.hasNode(from)) {
this.addNode(from);
}
if (!this.hasNode(to)) {
this.addNode(to);
}
super.addDependency(from, to);
}
unfilteredOrder() {
// these need to be added last, after the template map has been added (see addConfigCollectionName)
for (let collectionName of this.#configCollectionNames) {
this.uses(`${COLLECTION_PREFIX}[keys]`, `${COLLECTION_PREFIX}${collectionName}`);
}
return super.overallOrder();
}
overallOrder() {
let unfiltered = this.unfilteredOrder();
let filtered = unfiltered.filter((entry) => {
if (entry === `${COLLECTION_PREFIX}[keys]`) {
return true;
}
return !entry.startsWith(`${COLLECTION_PREFIX}[`) && !entry.endsWith("]");
});
let allKey = `${COLLECTION_PREFIX}all`;
// Add another collections.all entry to the end (if not already the last one)
if (filtered[filtered.length - 1] !== allKey) {
filtered.push(allKey);
}
return filtered;
}
}