Files
nani-translate-linux/scripts/patches/lib.mjs
T
2026-08-01 20:21:37 +09:00

67 lines
2.2 KiB
JavaScript

import { createHash } from "node:crypto";
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync } from "node:fs";
import path from "node:path";
export function countOccurrences(source, needle) {
if (needle.length === 0) throw new Error("Patch needle must not be empty");
let count = 0;
let offset = 0;
while ((offset = source.indexOf(needle, offset)) !== -1) {
count += 1;
offset += needle.length;
}
return count;
}
export function replaceExactly(source, needle, replacement, label) {
const matches = countOccurrences(source, needle);
if (matches !== 1) {
throw new Error(`${label}: expected exactly one semantic anchor, found ${matches}`);
}
return source.replace(needle, replacement);
}
export function markerStatus(source, marker) {
const matches = countOccurrences(source, marker);
if (matches > 1) throw new Error(`Patch marker '${marker}' occurs ${matches} times`);
return matches === 1 ? "already-applied" : null;
}
export function copyTreeContents(sourceDir, destinationDir) {
if (!existsSync(sourceDir) || !statSync(sourceDir).isDirectory()) {
throw new Error(`Replacement tree is not a directory: ${sourceDir}`);
}
mkdirSync(destinationDir, { recursive: true });
for (const entry of readdirSync(sourceDir, { withFileTypes: true })) {
cpSync(path.join(sourceDir, entry.name), path.join(destinationDir, entry.name), {
recursive: true,
force: true,
dereference: false,
});
}
}
export function sha256File(filePath) {
return createHash("sha256").update(readFileSync(filePath)).digest("hex");
}
export function walkFiles(root) {
if (!existsSync(root)) return [];
const files = [];
const visit = (directory) => {
for (const entry of readdirSync(directory, { withFileTypes: true })) {
const fullPath = path.join(directory, entry.name);
if (entry.isDirectory()) visit(fullPath);
else if (entry.isFile()) files.push(fullPath);
}
};
visit(root);
return files.sort((left, right) => left.localeCompare(right));
}
export function relativeFileHashes(root) {
return Object.fromEntries(
walkFiles(root).map((filePath) => [path.relative(root, filePath), sha256File(filePath)]),
);
}