68 lines
2.1 KiB
TypeScript
68 lines
2.1 KiB
TypeScript
import { readFileSync, writeFileSync, renameSync, existsSync, mkdirSync } from 'node:fs';
|
|
import { dirname } from 'node:path';
|
|
import type { Manifest, ManifestEntry } from './types';
|
|
|
|
export function createEmpty(): Manifest {
|
|
return {
|
|
$schema: './dev-indices.schema.json',
|
|
version: 1,
|
|
lastId: 0,
|
|
entries: {},
|
|
deleted: {},
|
|
};
|
|
}
|
|
|
|
export function loadManifest(path: string): Manifest {
|
|
if (!existsSync(path)) return createEmpty();
|
|
try {
|
|
const raw = readFileSync(path, 'utf8');
|
|
const parsed = JSON.parse(raw) as Manifest;
|
|
if (parsed.version !== 1) {
|
|
throw new Error(`dev-indices manifest version ${parsed.version} unsupported (expected 1)`);
|
|
}
|
|
parsed.entries ??= {};
|
|
parsed.deleted ??= {};
|
|
return parsed;
|
|
} catch (err) {
|
|
if (err instanceof SyntaxError) {
|
|
throw new Error(`dev-indices manifest at ${path} is corrupt JSON: ${err.message}`);
|
|
}
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
export function saveManifest(path: string, manifest: Manifest): void {
|
|
mkdirSync(dirname(path), { recursive: true });
|
|
const tmp = path + '.tmp';
|
|
const json = JSON.stringify(manifest, null, 2);
|
|
writeFileSync(tmp, json, 'utf8');
|
|
renameSync(tmp, path);
|
|
}
|
|
|
|
export function findBySignature(manifest: Manifest, signature: string): number | null {
|
|
for (const [id, entry] of Object.entries(manifest.entries)) {
|
|
if (entry.signature === signature) return Number(id);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function addEntry(manifest: Manifest, entry: ManifestEntry): number {
|
|
const id = manifest.lastId + 1;
|
|
manifest.lastId = id;
|
|
manifest.entries[String(id)] = entry;
|
|
return id;
|
|
}
|
|
|
|
export function markDeleted(manifest: Manifest, id: number): void {
|
|
const key = String(id);
|
|
const entry = manifest.entries[key];
|
|
// no-op if id was never added or already deleted — defensive, callers should not rely on this
|
|
if (!entry) return;
|
|
manifest.deleted[key] = {
|
|
lastSignature: entry.signature,
|
|
lastFile: entry.file,
|
|
deletedAt: new Date().toISOString(),
|
|
};
|
|
delete manifest.entries[key];
|
|
}
|