checkFeatureRegister function
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,
);
}