@@ -23,20 +23,46 @@ import SymbolKit
23
23
/// `Sources/SwiftDocC/SwiftDocC.docc/Resources/RenderIndex.spec.json`.
24
24
public struct RenderIndex : Codable , Equatable {
25
25
/// The current schema version of the Index JSON spec.
26
- public static let currentSchemaVersion = SemanticVersion ( major: 0 , minor: 1 , patch: 0 )
26
+ public static let currentSchemaVersion = SemanticVersion ( major: 0 , minor: 1 , patch: 1 )
27
27
28
28
/// The version of the RenderIndex spec that was followed when creating this index.
29
29
public let schemaVersion : SemanticVersion
30
30
31
31
/// A mapping of interface languages to the index nodes they contain.
32
32
public let interfaceLanguages : [ String : [ Node ] ]
33
33
34
+ /// The values of the image references used in the documentation index.
35
+ public private( set) var references : [ String : ImageReference ]
36
+
37
+ enum CodingKeys : CodingKey {
38
+ case schemaVersion
39
+ case interfaceLanguages
40
+ case references
41
+ }
42
+
34
43
/// Creates a new render index with the given interface language to node mapping.
35
44
public init (
36
- interfaceLanguages: [ String : [ Node ] ]
45
+ interfaceLanguages: [ String : [ Node ] ] ,
46
+ references: [ String : ImageReference ] = [ : ]
37
47
) {
38
48
self . schemaVersion = Self . currentSchemaVersion
39
49
self . interfaceLanguages = interfaceLanguages
50
+ self . references = references
51
+ }
52
+
53
+ public func encode( to encoder: Encoder ) throws {
54
+ var container = encoder. container ( keyedBy: CodingKeys . self)
55
+ try container. encode ( self . schemaVersion, forKey: . schemaVersion)
56
+ try container. encode ( self . interfaceLanguages, forKey: . interfaceLanguages)
57
+
58
+ try container. encodeIfNotEmpty ( self . references, forKey: . references)
59
+ }
60
+
61
+ public init ( from decoder: Decoder ) throws {
62
+ let container = try decoder. container ( keyedBy: CodingKeys . self)
63
+ self . schemaVersion = try container. decode ( SemanticVersion . self, forKey: . schemaVersion)
64
+ self . interfaceLanguages = try container. decode ( [ String : [ RenderIndex . Node ] ] . self, forKey: . interfaceLanguages)
65
+ self . references = try container. decodeIfPresent ( [ String : ImageReference ] . self, forKey: . references) ?? [ : ]
40
66
}
41
67
}
42
68
@@ -73,6 +99,9 @@ extension RenderIndex {
73
99
///
74
100
/// Allows renderers to use a specific design treatment for render index nodes that mark the node as in beta.
75
101
public let isBeta : Bool
102
+
103
+ /// Reference to the image that should be used to represent this node.
104
+ public let icon : RenderReferenceIdentifier ?
76
105
77
106
enum CodingKeys : String , CodingKey {
78
107
case title
@@ -82,6 +111,7 @@ extension RenderIndex {
82
111
case deprecated
83
112
case external
84
113
case beta
114
+ case icon
85
115
}
86
116
87
117
public func encode( to encoder: Encoder ) throws {
@@ -107,6 +137,8 @@ extension RenderIndex {
107
137
if isBeta {
108
138
try container. encode ( isBeta, forKey: . beta)
109
139
}
140
+
141
+ try container. encodeIfPresent ( icon, forKey: . icon)
110
142
}
111
143
112
144
public init ( from decoder: Decoder ) throws {
@@ -126,6 +158,8 @@ extension RenderIndex {
126
158
127
159
// `isBeta` defaults to false if it's not specified
128
160
isBeta = try values. decodeIfPresent ( Bool . self, forKey: . beta) ?? false
161
+
162
+ icon = try values. decodeIfPresent ( RenderReferenceIdentifier . self, forKey: . icon)
129
163
}
130
164
131
165
/// Creates a new node with the given title, path, type, and children.
@@ -146,7 +180,8 @@ extension RenderIndex {
146
180
children: [ Node ] ? ,
147
181
isDeprecated: Bool ,
148
182
isExternal: Bool ,
149
- isBeta: Bool
183
+ isBeta: Bool ,
184
+ icon: RenderReferenceIdentifier ? = nil
150
185
) {
151
186
self . title = title
152
187
self . path = path
@@ -155,14 +190,16 @@ extension RenderIndex {
155
190
self . isDeprecated = isDeprecated
156
191
self . isExternal = isExternal
157
192
self . isBeta = isBeta
193
+ self . icon = nil
158
194
}
159
195
160
196
init (
161
197
title: String ,
162
198
path: String ,
163
199
pageType: NavigatorIndex . PageType ? ,
164
200
isDeprecated: Bool ,
165
- children: [ Node ]
201
+ children: [ Node ] ,
202
+ icon: RenderReferenceIdentifier ?
166
203
) {
167
204
self . title = title
168
205
self . children = children. isEmpty ? nil : children
@@ -174,6 +211,7 @@ extension RenderIndex {
174
211
self . isExternal = false
175
212
176
213
self . isBeta = false
214
+ self . icon = icon
177
215
178
216
guard let pageType = pageType else {
179
217
self . type = nil
@@ -193,14 +231,20 @@ extension RenderIndex {
193
231
}
194
232
195
233
extension RenderIndex {
196
- static func fromNavigatorIndex( _ navigatorIndex: NavigatorIndex , with builder: NavigatorIndex . Builder ) -> RenderIndex {
234
+ static func fromNavigatorIndex(
235
+ _ navigatorIndex: NavigatorIndex ,
236
+ with builder: NavigatorIndex . Builder ,
237
+ context: DocumentationContext ?
238
+ ) -> RenderIndex {
197
239
// The immediate children of the root represent the interface languages
198
240
// described in this navigator tree.
199
241
let interfaceLanguageRoots = navigatorIndex. navigatorTree. root. children
200
242
201
243
let languageMaskToLanguage = navigatorIndex. languageMaskToLanguage
202
244
203
- return RenderIndex (
245
+ var iconIdentifiers = [ RenderReferenceIdentifier] ( )
246
+
247
+ var renderIndex = RenderIndex (
204
248
interfaceLanguages: Dictionary (
205
249
interfaceLanguageRoots. compactMap { interfaceLanguageRoot in
206
250
// If an interface language in the given navigator tree does not exist
@@ -210,19 +254,51 @@ extension RenderIndex {
210
254
211
255
return (
212
256
language: languageID,
213
- children: interfaceLanguageRoot. children. map {
214
- RenderIndex . Node. fromNavigatorTreeNode ( $0, in: navigatorIndex, with: builder)
257
+ children: interfaceLanguageRoot. children. map { node in
258
+ RenderIndex . Node. fromNavigatorTreeNode (
259
+ node,
260
+ in: navigatorIndex,
261
+ with: builder,
262
+ iconIdentifiers: & iconIdentifiers
263
+ )
215
264
}
216
265
)
217
266
} ,
218
267
uniquingKeysWith: +
219
268
)
220
269
)
270
+
271
+ guard let context = context else {
272
+ return renderIndex
273
+ }
274
+
275
+ let icons = iconIdentifiers. lazy. compactMap { iconReference -> ImageReference ? in
276
+ guard let dataAsset = context. resolveAsset (
277
+ named: iconReference. identifier,
278
+ bundleIdentifier: builder. bundleIdentifier
279
+ ) else {
280
+ return nil
281
+ }
282
+
283
+ return ImageReference ( identifier: iconReference, imageAsset: dataAsset)
284
+ }
285
+
286
+ let mappedReferences = Dictionary (
287
+ uniqueKeysWithValues: icons. map { ( $0. identifier. identifier, $0) }
288
+ )
289
+
290
+ renderIndex. references = mappedReferences
291
+ return renderIndex
221
292
}
222
293
}
223
294
224
295
extension RenderIndex . Node {
225
- static func fromNavigatorTreeNode( _ node: NavigatorTree . Node , in navigatorIndex: NavigatorIndex , with builder: NavigatorIndex . Builder ) -> RenderIndex . Node {
296
+ fileprivate static func fromNavigatorTreeNode(
297
+ _ node: NavigatorTree . Node ,
298
+ in navigatorIndex: NavigatorIndex ,
299
+ with builder: NavigatorIndex . Builder ,
300
+ iconIdentifiers: inout [ RenderReferenceIdentifier ]
301
+ ) -> RenderIndex . Node {
226
302
// If this node was deprecated on any platform version mark it as deprecated.
227
303
let isDeprecated : Bool
228
304
@@ -235,14 +311,19 @@ extension RenderIndex.Node {
235
311
isDeprecated = false
236
312
}
237
313
314
+ if let iconIdentifier = node. item. icon {
315
+ iconIdentifiers. append ( iconIdentifier)
316
+ }
317
+
238
318
return RenderIndex . Node (
239
319
title: node. item. title,
240
320
path: node. item. path,
241
321
pageType: NavigatorIndex . PageType ( rawValue: node. item. pageType) ,
242
322
isDeprecated: isDeprecated,
243
323
children: node. children. map {
244
- RenderIndex . Node. fromNavigatorTreeNode ( $0, in: navigatorIndex, with: builder)
245
- }
324
+ RenderIndex . Node. fromNavigatorTreeNode ( $0, in: navigatorIndex, with: builder, iconIdentifiers: & iconIdentifiers)
325
+ } ,
326
+ icon: node. item. icon
246
327
)
247
328
}
248
329
}
0 commit comments