diff --git a/supacode/Clients/Repositories/RepositoryIconDetectorScanner.swift b/supacode/Clients/Repositories/RepositoryIconDetectorScanner.swift
index 20912432..9b578753 100644
--- a/supacode/Clients/Repositories/RepositoryIconDetectorScanner.swift
+++ b/supacode/Clients/Repositories/RepositoryIconDetectorScanner.swift
@@ -184,7 +184,8 @@ extension RepositoryIconDetector {
/// won't turn into the missing-file placeholder. The declared
/// canvas must be finite and within the same pixel ceiling as
/// rasters — vectors have no quality floor, so only the upper
- /// bound applies.
+ /// bound applies. A final rasterization pass rejects SVGs that
+ /// load fine but draw nothing.
private func decodableSVGSize(at url: URL) -> CGSize? {
guard let prefix = boundedContents(of: url, limit: Scanner.maxImageBytes),
let head = String(data: prefix.prefix(4096), encoding: .utf8),
@@ -201,7 +202,45 @@ extension RepositoryIconDetector {
else {
return nil
}
- return size
+ return rendersVisiblePixels(image) ? size : nil
+ }
+
+ /// CoreSVG ignores embedded `"#
+ return Data(svg.utf8)
+ }
+
private struct ManifestEntry {
var filename: String
var size: String
@@ -568,6 +578,33 @@ struct RepositoryIconDetectorTests {
}
}
+ @Test func invisiblyRenderingSVGFaviconFallsBackToRasterFavicon() async throws {
+ try await withTemporaryProjectDirectory(
+ entries: [],
+ contents: [
+ "package.json": Data(#"{"name":"site"}"#.utf8),
+ "public/favicon.svg": styleColoredSVGData,
+ "public/favicon.png": pngData(width: 32, height: 32),
+ ]
+ ) { root in
+ let candidate = await RepositoryIconDetector.detect(at: root)
+ #expect(candidate?.evidence == .webAsset)
+ #expect(candidate?.imageURL.lastPathComponent == "favicon.png")
+ }
+ }
+
+ @Test func invisiblyRenderingSVGAloneYieldsNothing() async throws {
+ try await withTemporaryProjectDirectory(
+ entries: [],
+ contents: [
+ "package.json": Data(#"{"name":"site"}"#.utf8),
+ "public/favicon.svg": styleColoredSVGData,
+ ]
+ ) { root in
+ #expect(await RepositoryIconDetector.detect(at: root) == nil)
+ }
+ }
+
@Test func oversizedSVGCanvasIsRejected() async throws {
let hugeSVG =
#"