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
|
/*
This source file is part of the Swift.org open source project
Copyright (c) 2022 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
struct DirectiveIndex {
static let topLevelReferenceDirectives: [AutomaticDirectiveConvertible.Type] = [
Metadata.self,
Redirect.self,
Snippet.self,
DeprecationSummary.self,
Row.self,
Options.self,
Small.self,
TabNavigator.self,
Links.self,
ImageMedia.self,
VideoMedia.self,
]
static let topLevelTutorialDirectives: [AutomaticDirectiveConvertible.Type] = [
Tutorial.self,
]
/// Children of tutorial directives that have not yet been converted to be automatically
/// convertible.
///
/// This is a temporary workaround until the migration is complete and these child directives
/// can be automatically reflected from their parent directives.
private static let otherTutorialDirectives: [AutomaticDirectiveConvertible.Type] = [
Stack.self,
Chapter.self,
Choice.self,
]
private static var allTopLevelDirectives = topLevelTutorialDirectives
+ topLevelReferenceDirectives
+ otherTutorialDirectives
let indexedDirectives: [String : DirectiveMirror.ReflectedDirective]
let renderableDirectives: [String : AnyRenderableDirectiveConvertibleType]
static let shared = DirectiveIndex()
private init() {
// Pre-populate the directory index by iterating through the explicitly declared
// top-level directives, finding their children and reflecting those as well.
var indexedDirectives = [String : DirectiveMirror.ReflectedDirective]()
for directive in Self.allTopLevelDirectives {
let mirror = DirectiveMirror(reflecting: directive).reflectedDirective
indexedDirectives[mirror.name] = mirror
}
var foundDirectives = indexedDirectives.values.flatMap(\.childDirectives).map(\.type)
while !foundDirectives.isEmpty {
let directive = foundDirectives.removeFirst()
guard !indexedDirectives.keys.contains(directive.directiveName) else {
continue
}
guard let automaticDirectiveConvertible = directive as? AutomaticDirectiveConvertible.Type else {
continue
}
let mirror = DirectiveMirror(reflecting: automaticDirectiveConvertible).reflectedDirective
indexedDirectives[mirror.name] = mirror
for childDirective in mirror.childDirectives.map(\.type) {
guard !indexedDirectives.keys.contains(childDirective.directiveName) else {
continue
}
foundDirectives.append(childDirective)
}
}
self.indexedDirectives = indexedDirectives
self.renderableDirectives = indexedDirectives.compactMapValues { directive in
guard let renderableDirective = directive.type as? RenderableDirectiveConvertible.Type else {
return nil
}
return AnyRenderableDirectiveConvertibleType(underlyingType: renderableDirective)
}
}
func reflection(
of directiveConvertible: AutomaticDirectiveConvertible.Type
) -> DirectiveMirror.ReflectedDirective {
// It's a programmer error if an automatic directive convertible
// is not in the pre-populated index.
return indexedDirectives[directiveConvertible.directiveName]!
}
func reflection(of implementationName: String) -> DirectiveMirror.ReflectedDirective? {
return indexedDirectives.first(
where: { (directiveName: String, reflectedDirective: DirectiveMirror.ReflectedDirective) in
directiveName == implementationName || String(describing: reflectedDirective.type) == implementationName
}
)?.value
}
}
|