conformance function

List<KitProblem> conformance({
  1. required Catalog catalog,
  2. required Uint8List committedLibrary,
  3. required String committedSnapshot,
  4. required KitNames names,
  5. required List<String> locales,
  6. Map<String, Set<String>> sameAsEnglish = const {},
  7. Iterable<String> typeIds = const [],
  8. Iterable<String> toolIds = const [],
  9. Iterable<String> propertyIds = const [],
})

The problems of a kit: its catalog, its committedLibrary bytes, its committedSnapshot text, its names and its declared non-English locales. sameAsEnglish lists, per locale, the word ids whose right word is the English one. Empty when the kit conforms.

The code side (contract R3): typeIds, toolIds and propertyIds (a PlanKit's propertyIds, without the property: prefix) must be under the kit's id, and each one's word (type:<id>, tool:<id>, property:<id>) must have English and a word in every declared locale. A code-side word that names none of them is not reported: a kit may pass a part of its ids.

A unit kind the contract does not name (UnitKinds) needs an English unit:<kit>/<kind> word (KitProblemCode.unitKindWord, spec 2b S4).

A kit's text: words (spec 3a C1.6) are held to the declared locales like its code side's, and every locale's text must carry English's placeholders (KitProblemCode.placeholderMismatch).

Throws ArgumentError when locales lists English: English is always required, by stored text or by words.

Implementation

List<KitProblem> conformance({
  required Catalog catalog,
  required Uint8List committedLibrary,
  required String committedSnapshot,
  required KitNames names,
  required List<String> locales,
  Map<String, Set<String>> sameAsEnglish = const {},
  Iterable<String> typeIds = const [],
  Iterable<String> toolIds = const [],
  Iterable<String> propertyIds = const [],
}) {
  if (locales.contains(KitNames.english)) {
    throw ArgumentError.value(locales, 'locales',
        "lists the kit's other locales; English is always required");
  }
  final problems = _catalogProblems(catalog);
  if (problems.isNotEmpty) return problems;
  final Uint8List built;
  try {
    built = encodeLibrary(catalog);
  } catch (e) {
    return [
      KitProblem(
          KitProblemCode.catalogInvalid, 'the catalog does not build: $e'),
    ];
  }
  if (!listEquals(built, committedLibrary)) {
    problems.add(const KitProblem(KitProblemCode.builtDiffers,
        "the committed library is not the catalog's: run the kit's generator"));
  }
  try {
    final library = SymbolLibrary.decode(committedLibrary);
    if (library.kits.single != catalog.kit) {
      problems.add(KitProblem(
          KitProblemCode.libraryKitMismatch,
          'the committed library holds the kit "${library.kits.single}", not '
          '"${catalog.kit}"'));
    }
  } on SymbolLibraryError catch (e) {
    problems.add(KitProblem(KitProblemCode.libraryInvalid,
        'the committed library is refused, rule ${e.rule}: ${e.message}'));
  }
  final code = _codeIds(catalog.kit, typeIds, toolIds, propertyIds);
  problems
    ..addAll(_snapshotProblems(catalog, committedSnapshot))
    ..addAll(code.problems)
    ..addAll(_unitKindProblems(catalog, names))
    ..addAll(_wordProblems(catalog, names, locales, sameAsEnglish, code.words))
    ..addAll(_placeholderProblems(names));
  return problems;
}