measureProjectIdeaCoverage function
ProjectIdeaCoverageReport
measureProjectIdeaCoverage(
- ProjectIdea idea,
- Map<
String, String> sources, { - List<
CoverageExclusion> exclusions = const [],
Measures the coverage of idea by the requirements sources.
Implementation
ProjectIdeaCoverageReport measureProjectIdeaCoverage(
ProjectIdea idea,
Map<String, String> sources, {
List<CoverageExclusion> exclusions = const [],
}) {
final citedBy = <String, List<String>>{};
for (final r in sources.entries) {
for (final id in citations(r.value)) {
(citedBy[id] ??= []).add(r.key);
}
}
final superseded = <String, String>{};
for (final d in idea.items.where((i) => i.kind == 'decision')) {
for (final m in _supersedes.allMatches(d.text)) {
superseded[m.group(1)!] = d.id;
}
}
final outOfScope = citations(idea.outOfScopeText);
final excluded = {for (final e in exclusions) e.id: e};
final direct = <String, CoverageEntry>{};
for (final item in idea.items) {
final by = citedBy[item.id];
if (by != null) {
direct[item.id] = CoverageEntry(
item,
CoverageClass.covered,
by.join(', '),
);
} else if (item.area != null && citedBy[item.area] != null) {
direct[item.id] = CoverageEntry(
item,
CoverageClass.area,
'${item.area} cited by ${citedBy[item.area]!.join(', ')}',
);
}
}
final entries = <CoverageEntry>[];
for (final item in idea.items) {
final d = direct[item.id];
if (d != null) {
entries.add(d);
continue;
}
if (item.kind == 'decision') {
final carriers = [
for (final c in direct.values)
if (c.item.kind != 'decision' &&
citations(c.item.text).contains(item.id))
c.item.id,
];
if (carriers.isNotEmpty) {
entries.add(
CoverageEntry(
item,
CoverageClass.via,
'carried by ${carriers.join(', ')}',
),
);
continue;
}
final answered = [
for (final m in _answers.allMatches(item.text))
for (final q in citations(m.group(1)!))
if (q.startsWith('BQ-') && citedBy[q] != null) q,
];
if (answered.isNotEmpty) {
entries.add(
CoverageEntry(
item,
CoverageClass.via,
'answers ${answered.join(', ')}, cited by '
'${{for (final q in answered) ...citedBy[q]!}.join(', ')}',
),
);
continue;
}
}
final e = excluded[item.id];
if (e != null) {
entries.add(
CoverageEntry(
item,
CoverageClass.excluded,
'${e.reason} (${e.record})',
),
);
} else if (item.kind == 'decision' && outOfScope.contains(item.id)) {
entries.add(
CoverageEntry(
item,
CoverageClass.excluded,
'cited by the out-of-scope table (Project Idea ยง 6.2)',
),
);
} else if (superseded[item.id] != null) {
entries.add(
CoverageEntry(
item,
CoverageClass.excluded,
'superseded by ${superseded[item.id]}',
),
);
} else {
entries.add(CoverageEntry(item, CoverageClass.uncovered, ''));
}
}
final known = {for (final i in idea.items) i.id};
return ProjectIdeaCoverageReport(entries, sources.length, [
for (final e in exclusions)
if (!known.contains(e.id)) e.id,
]);
}