From ecbaa7dff3ae49570fd76dfde0a9b9da6862f788 Mon Sep 17 00:00:00 2001 From: Martijn Versluis Date: Sat, 14 Dec 2024 21:05:44 +0100 Subject: [PATCH] Test directive selector See https://www.chordpro.org/chordpro/chordpro-directives/#conditional-directives Related to https://github.com/martijnversluis/ChordSheetJS/issues/983 --- src/formatter/configuration/configuration.ts | 14 ++++- .../configuration/instrument_configuration.ts | 17 ++++++ .../configuration/metadata_configuration.ts | 4 +- .../configuration/user_configuration.ts | 17 ++++++ src/helpers.ts | 16 ++++++ test/helpers.test.ts | 55 ++++++++++++++++++- 6 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 src/formatter/configuration/instrument_configuration.ts create mode 100644 src/formatter/configuration/user_configuration.ts diff --git a/src/formatter/configuration/configuration.ts b/src/formatter/configuration/configuration.ts index 91949c4af..f730baf78 100644 --- a/src/formatter/configuration/configuration.ts +++ b/src/formatter/configuration/configuration.ts @@ -6,6 +6,9 @@ import MetadataConfiguration, { MetadataConfigurationProperties, } from './metadata_configuration'; +import InstrumentConfiguration, { InstrumentConfigurationProperties } from './instrument_configuration'; +import UserConfiguration, { UserConfigurationProperties } from './user_configuration'; + export type Delegate = (_string: string) => string; export const defaultDelegate: Delegate = (string: string) => string; @@ -17,6 +20,8 @@ export type ConfigurationProperties = Record & { useUnicodeModifiers: boolean, normalizeChords: boolean, delegates: Partial>; + instrument?: InstrumentConfigurationProperties; + user?: UserConfigurationProperties; }; export const defaultConfiguration: ConfigurationProperties = { @@ -41,8 +46,6 @@ class Configuration { key: Key | null; - configuration: Record; - expandChorusDirective: boolean; useUnicodeModifiers: boolean; @@ -51,6 +54,10 @@ class Configuration { delegates: Partial>; + instrument?: InstrumentConfiguration; + + user?: UserConfiguration; + get metadataSeparator(): string { return this.metadata.separator ?? ''; } @@ -64,7 +71,8 @@ class Configuration { this.metadata = new MetadataConfiguration(configuration.metadata); this.key = configuration.key ? Key.wrap(configuration.key) : null; this.delegates = { ...defaultConfiguration.delegates, ...configuration.delegates }; - this.configuration = { configuration, delegates: this.delegates }; + this.instrument = configuration.instrument ? new InstrumentConfiguration(configuration.instrument) : undefined; + this.user = configuration.user ? new UserConfiguration(configuration.user) : undefined; } } diff --git a/src/formatter/configuration/instrument_configuration.ts b/src/formatter/configuration/instrument_configuration.ts new file mode 100644 index 000000000..3ef1eb62e --- /dev/null +++ b/src/formatter/configuration/instrument_configuration.ts @@ -0,0 +1,17 @@ +export interface InstrumentConfigurationProperties { + type?: string; + description?: string; +} + +class InstrumentConfiguration { + type?: string; + + description?: string; + + constructor(instrumentConfiguration: Partial = {}) { + this.type = instrumentConfiguration.type; + this.description = instrumentConfiguration.description; + } +} + +export default InstrumentConfiguration; diff --git a/src/formatter/configuration/metadata_configuration.ts b/src/formatter/configuration/metadata_configuration.ts index d82401886..f324a7668 100644 --- a/src/formatter/configuration/metadata_configuration.ts +++ b/src/formatter/configuration/metadata_configuration.ts @@ -9,8 +9,8 @@ export const defaultMetadataConfiguration: MetadataConfigurationProperties = { class MetadataConfiguration { separator?: string; - constructor(metadataConfiguration: MetadataConfigurationProperties = defaultMetadataConfiguration) { - this.separator = metadataConfiguration.separator; + constructor(metadataConfiguration: Partial = {}) { + this.separator = metadataConfiguration.separator || defaultMetadataConfiguration.separator; } } diff --git a/src/formatter/configuration/user_configuration.ts b/src/formatter/configuration/user_configuration.ts new file mode 100644 index 000000000..0697809d7 --- /dev/null +++ b/src/formatter/configuration/user_configuration.ts @@ -0,0 +1,17 @@ +export interface UserConfigurationProperties { + name?: string; + fullname?: string; +} + +class UserConfiguration { + name?: string; + + fullname?: string; + + constructor(userConfiguration: Partial = {}) { + this.name = userConfiguration.name; + this.fullname = userConfiguration.fullname; + } +} + +export default UserConfiguration; diff --git a/src/helpers.ts b/src/helpers.ts index 797dbda8d..b5eb7f5ab 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -4,6 +4,8 @@ import { capos, majorKeys, minorKeys } from './key_config'; import Song from './chord_sheet/song'; import { CAPO, CHORD_STYLE, ChordType } from './chord_sheet/tag'; import Line from './chord_sheet/line'; +import Configuration from './formatter/configuration/configuration'; +import Metadata from './chord_sheet/metadata'; export function transposeDistance(transposeKey: string, songKey: string): number { if (/^\d+$/.test(transposeKey)) { @@ -109,3 +111,17 @@ export function getKeys(key: Key | string): string[] { const chordType = keyObj.type === 'solfege' ? 'solfege' : 'symbol'; return keyObj.isMinor() ? minorKeys[chordType] : majorKeys[chordType]; } + +export function testSelector(selector: string, configuration: Configuration, metadata: Metadata) { + if (selector === configuration.instrument?.type) { + return true; + } + + if (selector === configuration.user?.name) { + return true; + } + + const metadataValue = metadata.getSingle(selector); + + return !!(metadataValue && metadataValue !== ''); +} diff --git a/test/helpers.test.ts b/test/helpers.test.ts index 98d90d4e7..673fec4c2 100644 --- a/test/helpers.test.ts +++ b/test/helpers.test.ts @@ -1,7 +1,9 @@ import Song from '../src/chord_sheet/song'; import { createLine } from './utilities'; -import { renderChord } from '../src/helpers'; +import { renderChord, testSelector } from '../src/helpers'; import Key from '../src/key'; +import Metadata from '../src/chord_sheet/metadata'; +import Configuration from '../src/formatter/configuration/configuration'; describe('renderChord', () => { it('correctly normalizes when a capo is set', () => { @@ -29,3 +31,54 @@ describe('renderChord', () => { expect(renderChord('Dm7', line, song, { renderKey: Key.parse('B'), useUnicodeModifier: true })).toEqual('G♯m7'); }); }); + +describe('testSelector', () => { + it('returns true when the selector matches the configured instrument type', () => { + const configuration = new Configuration({ instrument: { type: 'guitar' } }); + const metadata = new Metadata(); + + expect(testSelector('guitar', configuration, metadata)).toEqual(true); + }); + + it('returns false when the selector does not match the configured instrument type', () => { + const configuration = new Configuration({ instrument: { type: 'guitar' } }); + const metadata = new Metadata(); + + expect(testSelector('piano', configuration, metadata)).toEqual(false); + }); + + it('return true when the selector matches the configured user name', () => { + const configuration = new Configuration({ user: { name: 'john' } }); + const metadata = new Metadata(); + + expect(testSelector('john', configuration, metadata)).toEqual(true); + }); + + it('returns false when the selector does not match the configured user name', () => { + const configuration = new Configuration({ user: { name: 'john' } }); + const metadata = new Metadata(); + + expect(testSelector('jane', configuration, metadata)).toEqual(false); + }); + + it('returns true when the selector matches a truthy metadata value', () => { + const configuration = new Configuration(); + const metadata = new Metadata({ 'horns': 'true' }); + + expect(testSelector('horns', configuration, metadata)).toEqual(true); + }); + + it('returns false when the selector matches an empty metadata value', () => { + const configuration = new Configuration(); + const metadata = new Metadata({ 'horns': '' }); + + expect(testSelector('horns', configuration, metadata)).toEqual(false); + }); + + it('returns false when the selector does not match a metadata value', () => { + const configuration = new Configuration(); + const metadata = new Metadata(); + + expect(testSelector('horns', configuration, metadata)).toEqual(false); + }); +});