@intlayer/chokidar
Version:
Scans and builds Intlayer declaration files into dictionaries based on Intlayer configuration.
230 lines (228 loc) • 10.5 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
const require_utils_formatter = require('./utils/formatter.cjs');
const require_handleContentDeclarationFileChange = require('./handleContentDeclarationFileChange.cjs');
const require_handleContentDeclarationFileMoved = require('./handleContentDeclarationFileMoved.cjs');
const require_handleAdditionalContentDeclarationFile = require('./handleAdditionalContentDeclarationFile.cjs');
const require_handleUnlinkedContentDeclarationFile = require('./handleUnlinkedContentDeclarationFile.cjs');
const require_prepareIntlayer = require('./prepareIntlayer.cjs');
const require_writeContentDeclaration_writeContentDeclaration = require('./writeContentDeclaration/writeContentDeclaration.cjs');
let node_fs_promises = require("node:fs/promises");
let node_path = require("node:path");
let _intlayer_config_logger = require("@intlayer/config/logger");
let _intlayer_config_node = require("@intlayer/config/node");
let node_fs = require("node:fs");
let _intlayer_config_utils = require("@intlayer/config/utils");
let _intlayer_config_colors = require("@intlayer/config/colors");
_intlayer_config_colors = require_runtime.__toESM(_intlayer_config_colors);
let node_url = require("node:url");
//#region src/watcher.ts
const pendingUnlinks = /* @__PURE__ */ new Map();
const taskQueue = [];
let isProcessing = false;
const processQueue = async () => {
if (isProcessing) return;
isProcessing = true;
while (taskQueue.length > 0) {
const task = taskQueue.shift();
try {
await task();
} catch (error) {
console.error(error);
}
}
isProcessing = false;
};
const processEvent = (task) => {
taskQueue.push(task);
processQueue();
};
const STABILITY_THRESHOLD = 1e3;
const createStabilityDebounce = () => {
const pending = /* @__PURE__ */ new Map();
return (path, handler) => {
const existing = pending.get(path);
if (existing) clearTimeout(existing);
pending.set(path, setTimeout(() => {
pending.delete(path);
handler();
}, STABILITY_THRESHOLD));
};
};
const watch = async (options) => {
const { subscribe } = await import("@parcel/watcher");
const configResult = (0, _intlayer_config_node.getConfigurationAndFilePath)(options?.configOptions);
const configurationFilePath = configResult.configurationFilePath;
let configuration = options?.configuration ?? configResult.configuration;
const appLogger = (0, _intlayer_config_logger.getAppLogger)(configuration);
const { watch: isWatchMode, fileExtensions, contentDir, excludedPath } = configuration.content;
if (!configuration.content.watch) return;
appLogger("Watching Intlayer content declarations");
if (configuration.build.optimize === true) appLogger([
`Build optimization is forced to ${(0, _intlayer_config_logger.colorize)("true", _intlayer_config_colors.GREY)}, but watching is enabled too.`,
"It may lead to dev mode performance degradation as well as import errors.",
"Its recommended to keep the",
(0, _intlayer_config_logger.colorize)("`build.optimized`", _intlayer_config_colors.BLUE),
"option",
(0, _intlayer_config_logger.colorize)("undefined", _intlayer_config_colors.GREY),
"to get the best dev mode experience"
], { level: "warn" });
const excludedSegments = excludedPath.map((segment) => segment.replace(/^\*\*\//, "").replace(/\/\*\*$/, ""));
const normalizedConfigPath = configurationFilePath ? (0, _intlayer_config_utils.normalizePath)(configurationFilePath) : null;
const { mainDir, baseDir } = configuration.system;
const normalizedMainDir = (0, _intlayer_config_utils.normalizePath)(mainDir);
const normalizedIntlayerDir = (0, _intlayer_config_utils.normalizePath)((0, node_path.dirname)(mainDir));
const subscriptions = [];
const scheduleStable = createStabilityDebounce();
if ((0, node_fs.existsSync)(mainDir)) {
const mainDirSub = await subscribe(normalizedMainDir, (err, events) => {
if (err || isProcessing) return;
for (const event of events) {
const rel = (0, _intlayer_config_utils.normalizePath)(event.path).slice(normalizedMainDir.length + 1);
if (!rel || rel.includes("/")) continue;
if (rel.endsWith(".tmp")) continue;
if (event.type === "update") processEvent(async () => {
(0, _intlayer_config_utils.clearModuleCache)(event.path);
try {
await import(`${(0, node_url.pathToFileURL)(event.path).href}?update=${Date.now()}`);
} catch {
appLogger(`Entry point ${(0, node_path.basename)(event.path)} failed to load, running clean rebuild...`, { level: "warn" });
await require_prepareIntlayer.prepareIntlayer(configuration, {
clean: true,
forceRun: true
});
}
});
else if (event.type === "delete") processEvent(async () => {
appLogger([
"Entry point",
require_utils_formatter.formatPath((0, node_path.basename)(event.path)),
"was removed, running clean rebuild..."
], { level: "warn" });
await require_prepareIntlayer.prepareIntlayer(configuration, {
clean: true,
forceRun: true
});
});
}
});
subscriptions.push(mainDirSub);
}
const intlayerDirName = (0, node_path.basename)(normalizedIntlayerDir);
const fsDirWatcher = (0, node_fs.watch)(baseDir, { persistent: isWatchMode }, (eventType, filename) => {
if (isProcessing || !filename) return;
if (filename !== intlayerDirName) return;
if ((0, _intlayer_config_utils.normalizePath)((0, node_path.resolve)(baseDir, filename)) !== normalizedIntlayerDir) return;
if (eventType === "rename" && !(0, node_fs.existsSync)(normalizedIntlayerDir)) {
appLogger([require_utils_formatter.formatPath(".intlayer"), "directory removed, running clean rebuild..."]);
processEvent(() => require_prepareIntlayer.prepareIntlayer(configuration, {
clean: true,
forceRun: true
}));
}
});
subscriptions.push({ unsubscribe: async () => {
fsDirWatcher.close();
} });
const ignorePatterns = excludedSegments.map((s) => `**/${s}/**`);
const contentDirs = contentDir.map((dir) => (0, _intlayer_config_utils.normalizePath)(dir)).filter(node_fs.existsSync);
const dirsToWatch = new Set(contentDirs);
if (normalizedConfigPath) dirsToWatch.add((0, _intlayer_config_utils.normalizePath)((0, node_path.dirname)(normalizedConfigPath)));
const contentHandler = (err, events) => {
if (err) {
appLogger(`Watcher error: ${err}`, { level: "error" });
appLogger("Restarting watcher");
require_prepareIntlayer.prepareIntlayer(configuration);
return;
}
for (const event of events) {
const filePath = event.path;
const path = (0, _intlayer_config_utils.normalizePath)(filePath);
const isConfigFile = normalizedConfigPath && path === normalizedConfigPath;
if (!isConfigFile) {
if (!contentDirs.some((d) => path.startsWith(`${d}/`) || path === d)) continue;
if (excludedSegments.some((segment) => path.includes(`/${segment}`))) continue;
if (!fileExtensions.some((extension) => path.endsWith(extension))) continue;
}
if (event.type === "create") {
const fileName = (0, node_path.basename)(filePath);
let isMove = false;
let matchedOldPath;
for (const [oldPath] of pendingUnlinks) if ((0, node_path.basename)(oldPath) === fileName) {
matchedOldPath = oldPath;
break;
}
if (!matchedOldPath && pendingUnlinks.size === 1) matchedOldPath = pendingUnlinks.keys().next().value;
if (matchedOldPath) {
const pending = pendingUnlinks.get(matchedOldPath);
if (pending) {
clearTimeout(pending.timer);
pendingUnlinks.delete(matchedOldPath);
}
isMove = true;
appLogger(`File moved from ${matchedOldPath} to ${filePath}`);
}
if (isMove && matchedOldPath) processEvent(async () => {
await require_handleContentDeclarationFileMoved.handleContentDeclarationFileMoved(matchedOldPath, filePath, configuration);
});
else scheduleStable(path, () => {
processEvent(async () => {
if (await (0, node_fs_promises.readFile)(filePath, "utf-8") === "") {
const extensionPattern = fileExtensions.map((ext) => ext.replace(/\./g, "\\.")).join("|");
await require_writeContentDeclaration_writeContentDeclaration.writeContentDeclaration({
key: fileName.replace(new RegExp(`(${extensionPattern})$`), ""),
content: {},
filePath
}, configuration);
}
await require_handleAdditionalContentDeclarationFile.handleAdditionalContentDeclarationFile(filePath, configuration);
});
});
} else if (event.type === "update") scheduleStable(path, () => {
processEvent(async () => {
if (isConfigFile) {
appLogger("Configuration file changed, repreparing Intlayer");
(0, _intlayer_config_utils.clearModuleCache)(filePath);
(0, _intlayer_config_utils.clearAllCache)();
const { configuration: newConfiguration } = (0, _intlayer_config_node.getConfigurationAndFilePath)(options?.configOptions);
configuration = options?.configuration ?? newConfiguration;
await require_prepareIntlayer.prepareIntlayer(configuration, { clean: false });
} else {
(0, _intlayer_config_utils.clearModuleCache)(filePath);
(0, _intlayer_config_utils.clearAllCache)();
(0, _intlayer_config_utils.clearDiskCacheMemory)();
await require_handleContentDeclarationFileChange.handleContentDeclarationFileChange(filePath, configuration);
}
});
});
else if (event.type === "delete") {
const timer = setTimeout(async () => {
pendingUnlinks.delete(filePath);
processEvent(async () => require_handleUnlinkedContentDeclarationFile.handleUnlinkedContentDeclarationFile(filePath, configuration));
}, 200);
pendingUnlinks.set(filePath, {
timer,
oldPath: filePath
});
}
}
};
for (const dir of dirsToWatch) {
const sub = await subscribe(dir, contentHandler, { ignore: ignorePatterns });
subscriptions.push(sub);
}
return subscriptions;
};
const buildAndWatchIntlayer = async (options) => {
const { skipPrepare, ...rest } = options ?? {};
const configuration = options?.configuration ?? (0, _intlayer_config_node.getConfiguration)(options?.configOptions);
if (!skipPrepare) await require_prepareIntlayer.prepareIntlayer(configuration, { forceRun: true });
if (options?.persistent) await watch({
...rest,
configuration
});
};
//#endregion
exports.buildAndWatchIntlayer = buildAndWatchIntlayer;
exports.watch = watch;
//# sourceMappingURL=watcher.cjs.map