feat: improve type definitions and refactor API responses for better type safety
Some checks failed
CI / lint (push) Failing after 7s
CI / test-backend (push) Has been skipped
CI / test-frontend (push) Has been skipped
CI / test-e2e (push) Has been skipped

This commit is contained in:
2026-03-18 19:37:23 +01:00
parent a07096d7c7
commit 3096a9b472
15 changed files with 528 additions and 161 deletions

View File

@@ -1,29 +1,15 @@
import { XMLParser } from 'fast-xml-parser';
import type { DatRom, DatGame, DatDatabase, DatVerifyResult, XmlGame, XmlRom } from '../types';
export type DatRom = {
name: string;
size?: number;
crc?: string;
md5?: string;
sha1?: string;
};
export type DatGame = {
name: string;
roms: DatRom[];
};
export type DatDatabase = {
games: DatGame[];
};
export type { DatRom, DatGame, DatDatabase };
function ensureArray<T>(v: T | T[] | undefined): T[] {
if (v === undefined || v === null) return [];
return Array.isArray(v) ? v : [v];
}
function normalizeHex(v?: string): string | undefined {
if (!v) return undefined;
function normalizeHex(v: unknown): string | undefined {
if (!v || typeof v !== 'string') return undefined;
return v.trim().toLowerCase();
}
@@ -34,18 +20,20 @@ export function parseDat(xml: string): DatDatabase {
trimValues: true,
});
const parsed = parser.parse(xml as any) as any;
const datafile = parsed?.datafile ?? parsed;
const parsed: Record<string, unknown> = parser.parse(xml);
const datafile =
(parsed?.datafile as { game?: XmlGame | XmlGame[] } | undefined) ??
(parsed as { game?: XmlGame | XmlGame[] });
const rawGames = ensureArray(datafile?.game);
const rawGames = ensureArray<XmlGame>(datafile?.game);
const games: DatGame[] = rawGames.map((g: any) => {
const games: DatGame[] = rawGames.map((g) => {
// game name may be an attribute or a child node
const nameAttr = g?.name ?? g?.['@_name'] ?? (g?.$?.name as any);
const nameAttr = g?.name ?? g?.['@_name'] ?? g?.$?.name;
const romNodes = ensureArray(g?.rom);
const romNodes = ensureArray<XmlRom>(g?.rom as XmlRom | XmlRom[] | undefined);
const roms: DatRom[] = romNodes.map((r: any) => {
const roms: DatRom[] = romNodes.map((r) => {
const rname = r?.name ?? r?.['@_name'] ?? r?.['@name'];
const sizeRaw = r?.size ?? r?.['@_size'];
const parsedSize = sizeRaw != null ? Number(sizeRaw) : undefined;
@@ -71,13 +59,13 @@ export function parseDat(xml: string): DatDatabase {
export function verifyHashesAgainstDat(
datDb: DatDatabase,
hashes: { crc?: string; md5?: string; sha1?: string; size?: number }
): { gameName: string; romName: string; matchedOn: 'crc' | 'md5' | 'sha1' | 'size' } | null {
): DatVerifyResult | null {
const cmp = {
crc: normalizeHex(hashes.crc),
md5: normalizeHex(hashes.md5),
sha1: normalizeHex(hashes.sha1),
size: hashes.size,
} as any;
};
for (const g of datDb.games) {
for (const r of g.roms) {