From b1bf1fbdf3f1a916491053664dd336ae4e995579 Mon Sep 17 00:00:00 2001 From: Christian Emmer <10749361+emmercm@users.noreply.github.com> Date: Thu, 3 Aug 2023 17:12:50 -0700 Subject: [PATCH 1/2] --dir-dat-description --- src/modules/argumentsParser.ts | 6 ++++++ src/types/logiqx/dat.ts | 4 ++++ src/types/options.ts | 11 +++++++++++ test/modules/argumentsParser.test.ts | 12 +++++++++++- test/types/options.test.ts | 11 +++++++++-- 5 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/modules/argumentsParser.ts b/src/modules/argumentsParser.ts index 3278ce9b6..e46f835c5 100644 --- a/src/modules/argumentsParser.ts +++ b/src/modules/argumentsParser.ts @@ -228,6 +228,12 @@ export default class ArgumentsParser { type: 'boolean', implies: 'dat', }) + .option('dir-dat-description', { + group: groupRomOutput, + description: 'Use the DAT description as the output subdirectory', + type: 'boolean', + implies: 'dat', + }) .option('dir-letter', { group: groupRomOutput, description: 'Append the first letter of the ROM name as an output subdirectory', diff --git a/src/types/logiqx/dat.ts b/src/types/logiqx/dat.ts index 0eeb05cdc..5d290a1b5 100644 --- a/src/types/logiqx/dat.ts +++ b/src/types/logiqx/dat.ts @@ -141,6 +141,10 @@ export default class DAT { .trim(); } + getDescription(): string | undefined { + return this.getHeader().getDescription(); + } + getRomNamesContainDirectories(): boolean { return this.getHeader().getRomNamesContainDirectories() || this.isBiosDat(); diff --git a/src/types/options.ts b/src/types/options.ts index 9fbd26b05..90f1103aa 100644 --- a/src/types/options.ts +++ b/src/types/options.ts @@ -42,6 +42,7 @@ export interface OptionsProps { readonly output?: string, readonly dirMirror?: boolean, readonly dirDatName?: boolean, + readonly dirDatDescription?: boolean, readonly dirLetter?: boolean, readonly dirLetterLimit?: number, readonly overwrite?: boolean, @@ -132,6 +133,8 @@ export default class Options implements OptionsProps { readonly dirDatName: boolean; + readonly dirDatDescription: boolean; + readonly dirLetter: boolean; readonly dirLetterLimit: number; @@ -256,6 +259,7 @@ export default class Options implements OptionsProps { this.output = options?.output ?? ''; this.dirMirror = options?.dirMirror ?? false; this.dirDatName = options?.dirDatName ?? false; + this.dirDatDescription = options?.dirDatDescription ?? false; this.dirLetter = options?.dirLetter ?? false; this.dirLetterLimit = options?.dirLetterLimit ?? 0; this.overwrite = options?.overwrite ?? false; @@ -681,6 +685,9 @@ export default class Options implements OptionsProps { if (this.getDirDatName() && dat.getNameShort()) { output = path.join(output, dat.getNameShort()); } + if (this.getDirDatDescription() && dat.getDescription()) { + output = path.join(output, dat.getDescription() as string); + } const dirLetter = this.getDirLetterParsed(romFilenameSanitized, romBasenames); if (dirLetter) { @@ -852,6 +859,10 @@ export default class Options implements OptionsProps { return this.dirDatName; } + getDirDatDescription(): boolean { + return this.dirDatDescription; + } + getDirLetter(): boolean { return this.dirLetter; } diff --git a/test/modules/argumentsParser.test.ts b/test/modules/argumentsParser.test.ts index cb79a625a..98d4d64c5 100644 --- a/test/modules/argumentsParser.test.ts +++ b/test/modules/argumentsParser.test.ts @@ -248,7 +248,7 @@ describe('options', () => { expect(argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dir-mirror', 'true', '--dir-mirror', 'false']).getDirMirror()).toEqual(false); }); - it('should parse "dir-datname"', () => { + it('should parse "dir-dat-name"', () => { expect(() => argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dir-dat-name'])).toThrow(/dependent|implication/i); expect(argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dat', os.devNull, '-D']).getDirDatName()).toEqual(true); expect(argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dat', os.devNull, '--dir-dat-name']).getDirDatName()).toEqual(true); @@ -259,6 +259,16 @@ describe('options', () => { expect(argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dat', os.devNull, '--dir-dat-name', 'true', '--dir-dat-name', 'false']).getDirDatName()).toEqual(false); }); + it('should parse "dir-dat-description"', () => { + expect(() => argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dir-dat-description'])).toThrow(/dependent|implication/i); + expect(argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dat', os.devNull, '--dir-dat-description']).getDirDatDescription()).toEqual(true); + expect(argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dat', os.devNull, '--dir-dat-description', 'true']).getDirDatDescription()).toEqual(true); + expect(argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dat', os.devNull, '--dir-dat-description', 'false']).getDirDatDescription()).toEqual(false); + expect(argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dat', os.devNull, '--dir-dat-description', '--dir-dat-description']).getDirDatDescription()).toEqual(true); + expect(argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dat', os.devNull, '--dir-dat-description', 'false', '--dir-dat-description', 'true']).getDirDatDescription()).toEqual(true); + expect(argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dat', os.devNull, '--dir-dat-description', 'true', '--dir-dat-description', 'false']).getDirDatDescription()).toEqual(false); + }); + it('should parse "dir-letter"', () => { expect(argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dir-letter']).getDirLetter()).toEqual(true); expect(argumentsParser.parse([...dummyCommandAndRequiredArgs, '--dir-letter', 'true']).getDirLetter()).toEqual(true); diff --git a/test/types/options.test.ts b/test/types/options.test.ts index 43ea7fe09..87b9fc71e 100644 --- a/test/types/options.test.ts +++ b/test/types/options.test.ts @@ -182,12 +182,19 @@ describe('getOutputFileParsed', () => { }); it('should respect "--dir-dat-name"', () => { - const dat = new DAT(new Header({ name: 'system' }), []); + const dat = new DAT(new Header({ name: 'name', description: 'description' }), []); expect(new Options({ commands: ['copy'], output: os.devNull, dirDatName: true }).getOutputFileParsed(dummyDat, dummyInputRomPath, dummyGame, dummyRelease, dummyRomFilename)).toEqual(os.devNull); - expect(new Options({ commands: ['copy'], output: os.devNull, dirDatName: true }).getOutputFileParsed(dat, dummyInputRomPath, dummyGame, dummyRelease, dummyRomFilename)).toEqual(path.join(os.devNull, 'system')); + expect(new Options({ commands: ['copy'], output: os.devNull, dirDatName: true }).getOutputFileParsed(dat, dummyInputRomPath, dummyGame, dummyRelease, dummyRomFilename)).toEqual(path.join(os.devNull, 'name')); expect(new Options({ commands: ['copy'], output: os.devNull, dirDatName: false }).getOutputFileParsed(dat, dummyInputRomPath, dummyGame, dummyRelease, dummyRomFilename)).toEqual(os.devNull); }); + it('should respect "--dir-dat-description"', () => { + const dat = new DAT(new Header({ name: 'name', description: 'description' }), []); + expect(new Options({ commands: ['copy'], output: os.devNull, dirDatDescription: true }).getOutputFileParsed(dummyDat, dummyInputRomPath, dummyGame, dummyRelease, dummyRomFilename)).toEqual(os.devNull); + expect(new Options({ commands: ['copy'], output: os.devNull, dirDatDescription: true }).getOutputFileParsed(dat, dummyInputRomPath, dummyGame, dummyRelease, dummyRomFilename)).toEqual(path.join(os.devNull, 'description')); + expect(new Options({ commands: ['copy'], output: os.devNull, dirDatDescription: false }).getOutputFileParsed(dat, dummyInputRomPath, dummyGame, dummyRelease, dummyRomFilename)).toEqual(os.devNull); + }); + it('should respect "--dir-letter"', () => { expect(new Options({ commands: ['copy'], output: os.devNull, dirLetter: true }).getOutputFileParsed(dummyDat, dummyInputRomPath, dummyGame, dummyRelease, dummyRomFilename)).toEqual(os.devNull); expect(new Options({ commands: ['copy'], output: os.devNull, dirLetter: true }).getOutputFileParsed(dummyDat, dummyInputRomPath, dummyGame, dummyRelease, 'file.rom')).toEqual(path.join(os.devNull, 'F', 'file.rom')); From b7bfecb677859f59a92d06c9e282ffb18a6443df Mon Sep 17 00:00:00 2001 From: Christian Emmer <10749361+emmercm@users.noreply.github.com> Date: Thu, 3 Aug 2023 17:16:36 -0700 Subject: [PATCH 2/2] {datDescription} --- docs/output/tokens.md | 1 + src/modules/argumentsParser.ts | 1 + src/types/options.ts | 10 +++++++++- test/types/options.test.ts | 4 +++- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/output/tokens.md b/docs/output/tokens.md index f0d6b5f1e..ed93d6253 100644 --- a/docs/output/tokens.md +++ b/docs/output/tokens.md @@ -42,6 +42,7 @@ ROMs-Sorted/ When using [DATs](../dats.md), you can make use of console & game information contained in them: - `{datName}` the matching DAT's name, similar to how the `--dir-dat-name` option works +- `{datDescription}` the matching DAT's description, similar to how the `--dir-dat-description` option works - `{datReleaseLanguage}` each of the ROM's language(s) (e.g. `EN`, `ES`, `JA`) - `{datReleaseRegion}` each of the ROM's region(s) (e.g. `USA`, `EUR`, `JPN`, `WORLD`) diff --git a/src/modules/argumentsParser.ts b/src/modules/argumentsParser.ts index e46f835c5..db07b1e73 100644 --- a/src/modules/argumentsParser.ts +++ b/src/modules/argumentsParser.ts @@ -532,6 +532,7 @@ Advanced usage: Tokens that are replaced when generating the output (--output) path of a ROM: {datName} The name of the DAT that contains the ROM (e.g. "Nintendo - Game Boy") + {datDescription} The description of the DAT that contains the ROM {datReleaseRegion} The region of the ROM release (e.g. "USA"), each ROM can have multiple {datReleaseLanguage} The language of the ROM release (e.g. "En"), each ROM can have multiple {gameType} The type of the game (e.g. "Retail", "Demo", "Prototype") diff --git a/src/types/options.ts b/src/types/options.ts index 90f1103aa..e33fb3ea6 100644 --- a/src/types/options.ts +++ b/src/types/options.ts @@ -732,7 +732,15 @@ export default class Options implements OptionsProps { } private static replaceDatTokens(input: string, dat: DAT): string { - return input.replace('{datName}', dat.getName().replace(/[\\/]/g, '_')); + let output = input; + output = output.replace('{datName}', dat.getName().replace(/[\\/]/g, '_')); + + const description = dat.getDescription(); + if (description) { + output = output.replace('{datDescription}', description.replace(/[\\/]/g, '_')); + } + + return output; } private static replaceGameTokens(input: string, game?: Game): string { diff --git a/test/types/options.test.ts b/test/types/options.test.ts index 87b9fc71e..bb836cd7c 100644 --- a/test/types/options.test.ts +++ b/test/types/options.test.ts @@ -19,6 +19,7 @@ describe('getOutputDirRoot', () => { ['games/{mister}/', 'games'], ['Roms/{onion}/', 'Roms'], ['{datName}', '.'], + ['{datDescription}', '.'], ])('should find the root dir: %s', (output, expectedPath) => { expect(new Options({ commands: ['copy'], output }).getOutputDirRoot()).toEqual(expectedPath); }); @@ -46,10 +47,11 @@ describe('getOutputFileParsed', () => { describe('token replacement', () => { test.each([ ['foo/{datName}/bar', path.join('foo', 'DAT _ Name', 'bar', 'game.rom')], + ['foo/{datDescription}/bar', path.join('foo', 'DAT _ Description', 'bar', 'game.rom')], ['root/{datReleaseRegion}', path.join('root', 'USA', 'game.rom')], ['root/{datReleaseLanguage}', path.join('root', 'En', 'game.rom')], ])('should replace {dat*}: %s', (output, expectedPath) => { - const dat = new DAT(new Header({ name: 'DAT / Name' }), []); + const dat = new DAT(new Header({ name: 'DAT / Name', description: 'DAT \\ Description' }), []); const release = new Release('Game Name', 'USA', 'En'); expect(new Options({ commands: ['copy'], output }).getOutputFileParsed(dat, dummyInputRomPath, dummyGame, release, 'game.rom')).toEqual(expectedPath); });