Skip to content

Commit

Permalink
feat: persistent cache for npm package data
Browse files Browse the repository at this point in the history
  • Loading branch information
ext committed Nov 23, 2023
1 parent 993e8ad commit b7134c2
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/utils/npm-info.spec.ts
Expand Up @@ -2,6 +2,7 @@ import { execa } from "execa";
import { npmInfo } from "./npm-info";

jest.mock("execa");
jest.mock("./persistent-cache");

const mockExeca = execa as unknown as jest.Mock;

Expand Down
7 changes: 7 additions & 0 deletions src/utils/npm-info.ts
@@ -1,5 +1,6 @@
import { execa } from "execa";
import { type PackageJson } from "../types";
import { persistentCacheGet, persistentCacheSet } from "./persistent-cache";

const cache = new Map<string, PackageJson>();

Expand All @@ -9,8 +10,14 @@ export async function npmInfo(pkg: string): Promise<PackageJson> {
return cached;
}

const persistent = await persistentCacheGet(pkg);
if (persistent) {
return persistent as PackageJson;
}

const result = await execa("npm", ["info", "--json", pkg]);
const pkgData = JSON.parse(result.stdout) as PackageJson;
cache.set(pkg, pkgData);
await persistentCacheSet(pkg, pkgData);
return pkgData;
}
42 changes: 42 additions & 0 deletions src/utils/persistent-cache.ts
@@ -0,0 +1,42 @@
import fs from "node:fs/promises";
import path from "node:path";
import crypto from "node:crypto";
import os from "node:os";

const enabled = os.platform() === "linux";
const cacheRoot = process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), ".cache");
const cacheDir = path.join(cacheRoot, "npm-pkg-lint");

function getFilePath(key: string): string {
const hash = crypto.createHash("md5").update(key).digest("hex");
const filename = `${hash.slice(0, 2)}/${hash.slice(2)}.json`;
return path.join(cacheDir, filename);
}

export async function persistentCacheGet(key: string): Promise<unknown | null> {
if (!enabled) {
return null;
}

const filePath = getFilePath(key);
try {
const content = await fs.readFile(filePath, "utf-8");
return JSON.parse(content) as unknown;
} catch (err: unknown) {
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
return null;
}
throw err;
}
}

export async function persistentCacheSet(key: string, data: unknown): Promise<void> {
if (!enabled) {
return;
}

const filePath = getFilePath(key);
const content = JSON.stringify(data, null, 2);
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, content, "utf-8");
}

0 comments on commit b7134c2

Please sign in to comment.