first
This commit is contained in:
237
node_modules/@11ty/eleventy-fetch/src/FileCache.js
generated
vendored
Normal file
237
node_modules/@11ty/eleventy-fetch/src/FileCache.js
generated
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const debugUtil = require("debug");
|
||||
const { parse } = require("flatted");
|
||||
|
||||
const debug = debugUtil("Eleventy:Fetch");
|
||||
const debugAssets = debugUtil("Eleventy:Assets");
|
||||
|
||||
const DirectoryManager = require("./DirectoryManager.js");
|
||||
const ExistsCache = require("./ExistsCache.js");
|
||||
|
||||
let existsCache = new ExistsCache();
|
||||
|
||||
class FileCache {
|
||||
#source;
|
||||
#directoryManager;
|
||||
#metadata;
|
||||
#defaultType;
|
||||
#contents;
|
||||
#dryRun = false;
|
||||
#cacheDirectory = ".cache";
|
||||
#savePending = false;
|
||||
#counts = {
|
||||
read: 0,
|
||||
write: 0,
|
||||
};
|
||||
|
||||
constructor(cacheFilename, options = {}) {
|
||||
this.cacheFilename = cacheFilename;
|
||||
if(options.dir) {
|
||||
this.#cacheDirectory = options.dir;
|
||||
}
|
||||
if(options.source) {
|
||||
this.#source = options.source;
|
||||
}
|
||||
}
|
||||
|
||||
setDefaultType(type) {
|
||||
if(type) {
|
||||
this.#defaultType = type;
|
||||
}
|
||||
}
|
||||
|
||||
setDryRun(val) {
|
||||
this.#dryRun = Boolean(val);
|
||||
}
|
||||
|
||||
setDirectoryManager(manager) {
|
||||
this.#directoryManager = manager;
|
||||
}
|
||||
|
||||
ensureDir() {
|
||||
if (this.#dryRun || existsCache.exists(this.#cacheDirectory)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.#directoryManager) {
|
||||
// standalone fallback (for tests)
|
||||
this.#directoryManager = new DirectoryManager();
|
||||
}
|
||||
|
||||
this.#directoryManager.create(this.#cacheDirectory);
|
||||
}
|
||||
|
||||
set(type, contents, extraMetadata = {}) {
|
||||
this.#savePending = true;
|
||||
|
||||
this.#metadata = {
|
||||
cachedAt: Date.now(),
|
||||
type,
|
||||
// source: this.#source,
|
||||
metadata: extraMetadata,
|
||||
};
|
||||
|
||||
this.#contents = contents;
|
||||
}
|
||||
|
||||
get fsPath() {
|
||||
return path.join(this.#cacheDirectory, this.cacheFilename);
|
||||
}
|
||||
|
||||
getContentsPath(type) {
|
||||
if(!type) {
|
||||
throw new Error("Missing cache type for " + this.fsPath);
|
||||
}
|
||||
|
||||
// normalize to storage type
|
||||
if(type === "xml") {
|
||||
type = "text";
|
||||
} else if(type === "parsed-xml") {
|
||||
type = "json";
|
||||
}
|
||||
|
||||
return `${this.fsPath}.${type}`;
|
||||
}
|
||||
|
||||
// only when side loaded (buffer content)
|
||||
get contentsPath() {
|
||||
return this.getContentsPath(this.#metadata?.type);
|
||||
}
|
||||
|
||||
get() {
|
||||
if(this.#metadata) {
|
||||
return this.#metadata;
|
||||
}
|
||||
|
||||
if(!existsCache.exists(this.fsPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug(`Fetching from cache ${this.fsPath}`);
|
||||
if(this.#source) {
|
||||
debugAssets("[11ty/eleventy-fetch] Reading via %o", this.#source);
|
||||
} else {
|
||||
debugAssets("[11ty/eleventy-fetch] Reading %o", this.fsPath);
|
||||
}
|
||||
|
||||
this.#counts.read++;
|
||||
let data = fs.readFileSync(this.fsPath, "utf8");
|
||||
|
||||
let json;
|
||||
// Backwards compatibility with previous caches usingn flat-cache and `flatted`
|
||||
if(data.startsWith(`[["1"],`)) {
|
||||
let flattedParsed = parse(data);
|
||||
if(flattedParsed?.[0]?.value) {
|
||||
json = flattedParsed?.[0]?.value
|
||||
}
|
||||
} else {
|
||||
json = JSON.parse(data);
|
||||
}
|
||||
|
||||
this.#metadata = json;
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
_backwardsCompatGetContents(rawData, type) {
|
||||
if (type === "json") {
|
||||
return rawData.contents;
|
||||
} else if (type === "text") {
|
||||
return rawData.contents.toString();
|
||||
}
|
||||
|
||||
// buffer
|
||||
return Buffer.from(rawData.contents);
|
||||
}
|
||||
|
||||
hasContents(type) {
|
||||
if(this.#contents) {
|
||||
return true;
|
||||
}
|
||||
if(this.get()?.contents) { // backwards compat with very old caches
|
||||
return true;
|
||||
}
|
||||
return existsCache.exists(this.getContentsPath(type));
|
||||
}
|
||||
|
||||
getType() {
|
||||
return this.#metadata?.type || this.#defaultType;
|
||||
}
|
||||
|
||||
getContents() {
|
||||
if(this.#contents) {
|
||||
return this.#contents;
|
||||
}
|
||||
|
||||
let metadata = this.get();
|
||||
// backwards compat with old caches
|
||||
if(metadata?.contents) {
|
||||
// already parsed, part of the top level file
|
||||
let normalizedContent = this._backwardsCompatGetContents(this.get(), this.getType());
|
||||
this.#contents = normalizedContent;
|
||||
return normalizedContent;
|
||||
}
|
||||
|
||||
if(!existsCache.exists(this.contentsPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug(`Fetching from cache ${this.contentsPath}`);
|
||||
if(this.#source) {
|
||||
debugAssets("[11ty/eleventy-fetch] Reading (side loaded) via %o", this.#source);
|
||||
} else {
|
||||
debugAssets("[11ty/eleventy-fetch] Reading (side loaded) %o", this.contentsPath);
|
||||
}
|
||||
|
||||
// It is intentional to store contents in a separate file from the metadata: we don’t want to
|
||||
// have to read the entire contents via JSON.parse (or otherwise) to check the cache validity.
|
||||
this.#counts.read++;
|
||||
let type = metadata?.type || this.getType();
|
||||
let data = fs.readFileSync(this.contentsPath);
|
||||
if (type === "json" || type === "parsed-xml") {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
this.#contents = data;
|
||||
return data;
|
||||
}
|
||||
|
||||
save() {
|
||||
if(this.#dryRun || !this.#savePending || this.#metadata && Object.keys(this.#metadata) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.ensureDir(); // doesn’t add to counts (yet?)
|
||||
|
||||
// contents before metadata
|
||||
debugAssets("[11ty/eleventy-fetch] Writing %o (side loaded) from %o", this.contentsPath, this.#source);
|
||||
|
||||
this.#counts.write++;
|
||||
// the contents must exist before the cache metadata are saved below
|
||||
let contents = this.#contents;
|
||||
let type = this.getType();
|
||||
if (type === "json" || type === "parsed-xml") {
|
||||
contents = JSON.stringify(contents);
|
||||
}
|
||||
fs.writeFileSync(this.contentsPath, contents);
|
||||
debug(`Writing ${this.contentsPath}`);
|
||||
|
||||
this.#counts.write++;
|
||||
debugAssets("[11ty/eleventy-fetch] Writing %o from %o", this.fsPath, this.#source);
|
||||
fs.writeFileSync(this.fsPath, JSON.stringify(this.#metadata), "utf8");
|
||||
debug(`Writing ${this.fsPath}`);
|
||||
}
|
||||
|
||||
// for testing
|
||||
getAllPossibleFilePaths() {
|
||||
let types = ["text", "buffer", "json"];
|
||||
let paths = new Set();
|
||||
paths.add(this.fsPath);
|
||||
for(let type of types) {
|
||||
paths.add(this.getContentsPath(type));
|
||||
}
|
||||
return Array.from(paths);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FileCache;
|
||||
Reference in New Issue
Block a user