soundTableIn function

({Set<String> declared, Set<String> inTheBank}) soundTableIn(
  1. String path
)

What path declares, and what its bank actually holds.

path is a Dart source file with static const SoundDef declarations and a static final SoundBank all = SoundBank(<SoundDef>[…]) beside them, which is the shape all three games use.

Implementation

({Set<String> declared, Set<String> inTheBank}) soundTableIn(String path) {
  final source = File(path).readAsStringSync();

  final declared = RegExp(
    r'static const SoundDef ([A-Za-z]+)',
  ).allMatches(source).map((RegExpMatch m) => m.group(1)!).toSet();

  final literal = RegExp(
    r'static final SoundBank all = SoundBank\(<SoundDef>\[(.*?)\]\);',
    dotAll: true,
  ).firstMatch(source);
  if (literal == null) {
    // Loud rather than empty. An empty set makes "the bank holds nothing" and
    // "the pattern stopped matching" the same answer, and only one of them is
    // the game's fault.
    throw StateError(
      'no `static final SoundBank all = SoundBank(<SoundDef>[…]);` in $path. '
      'If the bank has been written a different way, this scan has to learn '
      'the new shape or it will report every sound as missing.',
    );
  }

  final inTheBank = RegExp(
    r'([A-Za-z]+),',
  ).allMatches(literal.group(1)!).map((RegExpMatch m) => m.group(1)!).toSet();

  return (declared: declared, inTheBank: inTheBank);
}