checkFeatureRegister function

FeatureRegisterReport checkFeatureRegister(
  1. String yamlText
)

Checks the feature register of the Blueprint in yamlText.

Implementation

FeatureRegisterReport checkFeatureRegister(String yamlText) {
  final root = loadYaml(yamlText);
  final ids = <String>{};
  final functional = <String>[];
  final featureLinks = <String, List<String>>{};
  final prototypeRefs = <String, String>{};
  String? statedTotal;

  void walk(Object? node, String? feature, String? prototype) {
    if (node is! YamlMap) return;
    for (final entry in node.entries) {
      final key = '${entry.key}';
      final value = entry.value;
      final match = _itemKey.firstMatch(key);
      var currentFeature = feature;
      var currentPrototype = prototype;
      if (match != null && !key.contains(' ')) {
        final id = match.group(1)!;
        ids.add(id);
        if (id.startsWith('FRE-REQU-')) functional.add(id);
        if (id.startsWith('FPE-ITEM-') && !id.endsWith('-LST')) {
          currentFeature = id;
          featureLinks.putIfAbsent(id, () => <String>[]);
        }
        if (id.startsWith('PFE-FEAT-') && !id.endsWith('-LST')) {
          currentPrototype = id;
        }
      }
      if (key == 'linkedRequirements' && currentFeature != null) {
        featureLinks[currentFeature]!.addAll(_idList('$value'));
      }
      if (key == 'featureId' && currentPrototype != null) {
        prototypeRefs[currentPrototype] = '$value'.trim();
      }
      if (key == 'totalRegisteredFeatures') statedTotal = '$value'.trim();
      walk(value, currentFeature, currentPrototype);
    }
  }

  walk(root, null, null);

  final findings = <FeatureRegisterFinding>[];
  final owners = <String, List<String>>{};
  featureLinks.forEach((feature, links) {
    if (links.isEmpty) {
      findings.add(
        FeatureRegisterFinding('emptyFeature', feature, 'links no requirement'),
      );
    }
    for (final link in links) {
      if (!ids.contains(link)) {
        findings.add(
          FeatureRegisterFinding(
            'unknownRequirement',
            feature,
            'links $link, which the document does not contain',
          ),
        );
      }
      if (link.startsWith('FRE-REQU-')) {
        owners.putIfAbsent(link, () => <String>[]).add(feature);
      }
    }
  });
  for (final requirement in functional) {
    final featuresOf = owners[requirement] ?? const <String>[];
    if (featuresOf.isEmpty) {
      findings.add(
        FeatureRegisterFinding(
          'unassigned',
          requirement,
          'is linked by no feature',
        ),
      );
    } else if (featuresOf.length > 1) {
      findings.add(
        FeatureRegisterFinding(
          'assignedTwice',
          requirement,
          'is linked by ${featuresOf.join(', ')}',
        ),
      );
    }
  }
  prototypeRefs.forEach((prototype, featureId) {
    if (!featureLinks.containsKey(featureId)) {
      findings.add(
        FeatureRegisterFinding(
          'unknownFeature',
          prototype,
          'names $featureId, which is not a feature of the register',
        ),
      );
    }
  });
  if (statedTotal != null && statedTotal != '${featureLinks.length}') {
    findings.add(
      FeatureRegisterFinding(
        'countMismatch',
        'FPE',
        'totalRegisteredFeatures says $statedTotal, the register has '
            '${featureLinks.length}',
      ),
    );
  }
  return FeatureRegisterReport(
    featureLinks.length,
    functional.length,
    prototypeRefs.length,
    findings,
  );
}