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

Prepping v0.3.8 for release #62

Merged
merged 7 commits into from
Sep 28, 2023
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
14 changes: 7 additions & 7 deletions .github/workflows/syndikit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
strategy:
matrix:
runs-on: [ubuntu-20.04, ubuntu-22.04]
swift-version: [5.7.3, 5.8]
swift-version: [5.7.3, 5.8.1, 5.9]
include:
- runs-on: ubuntu-20.04
swift-version: 5.5.3
Expand Down Expand Up @@ -135,7 +135,7 @@ jobs:
${{ runner.os }}-build-
${{ runner.os }}-
- name: Cache mint
if: ${{ github.event_name == 'pull_request' && github.base_ref == 'main' && matrix.xcode == '/Applications/Xcode_14.3.1.app' }}
if: ${{ github.event_name == 'pull_request' && ( github.base_ref == 'main' || endsWith( github.ref_name , 'Prep') ) && matrix.xcode == '/Applications/Xcode_14.3.1.app' }}
id: cache-mint
uses: actions/cache@v3
env:
Expand All @@ -152,7 +152,7 @@ jobs:
- name: Setup Xcode
run: sudo xcode-select -s ${{ matrix.xcode }}/Contents/Developer
- name: Install mint
if: ${{ github.event_name == 'pull_request' && github.base_ref == 'main' && matrix.xcode == '/Applications/Xcode_14.3.1.app' }}
if: ${{ github.event_name == 'pull_request' && ( github.base_ref == 'main' || endsWith( github.ref_name , 'Prep') ) && matrix.xcode == '/Applications/Xcode_14.3.1.app' }}
run: |
brew update
brew install mint
Expand All @@ -168,7 +168,7 @@ jobs:
uses: github/codeql-action/analyze@v2
- name: Run Swift Package tests
run: swift test -v --enable-code-coverage
- uses: sersoft-gmbh/swift-coverage-action@v2
- uses: sersoft-gmbh/swift-coverage-action@v4
- name: Upload SPM to CodeCov.io
run: bash <(curl https://codecov.io/bash) -F spm -F macOS -F ${XCODE_NAME}
env:
Expand All @@ -177,7 +177,7 @@ jobs:
run: rm -rf .build
- name: Lint
run: ./scripts/lint.sh
if: ${{ github.event_name == 'pull_request' && github.base_ref == 'main' && matrix.xcode == '/Applications/Xcode_14.3.app' }}
if: ${{ github.event_name == 'pull_request' && ( github.base_ref == 'main' || endsWith( github.ref_name , 'Prep') ) && matrix.xcode == '/Applications/Xcode_14.3.1.app' }}
- name: Dump PIF
if: startsWith(matrix.xcode,'/Applications/Xcode_14')
run: |
Expand All @@ -190,14 +190,14 @@ jobs:
done
- name: Run iOS target tests
run: xcodebuild test -scheme SyndiKit -sdk iphonesimulator -destination 'platform=iOS Simulator,name=${{ matrix.iPhoneName }},OS=${{ matrix.iOSVersion }}' -enableCodeCoverage YES build test
- uses: sersoft-gmbh/swift-coverage-action@v2
- uses: sersoft-gmbh/swift-coverage-action@v4
- name: Upload iOS Coverage to CodeCov.io
run: bash <(curl https://codecov.io/bash) -F iOS -F iOS${{ matrix.iOSVersion }} -F macOS -F ${XCODE_NAME}
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- name: Run watchOS target tests
run: xcodebuild test -scheme SyndiKit -sdk watchsimulator -destination 'platform=watchOS Simulator,name=${{ matrix.watchName }},OS=${{ matrix.watchOSVersion }}' -enableCodeCoverage YES build test
- uses: sersoft-gmbh/swift-coverage-action@v2
- uses: sersoft-gmbh/swift-coverage-action@v4
- name: Upload watchOS Coverage to CodeCov.io
run: bash <(curl https://codecov.io/bash) -F watchOS -F watchOS${{ matrix.watchOSVersion }} -F macOS -F ${XCODE_NAME}
env:
Expand Down
3 changes: 1 addition & 2 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,8 @@ identifier_name:
excluded:
- id
excluded:
- Tests/*/XCTestManifests.swift
- Tests
- DerivedData
- .build
- Tests/LinuxMain.swift
indentation_width:
indentation_width: 2
6 changes: 3 additions & 3 deletions Sources/SyndiKit/Collection.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

extension Collection {
subscript(safe index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil
}
subscript(safe index: Index) -> Element? {
indices.contains(index) ? self[index] : nil
}
}
2 changes: 1 addition & 1 deletion Sources/SyndiKit/Common/Feedable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation
/// - ``siteURL``
/// - ``summary``
/// - ``updated``
/// - ``author``
/// - ``authors``
/// - ``copyright``
/// - ``image``
/// - ``children``
Expand Down
39 changes: 39 additions & 0 deletions Sources/SyndiKit/Common/Primitives/ListString.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Foundation

public struct ListString<
Value: LosslessStringConvertible & Equatable
>: Codable, Equatable {
public let values: [Value]

internal init(values: [Value]) {
self.values = values
}

public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let listString = try container.decode(String.self)
let strings = listString.components(separatedBy: ",")
let values = try strings
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
.filter { !$0.isEmpty }
.map(Self.createValueFrom)
self.init(values: values)
}

private static func createValueFrom(_ string: String) throws -> Value {
guard let value: Value = .init(string) else {
throw DecodingError.typeMismatch(
Value.self,
.init(codingPath: [], debugDescription: "Invalid value: \(string)")
)
}
return value
}

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
let strings = values.map(String.init)
let listString = strings.joined(separator: ",")
try container.encode(listString)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ extension PodcastChapters {
} else if case let .unknown(string) = self {
return string
} else {
fatalError("Type attribute of <podcast:chapters> should either be `KnownMimeType`, or unknown!")
fatalError(
// swiftlint:disable:next line_length
"Type attribute of <podcast:chapters> with value: \(self) should either be `KnownMimeType`, or unknown!"
)
}
}

Expand Down
104 changes: 74 additions & 30 deletions Sources/SyndiKit/Formats/Media/Podcast/PodcastLocation+GeoURI.swift
Original file line number Diff line number Diff line change
@@ -1,62 +1,106 @@
import Foundation

extension PodcastLocation {
public struct GeoURI: Codable, Equatable {
let latitude: Double
let longitude: Double
let altitude: Double?
let accuracy: Double?

public init(latitude: Double, longitude: Double, altitude: Double? = nil, accuracy: Double? = nil) {
public extension PodcastLocation {
struct GeoURI: Codable, Equatable, LosslessStringConvertible {
public let latitude: Double
public let longitude: Double
public let altitude: Double?
public let accuracy: Double?

public var description: String {
var description = "geo:\(latitude),\(longitude)"

if let altitude = altitude {
description += ",\(altitude)"
}

if let accuracy = accuracy {
description += ";u=\(accuracy)"
}

return description
}

public init(
latitude: Double,
longitude: Double,
altitude: Double? = nil,
accuracy: Double? = nil
) {
self.latitude = latitude
self.longitude = longitude
self.altitude = altitude
self.accuracy = accuracy
}

public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let geoStr = try container.decode(String.self)
public init?(_ description: String) {
try? self.init(singleValue: description)
}

public init(singleValue: String) throws {
let pathComponents = try Self.pathComponents(from: singleValue)

guard
let geoScheme = geoStr.split(separator: ":")[safe: 0],
geoScheme == "geo" else {
let geoCoords = pathComponents[safe: 0]?.split(separator: ","),
let latitude = geoCoords[safe: 0]?.asDouble(),
let longitude = geoCoords[safe: 1]?.asDouble()
else {
throw DecodingError.dataCorrupted(
.init(
codingPath: [PodcastLocation.CodingKeys.geo],
debugDescription: "Invalid prefix for geo attribute: \(geoStr)"
debugDescription: "Invalid coordinates for geo attribute: \(singleValue)"
)
)
}
guard let geoPath = geoStr.split(separator: ":")[safe: 1] else {

let altitude = geoCoords[safe: 2]?.asDouble()

let accuracy = pathComponents[safe: 1]?
.split(separator: "=")[safe: 1]?
.asDouble()

self.init(
latitude: latitude,
longitude: longitude,
altitude: altitude,
accuracy: accuracy
)
}

public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let singleValue = try container.decode(String.self)

try self.init(singleValue: singleValue)
}

private static func pathComponents(from string: String) throws -> [Substring] {
let components = string.split(separator: ":")

guard
components[safe: 0] == "geo" else {
throw DecodingError.dataCorrupted(
.init(
codingPath: [PodcastLocation.CodingKeys.geo],
debugDescription: "Invalid path for geo attribute: \(geoStr)"
debugDescription: "Invalid prefix for geo attribute: \(string)"
)
)
}
guard
let geoCoords = geoPath.split(separator: ";")[safe: 0],
let latitude = geoCoords.split(separator: ",")[safe: 0]?.asDouble(),
let longitude = geoCoords.split(separator: ",")[safe: 1]?.asDouble()
else {
guard let geoPath = components[safe: 1] else {
throw DecodingError.dataCorrupted(
.init(
codingPath: [PodcastLocation.CodingKeys.geo],
debugDescription: "Invalid coordinates for geo attribute: \(geoStr)"
debugDescription: "Invalid path for geo attribute: \(string)"
)
)
}
let altitude = geoCoords.split(separator: ",")[safe: 2]?.asDouble()
let accuracy = geoPath.split(separator: ";")[safe: 1]?
.split(separator: "=")[safe: 1]?
.asDouble()

self.latitude = latitude
self.longitude = longitude
self.altitude = altitude
self.accuracy = accuracy
return geoPath.split(separator: ";")
}

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(description)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

extension PodcastLocation {
public struct OsmQuery: Codable, Equatable {
public extension PodcastLocation {
struct OsmQuery: Codable, Equatable {
enum OsmType: String, Codable, CaseIterable {
case node = "N"
case way = "W"
Expand Down Expand Up @@ -39,9 +39,9 @@ extension PodcastLocation {
}
let osmRevision = osmStr.split(separator: "#")[safe: 1]?.asInt()

self.id = osmID
self.type = osmType
self.revision = osmRevision
id = osmID
type = osmType
revision = osmRevision
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ extension PodcastPerson {
} else if case let .unknown(string) = self {
return string
} else {
fatalError("Role attribute of <podcast:person> should either be a `KnownRole`, or unknown!")
fatalError(
// swiftlint:disable:next line_length
"Role attribute of <podcast:person> with value: \(self) should either be a `KnownRole`, or unknown!"
)
}
}

Expand Down
10 changes: 5 additions & 5 deletions Sources/SyndiKit/Formats/Media/Podcast/PodcastPerson.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ public struct PodcastPerson: Codable, Equatable {

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.role = try container.decodeIfPresent(Role.self, forKey: .role)
self.group = try container.decodeIfPresent(String.self, forKey: .group)
self.fullname = try container.decode(String.self, forKey: .fullname)
role = try container.decodeIfPresent(Role.self, forKey: .role)
group = try container.decodeIfPresent(String.self, forKey: .group)
fullname = try container.decode(String.self, forKey: .fullname)

let hrefUrl = try container.decodeIfPresent(String.self, forKey: .href) ?? ""
self.href = hrefUrl.isEmpty ? nil : URL(string: hrefUrl)
href = hrefUrl.isEmpty ? nil : URL(string: hrefUrl)

let imgUrl = try container.decodeIfPresent(String.self, forKey: .img) ?? ""
self.img = imgUrl.isEmpty ? nil : URL(string: imgUrl)
img = imgUrl.isEmpty ? nil : URL(string: imgUrl)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ extension PodcastTranscript {
} else if case let .unknown(string) = self {
return string
} else {
fatalError("Type attribute of <podcast:transcript> should either be a `KnownMimeType`, or unknown!")
fatalError(
// swiftlint:disable:next line_length
"Type attribute of <podcast:transcript> with value: \(self) should either be a `KnownMimeType`, or unknown!"
)
}
}

Expand Down
5 changes: 4 additions & 1 deletion Sources/SyndiKit/Formats/Media/Wordpress/WPCategory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ public extension WordPressElements {
}

extension WordPressElements.Category: Equatable {
public static func == (lhs: WordPressElements.Category, rhs: WordPressElements.Category) -> Bool {
public static func == (
lhs: WordPressElements.Category,
rhs: WordPressElements.Category
) -> Bool {
lhs.termID == rhs.termID
&& lhs.niceName == rhs.niceName
&& lhs.parent == rhs.parent
Expand Down
5 changes: 4 additions & 1 deletion Sources/SyndiKit/Formats/Media/Wordpress/WPPostMeta.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ public extension WordPressElements {
}

extension WordPressElements.PostMeta: Equatable {
public static func == (lhs: WordPressElements.PostMeta, rhs: WordPressElements.PostMeta) -> Bool {
public static func == (
lhs: WordPressElements.PostMeta,
rhs: WordPressElements.PostMeta
) -> Bool {
lhs.key == rhs.key
&& lhs.value == rhs.value
}
Expand Down
Loading