brocolito
Version:
Create type-safe CLIs to align local development and pipeline workflows
69 lines (60 loc) • 1.81 kB
JavaScript
import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
/**
* @param {string} filePath
* @returns {string}
*/
const getShortHashForFile = (filePath) => {
const file = fs.readFileSync(filePath);
return crypto.createHash("md5").update(file).digest("hex").substring(0, 8);
};
/**
* @param {string} dir
* @returns {[string, string][]}
*/
const getHashEntries = (dir) =>
fs.readdirSync(dir, { withFileTypes: true }).flatMap((fileOrDir) => {
const fileOrDirName = path.join(dir, fileOrDir.name);
if (fileOrDir.isFile()) {
return [[fileOrDirName, getShortHashForFile(fileOrDirName)]];
}
return getHashEntries(fileOrDirName);
});
/**
* @param {string} dir
* @returns {[string, string][]}
*/
const getHashes = (dir) => {
const srcHashes = getHashEntries(path.join(dir, "src"));
const packageJsonPath = path.join(dir, "package.json");
return [
[packageJsonPath, getShortHashForFile(packageJsonPath)],
...srcHashes,
];
};
/**
* @param {string} packageDir
*/
export const updateHashes = (packageDir) => {
const hashes = getHashes(packageDir);
const hashesCacheFile = path.join(packageDir, "build/hashes.json");
fs.writeFileSync(hashesCacheFile, JSON.stringify(hashes));
};
/**
* @param {string} packageDir
*/
export const needsUpdate = (packageDir) => {
const hashes = getHashes(packageDir);
const hashesMap = Object.fromEntries(hashes);
const hashesCacheFile = path.join(packageDir, "build/hashes.json");
/** @type {typeof hashes} */
const lastHashes = fs.existsSync(hashesCacheFile)
? JSON.parse(fs.readFileSync(hashesCacheFile, "utf-8"))
: undefined;
return (
!lastHashes ||
hashes.length !== lastHashes.length ||
lastHashes.some(([name, hash]) => hashesMap[name] !== hash)
);
};