@file-cache/core
Version:
A cache for file metadata or file content.
142 lines (137 loc) • 4.43 kB
text/typescript
import path from "node:path";
import { createFileCache } from "./createFileCache.js";
import fs from "node:fs/promises";
import { createCacheKey, CreateCacheKeyGenerator } from "./createCacheKey.js";
import { createNoCache } from "./noCache.js";
export type { CreateCacheKeyGenerator } from "./createCacheKey.js";
export type CreateCacheOptions = {
/**
* The name of the cache
* It is used for the cache directory name
*
*/
name: string;
/**
* - content: Using the hash value of file content
* - Slow but accurate
* - metadata: Using the metadata of file
* - Fast but not accurate
* - It can not be used in CI env
*/
mode: "content" | "metadata";
/**
* The key generators for cache file
*/
keys: CreateCacheKeyGenerator[];
/**
* Custom cache directory.
* Default: node_modules/.cache/<name>
*/
cacheDirectory?: string;
/**
* If true, the cache will not be used.
* Default: false
*
* - getAndUpdateCache(): return { changed: true }
* - delete(): nope. return true.
* - clear(): nope. return true.
* - reconcile(): nope. return true.
*/
noCache?: boolean;
};
export type DeleteCacheOptions = Omit<CreateCacheOptions, "noCache">;
/**
* Delete cache file
* Note: It does not clear in-memory cache in the cache.
* @param options
*/
export const deleteCacheFile = async (options: DeleteCacheOptions) => {
const findCacheDir = await import("find-cache-dir").then((m) => m.default);
const cacheDir = options.cacheDirectory
? options.cacheDirectory
: // node_modules/.cache/<name>
// https://github.com/sindresorhus/find-cache-dir
findCacheDir({ name: options.name, create: true });
if (!cacheDir) {
throw new Error(`Not found cache directory. Please set cacheDirectory option or findCacheDir is failed.`);
}
const cacheFile = path.join(cacheDir, createCacheKey(options.keys));
try {
await fs.unlink(cacheFile);
return true;
} catch {
return false;
}
};
const getPackageName = async (pkgPath: string) => {
const pkgFile = path.join(pkgPath, "package.json");
try {
const pkg = await fs.readFile(pkgFile, "utf8");
const pkgJson = JSON.parse(pkg);
return pkgJson.name;
} catch {
return "file-cache";
}
};
/**
* Create cache instance
* @param options
*/
export const createCache = async (options: CreateCacheOptions) => {
if (options.noCache) {
return createNoCache(); // disable cache. It is noop implemention.
}
const findCacheDir = await import("find-cache-dir").then((m) => m.default);
const cacheDir = options.cacheDirectory
? options.cacheDirectory
: // node_modules/.cache/<name>
// https://github.com/sindresorhus/find-cache-dir
findCacheDir({ name: options.name });
if (!cacheDir) {
throw new Error(`Not found cache directory. Please set cacheDirectory option or findCacheDir is failed.`);
}
await fs.mkdir(cacheDir, { recursive: true });
const cacheFile = path.join(cacheDir, createCacheKey(options.keys));
const cache = await createFileCache(cacheFile, options.mode);
return {
/**
* Experimental method
* @param cb
*/
async try(cb: () => Promise<void>) {
await cb();
await this.reconcile();
},
/**
* Get cache status and update the cache value
* You need to confirm the status via call `reconcile()` after that
* @param filePath
*/
async getAndUpdateCache(filePath: string | URL) {
const descriptor = await cache.getFileDescriptor(filePath);
return {
error: descriptor.error,
changed: descriptor.changed
} as const;
},
/**
* Delete cache value for the key
* @param filePath
*/
async delete(filePath: string): Promise<boolean> {
return cache.delete(filePath);
},
/**
* Clear cache values
*/
async clear(): Promise<void> {
cache.clear();
},
/**
* Confirm the changes
*/
async reconcile(): Promise<boolean> {
return cache.reconcile();
}
};
};