From 251793de06d9c988a9c4f7adc9f4e0a92f09579e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Ma=C3=B1osa?= Date: Thu, 6 Apr 2023 00:01:05 +0200 Subject: [PATCH 1/6] chore(vscode): include `settings.json` --- .gitignore | 1 - .vscode/settings.json | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index be3454dc..6f752892 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,6 @@ coverage/ test/.test_coverage.dart .coveralls.yaml -.vscode/ doc/api/ # Avoid committing generated Javascript files: diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..70b5ac5e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cSpell.ignoreWords": ["music"] +} From 366be5eed0cb8521cf9df1192c9fed88b9d71e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Ma=C3=B1osa?= Date: Thu, 6 Apr 2023 00:01:39 +0200 Subject: [PATCH 2/6] chore(pubspec): bump versions as of Dart SDK 2.19 --- pubspec.yaml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 4a7cd105..262f31c7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,13 +5,14 @@ version: 0.1.0 repository: https://github.com/albertms10/music_notes.git environment: - sdk: ">=2.16.1 <3.0.0" + sdk: ">=2.19.0 <3.0.0" dependencies: - collection: ^1.16.0 - meta: ^1.7.0 - quiver: ^3.0.1+1 - test: ^1.20.1 + collection: any + meta: any + quiver: ^3.2.1 + test: ^1.24.1 dev_dependencies: - very_good_analysis: ^2.4.0 + dart_code_metrics: ^5.7.0 + very_good_analysis: ^4.0.0+1 From 87bf17d34267db8b45330ee1668ec53e7c120954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Ma=C3=B1osa?= Date: Thu, 6 Apr 2023 00:04:47 +0200 Subject: [PATCH 3/6] feat(analysis): add `dart_code_metrics` and refactor code --- analysis_options.yaml | 119 +++++++++++++---------- lib/src/classes/enharmonic.dart | 2 +- lib/src/classes/enharmonic_interval.dart | 6 +- lib/src/classes/enharmonic_note.dart | 4 +- lib/src/classes/interval.dart | 2 +- lib/src/classes/key_signature.dart | 2 +- lib/src/classes/note.dart | 2 +- lib/src/classes/relative_tonalities.dart | 2 +- lib/src/classes/tonality.dart | 2 +- lib/src/enums/accidentals.dart | 2 +- lib/src/enums/intervals.dart | 6 +- lib/src/enums/modes.dart | 2 +- lib/src/enums/notes.dart | 2 +- lib/src/enums/qualities.dart | 5 +- lib/src/interfaces/music_item.dart | 2 +- lib/src/interfaces/transposable.dart | 2 +- lib/src/utils/iterable.dart | 1 + lib/src/utils/music.dart | 3 +- test/music_test.dart | 10 +- 19 files changed, 99 insertions(+), 77 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 9fdb62cb..493095c8 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -2,62 +2,77 @@ include: package:very_good_analysis/analysis_options.yaml linter: rules: - - always_put_required_named_parameters_first - - avoid_bool_literals_in_conditional_expressions - - avoid_catches_without_on_clauses - avoid_classes_with_only_static_members - - avoid_dynamic_calls - - avoid_function_literals_in_foreach_calls - - avoid_redundant_argument_values - - avoid_renaming_method_parameters - - avoid_returning_null_for_future - - avoid_void_async - - avoid_web_libraries_in_flutter - - cascade_invocations - - lines_longer_than_80_chars + - avoid_types_on_closure_parameters - cancel_subscriptions - - constant_identifier_names - - deprecated_consistency - - depend_on_referenced_packages - - directives_ordering - - eol_at_end_of_file - - flutter_style_todos - - no_default_cases - - noop_primitive_operations - - omit_local_variable_types - - only_throw_errors - - prefer_const_constructors - - prefer_const_literals_to_create_immutables - - prefer_expression_function_bodies - - prefer_contains - - prefer_final_in_for_each - - prefer_final_locals - # - prefer_final_parameters - # - public_member_api_docs - - prefer_if_elements_to_conditional_expressions - - prefer_interpolation_to_compose_strings - - prefer_is_empty - - prefer_is_not_empty - - prefer_single_quotes - - prefer_void_to_null - - require_trailing_commas - - sort_pub_dependencies - - sort_unnamed_constructors_first - - type_annotate_public_apis - - unawaited_futures - - unnecessary_null_checks - - unnecessary_parenthesis - - unnecessary_statements - - use_build_context_synchronously - - use_late_for_private_fields_and_variables - - use_setters_to_change_properties - - use_test_throws_matchers - - use_to_and_as_if_applicable + # - discarded_futures + - unnecessary_null_aware_operator_on_extension_on_nullable + +dart_code_metrics: + metrics: + cyclomatic-complexity: 20 + maximum-nesting-level: 5 + number-of-arguments: 4 + metrics-exclude: + - test/** + rules: + - arguments-ordering + - avoid-cascade-after-if-null + - avoid-collection-methods-with-unrelated-types + - avoid-double-slash-imports + - avoid-duplicate-exports + - avoid-global-state + - avoid-missing-enum-constant-in-map + - avoid-nested-conditional-expressions: + acceptable-level: 2 + - avoid-redundant-async + - avoid-throw-in-catch-block + - avoid-unnecessary-conditionals + - avoid-unnecessary-setstate + - avoid-unnecessary-type-assertions + - avoid-unnecessary-type-casts + - avoid-unrelated-type-assertions + - binary-expression-operand-order + - double-literal-format + - format-comment: + ignored-patterns: + - ^coverage.* + # - member-ordering + - missing-test-assertion + - newline-before-return + - no-boolean-literal-compare + - no-equal-then-else + # - no-magic-number + - prefer-conditional-expressions + - prefer-correct-test-file-name: + exclude: + - lib/** + - bin/** + - "**/main.dart" + - prefer-enums-by-name + # - prefer-extracting-callbacks + - prefer-first + - prefer-immediate-return + - prefer-iterable-of + - prefer-last + - prefer-match-file-name: + exclude: + - test/** + # - prefer-moving-to-variable + - prefer-trailing-comma + anti-patterns: + - long-parameter-list analyzer: + plugins: + - dart_code_metrics + errors: - always_put_required_named_parameters_first: ignore - implicit_dynamic_map_literal: ignore - prefer_int_literals: ignore + avoid_equals_and_hash_code_on_mutable_classes: ignore public_member_api_docs: ignore + unused_element: ignore # See https://github.com/dart-lang/sdk/issues/49025 + + # Style decisions + always_put_required_named_parameters_first: ignore + always_use_package_imports: ignore sort_constructors_first: ignore diff --git a/lib/src/classes/enharmonic.dart b/lib/src/classes/enharmonic.dart index 05dbcd1c..a2650e18 100644 --- a/lib/src/classes/enharmonic.dart +++ b/lib/src/classes/enharmonic.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; @immutable abstract class Enharmonic diff --git a/lib/src/classes/enharmonic_interval.dart b/lib/src/classes/enharmonic_interval.dart index 52b75612..993032c5 100644 --- a/lib/src/classes/enharmonic_interval.dart +++ b/lib/src/classes/enharmonic_interval.dart @@ -1,7 +1,7 @@ -part of music_notes; +part of '../../music_notes.dart'; class EnharmonicInterval extends Enharmonic { - EnharmonicInterval(Set items) : super(items); + EnharmonicInterval(super.items); EnharmonicInterval.fromSemitones(int semitones) : this(_fromSemitones(semitones)); @@ -34,7 +34,7 @@ class EnharmonicInterval extends Enharmonic { if (QualitiesValues.exists(intervalBelow, semitones)) Interval.fromDesiredSemitones(intervalBelow!, semitones), if (QualitiesValues.exists(intervalAbove, semitones)) - Interval.fromDesiredSemitones(intervalAbove!, semitones) + Interval.fromDesiredSemitones(intervalAbove!, semitones), }); } diff --git a/lib/src/classes/enharmonic_note.dart b/lib/src/classes/enharmonic_note.dart index edcd269b..21efe8f5 100644 --- a/lib/src/classes/enharmonic_note.dart +++ b/lib/src/classes/enharmonic_note.dart @@ -1,7 +1,7 @@ -part of music_notes; +part of '../../music_notes.dart'; class EnharmonicNote extends Enharmonic { - EnharmonicNote(Set items) : super(items); + EnharmonicNote(super.items); EnharmonicNote.fromSemitones(int semitones) : this(_fromSemitones(semitones)); diff --git a/lib/src/classes/interval.dart b/lib/src/classes/interval.dart index bb51d6a6..b9863054 100644 --- a/lib/src/classes/interval.dart +++ b/lib/src/classes/interval.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; @immutable class Interval implements MusicItem, Comparable { diff --git a/lib/src/classes/key_signature.dart b/lib/src/classes/key_signature.dart index 83d769a5..8fbc5f14 100644 --- a/lib/src/classes/key_signature.dart +++ b/lib/src/classes/key_signature.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; @immutable class KeySignature { diff --git a/lib/src/classes/note.dart b/lib/src/classes/note.dart index 8ea68fca..31335c76 100644 --- a/lib/src/classes/note.dart +++ b/lib/src/classes/note.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; @immutable class Note implements MusicItem, Comparable { diff --git a/lib/src/classes/relative_tonalities.dart b/lib/src/classes/relative_tonalities.dart index 5cbac137..62283f8a 100644 --- a/lib/src/classes/relative_tonalities.dart +++ b/lib/src/classes/relative_tonalities.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; @immutable class RelativeTonalities implements Comparable { diff --git a/lib/src/classes/tonality.dart b/lib/src/classes/tonality.dart index 52325603..642dc1f6 100644 --- a/lib/src/classes/tonality.dart +++ b/lib/src/classes/tonality.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; @immutable class Tonality implements Comparable { diff --git a/lib/src/enums/accidentals.dart b/lib/src/enums/accidentals.dart index d6db46eb..774018b1 100644 --- a/lib/src/enums/accidentals.dart +++ b/lib/src/enums/accidentals.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; enum Accidentals { tripleSharp, diff --git a/lib/src/enums/intervals.dart b/lib/src/enums/intervals.dart index 3281e5db..b6015577 100644 --- a/lib/src/enums/intervals.dart +++ b/lib/src/enums/intervals.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; enum Intervals { unison, @@ -18,7 +18,8 @@ enum Intervals { } extension IntervalsValues on Intervals { - static const intervalsQualitiesIndex = { + // ignore: avoid-missing-enum-constant-in-map + static const Map intervalsQualitiesIndex = { Intervals.unison: 0, Intervals.second: 1, Intervals.third: 3, @@ -142,6 +143,7 @@ extension IntervalsValues on Intervals { /// ``` Intervals get inverted { final diff = 9 - simplified.ordinal; + return fromOrdinal(diff > 0 ? diff : diff.abs() + 2); } } diff --git a/lib/src/enums/modes.dart b/lib/src/enums/modes.dart index b5b626cf..6570894e 100644 --- a/lib/src/enums/modes.dart +++ b/lib/src/enums/modes.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; enum Modes { major, minor } diff --git a/lib/src/enums/notes.dart b/lib/src/enums/notes.dart index c0f3ee26..2d6a9747 100644 --- a/lib/src/enums/notes.dart +++ b/lib/src/enums/notes.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; enum Notes { ut, re, mi, fa, sol, la, si } diff --git a/lib/src/enums/qualities.dart b/lib/src/enums/qualities.dart index 39ecc03d..5e86f18d 100644 --- a/lib/src/enums/qualities.dart +++ b/lib/src/enums/qualities.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; enum Qualities { augmented, major, perfect, minor, diminished } @@ -24,6 +24,7 @@ extension QualitiesValues on Qualities { Qualities.augmented, }; + // ignore: avoid-missing-enum-constant-in-map static const invertedQualities = { Qualities.augmented: Qualities.diminished, Qualities.perfect: Qualities.perfect, @@ -57,6 +58,7 @@ extension QualitiesValues on Qualities { if (interval == null) return false; final delta = semitones - interval.semitones + (interval.isPerfect ? 0 : 1); + return delta > 0 && delta <= intervalQualities(interval).length; } @@ -91,6 +93,7 @@ extension QualitiesValues on Qualities { /// ``` Qualities get inverted { final inverted = invertedQualities[this]; + return inverted ?? invertedQualities.keys .firstWhere((quality) => this == invertedQualities[quality]); diff --git a/lib/src/interfaces/music_item.dart b/lib/src/interfaces/music_item.dart index eb20deff..24dda11d 100644 --- a/lib/src/interfaces/music_item.dart +++ b/lib/src/interfaces/music_item.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; abstract class MusicItem { /// Returns the number of semitones that correspond to this [MusicItem]. diff --git a/lib/src/interfaces/transposable.dart b/lib/src/interfaces/transposable.dart index 89baa218..6643f358 100644 --- a/lib/src/interfaces/transposable.dart +++ b/lib/src/interfaces/transposable.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; abstract class Transposable { /// Returns a transposed [T] by [semitones] from this [T]. diff --git a/lib/src/utils/iterable.dart b/lib/src/utils/iterable.dart index 581231c0..bc3f478d 100644 --- a/lib/src/utils/iterable.dart +++ b/lib/src/utils/iterable.dart @@ -5,5 +5,6 @@ int compareMultiple(Iterable comparables) { compareValue = comparable(); if (compareValue != 0) break; } + return compareValue; } diff --git a/lib/src/utils/music.dart b/lib/src/utils/music.dart index 7825b52a..7f416b82 100644 --- a/lib/src/utils/music.dart +++ b/lib/src/utils/music.dart @@ -1,4 +1,4 @@ -part of music_notes; +part of '../../music_notes.dart'; /// Number of chromatic divisions in an octave. const int chromaticDivisions = 12; @@ -106,5 +106,6 @@ int chromaticModExcludeZero(int value) => /// ``` int nModExcludeZero(int value, int n) { final modValue = value % n; + return modValue == 0 ? n : modValue; } diff --git a/test/music_test.dart b/test/music_test.dart index 4dbdfb4f..088c4028 100644 --- a/test/music_test.dart +++ b/test/music_test.dart @@ -11,14 +11,14 @@ void main() { }), EnharmonicNote({ const Note(Notes.ut, Accidentals.sharp), - const Note(Notes.re, Accidentals.flat) + const Note(Notes.re, Accidentals.flat), }), EnharmonicNote({ const Note(Notes.re), }), EnharmonicNote({ const Note(Notes.re, Accidentals.sharp), - const Note(Notes.mi, Accidentals.flat) + const Note(Notes.mi, Accidentals.flat), }), EnharmonicNote({ const Note(Notes.mi), @@ -28,14 +28,14 @@ void main() { }), EnharmonicNote({ const Note(Notes.fa, Accidentals.sharp), - const Note(Notes.sol, Accidentals.flat) + const Note(Notes.sol, Accidentals.flat), }), EnharmonicNote({ const Note(Notes.sol), }), EnharmonicNote({ const Note(Notes.sol, Accidentals.sharp), - const Note(Notes.la, Accidentals.flat) + const Note(Notes.la, Accidentals.flat), }), EnharmonicNote({ const Note(Notes.la), @@ -46,7 +46,7 @@ void main() { }), EnharmonicNote({ const Note(Notes.si), - }) + }), ]), ); }); From e2d6bda4f3eea587dbfd0b8056cf4bef949f6f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Ma=C3=B1osa?= Date: Thu, 6 Apr 2023 00:17:32 +0200 Subject: [PATCH 4/6] ci(analysis): bump versions, run DCM and strengthen security --- .github/workflows/analysis-ci.yml | 63 +++++++++++++++++++++++++++++++ .github/workflows/dart.yml | 38 ------------------- 2 files changed, 63 insertions(+), 38 deletions(-) create mode 100644 .github/workflows/analysis-ci.yml delete mode 100644 .github/workflows/dart.yml diff --git a/.github/workflows/analysis-ci.yml b/.github/workflows/analysis-ci.yml new file mode 100644 index 00000000..92d981f4 --- /dev/null +++ b/.github/workflows/analysis-ci.yml @@ -0,0 +1,63 @@ +name: Analysis CI + +on: + push: + branches: [main] + + pull_request: + branches: [main] + types: [opened, synchronize, ready_for_review, reopened] + +env: + DART_SDK_VERSION: "2.19.6" + +permissions: + contents: read + +jobs: + build: + name: Analyze + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 + + - name: Cache dependencies + uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + id: cache + with: + path: ~/.pub-cache/hosted + key: ${{ runner.os }}-pubspec-${{ env.DART_SDK_VERSION }}-${{ hashFiles('**/pubspec.lock') }} + restore-keys: | + ${{ runner.os }}-pubspec-${{ env.DART_SDK_VERSION }}- + ${{ runner.os }}-pubspec- + ${{ runner.os }}- + + - name: Set up Dart + uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f # v1.5.0 + with: + sdk: ${{ env.DART_SDK_VERSION }} + + - name: Verify formatting + run: dart format --output=none --set-exit-if-changed . + + - name: Install dependencies + run: dart pub get + + - name: Analyze project source + run: dart analyze --no-pub --fatal-infos + + - name: Analyze Dart Code Metrics + run: dart run dart_code_metrics:metrics analyze lib --fatal-style --fatal-performance + + - name: Run tests + run: | + dart pub global activate coverage + dart test --coverage=coverage + dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.packages --report-on=lib + + - name: Coveralls upload + uses: coverallsapp/github-action@67662d24394fd74bffcf7b462d1b432814159afd # v2.0.0 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml deleted file mode 100644 index f5b46bf2..00000000 --- a/.github/workflows/dart.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Dart CI - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - uses: dart-lang/setup-dart@v1.3 - with: - sdk: '2.16.1' - - - name: Install dependencies - run: dart pub get - - - name: Verify formatting - run: dart format --output=none --set-exit-if-changed . - - - name: Analyze project source - run: dart analyze --fatal-infos - - - name: Run tests - run: | - dart pub global activate coverage - dart test --coverage=coverage - dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.packages --report-on=lib - - - name: Coveralls upload - uses: coverallsapp/github-action@1.1.3 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} From 19631f5c6a9639c8785d2766223d9a57a9773761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Ma=C3=B1osa?= Date: Thu, 6 Apr 2023 00:20:02 +0200 Subject: [PATCH 5/6] ci(analysis): remove `--no-pub` option from `dart analyze` Only available in `flutter analyze` --- .github/workflows/analysis-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/analysis-ci.yml b/.github/workflows/analysis-ci.yml index 92d981f4..bbbb7f6d 100644 --- a/.github/workflows/analysis-ci.yml +++ b/.github/workflows/analysis-ci.yml @@ -46,7 +46,7 @@ jobs: run: dart pub get - name: Analyze project source - run: dart analyze --no-pub --fatal-infos + run: dart analyze --fatal-infos - name: Analyze Dart Code Metrics run: dart run dart_code_metrics:metrics analyze lib --fatal-style --fatal-performance From 88955ef22d54aa695ef664138654d3f4927cb21a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Ma=C3=B1osa?= Date: Thu, 6 Apr 2023 00:23:50 +0200 Subject: [PATCH 6/6] ci(analysis): remove discontinued `.packages` file reference See https://github.com/dart-lang/sdk/issues/48272 --- .github/workflows/analysis-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/analysis-ci.yml b/.github/workflows/analysis-ci.yml index bbbb7f6d..898241ba 100644 --- a/.github/workflows/analysis-ci.yml +++ b/.github/workflows/analysis-ci.yml @@ -55,7 +55,7 @@ jobs: run: | dart pub global activate coverage dart test --coverage=coverage - dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.packages --report-on=lib + dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --report-on=lib - name: Coveralls upload uses: coverallsapp/github-action@67662d24394fd74bffcf7b462d1b432814159afd # v2.0.0