Skip to content
Open
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
6 changes: 3 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import PackageDescription
let package = Package(
name: "OPML",
platforms: [
.iOS(.v13),
.macOS(.v10_15),
.tvOS(.v13),
.iOS(.v14),
.macOS(.v11),
.tvOS(.v14),
],
products: [
.library(name: "OPML", targets: ["OPML"])
Expand Down
17 changes: 17 additions & 0 deletions Sources/OPML/Conveniences/OPMLEntry+Values.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Foundation

public extension OPMLEntry {
func attributeBoolValue(_ name: String) -> Bool? {
guard let value = attributes?.first(where: { $0.name == name })?.value else { return nil }
return value == "true"
}

func attributeStringValue(_ name: String) -> String? {
return attributes?.first(where: { $0.name == name })?.value
}

func attributeUUIDValue(_ name: String) -> UUID? {
guard let value = attributes?.first(where: { $0.name == name })?.value else { return nil }
return UUID(uuidString: value)
}
}
21 changes: 12 additions & 9 deletions Sources/OPML/Exporter/Exporter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import Foundation
import Html

public extension OPML {

var xml: String {
render(document)
}

func xml(indented: Bool) -> String {
if indented {
return debugRender(document, config: Config.pretty)
}
return xml
}
// TODO: Reintroduce indentation when bugs are fixed. Currently doesn't escape attribute values.
// func xml(indented: Bool) -> String {
// if indented {
// return debugRender(document, config: Config.pretty)
// }
// return xml
// }

private static let dateFormatter = DateFormatter.iso8601

Expand Down Expand Up @@ -53,11 +53,9 @@ public extension OPML {
}
return .head(children)
}

}

extension OPMLEntry {

var htmlAttributes: [(String, String)] {
var htmlAttributes: [(String, String)] = attributes?.compactMap {
guard !$0.value.isEmpty else { return nil }
Expand All @@ -70,5 +68,10 @@ extension OPMLEntry {
var node: Node {
.outline(attributes: htmlAttributes, children?.map { $0.node } ?? [])
}
}

public extension OPMLEntry {
var xml: String {
render(node)
}
}
1 change: 0 additions & 1 deletion Sources/OPML/Models/OPMLEntry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,4 @@ public struct OPMLEntry: Codable, Hashable {
] + (attributes ?? [])
children = nil
}

}
43 changes: 43 additions & 0 deletions Sources/OPML/Transfer/OPML+Transferable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import SwiftUI
import UniformTypeIdentifiers

enum TransferError: Error {
case importFailed
}

@available(iOS 16.0, macOS 13.0, *)
extension OPML: Transferable {
public static var transferRepresentation: some TransferRepresentation {
FileRepresentation(contentType: .fileURL,
shouldAttemptToOpenInPlace: false) { opml in
let resultURL = FileManager.default.temporaryDirectory
.appendingPathComponent(opml.title ?? UUID().uuidString)
.appendingPathExtension("opml")
if FileManager.default.fileExists(atPath: resultURL.path) {
try FileManager.default.removeItem(at: resultURL)
}
let data = opml.xml.data(using: .utf8) ?? Data()
try data.write(to: resultURL, options: [.atomic])
return SentTransferredFile(resultURL, allowAccessingOriginalFile: true)
} importing: { opmlFile in
let data = try Data(contentsOf: opmlFile.file, options: [.uncached])
return (try? OPML(data)) ?? OPML(entries: [])
}

DataRepresentation(contentType: .opml) { opml in
opml.xml.data(using: .utf8) ?? Data()
} importing: { data in
return (try? OPML(data)) ?? OPML(entries: [])
}

DataRepresentation(contentType: .utf8PlainText) { opml in
opml.xml.data(using: .utf8) ?? Data()
} importing: { data in
return (try? OPML(data)) ?? OPML(entries: [])
}
}
}

extension UTType {
static let opml = UTType(exportedAs: "public.opml", conformingTo: .xml)
}
32 changes: 32 additions & 0 deletions Sources/OPML/Transfer/OPMLFile.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Foundation
import SwiftUI
import UniformTypeIdentifiers

public struct OPMLFile: FileDocument {
// tell the system we support only plain text
public static var readableContentTypes = [UTType(exportedAs: "public.opml"), UTType.plainText]

public var title = ""

// by default our document is empty
public var text = ""

// a simple initializer that creates new, empty documents
public init(opml: OPML) {
text = opml.xml
title = opml.title ?? ""
}

// this initializer loads data that has been saved previously
public init(configuration: ReadConfiguration) throws {
if let data = configuration.file.regularFileContents {
text = String(decoding: data, as: UTF8.self)
}
}

// this will be called when the system wants to write our data to disk
public func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
let data = Data(text.utf8)
return FileWrapper(regularFileWithContents: data)
}
}