scan method
Scans text and returns the surviving matches: merged by layer
priority (higher priority wins overlaps), sorted by RedactionMatch.start,
non-overlapping.
pathHint is the tool's file path when known; a credential-file hint
makes the path layer treat the whole text as one span. Matches fully
covered by an allowlist regex, spans inside existing
[REDACTED:...] markers or inside data: base64 URLs are not
reported (registered exact values remain exempt from marker
suppression so secrets containing the literal marker text still get
masked).
Implementation
List<RedactionMatch> scan(String text, {String? pathHint}) {
final cfg = config;
if (!cfg.enabled || text.isEmpty) return const [];
// Collect matches layer by layer in priority order; lower layers see
// the spans already claimed by higher layers (kept in `prior`).
final prior = <RedactionMatch>[];
final candidates = <RedactionMatch>[];
for (final layer in RedactionLayer.values) {
if (!cfg.isLayerEnabled(layer)) continue;
final found = _scanLayer(
layer,
text,
cfg,
pathHint: pathHint,
secrets: _secrets,
prior: prior,
);
candidates.addAll(found);
prior.addAll(found);
}
final merged = _merge(candidates);
final protected = [
for (final m in _dataUrl.allMatches(text)) (m.start, m.end),
];
final markers = [
for (final m in _existingMarker.allMatches(text)) (m.start, m.end),
];
final surviving =
merged
.where((match) => _kept(match, protected, markers, cfg, text))
.toList()
..sort(_compareByStart);
for (final match in surviving) {
stats._countMatch(match);
}
return surviving;
}