Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Decodable implementation #7

Merged
merged 2 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions Sources/Core/Spec+Context.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Spec+Context.swift

import Foundation

extension Spec.Product {
func makeContext() -> [String: Any] {
[
"name": name,
"productType": productType.rawValue,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although the keys in the rest of the file use snake casing, I left this one to match the name of the property to avoid breaking backward compatibility with the Stencil file provided as part of the current major version.

"targets": targets
]
}
}

extension Spec.RemoteDependency {
func makeContext() -> [String: Any] {
var retVal = [
"name": name,
"url": url
]
if let ref {
switch ref {
case .branch(let value):
retVal["branch"] = value
case .revision(let value):
retVal["revision"] = value
case .version(let value):
retVal["version"] = value
}
}
return retVal.compactMapValues { $0 }
}
}

extension Spec {
func makeContext() -> [String: Any] {
let values: [String: Any?] = [
"package_name": name,
"platforms": platforms,
"local_dependencies": localDependencies,
"remote_dependencies": remoteDependencies.map { $0.makeContext() },
"products": products.map { $0.makeContext() },
"targets": targets,
"local_binary_targets": localBinaryTargets,
"remote_binary_targets": remoteBinaryTargets,
"swift_tools_version": swiftToolsVersion,
"swift_versions": swiftLanguageVersions
]
return values.compactMapValues { $0 }
}
}
4 changes: 1 addition & 3 deletions Sources/Core/SpecGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ final class SpecGenerator {
return Spec.RemoteDependency(
name: dependency.name,
url: remoteDependency.url ?? dependency.url,
version: remoteDependency.version ?? dependency.version,
revision: remoteDependency.revision ?? dependency.revision,
branch: remoteDependency.branch ?? dependency.branch
ref: remoteDependency.ref ?? dependency.ref
)
}

Expand Down
26 changes: 15 additions & 11 deletions Sources/Models/Dependencies.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,23 @@ struct Dependencies: Decodable {
struct Dependency: Decodable {
let name: String
let url: String
let version: String?
let revision: String?
let branch: String?
let ref: Ref

init(name: String, url: String, version: String?, revision: String?, branch: String?) {
guard version != nil || revision != nil || branch != nil else {
fatalError("You need to provide at least one of the following: version, revision or branch")
}

enum CodingKeys: String, CodingKey {
case name
case url
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
self.url = try container.decode(String.self, forKey: .url)
self.ref = try Ref(from: decoder)
}

init(name: String, url: String, ref: Ref) {
self.name = name
self.url = url
self.version = version
self.revision = revision
self.branch = branch
self.ref = ref
}
}
29 changes: 29 additions & 0 deletions Sources/Models/Ref.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Ref.swift

import Foundation

enum Ref: Decodable {
case version(String)
case revision(String)
case branch(String)

enum CodingKeys: String, CodingKey {
case version
case revision
case branch
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

if let version = try container.decodeIfPresent(String.self, forKey: .version) {
self = .version(version)
} else if let revision = try container.decodeIfPresent(String.self, forKey: .revision) {
self = .revision(revision)
} else if let branch = try container.decodeIfPresent(String.self, forKey: .branch) {
self = .branch(branch)
} else {
throw DecodingError.dataCorruptedError(forKey: CodingKeys.version, in: container, debugDescription: "Expected one of version, revision, or branch to be present.")
}
}
}
48 changes: 5 additions & 43 deletions Sources/Models/Spec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,14 @@ struct Spec: Decodable {

struct Product: Decodable {
let name: String
let productType: String
let productType: ProductType
let targets: [String]

enum CodingKeys: CodingKey {
case name
case productType
case targets
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
self.productType = try container.decode(ProductType.self, forKey: .productType).rawValue
self.targets = try container.decode([String].self, forKey: .targets)
}
}

enum ProductType: String, Decodable {
Expand All @@ -39,37 +32,24 @@ struct Spec: Decodable {
struct RemoteDependency: Decodable {
let name: String
let url: String?
let version: String?
let revision: String?
let branch: String?
let ref: Ref?

enum CodingKeys: CodingKey {
case name
case url
case version
case revision
case branch
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
self.url = try container.decodeIfPresent(String.self, forKey: .url)
self.version = try container.decodeIfPresent(String.self, forKey: .version)
self.revision = try container.decodeIfPresent(String.self, forKey: .revision)
self.branch = try container.decodeIfPresent(String.self, forKey: .branch)
self.ref = try? Ref(from: decoder)
}

init(name: String, url: String, version: String?, revision: String?, branch: String?) {
guard version != nil || revision != nil || branch != nil else {
fatalError("You need to provide at least one of the following: version, revision or branch")
}

init(name: String, url: String, ref: Ref) {
self.name = name
self.url = url
self.version = version
self.revision = revision
self.branch = branch
self.ref = ref
}
}

Expand Down Expand Up @@ -181,21 +161,3 @@ struct Spec: Decodable {
self.swiftLanguageVersions = swiftLanguageVersions
}
}

extension Spec {
func makeContext() -> [String: Any] {
let values: [String: Any?] = [
"package_name": name,
"platforms": platforms,
"local_dependencies": localDependencies,
"remote_dependencies": remoteDependencies,
"products": products,
"targets": targets,
"local_binary_targets": localBinaryTargets,
"remote_binary_targets": remoteBinaryTargets,
"swift_tools_version": swiftToolsVersion,
"swift_versions": swiftLanguageVersions
]
return values.compactMapValues { $0 }
}
}