MCPcopy Index your code
hub / github.com/garrytan/gstack / redactFindingSpans

Function redactFindingSpans

lib/redact-engine.ts:452–480  ·  view source on GitHub ↗
(input: string, opts: ScanOptions = {})

Source from the content-addressed store, hash-verified

450 * structure-preserving path.)
451 */
452export function redactFindingSpans(input: string, opts: ScanOptions = {}): string | null {
453 const { findings } = scan(input, opts);
454 if (findings.some((f) => MARKER_ONLY_PATTERN_IDS.has(f.id))) return null;
455 const targets = findings.map((f) => ({ f, ...locateSpan(input, f) }));
456 if (targets.some((t) => t.start < 0)) return null;
457
458 // Coalesce overlapping/touching ranges — splicing two intersecting spans
459 // independently applies a stale end offset to already-modified text and
460 // can leave trailing secret bytes in place.
461 targets.sort((a, b) => a.start - b.start);
462 const merged: Array<{ start: number; end: number; ids: string[] }> = [];
463 for (const t of targets) {
464 const last = merged[merged.length - 1];
465 if (last && t.start <= last.end) {
466 last.end = Math.max(last.end, t.end);
467 if (!last.ids.includes(t.f.id)) last.ids.push(t.f.id);
468 } else {
469 merged.push({ start: t.start, end: t.end, ids: [t.f.id] });
470 }
471 }
472
473 // Right-to-left so earlier offsets remain valid after splicing.
474 let body = input;
475 for (let i = merged.length - 1; i >= 0; i--) {
476 const m = merged[i];
477 body = body.slice(0, m.start) + `<REDACTED-${m.ids.join("+")}>` + body.slice(m.end);
478 }
479 return body;
480}
481
482function locateSpan(input: string, f: Finding): { start: number; end: number } {
483 // Re-derive the offset from line/col on the original text.

Callers 1

Calls 3

scanFunction · 0.85
locateSpanFunction · 0.85
pushMethod · 0.45

Tested by

no test coverage detected