From 1c3d19b233f135a059f5d111dd1a7514af25ed3f Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Mon, 20 Jul 2026 14:48:00 -0500 Subject: fix: markdown report underlines and duplicate DNS record values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The plain-text-to-Markdown transform only recognized '-' underlines, but batchText writes '=' — under the document title and as a 48-character separator between reports. Both leaked through as literal bullets, so a generated report opened with: # Scheduled Watchlist Report - ========================== Title underlines are now consumed alongside the title, '=' underlines promote to H2 the same as '-', and standalone divider runs render as a Markdown horizontal rule. Separately, the DNS section concatenated apex and wildcard records without dedup. On a domain with wildcard DNS resolving to the same addresses as the apex, every value was listed twice. Now deduped while preserving order, so a wildcard value that genuinely differs is still shown. --- DomainReportExporter.swift | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'DomainReportExporter.swift') diff --git a/DomainReportExporter.swift b/DomainReportExporter.swift index 7199d03..a8e2ee9 100644 --- a/DomainReportExporter.swift +++ b/DomainReportExporter.swift @@ -77,14 +77,23 @@ enum DomainReportExporter { let line = lines[index] if index == 0, line == title { index += 1 + if index < lines.count, isUnderline(lines[index], for: line) { + index += 1 + } continue } - if index + 1 < lines.count, !line.isEmpty, lines[index + 1] == String(repeating: "-", count: line.count) { + if index + 1 < lines.count, !line.isEmpty, isUnderline(lines[index + 1], for: line) { output.append("") output.append("## \(line)") index += 2 continue } + if isRule(line) { + output.append("") + output.append("---") + index += 1 + continue + } if line.isEmpty || line.hasPrefix("-") || line.hasPrefix(" ") { output.append(line) } else { @@ -95,6 +104,21 @@ enum DomainReportExporter { return output.joined(separator: "\n") } + /// True when `line` is a run of `-` or `=` exactly as long as the heading it + /// underlines. `batchText` uses `=` for the document title, `appendSection` + /// uses `-` for section headers. + private static func isUnderline(_ line: String, for heading: String) -> Bool { + guard !heading.isEmpty else { return false } + return line == String(repeating: "-", count: heading.count) + || line == String(repeating: "=", count: heading.count) + } + + /// True for a standalone divider not attached to a heading — `batchText` + /// emits a fixed 48-character `=` run between reports. + private static func isRule(_ line: String) -> Bool { + line.count >= 3 && (line.allSatisfy { $0 == "=" } || line.allSatisfy { $0 == "-" }) + } + /// Renders Markdown as a simple monospaced multi-page PDF. Foundation-only /// consumers (no UIKit available) get the Markdown bytes back instead. static func pdfData(fromMarkdown markdown: String) -> Data { @@ -249,7 +273,10 @@ enum DomainReportExporter { } else { dnsLines.append("Records:") for section in report.dns.recordSections { - let values = (section.records + section.wildcardRecords).map(\.value) + var seen: Set = [] + let values = (section.records + section.wildcardRecords) + .map(\.value) + .filter { seen.insert($0).inserted } let renderedValues = values.isEmpty ? "None" : values.joined(separator: " | ") dnsLines.append(" \(section.recordType.rawValue): \(renderedValues)") } -- cgit v1.2.3