Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import Foundation
- @_functionBuilder
- struct ContentListBuilder {
- static func buildBlock() -> ContentList {
- return EmptyContentList()
- }
- static func buildBlock(_ list: ContentList) -> ContentList {
- return list
- }
- static func buildBlock(_ lists: ContentList...) -> ContentList {
- return TupleContentList(lists)
- }
- }
- @_functionBuilder
- struct ContentBuilder {
- static func buildBlock() -> Content {
- return EmptyContent()
- }
- static func buildBlock(_ content: Content) -> Content {
- return content
- }
- static func buildBlock(_ contents: Content...) -> Content {
- return TupleContent(contents)
- }
- }
- protocol Content: Encodable {}
- extension Content {
- func getAll<T>() -> [T] {
- switch self {
- case let tuple as TupleContent:
- return (tuple.values as? [T]) ?? []
- case let content as T:
- return [content]
- default:
- return []
- }
- }
- }
- protocol ContentList: Content {
- var content: Content { get }
- }
- extension ContentList {
- var all: [ContentList] {
- switch self {
- case let tuple as TupleContentList:
- return tuple.values
- case let list as ContentList:
- return [list]
- default:
- return []
- }
- }
- }
- struct EmptyContent: Content {}
- struct EmptyContentList: ContentList {
- var content: Content { EmptyContent() }
- }
- protocol Tuple {
- associatedtype Body
- var values: [Body] { get }
- init(_ values: [Body])
- }
- struct TupleContent: Tuple, Content {
- let values: [Content]
- init(_ values: [Content]) {
- self.values = values
- }
- }
- extension TupleContent {
- func encode(to encoder: Encoder) throws {}
- }
- struct TupleContentList: Tuple, ContentList {
- var content: Content {
- return self
- }
- let values: [ContentList]
- init(_ values: [ContentList]) {
- self.values = values
- }
- }
- extension TupleContentList {
- func encode(to encoder: Encoder) throws {}
- }
- struct Package: Content {
- enum CodingKeys: CodingKey {
- case name
- case products
- case dependencies
- case targets
- }
- let name: String
- let contentList: ContentList
- init(name: String, @ContentListBuilder builder: () -> ContentList) {
- self.name = name
- self.contentList = builder()
- }
- }
- extension Package {
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(name, forKey: .name)
- let lists = contentList.all
- for list in lists {
- switch list {
- case let productList as ProductList:
- try container.encode(productList, forKey: .products)
- case let dependencyList as DependencyList:
- try container.encode(dependencyList, forKey: .dependencies)
- case let targetList as TargetList:
- try container.encode(targetList, forKey: .targets)
- default:
- break
- }
- }
- }
- }
- struct ProductList: ContentList {
- let content: Content
- init(@ContentBuilder builder: () -> Content) {
- self.content = builder()
- }
- }
- extension ProductList {
- func encode(to encoder: Encoder) throws {
- var container = encoder.unkeyedContainer()
- let products: [Product] = content.getAll()
- try container.encode(contentsOf: products)
- }
- }
- struct Product: Content {
- enum CodingKeys: CodingKey {
- case name
- case type
- case targets
- }
- enum `Type`: String, Codable {
- case executable, `static`, dynamic
- }
- let name: String
- let type: Type
- let targetList: ContentList
- init(name: String, type: Type = .executable, @ContentListBuilder builder: () -> ContentList = { EmptyContentList() }) {
- self.name = name
- self.type = type
- self.targetList = builder()
- }
- }
- extension Product {
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(name, forKey: .name)
- try container.encode(type, forKey: .type)
- try container.encodeIfPresent(targetList as? TargetList, forKey: .targets)
- }
- }
- struct TargetList: ContentList {
- let content: Content
- init(@ContentBuilder builder: () -> Content) {
- self.content = builder()
- }
- }
- extension TargetList {
- func encode(to encoder: Encoder) throws {
- var container = encoder.unkeyedContainer()
- let targets: [Target] = content.getAll()
- try container.encode(contentsOf: targets)
- }
- }
- struct Target: Content {
- enum CodingKeys: CodingKey {
- case name
- case dependencies
- }
- let name: String
- let dependencyList: ContentList
- init(name: String, @ContentListBuilder builder: () -> ContentList = { EmptyContentList() }) {
- self.name = name
- self.dependencyList = builder()
- }
- }
- extension Target {
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(name, forKey: .name)
- try container.encodeIfPresent(dependencyList as? TargetDependencyList, forKey: .dependencies)
- }
- }
- struct TargetDependencyList: ContentList {
- let content: Content
- init(@ContentBuilder builder: () -> Content) {
- self.content = builder()
- }
- }
- extension TargetDependencyList {
- func encode(to encoder: Encoder) throws {
- var container = encoder.unkeyedContainer()
- let dependencies: [Content] = content.getAll()
- for dependency in dependencies {
- switch dependency {
- case let value as TargetDependency:
- try container.encode(value)
- case let value as Target:
- try container.encode(value)
- case let value as Product:
- try container.encode(value)
- default:
- break
- }
- }
- }
- }
- struct TargetDependency: Content {
- let name: String
- }
- struct DependencyList: ContentList {
- let content: Content
- init(@ContentBuilder builder: () -> Content = { EmptyContent() }) {
- self.content = builder()
- }
- }
- extension DependencyList {
- func encode(to encoder: Encoder) throws {
- var container = encoder.unkeyedContainer()
- let dependencies: [Dependency] = content.getAll()
- try container.encode(contentsOf: dependencies)
- }
- }
- struct Dependency: Content {
- enum CodingKeys: CodingKey {
- case url
- case from
- case exact
- }
- var url: String?
- var from: String?
- var exact: String?
- init(url: String) {
- self.url = url
- }
- init(url: String, from: String) {
- self.url = url
- self.from = from
- }
- init(url: String, exact: String) {
- self.url = url
- self.exact = exact
- }
- }
- extension Dependency {
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encodeIfPresent(url, forKey: .url)
- try container.encodeIfPresent(from, forKey: .from)
- try container.encodeIfPresent(exact, forKey: .exact)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement