🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@11ty/eleventy

Package Overview
Dependencies
Maintainers
2
Versions
218
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@11ty/eleventy - npm Package Compare versions

Comparing version
4.0.0-alpha.3
to
4.0.0-alpha.4
+128
src/Watch.js
import debugUtil from "debug";
import { TemplatePath } from "@11ty/eleventy-utils";
import chokidar from "chokidar";
import { isGlobMatch } from "./Util/GlobMatcher.js";
import { GlobStripper } from "./Util/GlobStripper.js";
const debug = debugUtil("Eleventy:Watch");
export class Watch {
/** @type {module:chokidar} */
#chokidar;
/** @type {Set} */
#watchedGlobs = [];
/** @type {Set} */
#ignoredGlobs = [];
constructor(config) {
if (!config || config.constructor.name !== "TemplateConfig") {
throw new Error("Internal error: Missing or invalid `config` argument.");
}
this.templateConfig = config;
}
getChokidarConfig() {
let options = Object.assign(
{
ignoreInitial: true,
awaitWriteFinish: {
stabilityThreshold: 150,
pollInterval: 25,
},
},
this.templateConfig.userConfig.chokidarConfig,
);
// unsupported: using your own `ignored`
if (options.ignored) {
delete options.ignored;
}
return options;
}
// alias for watchTargets() (backwards compat)
add(targets = []) {
this.watchTargets(targets);
}
watchTargets(targets = []) {
let uniqueSet = new Set();
for (let target of targets) {
this.#watchedGlobs.push(TemplatePath.stripLeadingDotSlash(target));
// strip globs off of target, chokidar@4
let { path } = GlobStripper.parse(target);
if (path) {
uniqueSet.add(path);
}
}
this.#chokidar?.add(Array.from(uniqueSet));
}
addIgnores(ignores) {
for (let target of ignores) {
this.#ignoredGlobs.push(target);
}
}
#isDirectory(path) {
return this.templateConfig.existsCache.isDirectory(path);
}
async start() {
let options = this.getChokidarConfig();
options.ignored = (filepath) => {
// don’t ignore root (if specified)
if (filepath === ".") {
return false;
}
if (this.#ignoredGlobs.length > 0 && isGlobMatch(filepath, this.#ignoredGlobs)) {
debug("Ignore file (ignore globs)", filepath);
return true;
}
// don’t ignore directories that are not in ignores
if (this.#isDirectory(filepath)) {
return false;
}
// make sure this matches at least one of the original globs
if (this.#watchedGlobs.length === 0 || !isGlobMatch(filepath, this.#watchedGlobs)) {
debug("Ignore file (no glob match)", filepath, this.#watchedGlobs);
return true;
}
return false;
};
// strip globs off of target, chokidar@4
let targets = this.#watchedGlobs
.map((target) => {
let { path } = GlobStripper.parse(target);
return path;
})
.filter(Boolean);
this.#chokidar = chokidar.watch(targets, options);
// Note: if there are no watch targets the `ready` event doesn’t fire so skip it
if (targets.length > 0) {
await new Promise((resolve) => {
this.#chokidar.on("ready", () => resolve());
});
}
}
on(event, callback) {
this.#chokidar.on(event, callback);
}
async close() {
return this.#chokidar?.close();
}
}
import { TemplatePath } from "@11ty/eleventy-utils";
import PathNormalizer from "./Util/PathNormalizer.js";
/* Decides when to watch and in what mode to watch
* Incremental builds don’t batch changes, they queue.
* Nonincremental builds batch.
*/
class WatchQueue {
constructor() {
this.incremental = false;
this.isActive = false;
this.activeQueue = [];
}
isBuildRunning() {
return this.isActive;
}
setBuildRunning() {
this.isActive = true;
// pop waiting queue into the active queue
this.activeQueue = this.popNextActiveQueue();
}
setBuildFinished() {
this.isActive = false;
this.activeQueue = [];
}
getIncrementalFile() {
if (this.incremental) {
return this.activeQueue.length ? this.activeQueue[0] : false;
}
return false;
}
/* Returns the changed files currently being operated on in the current `watch` build
* Works with or without incremental (though in incremental only one file per time will be processed)
*/
getActiveQueue() {
if (!this.isActive) {
return [];
} else if (this.incremental && this.activeQueue.length === 0) {
return [];
} else if (this.incremental) {
return [this.activeQueue[0]];
}
return this.activeQueue;
}
_queueMatches(file) {
let filterCallback;
if (typeof file === "function") {
filterCallback = file;
} else {
filterCallback = (path) => path === file;
}
return this.activeQueue.filter(filterCallback);
}
hasAllQueueFiles(file) {
return (
this.activeQueue.length > 0 && this.activeQueue.length === this._queueMatches(file).length
);
}
hasQueuedFile(file) {
if (file) {
return this._queueMatches(file).length > 0;
}
return false;
}
hasQueuedFiles(files) {
for (const file of files) {
if (this.hasQueuedFile(file)) {
return true;
}
}
return false;
}
get pendingQueue() {
if (!this._queue) {
this._queue = [];
}
return this._queue;
}
set pendingQueue(value) {
this._queue = value;
}
addToPendingQueue(path) {
if (path) {
path = PathNormalizer.normalizeSeperator(TemplatePath.addLeadingDotSlash(path));
this.pendingQueue.push(path);
}
}
getPendingQueueSize() {
return this.pendingQueue.length;
}
getPendingQueue() {
return this.pendingQueue;
}
getActiveQueueSize() {
return this.activeQueue.length;
}
// returns array
popNextActiveQueue() {
if (this.incremental) {
return this.pendingQueue.length ? [this.pendingQueue.shift()] : [];
}
let ret = this.pendingQueue.slice();
this.pendingQueue = [];
return ret;
}
}
export default WatchQueue;
import { TemplatePath } from "@11ty/eleventy-utils";
import { DepGraph } from "dependency-graph";
import JavaScriptDependencies from "./Util/JavaScriptDependencies.js";
import eventBus from "./EventBus.js";
export default class WatchTargets {
#templateConfig;
constructor(templateConfig) {
this.targets = new Set();
this.dependencies = new Set();
this.newTargets = new Set();
this.isEsm = false;
this.graph = new DepGraph();
this.#templateConfig = templateConfig;
}
setProjectUsingEsm(isEsmProject) {
this.isEsm = !!isEsmProject;
}
isJavaScriptDependency(path) {
return this.dependencies.has(path);
}
reset() {
this.newTargets = new Set();
}
addToDependencyGraph(parent, deps) {
if (!this.graph.hasNode(parent)) {
this.graph.addNode(parent);
}
for (let dep of deps) {
if (!this.graph.hasNode(dep)) {
this.graph.addNode(dep);
}
this.graph.addDependency(parent, dep);
}
}
uses(parent, dep) {
return this.getDependenciesOf(parent).includes(dep);
}
getDependenciesOf(parent) {
if (!this.graph.hasNode(parent)) {
return [];
}
return this.graph.dependenciesOf(parent);
}
getDependantsOf(child) {
if (!this.graph.hasNode(child)) {
return [];
}
return this.graph.dependantsOf(child);
}
addRaw(targets, isDependency) {
for (let target of targets) {
let path = TemplatePath.addLeadingDotSlash(target);
if (!this.targets.has(target)) {
this.newTargets.add(path);
}
this.targets.add(path);
if (isDependency) {
this.dependencies.add(path);
}
}
}
static normalize(targets) {
if (!targets) {
return [];
} else if (Array.isArray(targets)) {
return targets;
}
return [targets];
}
// add only a target
add(targets) {
this.addRaw(WatchTargets.normalize(targets));
}
static normalizeToGlobs(targets) {
return WatchTargets.normalize(targets).map((entry) =>
TemplatePath.convertToRecursiveGlobSync(entry),
);
}
// add only a target’s dependencies
async addDependencies(targets, filterCallback) {
if (this.#templateConfig && !this.#templateConfig.shouldSpiderJavaScriptDependencies()) {
return;
}
targets = WatchTargets.normalize(targets);
let deps = await JavaScriptDependencies.getDependencies(targets, this.isEsm);
if (filterCallback) {
deps = deps.filter(filterCallback);
}
for (let target of targets) {
this.addToDependencyGraph(target, deps);
}
this.addRaw(deps, true);
}
setWriter(templateWriter) {
this.writer = templateWriter;
}
clearImportCacheFor(filePathArray) {
let paths = new Set();
for (const filePath of filePathArray) {
paths.add(filePath);
// Delete from require cache so that updates to the module are re-required
let importsTheChangedFile = this.getDependantsOf(filePath);
for (let dep of importsTheChangedFile) {
paths.add(dep);
}
let isImportedInTheChangedFile = this.getDependenciesOf(filePath);
for (let dep of isImportedInTheChangedFile) {
paths.add(dep);
}
// Use GlobalDependencyMap
if (this.#templateConfig) {
for (let dep of this.#templateConfig.usesGraph.getDependantsFor(filePath)) {
paths.add(dep);
}
}
}
eventBus.emit("eleventy.importCacheReset", paths);
}
getNewTargetsSinceLastReset() {
return Array.from(this.newTargets);
}
getTargets() {
return Array.from(this.targets);
}
}
+4
-4
{
"name": "@11ty/eleventy",
"version": "4.0.0-alpha.3",
"version": "4.0.0-alpha.4",
"description": "A simpler static site generator.",

@@ -127,5 +127,5 @@ "publishConfig": {

"sass": "^1.89.2",
"simple-git-hooks": "^2.13.0",
"simple-git-hooks": "^2.13.1",
"tsx": "^4.20.3",
"typescript": "^5.8.3",
"typescript": "^5.9.2",
"vue": "^3.5.18",

@@ -138,3 +138,3 @@ "zod": "^3.25.76",

"@11ty/dependency-tree-esm": "^2.0.0",
"@11ty/eleventy-dev-server": "3.0.0-alpha.2",
"@11ty/eleventy-dev-server": "3.0.0-alpha.3",
"@11ty/eleventy-plugin-bundle": "^3.0.6",

@@ -141,0 +141,0 @@ "@11ty/eleventy-utils": "^2.0.7",

@@ -794,3 +794,3 @@ import debugUtil from "debug";

let incrementalFile =
this.programmaticApiIncrementalFile || this.watchManager?.getIncrementalFile();
this.programmaticApiIncrementalFile || this.watchQueue?.getIncrementalFile();
if (incrementalFile) {

@@ -797,0 +797,0 @@ this.writer.setIncrementalFile(incrementalFile);

@@ -8,4 +8,5 @@ import { relative } from "node:path";

import EleventyServe from "./EleventyServe.js";
import EleventyWatch from "./EleventyWatch.js";
import WatchTargets from "./EleventyWatchTargets.js";
import { Watch } from "./Watch.js";
import WatchQueue from "./WatchQueue.js";
import WatchTargets from "./WatchTargets.js";
import EleventyBaseError from "./Errors/EleventyBaseError.js";

@@ -20,3 +21,2 @@

import { withResolvers } from "./Util/PromiseUtil.js";
import GlobRemap from "./Util/GlobRemap.js";

@@ -29,8 +29,5 @@ const debug = debugUtil("Eleventy");

/** @type {module:chokidar} */
#chokidar;
/** @type {WatchQueue} */
#watchQueue;
/** @type {EleventyWatch} */
#watchManager;
// constructor(input, output, options = {}, eleventyConfig = null) {

@@ -48,13 +45,13 @@ // super(input, output, options, eleventyConfig);

if (this.#watchManager) {
this.watchManager.incremental = !!isIncremental;
if (this.#watchQueue) {
this.watchQueue.incremental = !!isIncremental;
}
}
get watchManager() {
if (!this.#watchManager) {
this.#watchManager = new EleventyWatch();
this.#watchManager.incremental = this.isIncremental;
get watchQueue() {
if (!this.#watchQueue) {
this.#watchQueue = new WatchQueue();
this.#watchQueue.incremental = this.isIncremental;
}
return this.#watchManager;
return this.#watchQueue;
}

@@ -132,3 +129,3 @@

this.watchManager.addToPendingQueue(changedFilePath);
this.watchQueue.addToPendingQueue(changedFilePath);
}

@@ -181,9 +178,9 @@

async #rewatch(isResetConfig = false) {
if (this.watchManager.isBuildRunning()) {
if (this.watchQueue.isBuildRunning()) {
return;
}
this.watchManager.setBuildRunning();
this.watchQueue.setBuildRunning();
let queue = this.watchManager.getActiveQueue();
let queue = this.watchQueue.getActiveQueue();

@@ -220,3 +217,3 @@ await this.config.events.emit("beforeWatch", queue);

let newWatchTargets = this.watchTargets.getNewTargetsSinceLastReset();
this.watcher.add(newWatchTargets);
this.watcher.watchTargets(newWatchTargets);

@@ -226,3 +223,3 @@ // Is a CSS input file and is not in the includes folder

// TODO add additional API for this, maybe a config callback?
let onlyCssChanges = this.watchManager.hasAllQueueFiles((path) => {
let onlyCssChanges = this.watchQueue.hasAllQueueFiles((path) => {
return (

@@ -235,3 +232,3 @@ path.endsWith(".css") &&

let files = this.watchManager.getActiveQueue();
let files = this.watchQueue.getActiveQueue();

@@ -278,5 +275,5 @@ // Maps passthrough copy files to output URLs for CSS live reload

this.watchManager.setBuildFinished();
this.watchQueue.setBuildFinished();
let queueSize = this.watchManager.getPendingQueueSize();
let queueSize = this.watchQueue.getPendingQueueSize();
if (queueSize > 0) {

@@ -299,16 +296,2 @@ this.logger.log(

get chokidar() {
if (!this.#chokidar) {
// We use a string module name and try/catch here to hide this from the zisi and esbuild serverless bundlers
// eslint-disable-next-line no-useless-catch
try {
let moduleName = "chokidar";
this.#chokidar = import(moduleName).then((mod) => mod.default);
} catch (e) {
throw e;
}
}
return this.#chokidar;
}
/**

@@ -340,36 +323,19 @@ * Set up watchers and benchmarks.

// setup chokidar instance
let promises = [];
promises.push(this.chokidar);
// Close previous watcher
if (this.watcher) {
// Close previous watcher
promises.push(this.watcher.close());
await this.watcher.close();
}
// TODO improve unwatching if JS dependencies are removed (or files are deleted)
let { targets, cwd, ignores } = await this.getWatchedTargets();
let { targets, ignores } = await this.getWatchedTargets();
debug("Watching for changes to: %o", targets);
let options = this.getChokidarConfig();
this.watcher = new Watch(this.eleventyConfig);
this.watcher.watchTargets(targets);
this.watcher.addIgnores(ignores);
if (cwd) {
options.cwd = cwd;
}
await this.watcher.start();
debug("Ignoring watcher changes to: %o", ignores);
this.logger.forceLog("Watching…");
options.alwaysStat = true;
options.ignored = (path, stats) => {
if (stats?.isFile()) {
let isMatch = this.watchTargets.isWatchMatch(path, ignores);
if (!isMatch) {
return true;
}
}
};
let [chokidar] = await Promise.all(promises);
this.watcher = chokidar.watch(targets, options);
let watchDelay;

@@ -394,3 +360,3 @@ let watchRun = async (path) => {

this.errorHandler.error(e, "Eleventy watch error");
this.watchManager.setBuildFinished();
this.watchQueue.setBuildFinished();
} else {

@@ -439,8 +405,2 @@ this.errorHandler.fatal(e, "Eleventy fatal watch error");

// wait for chokidar to be ready.
await new Promise((resolve) => {
this.watcher.on("ready", () => resolve());
});
this.logger.forceLog("Watching…");
// For testability

@@ -491,52 +451,11 @@ return watchRun;

* @method
* @returns {Object} containing `cwd` string, `targets` file paths, and `ignores` globs Array
* @returns {Object} `targets` file paths, and `ignores` globs Array
*/
async getWatchedTargets() {
let rawWatchedGlobs = await this.watchTargets.getTargets();
let ignores = this.eleventyFiles.getGlobWatcherIgnores();
// Remap all paths to `cwd` if in play (Issue #3854)
// This is likely unnecessary since #3854 was for tinyglobby it’s probably better to have a cwd
// anyway to have nice paths passed into chokidar events
let remapper = new GlobRemap(rawWatchedGlobs);
let cwd = remapper.getCwd();
if (cwd) {
rawWatchedGlobs = remapper.getInput().map((entry) => {
return TemplatePath.stripLeadingDotSlash(entry);
});
ignores = remapper.getRemapped(ignores || []);
}
ignores = ignores.map((entry) => {
return TemplatePath.stripLeadingDotSlash(entry);
});
debug("Ignoring watcher changes to: %o", ignores);
return {
cwd,
targets: rawWatchedGlobs,
ignores,
targets: await this.watchTargets.getTargets(),
ignores: this.eleventyFiles.getGlobWatcherIgnores(),
};
}
getChokidarConfig() {
let configOptions = this.config.chokidarConfig;
// unsupported: using your own `ignored`
delete configOptions.ignored;
return Object.assign(
{
ignoreInitial: true,
awaitWriteFinish: {
stabilityThreshold: 150,
pollInterval: 25,
},
},
configOptions,
);
}
/**

@@ -543,0 +462,0 @@ * Start watching files

import debugUtil from "debug";
import { Merge, TemplatePath } from "@11ty/eleventy-utils";
import { GlobStripper } from "./Util/GlobStripper.js";
import { Watch } from "./Watch.js";

@@ -42,7 +42,5 @@ function stringifyOptions(options) {

#initOptionsFetched = false;
#chokidar;
// these are *not* normalized
#watchTargets = new Set();
// these *are* normalized
#queuedWatchTargets = new Set();
#defaultWatchIgnores = ["**/node_modules/**", ".git"];

@@ -207,16 +205,13 @@ constructor() {

// Fix for missing globs in Chokidar@4
if (this.options.module === DEFAULT_SERVER_OPTIONS.module) {
this.options.chokidarOptions ??= {};
((this.options.chokidarOptions.alwaysStat = true),
(this.options.chokidarOptions.ignored = (filepath, stats) => {
if (stats?.isFile()) {
if (
!isGlobMatch(filepath, Array.from(this.#watchTargets)) ||
isGlobMatch(filepath, this.#defaultWatchIgnores)
) {
return true;
}
}
}));
// Fix for missing globs in Chokidar@4
let copyWatch = new Watch(this.eleventyConfig);
copyWatch.watchTargets(this.#watchTargets);
// Careful with ignores here: https://github.com/11ty/eleventy/issues/1134
// copyWatch.addIgnores();
await copyWatch.start();
this.#chokidar = copyWatch;
this.options.chokidar = copyWatch;
}

@@ -228,6 +223,2 @@

this.setAliases(this.#aliases);
if (this.#queuedWatchTargets.size > 0) {
this.#watch(this.#watchTargets);
}
}

@@ -304,3 +295,2 @@

this.#watchTargets = new Set();
this.#queuedWatchTargets = new Set();
}

@@ -319,40 +309,4 @@

await this.serve(this._commandLinePort);
// rewatch the saved watched files (passthrough copy)
this.#watch(this.#watchTargets);
}
queueWatchTargets(globs = []) {
for (let glob of globs) {
this.#queuedWatchTargets.add(glob);
}
}
unqueueWatchTargets(globs = []) {
for (let glob of globs) {
this.#queuedWatchTargets.delete(glob);
}
}
#watch(globs = []) {
let normalizedGlobs = Array.from(globs)
.map((target) => {
let { path } = GlobStripper.parse(target);
if (path && path !== ".") {
return path;
}
})
.filter(Boolean);
if (normalizedGlobs.length > 0) {
if (this._server && "watchFiles" in this.server) {
this.server.watchFiles(normalizedGlobs);
this.unqueueWatchTargets(normalizedGlobs);
} else {
// server not yet available
this.queueWatchTargets(normalizedGlobs);
}
}
}
// checkPassthroughCopyBehavior check is called upstream in Eleventy.js

@@ -363,3 +317,7 @@ watchPassthroughCopy(globs = []) {

}
this.#watch(this.#watchTargets);
// if the watcher has already started, add the targets
if (this.#chokidar) {
this.#chokidar.watchTargets(globs);
}
}

@@ -366,0 +324,0 @@

import { TemplatePath } from "@11ty/eleventy-utils";
import PathNormalizer from "./Util/PathNormalizer.js";
/* Decides when to watch and in what mode to watch
* Incremental builds don’t batch changes, they queue.
* Nonincremental builds batch.
*/
class EleventyWatch {
constructor() {
this.incremental = false;
this.isActive = false;
this.activeQueue = [];
}
isBuildRunning() {
return this.isActive;
}
setBuildRunning() {
this.isActive = true;
// pop waiting queue into the active queue
this.activeQueue = this.popNextActiveQueue();
}
setBuildFinished() {
this.isActive = false;
this.activeQueue = [];
}
getIncrementalFile() {
if (this.incremental) {
return this.activeQueue.length ? this.activeQueue[0] : false;
}
return false;
}
/* Returns the changed files currently being operated on in the current `watch` build
* Works with or without incremental (though in incremental only one file per time will be processed)
*/
getActiveQueue() {
if (!this.isActive) {
return [];
} else if (this.incremental && this.activeQueue.length === 0) {
return [];
} else if (this.incremental) {
return [this.activeQueue[0]];
}
return this.activeQueue;
}
_queueMatches(file) {
let filterCallback;
if (typeof file === "function") {
filterCallback = file;
} else {
filterCallback = (path) => path === file;
}
return this.activeQueue.filter(filterCallback);
}
hasAllQueueFiles(file) {
return (
this.activeQueue.length > 0 && this.activeQueue.length === this._queueMatches(file).length
);
}
hasQueuedFile(file) {
if (file) {
return this._queueMatches(file).length > 0;
}
return false;
}
hasQueuedFiles(files) {
for (const file of files) {
if (this.hasQueuedFile(file)) {
return true;
}
}
return false;
}
get pendingQueue() {
if (!this._queue) {
this._queue = [];
}
return this._queue;
}
set pendingQueue(value) {
this._queue = value;
}
addToPendingQueue(path) {
if (path) {
path = PathNormalizer.normalizeSeperator(TemplatePath.addLeadingDotSlash(path));
this.pendingQueue.push(path);
}
}
getPendingQueueSize() {
return this.pendingQueue.length;
}
getPendingQueue() {
return this.pendingQueue;
}
getActiveQueueSize() {
return this.activeQueue.length;
}
// returns array
popNextActiveQueue() {
if (this.incremental) {
return this.pendingQueue.length ? [this.pendingQueue.shift()] : [];
}
let ret = this.pendingQueue.slice();
this.pendingQueue = [];
return ret;
}
}
export default EleventyWatch;
import { TemplatePath } from "@11ty/eleventy-utils";
import { DepGraph } from "dependency-graph";
import { isGlobMatch } from "./Util/GlobMatcher.js";
import { GlobStripper } from "./Util/GlobStripper.js";
import JavaScriptDependencies from "./Util/JavaScriptDependencies.js";
import eventBus from "./EventBus.js";
export default class WatchTargets {
#templateConfig;
constructor(templateConfig) {
this.targets = new Set();
this.dependencies = new Set();
this.newTargets = new Set();
this.globMatch = new Set();
this.isEsm = false;
this.graph = new DepGraph();
this.#templateConfig = templateConfig;
}
setProjectUsingEsm(isEsmProject) {
this.isEsm = !!isEsmProject;
}
isJavaScriptDependency(path) {
return this.dependencies.has(path);
}
reset() {
this.newTargets = new Set();
}
addToDependencyGraph(parent, deps) {
if (!this.graph.hasNode(parent)) {
this.graph.addNode(parent);
}
for (let dep of deps) {
if (!this.graph.hasNode(dep)) {
this.graph.addNode(dep);
}
this.graph.addDependency(parent, dep);
}
}
uses(parent, dep) {
return this.getDependenciesOf(parent).includes(dep);
}
getDependenciesOf(parent) {
if (!this.graph.hasNode(parent)) {
return [];
}
return this.graph.dependenciesOf(parent);
}
getDependantsOf(child) {
if (!this.graph.hasNode(child)) {
return [];
}
return this.graph.dependantsOf(child);
}
addRaw(targets, isDependency) {
for (let target of targets) {
let path = TemplatePath.addLeadingDotSlash(target);
if (!this.targets.has(target)) {
this.newTargets.add(path);
}
this.targets.add(path);
if (isDependency) {
this.dependencies.add(path);
}
}
}
static normalize(targets) {
if (!targets) {
return [];
} else if (Array.isArray(targets)) {
return targets;
}
return [targets];
}
isWatchMatch(filepath, ignoreGlobs = []) {
return (
isGlobMatch(filepath, Array.from(this.globMatch)) &&
(ignoreGlobs.length > 0 ? !isGlobMatch(filepath, ignoreGlobs) : true)
);
}
// add only a target
add(targets) {
let arrTargets = WatchTargets.normalize(targets)
.map((target) => {
let { path } = GlobStripper.parse(target);
if (!path || path !== ".") {
this.globMatch.add(TemplatePath.stripLeadingDotSlash(target));
}
if (path && path !== ".") {
return path;
}
})
.filter(Boolean);
this.addRaw(arrTargets);
}
static normalizeToGlobs(targets) {
return WatchTargets.normalize(targets).map((entry) =>
TemplatePath.convertToRecursiveGlobSync(entry),
);
}
// add only a target’s dependencies
async addDependencies(targets, filterCallback) {
if (this.#templateConfig && !this.#templateConfig.shouldSpiderJavaScriptDependencies()) {
return;
}
targets = WatchTargets.normalize(targets);
let deps = await JavaScriptDependencies.getDependencies(targets, this.isEsm);
if (filterCallback) {
deps = deps.filter(filterCallback);
}
for (let target of targets) {
this.addToDependencyGraph(target, deps);
}
this.addRaw(deps, true);
}
setWriter(templateWriter) {
this.writer = templateWriter;
}
clearImportCacheFor(filePathArray) {
let paths = new Set();
for (const filePath of filePathArray) {
paths.add(filePath);
// Delete from require cache so that updates to the module are re-required
let importsTheChangedFile = this.getDependantsOf(filePath);
for (let dep of importsTheChangedFile) {
paths.add(dep);
}
let isImportedInTheChangedFile = this.getDependenciesOf(filePath);
for (let dep of isImportedInTheChangedFile) {
paths.add(dep);
}
// Use GlobalDependencyMap
if (this.#templateConfig) {
for (let dep of this.#templateConfig.usesGraph.getDependantsFor(filePath)) {
paths.add(dep);
}
}
}
eventBus.emit("eleventy.importCacheReset", paths);
}
getNewTargetsSinceLastReset() {
return Array.from(this.newTargets);
}
getTargets() {
return Array.from(this.targets);
}
}