Generator/Sources/NeedleFramework/Generating/DependencyProviderDeclarerTask.swift (45 lines of code) (raw):
//
// Copyright (c) 2018. Uber Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Concurrency
import Foundation
import SourceParsingFramework
/// The task that generates the declarations of the dependency providers
/// for a specific component, for all of its ancestor paths.
class DependencyProviderDeclarerTask: AbstractTask<[DependencyProvider]> {
/// Initializer.
///
/// - parameter component: The component that requires the dependency
/// provider.
init(component: Component) {
self.component = component
super.init(id: TaskIds.dependencyProviderDeclarerTask.rawValue)
}
/// Execute the task and returns the in-memory dependency graph data models.
///
/// - returns: The list of `DependencyProvider`.
override func execute() -> [DependencyProvider] {
// Do not produce a provider if the component is not a root and
// has no parents. In this case, the component is just an orphan
// scope that should be ignored.
if component.parents.isEmpty && !component.isRoot {
info("\(component.name) is an orphan scope therefore ignored from parsing.")
return []
}
return ancestorPaths(for: component)
.filter { !$0.isEmpty }
.compactMap { (path: [Component]) -> DependencyProvider? in
guard let first = path.first else {
return nil
}
// A component's ancestor chain may be an orphan as well.
if first.isRoot {
return DependencyProvider(path: path, dependency: component.dependency)
} else {
let pathString = path.map { $0.name }.joined(separator: "->")
info("\(pathString) is an orphan chain, therefore all scopes within the chain are ignored from parsing.")
return nil
}
}
}
// MARK: - Private
private let component: Component
private func ancestorPaths(for component: Component) -> [[Component]] {
if component.parents.isEmpty {
return [[component]]
} else {
var allPaths = [[Component]]()
for parent in component.parents {
let parentAncestorPaths = ancestorPaths(for: parent)
.map { (path: [Component]) -> [Component] in
return path + [component]
}
allPaths.append(contentsOf: parentAncestorPaths)
}
return allPaths
}
}
}