File: ImageReference.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (155 lines) | stat: -rw-r--r-- 6,369 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
 This source file is part of the Swift.org open source project

 Copyright (c) 2021-2024 Apple Inc. and the Swift project authors
 Licensed under Apache License v2.0 with Runtime Library Exception

 See https://swift.org/LICENSE.txt for license information
 See https://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import Foundation

/// A reference to an image.
public struct ImageReference: MediaReference, URLReference, Equatable {
    /// The type of this image reference.
    ///
    /// This value is always `.image`.
    public var type: RenderReferenceType = .image
    
    /// The identifier of this reference.
    public var identifier: RenderReferenceIdentifier
    
    /// Alternate text for the image.
    ///
    /// This text helps screen-readers describe the image.
    public var altText: String?
    
    /// The data associated with this asset, including its variants.
    public var asset: DataAsset
    
    /// Creates a new image reference.
    ///
    /// - Parameters:
    ///   - identifier: The identifier for this image reference.
    ///   - altText: Alternate text for the image.
    ///   - asset: The data associated with this asset, including its variants.
    public init(identifier: RenderReferenceIdentifier, altText: String? = nil, imageAsset asset: DataAsset) {
        self.identifier = identifier
        self.asset = asset
        self.altText = altText
    }
    
    enum CodingKeys: String, CodingKey {
        case type
        case identifier
        case alt
        case variants
    }
    
    public init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        type = try values.decode(RenderReferenceType.self, forKey: .type)
        identifier = try values.decode(RenderReferenceIdentifier.self, forKey: .identifier)
        altText = try values.decodeIfPresent(String.self, forKey: .alt)
        
        // rebuild the data asset
        asset = DataAsset()
        let variants = try values.decode([VariantProxy].self, forKey: .variants)
        variants.forEach { (variant) in
            asset.register(variant.url, with: DataTraitCollection(from: variant.traits), metadata: .init(svgID: variant.svgID))
        }
    }
    
    /// The relative URL to the folder that contains all images in the built documentation output.
    public static let baseURL = URL(string: "/images/")!
    
    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.encode(altText, forKey: .alt)
        
        // convert the data asset to a serializable object
        var result = [VariantProxy]()
        // sort assets by URL path for deterministic sorting of images
        asset.variants.sorted(by: \.value.path).forEach { (key, value) in
            let url = value.isAbsoluteWebURL ? value : destinationURL(for: value.lastPathComponent, prefixComponent: encoder.assetPrefixComponent)
            result.append(VariantProxy(url: url, traits: key, svgID: asset.metadata[value]?.svgID))
        }
        try container.encode(result, forKey: .variants)
    }
    
    
    /// A codable proxy value that the image reference uses to serialize information about its asset variants.
    public struct VariantProxy: Codable, Equatable {
        /// The URL to the file for this image variant.
        public var url: URL
        /// The traits of this image reference.
        public var traits: [String]
        /// The ID for the SVG that should be rendered for this variant.
        ///
        /// This value is `nil` for variants that are not SVGs and for SVGs that do not include ids.
        public var svgID: String?
        
        /// Creates a new proxy value with the given information about an image variant.
        /// 
        /// - Parameters:
        ///   - size: The size of the image variant.
        ///   - url: The URL to the file for this image variant.
        ///   - traits: The traits of this image reference.
        init(url: URL, traits: DataTraitCollection, svgID: String?) {
            self.url = url
            self.traits = traits.toArray()
            self.svgID = svgID
        }
        
        enum CodingKeys: String, CodingKey {
            case size
            case url
            case traits
            case svgID
        }
        
        public init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            url = try values.decode(URL.self, forKey: .url)
            traits = try values.decode([String].self, forKey: .traits)
            svgID = try values.decodeIfPresent(String.self, forKey: .svgID)
        }
        
        public func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: CodingKeys.self)
            try container.encode(url, forKey: .url)
            try container.encode(traits, forKey: .traits)
            try container.encodeIfPresent(svgID, forKey: .svgID)
        }
    }
}

// Diffable conformance
extension ImageReference: RenderJSONDiffable {
    /// Returns the difference between this ImageReference and the given one.
    func difference(from other: ImageReference, at path: CodablePath) -> JSONPatchDifferences {
        var diffBuilder = DifferenceBuilder(current: self, other: other, basePath: path)

        diffBuilder.addDifferences(atKeyPath: \.asset, forKey: CodingKeys.variants)
        diffBuilder.addDifferences(atKeyPath: \.altText, forKey: CodingKeys.alt)

        return diffBuilder.differences
    }
}

// Diffable conformance
extension ImageReference.VariantProxy: RenderJSONDiffable {
    /// Returns the difference between this VariantProxy and the given one.
    func difference(from other: ImageReference.VariantProxy, at path: CodablePath) -> JSONPatchDifferences {
        var diffBuilder = DifferenceBuilder(current: self, other: other, basePath: path)

        diffBuilder.addDifferences(atKeyPath: \.url, forKey: CodingKeys.url)
        diffBuilder.addDifferences(atKeyPath: \.traits, forKey: CodingKeys.traits)
        diffBuilder.addDifferences(atKeyPath: \.svgID, forKey: CodingKeys.svgID)

        return diffBuilder.differences
    }
}