src/modules/dir2DatCreator.ts
import path from 'node:path';
import ProgressBar, { ProgressBarSymbol } from '../console/progressBar.js';
import fsPoly from '../polyfill/fsPoly.js';
import DAT from '../types/dats/dat.js';
import Game from '../types/dats/game.js';
import LogiqxDAT from '../types/dats/logiqx/logiqxDat.js';
import Parent from '../types/dats/parent.js';
import Options from '../types/options.js';
import OutputFactory from '../types/outputFactory.js';
import ReleaseCandidate from '../types/releaseCandidate.js';
import Module from './module.js';
/**
* Write a DAT that was generated by {@link DATGameInferrer} to disk.
*/
export default class Dir2DatCreator extends Module {
private readonly options: Options;
constructor(options: Options, progressBar: ProgressBar) {
super(progressBar, Dir2DatCreator.name);
this.options = options;
}
/**
* Write the DAT.
*/
async create(
dat: DAT,
parentsToCandidates: Map<Parent, ReleaseCandidate[]>,
): Promise<string | undefined> {
if (!this.options.shouldDir2Dat()) {
return undefined;
}
this.progressBar.logTrace(`${dat.getNameShort()}: writing dir2dat`);
this.progressBar.setSymbol(ProgressBarSymbol.WRITING);
this.progressBar.reset(1);
const datDir = this.options.shouldWrite()
? OutputFactory.getDir(this.options, dat)
: process.cwd();
if (!(await fsPoly.exists(datDir))) {
await fsPoly.mkdir(datDir, { recursive: true });
}
const datPath = path.join(datDir, dat.getFilename());
// It is possible that the {@link ROM} embedded within {@link ReleaseCandidate}s has been
// manipulated, such as from {@link CandidateExtensionCorrector}. Use the {@link Game}s and
// {@link ROM}s from the {@link ReleaseCandidate}s instead of the original {@link DAT}.
const gamesToCandidates = [...parentsToCandidates.values()]
.flat()
.reduce((map, releaseCandidate) => {
const key = releaseCandidate.getGame();
if (!map.has(key)) {
map.set(key, [releaseCandidate]);
} else {
map.get(key)?.push(releaseCandidate);
}
return map;
}, new Map<Game, ReleaseCandidate[]>());
const gamesFromCandidates = [...gamesToCandidates.entries()].map(
([game, releaseCandidates]) => {
const roms = releaseCandidates
.at(0)
?.getRomsWithFiles()
.map((romWithFiles) => romWithFiles.getRom());
return game.withProps({ rom: roms });
},
);
const datFromCandidates = new LogiqxDAT(dat.getHeader(), gamesFromCandidates);
this.progressBar.logInfo(`${datFromCandidates.getNameShort()}: creating dir2dat '${datPath}'`);
const datContents = datFromCandidates.toXmlDat();
await fsPoly.writeFile(datPath, datContents);
this.progressBar.logTrace(`${datFromCandidates.getNameShort()}: done writing dir2dat`);
return datPath;
}
}