UNPKG

dejarun

Version:

A file system operation cache for Node.js, using a hash of the file or folder contents as the cache key.

80 lines 3.11 kB
import chalk from "chalk"; import { defaults, hashElement } from "folder-hash"; import { createHash } from "node:crypto"; import fs from "node:fs/promises"; import logger from "./logger.js"; import { each } from "./utils/tagged-templates.js"; function hashValue(value) { return createHash(defaults.algo ?? "sha1") .update(JSON.stringify(value)) .digest(defaults.encoding ?? "base64"); } const hashFileOrDirList = (paths = []) => Promise.all(paths.map(async (path) => { try { return (await hashElement(path)).hash; } catch { return null; } })); /** * Caches the result of a callback function based on the hashes of input and output files or directories and additional dependencies. * If the hashes of the inputs, outputs and other dependencies have not changed since the last run, the callback will not be executed. * * @param name - A unique name for the cache entry. Example: "build". * @param callback - The function to execute if the cache is missed. * @param options - An object containing the following optional properties: * - inputs: An array of file or directory paths to hash for cache validation. * - outputs: An array of file or directory paths to hash for cache validation. * - dependencies: An array of arbitrary values to hash for cache validation. * - clean: A boolean indicating whether to clean the cache (default: false). * - debug: A boolean indicating whether to log debug information (default: false). * - logo: A string or false to customize the logo in the logs (default: '[déjàrun]'). */ export default async function dejarun(name, callback, options) { const cacheName = `${process.env.npm_package_name}/${name}`; const CACHE_FILE = new URL("../.cache.json", import.meta.url).pathname; let cache = {}; try { cache = JSON.parse(await fs.readFile(CACHE_FILE, "utf8")); } catch { } const inputs = await hashFileOrDirList(options?.inputs); const totalHash = hashValue({ inputs, outputs: await hashFileOrDirList(options?.outputs), dependencies: options?.dependencies, }); if (options?.debug) { logger("debug", ` name: ${chalk.bold(name)} cache name: ${chalk.bold(cacheName)} cache file: ${chalk.bold(CACHE_FILE)} inputs:${chalk.bold(each ` ${options.inputs}`)} outputs:${chalk.bold(each ` ${options.outputs}`)} dependencies:${chalk.bold(each ` ${options.dependencies}`)} total hash: ${totalHash}`, options.logo); } if (options?.clean) { logger("clean", name, options.logo); delete cache[cacheName]; } else { if (totalHash === cache[cacheName]) { logger("hit", name, options?.logo); return; } logger("miss", name, options?.logo); } await callback(); cache[cacheName] = hashValue({ inputs, outputs: await hashFileOrDirList(options?.outputs), dependencies: options?.dependencies, }); await fs.writeFile(CACHE_FILE, JSON.stringify(cache, null, 2)); } //# sourceMappingURL=main.js.map