Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

keep the original URL when decoding Download/ExternalLocationReference #621

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,16 @@ public struct ExternalLocationReference: RenderReference, URLReference {

public private(set) var type: RenderReferenceType = .externalLocation

public var identifier: RenderReferenceIdentifier
public var identifier: RenderReferenceIdentifier {
didSet {
// Keep the url property in sync if it was just a copy of the reference identifier
if self.url == oldValue.identifier {
QuietMisdreavus marked this conversation as resolved.
Show resolved Hide resolved
self.url = identifier.identifier
}
}
}

private var url: String

enum CodingKeys: String, CodingKey {
case type
Expand All @@ -34,21 +43,26 @@ public struct ExternalLocationReference: RenderReference, URLReference {

public init(identifier: RenderReferenceIdentifier) {
self.identifier = identifier
self.url = identifier.identifier
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

self.identifier = try container.decode(RenderReferenceIdentifier.self, forKey: .identifier)
let url = try container.decodeIfPresent(String.self, forKey: .url)
if let url = url {
self.url = url
} else {
self.url = self.identifier.identifier
}
QuietMisdreavus marked this conversation as resolved.
Show resolved Hide resolved
self.type = try container.decode(RenderReferenceType.self, forKey: .type)
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(type.rawValue, forKey: .type)
try container.encode(identifier, forKey: .identifier)

// Enter the given URL verbatim into the Render JSON
try container.encode(identifier.identifier, forKey: .url)
try container.encode(url, forKey: .url)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ public struct DownloadReference: RenderReference, URLReference, Equatable {

/// The location of the downloadable resource.
public var url: URL


private var urlWasDecoded = false

/// The SHA512 hash value for the resource.
public var checksum: String?

Expand Down Expand Up @@ -60,15 +62,41 @@ public struct DownloadReference: RenderReference, URLReference, Equatable {
public init(identifier: RenderReferenceIdentifier, renderURL url: URL, sha512Checksum: String) {
self.init(identifier: identifier, renderURL: url, checksum: sha512Checksum)
}


enum CodingKeys: CodingKey {
case type
case identifier
case url
case checksum
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.type = try container.decode(RenderReferenceType.self, forKey: .type)
self.identifier = try container.decode(RenderReferenceIdentifier.self, forKey: .identifier)
self.url = try container.decode(URL.self, forKey: .url)
self.urlWasDecoded = true
QuietMisdreavus marked this conversation as resolved.
Show resolved Hide resolved
self.checksum = try container.decodeIfPresent(String.self, forKey: .checksum)
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(type.rawValue, forKey: .type)
try container.encode(identifier, forKey: .identifier)
try container.encodeIfPresent(checksum, forKey: .checksum)

// Render URL
try container.encode(renderURL(for: url), forKey: .url)
if !urlWasDecoded {
try container.encode(renderURL(for: url), forKey: .url)
} else {
try container.encode(url, forKey: .url)
}
}

static public func ==(lhs: DownloadReference, rhs: DownloadReference) -> Bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Off-topic but I wonder if it's possible to make an @EquatableIgnored macro like: https://developer.apple.com/documentation/observation/observationignored...

lhs.identifier == rhs.identifier
&& lhs.url == rhs.url
&& lhs.checksum == rhs.checksum
}
}

Expand Down
18 changes: 18 additions & 0 deletions Tests/SwiftDocCTests/Rendering/SampleDownloadTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -240,4 +240,22 @@ class SampleDownloadTests: XCTestCase {
let reference = try XCTUnwrap(renderNode.references[identifier.identifier])
XCTAssert(reference is ExternalLocationReference)
}

/// Ensure that a DownloadReference where the URL is different from the reference identifier
/// can still round-trip through an ExternalLocationReference with the URL and reference identifier intact.
func testRoundTripWithDifferentUrl() throws {
ethan-kusters marked this conversation as resolved.
Show resolved Hide resolved
let baseReference = DownloadReference(identifier: .init("DownloadReference.zip"), renderURL: .init(string: "https://example.com/DownloadReference.zip")!, checksum: nil)

let encoder = JSONEncoder()
let decoder = JSONDecoder()

let encodedReference = try encoder.encode(baseReference)

let interimReference = try decoder.decode(ExternalLocationReference.self, from: encodedReference)
let interimEncodedReference = try encoder.encode(interimReference)

let roundTripReference = try decoder.decode(DownloadReference.self, from: interimEncodedReference)

XCTAssertEqual(baseReference, roundTripReference)
}
}