Move html parser to deserialization.

This commit is contained in:
Marcin Czachursk 2023-02-24 15:52:57 +01:00
parent 47a896913c
commit 615b78c7af
11 changed files with 56 additions and 55 deletions

View File

@ -19,17 +19,15 @@ let package = Package(
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(
url: "https://github.com/OAuthSwift/OAuthSwift.git",
.upToNextMajor(from: "2.2.0")
)
.package(url: "https://github.com/OAuthSwift/OAuthSwift.git", .upToNextMajor(from: "2.2.0")),
.package(url: "https://gitlab.com/mflint/HTML2Markdown", .upToNextMajor(from: "1.0.0"))
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "PixelfedKit",
dependencies: ["OAuthSwift"]),
dependencies: ["OAuthSwift", "HTML2Markdown"]),
.testTarget(
name: "PixelfedKitTests",
dependencies: ["PixelfedKit"]),

View File

@ -22,7 +22,7 @@ public struct Account: Codable {
public let displayName: String?
/// The profiles bio or description.
public let note: String?
public let note: Html?
/// The location of the users profile page.
public let url: URL?

View File

@ -0,0 +1,46 @@
//
// https://mczachurski.dev
// Copyright © 2023 Marcin Czachurski and the repository contributors.
// Licensed under the MIT License.
//
import Foundation
import HTML2Markdown
public struct Html: Codable {
public var htmlValue: String = ""
public var asMarkdown: String = ""
init(_ htmlValue: String) {
do {
self.htmlValue = htmlValue
self.asMarkdown = try self.parseToMarkdown(html: htmlValue)
} catch {
self.htmlValue = ""
self.asMarkdown = ""
}
}
public init(from decoder: Decoder) {
do {
let container = try decoder.singleValueContainer()
self.htmlValue = try container.decode(String.self)
self.asMarkdown = try self.parseToMarkdown(html: htmlValue)
} catch {
self.htmlValue = ""
self.asMarkdown = ""
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(htmlValue)
}
private func parseToMarkdown(html: String) throws -> String {
let dom = try HTMLParser().parse(html: html)
return dom.toMarkdown()
// Add space between hashtags and mentions that follow each other
.replacingOccurrences(of: ")[", with: ") [")
}
}

View File

@ -75,7 +75,7 @@ public struct Instance: Codable {
self.title = try? container.decodeIfPresent(String.self, forKey: .title)
self.sourceUrl = try? container.decodeIfPresent(URL.self, forKey: .sourceUrl)
self.shortDescription = try? container.decodeIfPresent(String.self, forKey: .shortDescription)
self.description = try? container.decodeIfPresent(String.self, forKey: .description)
self.description = try? container.decodeIfPresent(Html.self, forKey: .description)
self.thumbnail = try? container.decodeIfPresent(URL.self, forKey: .thumbnail)
self.languages = try? container.decodeIfPresent([String].self, forKey: .languages)
self.configuration = try? container.decodeIfPresent(Configuration.self, forKey: .configuration)

View File

@ -158,7 +158,7 @@ public class Status: Codable {
self.uri = try container.decode(String.self, forKey: .uri)
self.url = try? container.decode(URL.self, forKey: .url)
self.account = try container.decode(Account.self, forKey: .account)
self.content = try container.decode(Html.self, forKey: .content)
self.content = (try? container.decode(Html.self, forKey: .content)) ?? Html("")
self.createdAt = try container.decode(String.self, forKey: .createdAt)
self.inReplyToId = try? container.decode(EntityId.self, forKey: .inReplyToId)
self.inReplyToAccount = try? container.decode(EntityId.self, forKey: .inReplyToAccount)

View File

@ -7,7 +7,6 @@
import Foundation
public typealias EntityId = String
public typealias Html = String
public typealias SearchQuery = String
public typealias ClientId = String

View File

@ -91,8 +91,6 @@
F88E4D48297E90CD0057491A /* TrendStatusesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88E4D47297E90CD0057491A /* TrendStatusesView.swift */; };
F88E4D4A297EA0490057491A /* RouterPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88E4D49297EA0490057491A /* RouterPath.swift */; };
F88E4D4D297EA4290057491A /* EmojiText in Frameworks */ = {isa = PBXBuildFile; productRef = F88E4D4C297EA4290057491A /* EmojiText */; };
F88E4D50297EA5230057491A /* HTML2Markdown in Frameworks */ = {isa = PBXBuildFile; productRef = F88E4D4F297EA5230057491A /* HTML2Markdown */; };
F88E4D52297EA6DA0057491A /* String+Markdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88E4D51297EA6DA0057491A /* String+Markdown.swift */; };
F88E4D54297EA7EE0057491A /* MarkdownFormattedText.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88E4D53297EA7EE0057491A /* MarkdownFormattedText.swift */; };
F88E4D56297EAD6E0057491A /* AppRouteur.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88E4D55297EAD6E0057491A /* AppRouteur.swift */; };
F88FAD21295F3944009B20C9 /* HomeFeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88FAD20295F3944009B20C9 /* HomeFeedView.swift */; };
@ -234,7 +232,6 @@
F88E4D43297E82EB0057491A /* Status+MediaAttachmentType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Status+MediaAttachmentType.swift"; sourceTree = "<group>"; };
F88E4D47297E90CD0057491A /* TrendStatusesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendStatusesView.swift; sourceTree = "<group>"; };
F88E4D49297EA0490057491A /* RouterPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterPath.swift; sourceTree = "<group>"; };
F88E4D51297EA6DA0057491A /* String+Markdown.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Markdown.swift"; sourceTree = "<group>"; };
F88E4D53297EA7EE0057491A /* MarkdownFormattedText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkdownFormattedText.swift; sourceTree = "<group>"; };
F88E4D55297EAD6E0057491A /* AppRouteur.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouteur.swift; sourceTree = "<group>"; };
F88FAD20295F3944009B20C9 /* HomeFeedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeFeedView.swift; sourceTree = "<group>"; };
@ -307,7 +304,6 @@
F8210DD92966BB7E001D9973 /* NukeUI in Frameworks */,
F85E132529741F05006A051D /* ActivityIndicatorView in Frameworks */,
F8B1E64F2973F61400EE0D10 /* Drops in Frameworks */,
F88E4D50297EA5230057491A /* HTML2Markdown in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -380,7 +376,6 @@
F8341F8F295C636C009C8EE6 /* Data+Exif.swift */,
F85D49862964334100751DF7 /* String+Date.swift */,
F8C14391296AF0B3001FE31D /* String+Exif.swift */,
F88E4D51297EA6DA0057491A /* String+Markdown.swift */,
F898DE6F2972868A004B4A6A /* String+Empty.swift */,
F8AD061229A565620042F111 /* String+Random.swift */,
F8210DE42966E160001D9973 /* Color+SystemColors.swift */,
@ -713,7 +708,6 @@
F8B1E64E2973F61400EE0D10 /* Drops */,
F85E132429741F05006A051D /* ActivityIndicatorView */,
F88E4D4C297EA4290057491A /* EmojiText */,
F88E4D4F297EA5230057491A /* HTML2Markdown */,
F83E00EC29A2237C005D25A3 /* PixelfedKit */,
);
productName = Vernissage;
@ -749,7 +743,6 @@
F8B1E64D2973F61400EE0D10 /* XCRemoteSwiftPackageReference "Drops" */,
F85E132329741F05006A051D /* XCRemoteSwiftPackageReference "ActivityIndicatorView" */,
F88E4D4B297EA4290057491A /* XCRemoteSwiftPackageReference "EmojiText" */,
F88E4D4E297EA5230057491A /* XCRemoteSwiftPackageReference "HTML2Markdown" */,
);
productRefGroup = F88C2469295C37B80006098B /* Products */;
projectDirPath = "";
@ -850,7 +843,6 @@
F8B9B34B298D4ACE009CC69C /* Client+Tags.swift in Sources */,
F88C2478295C37BB0006098B /* Vernissage.xcdatamodeld in Sources */,
F8AD061329A565620042F111 /* String+Random.swift in Sources */,
F88E4D52297EA6DA0057491A /* String+Markdown.swift in Sources */,
F898DE7229728CB2004B4A6A /* CommentModel.swift in Sources */,
F89A46DE296EABA20062125F /* StatusPlaceholderView.swift in Sources */,
F88C2482295C3A4F0006098B /* StatusView.swift in Sources */,
@ -1150,14 +1142,6 @@
minimumVersion = 1.3.0;
};
};
F88E4D4E297EA5230057491A /* XCRemoteSwiftPackageReference "HTML2Markdown" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://gitlab.com/mflint/HTML2Markdown";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.0.0;
};
};
F8B1E64D2973F61400EE0D10 /* XCRemoteSwiftPackageReference "Drops" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/omaralbeik/Drops";
@ -1198,11 +1182,6 @@
package = F88E4D4B297EA4290057491A /* XCRemoteSwiftPackageReference "EmojiText" */;
productName = EmojiText;
};
F88E4D4F297EA5230057491A /* HTML2Markdown */ = {
isa = XCSwiftPackageProductDependency;
package = F88E4D4E297EA5230057491A /* XCRemoteSwiftPackageReference "HTML2Markdown" */;
productName = HTML2Markdown;
};
F8B1E64E2973F61400EE0D10 /* Drops */ = {
isa = XCSwiftPackageProductDependency;
package = F8B1E64D2973F61400EE0D10 /* XCRemoteSwiftPackageReference "Drops" */;

View File

@ -27,7 +27,7 @@ extension StatusData {
self.applicationName = status.application?.name
self.applicationWebsite = status.application?.website
self.bookmarked = status.bookmarked
self.content = status.content
self.content = status.content.htmlValue
self.favourited = status.favourited
self.favouritesCount = Int32(status.favouritesCount)
self.inReplyToAccount = status.inReplyToAccount

View File

@ -1,21 +0,0 @@
//
// https://mczachurski.dev
// Copyright © 2023 Marcin Czachurski and the repository contributors.
// Licensed under the MIT License.
//
import Foundation
import HTML2Markdown
extension String {
public var asMarkdown: String {
do {
let dom = try HTMLParser().parse(html: self)
return dom.toMarkdown()
// Add space between hashtags and mentions that follow each other
.replacingOccurrences(of: ")[", with: ") [")
} catch {
return self
}
}
}

View File

@ -81,7 +81,7 @@ public class AuthorizationService {
accountData.username = account.username
accountData.acct = account.acct
accountData.displayName = account.displayNameWithoutEmojis
accountData.note = account.note
accountData.note = account.note?.htmlValue
accountData.url = account.url
accountData.avatar = account.avatar
accountData.header = account.header
@ -207,7 +207,7 @@ public class AuthorizationService {
dbAccount.username = account.username
dbAccount.acct = account.acct
dbAccount.displayName = account.displayNameWithoutEmojis
dbAccount.note = account.note
dbAccount.note = account.note?.htmlValue
dbAccount.url = account.url
dbAccount.avatar = account.avatar
dbAccount.header = account.header

View File

@ -73,7 +73,7 @@ struct UserProfileHeaderView: View {
}
}
if let note = account.note, !note.isEmpty {
if let note = account.note, !note.asMarkdown.isEmpty {
MarkdownFormattedText(note.asMarkdown, withFontSize: 14, andWidth: Int(UIScreen.main.bounds.width) - 16)
.environment(\.openURL, OpenURLAction { url in
routerPath.handle(url: url)