scan method

List<RedactionMatch> scan(
  1. String text, {
  2. String? pathHint,
})

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;
}