textlint
Version:
The pluggable linting tool for text and markdown.
92 lines • 3.31 kB
JavaScript
// MIT © 2016 azu
;
import fileEntryCache from "file-entry-cache";
import debug0 from "debug";
import path from "node:path";
import fs from "node:fs";
const debug = debug0("textlint:CacheBacker");
const createFileEntryCache = (cacheLocation) => {
const filename = path.basename(cacheLocation);
const cacheDir = path.dirname(cacheLocation);
try {
// use the metadata for cache instead of the file content
// TODO: if we want to reuse the cache in CI, we should use the file content cache and save relative path into the cache
return fileEntryCache.create(filename, cacheDir, false);
}
catch (error) {
debug(`Failed to create fileEntryCache, filename: ${filename}, cacheDir: ${cacheDir}`, error);
// remove old cache file and retry
try {
fs.unlinkSync(path.join(cacheDir, filename));
}
catch (error) {
debug(`Failed to remove cache file, filename: ${filename}, cacheDir: ${cacheDir}`, error);
}
return fileEntryCache.create(filename, cacheDir, false);
}
};
export class CacheBacker {
constructor(config) {
this.config = config;
this.isEnabled = config.cache;
this.fileCache = createFileEntryCache(config.cacheLocation);
}
/**
* @param {string} filePath
* @returns {boolean}
*/
shouldExecute({ filePath }) {
if (!this.isEnabled) {
return true;
}
try {
const descriptor = this.fileCache.getFileDescriptor(filePath);
const meta = descriptor.meta || {};
// if the config is changed or file is changed, should execute return true
const isChanged = descriptor.changed || meta.data.hashOfConfig !== this.config.hash;
debug(`Skipping file since hasn't changed: ${filePath}`);
return isChanged;
}
catch (error) {
debug(`shouldExecute: Failed to read cache file: ${filePath}`, error);
return true; // if cache file version is changed, it may throw an error
}
}
didExecute({ result }) {
if (!this.isEnabled) {
return;
}
const filePath = result.filePath;
try {
const descriptor = this.fileCache.getFileDescriptor(filePath);
const meta = descriptor.meta || {};
/*
* if a file contains messages we don't want to store the file in the cache
* so we can guarantee that next execution will also operate on this file
*/
if (result.messages.length > 0) {
debug(`File has problems, skipping it: ${filePath}`);
// remove the entry from the cache
this.fileCache.removeEntry(filePath);
}
else {
// cache `config.hash`
meta.data = { hashOfConfig: this.config.hash };
}
}
catch (error) {
debug(`didExecute: Failed to read cache file: ${filePath}`, error);
}
}
/**
* destroy all cache
*/
destroyCache() {
this.fileCache.destroy();
}
afterAll() {
// persist cache
this.fileCache.reconcile();
}
}
//# sourceMappingURL=cache-backer.js.map