• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

albertms10 / music_notes / 17359725584

31 Aug 2025 04:36PM UTC coverage: 99.76% (-0.2%) from 100.0%
17359725584

Pull #632

github

web-flow
Merge 5e46bd8c9 into 420ec2405
Pull Request #632: refactor(notation_system): ♻️ use regular expressions consistently

168 of 172 new or added lines in 15 files covered. (97.67%)

1 existing line in 1 file now uncovered.

1663 of 1667 relevant lines covered (99.76%)

1.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.21
/lib/src/notation_system.dart
1
// ignore_for_file: one_member_abstracts - Code reusability
2

3
/// An abstract representation of a notation system for parsing
4
/// and formatting [T].
5
///
6
/// The [format] and [parse] methods should be designed to be [inverses](https://en.wikipedia.org/wiki/Inverse_function)
7
/// of each other:
8
/// the output of [format] should be a valid argument for [parse], and
9
/// `parse(format(value))` should return a value equal to the original value.
10
abstract class NotationSystem<T> implements Formatter<T>, Parser<T> {
11
  /// Creates a new formatter.
12
  const NotationSystem();
1✔
13

14
  /// Formats this [T].
15
  ///
16
  /// The output of this method should be accepted by [parse] to reconstruct
17
  /// the original value.
18
  @override
19
  String format(T value);
20

21
  @override
1✔
22
  RegExp? get regExp => null;
23

24
  @override
1✔
25
  bool matches(String source) =>
26
      regExp == null ||
1✔
27
      RegExp(
1✔
28
        '^${regExp?.pattern}\$',
3✔
29
        caseSensitive: regExp?.isCaseSensitive ?? true,
2✔
30
        unicode: regExp?.isUnicode ?? false,
2✔
31
      ).hasMatch(source);
1✔
32

33
  /// Parses [source] as [T].
34
  ///
35
  /// The input [source] should typically be produced by [format], ensuring
36
  /// that `parse(format(value)) == value`.
37
  ///
38
  /// If the [source] string does not contain a valid [T], a [FormatException]
39
  /// should be thrown.
40
  @override
1✔
41
  T parse(String source) => parseMatch(
1✔
42
    regExp?.firstMatch(source) ?? (throw FormatException('Invalid $T', source)),
4✔
43
  );
44

NEW
45
  @override
×
NEW
46
  T parseMatch(RegExpMatch match) => throw UnimplementedError(
×
NEW
47
    'parseMatch is not implemented for $runtimeType.',
×
48
  );
49
}
50

51
/// An abstract representation of a formatter for [T].
52
abstract interface class Formatter<T> {
53
  /// Formats this [T].
54
  String format(T value);
55
}
56

57
/// An abstract representation of a parser for [T].
58
abstract interface class Parser<T> {
59
  /// The regular expression for matching [T].
60
  RegExp? get regExp;
61

62
  /// Whether [source] can be parsed with [parse].
63
  bool matches(String source);
64

65
  /// Parses [source] as [T].
66
  T parse(String source);
67

68
  /// Parses [match] from [regExp] as [T].
69
  T parseMatch(RegExpMatch match);
70
}
71

72
/// A [Parser] chain.
73
extension ParserChain<T> on List<Parser<T>> {
74
  /// Parses [source] from this chain of [Parser]s.
75
  T parse(String source) {
1✔
76
    for (final parser in this) {
2✔
77
      if (parser.matches(source)) return parser.parse(source);
2✔
78
    }
79
    throw FormatException('End of parser chain: invalid $T', source);
2✔
80
  }
81
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc