From cb7ac26e117067cd9c42c48798c88405081f998e Mon Sep 17 00:00:00 2001 From: Grzegorz Pietrzak Date: Mon, 15 Jan 2024 18:46:11 +0100 Subject: [PATCH] Add code quality workflow and update composer.json. Also add data-chord attribute. --- .github/workflows/codequality.yml | 45 ++++++++++++++++++++++++ README.md | 49 +++++++++++++++------------ composer.json | 13 +++++++ src/Formatter/HtmlFormatter.php | 9 +++-- src/Formatter/JSONFormatter.php | 6 +++- tests/Formatter/HtmlFormatterTest.php | 4 +-- 6 files changed, 100 insertions(+), 26 deletions(-) create mode 100644 .github/workflows/codequality.yml diff --git a/.github/workflows/codequality.yml b/.github/workflows/codequality.yml new file mode 100644 index 0000000..af1f347 --- /dev/null +++ b/.github/workflows/codequality.yml @@ -0,0 +1,45 @@ +name: PHP Composer + +on: + push: + branches: [ "master", "develop" ] + pull_request: + branches: [ "master", "develop" ] + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v3 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + - name: Run test suite + run: composer run-script test + + - name: Run phpcs + run: composer run-script cs + + - name: Run phpstan + run: composer run-script phpstan + + - name: Run php-compatibility + run: composer run-script php-compatibility diff --git a/README.md b/README.md index 954333c..310560f 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,25 @@ -# The chordpro-php library +# The chordpro-php library 🎸 A simple tool to parse, transpose & format [ChordPro](https://www.chordpro.org) songs with lyrics & chords. -Forked from by [Nicolaz Wurtz](https://github.com/nicolaswurtz), on LGPL-3 license. +_Forked from by [Nicolaz Wurtz](https://github.com/nicolaswurtz), on LGPL-3 license._ -The following output formats are currently supported +The following output formats are currently supported: -- HTML (verses contain blocks with embedded `span` for aligning chords with lyrics) -- JSON (verses are arrays of chords and lyrics for alignment purposes) -- Plain text (chords are aligned with monospace text thanks to whitespace) +- **HTML** (verses contain blocks with embedded `span` for aligning chords with lyrics). +- **JSON** (verses are arrays of chords and lyrics for alignment purposes). +- **Plain text** (chords are aligned with monospace text thanks to whitespace). -And provides some extra functionality: +The library provides some extra functionality: - Tranpose chords by semitones or to the target key. - Parse and display various chord notations: - - French (`Do`, `Ré`, `Mi`) - - German (`Fis`, `a`) - - With UTF characters (`A♭`, `F♯`) + - French (`Do`, `Ré`, `Mi`). + - German (`Fis`, `a`). + - With UTF characters (`A♭`, `F♯`). - Guess the key of a song. -## Install +## Installation Via composer: @@ -29,17 +29,19 @@ composer require intelektron/chordpro-php ## Usage -See `web/example.php` for demo with CSS styling. +See [web/example.php] for demo with CSS styling. ``` php parse($txt); $transposer = new ChordPro\Transposer(); // Define how many semitones you want to transpose by. -$transposer->transpose($song,-5); +$transposer->transpose($song, -5); // If the song key is known, you can also transpose from key to key. // $transposer->transpose($song,'Abm'); @@ -100,7 +103,7 @@ Simply give an array with values at true or false for each key/option. The key can be set/changed in the following ways: - Manually, by calling `$song->setKey('A')`. -- By parsing a song with metadata, e.g. `{key:A}` +- By parsing a song with metadata, e.g. `{key:A}`. - By transposing the song to another key. You can get the key by calling: @@ -117,7 +120,7 @@ $key = $guess->guessKey($song); ## Chord notations -The library supports several chord notations. You can also create your own (by implementing `ChordNotationInterface`). Notations are used for both parsing and formatting. So you can parse a song in German notation and display it as French: +The library supports several chord notations. You can also create your own (by implementing [src/Notation/ChordNotationInterface.php]). Notations are used for both parsing and formatting. So you can parse a song in German notation and display it as French: ```php $txt = 'A typical [fis]German [a]verse'; @@ -126,7 +129,7 @@ $notation = new ChordPro\Notation\GermanChordNotation(); $song = $parser->parse($song, [$notation]) ``` -At this point, `fis` is recognized and saved as `F#m`, and `a` is saved as `Am`. Note that you can pass multiple notations to the parser, in order of precedence. This can be useful if you have mixed up chord notations in one song. +At this point, `fis` is recognized and saved internally as `F#m`, and `a` is saved as `Am`. Note that you can pass multiple notations to the parser, in order of precedence. This can be useful if you have mixed up chord notations in one song. Now, to show this song in French: @@ -140,27 +143,31 @@ $html = $monospaceFormatter->format($song, [ // A typical German verse ``` +The `UtfChordFormatter` provides a nice-looking chords with `♭` and `♯` symbols instead of ASCII characters. + ## Styling the HTML code ### Song lines -Lines are made up of blocks. Each block consists of a text and a chord. The chord has the class `chordpro-chord' and the text has the class `chordpro-text'. +Lines are made up of blocks. Each block consists of a text and a chord. The chord has the class `chordpro-chord` and the text has the class `chordpro-text`. A typical line of the song looks like this: ```html
- C + C This is the - + Dm beautiful song
``` +The `data-chord` attribute stores an English representation of the chord, regardless of the output notation. + ### Song sections The ChordPro format allows to organize your songs into sections. The following song fragment: diff --git a/composer.json b/composer.json index 6ec8491..fc735b9 100644 --- a/composer.json +++ b/composer.json @@ -33,6 +33,19 @@ "email": "grzegorz.pietrzak@gmail.com" } ], + "scripts": { + "test": "phpunit tests", + "phpstan": "phpstan analyse", + "php-compatibility": "phpcs --standard=phpcs.xml", + "cs": "php-cs-fixer fix --config=.php-cs-fixer.php --dry-run --diff", + "cs-fix": "php-cs-fixer fix --config=.php-cs-fixer.php", + "check": [ + "@test", + "@phpstan", + "@php-compatibility", + "@cs" + ] + }, "config": { "allow-plugins": { "phpstan/extension-installer": true diff --git a/src/Formatter/HtmlFormatter.php b/src/Formatter/HtmlFormatter.php index 4987caa..29fe460 100644 --- a/src/Formatter/HtmlFormatter.php +++ b/src/Formatter/HtmlFormatter.php @@ -73,26 +73,31 @@ private function getLyricsHtml(Lyrics $lyrics): string $line = '
'."\n"; foreach ($lyrics->getBlocks() as $block) { + $originalChords = []; $chords = []; $slicedChords = $block->getChords(); foreach ($slicedChords as $slicedChord) { if ($slicedChord->isKnown()) { - $ext = $slicedChord->getExt(); + $ext = $slicedChord->getExt($this->notation); if ($ext !== '') { $ext = ''.$ext.''; } + $chords[] = $slicedChord->getRootChord($this->notation).$ext; + $originalChords[] = $slicedChord->getRootChord().$slicedChord->getExt(); } else { $chords[] = $slicedChord->getOriginalName(); + $originalChords[] = $slicedChord->getOriginalName(); } } $chord = implode('/', $chords); + $originalChord = implode('/', $originalChords); $text = $this->blankChars($block->getText()); $line .= '' . - ''.$chord.'' . + ''.$chord.'' . ''.$text.'' . ''; } diff --git a/src/Formatter/JSONFormatter.php b/src/Formatter/JSONFormatter.php index 2b3e5f6..186cc87 100644 --- a/src/Formatter/JSONFormatter.php +++ b/src/Formatter/JSONFormatter.php @@ -69,18 +69,22 @@ private function getLyricsJSON(Lyrics $lyrics): array $return = []; foreach ($lyrics->getBlocks() as $block) { $chords = []; + $originalChords = []; $slicedChords = $block->getChords(); foreach ($slicedChords as $slicedChord) { if ($slicedChord->isKnown()) { $chords[] = $slicedChord->getRootChord($this->notation).$slicedChord->getExt($this->notation); + $originalChords[] = $slicedChord->getRootChord().$slicedChord->getExt(); } else { $chords[] = $slicedChord->getOriginalName(); + $originalChords[] = $slicedChord->getOriginalName(); } } $chord = implode('/', $chords).' '; + $originalChord = implode('/', $originalChords).' '; $text = $block->getText(); - $return[] = ['chord' => trim($chord), 'text' => $text]; + $return[] = ['chord' => trim($chord), 'text' => $text, 'originalChord' => trim($originalChord)]; } return [ 'type' => 'line', diff --git a/tests/Formatter/HtmlFormatterTest.php b/tests/Formatter/HtmlFormatterTest.php index f01adeb..0b47f38 100644 --- a/tests/Formatter/HtmlFormatterTest.php +++ b/tests/Formatter/HtmlFormatterTest.php @@ -20,7 +20,7 @@ public function testWithChords(): void '
' . "\n" . '
' . "\n" . '
' . "\n" . - 'C7Test DTest2' . "\n" . + 'C7Test DTest2' . "\n" . '
' . "\n" . '
' . "\n"; @@ -61,7 +61,7 @@ public function testWithoutMetadata(): void $expected = '
' . "\n" . '
' . "\n" . '
' . "\n" . - 'C7Test DTest2' . "\n" . + 'C7Test DTest2' . "\n" . '
' . "\n" . '
' . "\n";