forked from aparoksha/adwaita-swift
164 lines
6.0 KiB
Swift
164 lines
6.0 KiB
Swift
//
|
||
// String.swift
|
||
// Adwaita
|
||
//
|
||
// Created by david-swift on 14.01.24.
|
||
//
|
||
|
||
extension String: @retroactive CodingKey {
|
||
|
||
/// The string.
|
||
public var stringValue: String {
|
||
self
|
||
}
|
||
|
||
/// A string cannot be represented as an integer.
|
||
public var intValue: Int? {
|
||
nil
|
||
}
|
||
|
||
/// Initialize from an int value.
|
||
/// - Parameter intValue: The int value.
|
||
public init?(intValue: Int) {
|
||
nil
|
||
}
|
||
|
||
/// Initialize from a string value.
|
||
/// - Parameter stringValue: The string value.
|
||
public init?(stringValue: String) {
|
||
self = stringValue
|
||
}
|
||
|
||
/// Generate a doc comment out of the string.
|
||
/// - Parameters:
|
||
/// - configuration: The generation configuration.
|
||
/// - indent: Indentation added at the beginning of every line.
|
||
/// - Returns: The comment.
|
||
func docComment(configuration: GenerationConfiguration, indent: String = "") -> String {
|
||
applyDocRegex(configuration: configuration)
|
||
.split(separator: "\n", omittingEmptySubsequences: false)
|
||
.map { $0.trimmingCharacters(in: .whitespaces) }
|
||
.enumerated()
|
||
.map { $0.offset == 0 ? $0.element.prefix(1).capitalized + $0.element.dropFirst() : $0.element }
|
||
.map { "\(indent)/// \($0)" }
|
||
.joined(separator: "\n")
|
||
}
|
||
|
||
/// Convert delimited to camel casing.
|
||
/// - Parameters:
|
||
/// - delimiter: The demiliter.
|
||
/// - unshorten: Whether to unshorten.
|
||
/// - configuration: The generation configuration.
|
||
/// - Returns: The string using camel casing.
|
||
func convertDelimitedCasingToCamel(
|
||
delimiter: Character,
|
||
configuration: GenerationConfiguration,
|
||
unshorten: Bool = false
|
||
) -> String {
|
||
var parts = split(separator: delimiter).map(String.init)
|
||
for (index, part) in parts.enumerated() {
|
||
if let replacement = configuration.unshorteningMap[part] {
|
||
parts[index] = replacement
|
||
}
|
||
}
|
||
let first = parts.removeFirst()
|
||
return first + parts.map(\.capitalized).joined()
|
||
}
|
||
|
||
/// Convert a C type to its Swift equivalent using the generation configuration.
|
||
/// - Parameter configuration: The generation configuration.
|
||
/// - Returns: The Swift type.
|
||
func convertCType(configuration: GenerationConfiguration) -> String {
|
||
if let replacement = configuration.cTypeReplacements[self] {
|
||
return replacement
|
||
}
|
||
var type = self
|
||
if type.last == "*" {
|
||
let pointeeType = String(type.dropLast()).convertCType(configuration: configuration)
|
||
type = "UnsafeMutablePointer<\(pointeeType)>!"
|
||
}
|
||
return type
|
||
}
|
||
|
||
/// Apply the documentation regex.
|
||
/// - Parameter configuration: The generation configuration.
|
||
/// - Returns: The documentation with the regex applied.
|
||
func applyDocRegex(configuration: GenerationConfiguration) -> String {
|
||
var modified = self
|
||
do {
|
||
modified = try modified.applyExtraContentRegex()
|
||
modified = try modified.applySimpleRegex()
|
||
modified = try modified.applyPropertyRegex(configuration: configuration)
|
||
modified = try modified.applyBooleanRegex()
|
||
modified = try modified.applyHTMLRegex()
|
||
modified = try modified.applyNoteRegex()
|
||
return modified
|
||
} catch {
|
||
print("FAIL!")
|
||
return modified
|
||
}
|
||
}
|
||
|
||
/// Apply the regex to remove additional documentation content.
|
||
/// - Returns: The documentation with the regex applied.
|
||
func applyExtraContentRegex() throws -> String {
|
||
let extraContent = try Regex("##?(.|\\n)*")
|
||
return replacing(extraContent, with: "")
|
||
}
|
||
|
||
/// Translate simple definitions into Markdown inline code.
|
||
/// - Returns: The documentation with the regex applied.
|
||
func applySimpleRegex() throws -> String {
|
||
let regex = try Regex("\\[(class|func|method|ctor|signal|const|iface)@(.*?)\\]")
|
||
return replacing(regex) { match in
|
||
"`\(match.output[2].substring ?? "")`"
|
||
}
|
||
}
|
||
|
||
/// Translate property definitions into Swift references.
|
||
/// - Parameter configuration: The generation configuration.
|
||
/// - Returns: The documentation with the regex applied.
|
||
func applyPropertyRegex(configuration: GenerationConfiguration) throws -> String {
|
||
let property = try Regex("\\[property@(.*?)\\:(.*?)\\]")
|
||
return replacing(property) { match in
|
||
let method = String(match.output[2].substring ?? "")
|
||
.convertDelimitedCasingToCamel(delimiter: "-", configuration: configuration, unshorten: true)
|
||
return "``\(method)(_:)``"
|
||
}
|
||
}
|
||
|
||
/// Translate booleans into inline Markdown code with Swift booleans.
|
||
/// - Returns: The documentation with the regex applied.
|
||
func applyBooleanRegex() throws -> String {
|
||
var modified = self
|
||
let `false` = try Regex("(`|%)FALSE`?")
|
||
modified = modified.replacing(`false`, with: "`false`")
|
||
let `true` = try Regex("(`|%)TRUE`?")
|
||
modified = modified.replacing(`true`, with: "`true`")
|
||
return modified
|
||
}
|
||
|
||
/// Remove broken HTML tags.
|
||
/// - Returns: The documentation with the regex applied.
|
||
func applyHTMLRegex() throws -> String {
|
||
let picture = try Regex("<picture>.*?</picture>")
|
||
return replacing(picture, with: "")
|
||
}
|
||
|
||
/// Interpret note/warning blocks.
|
||
/// - Returns: The documentation with the regex applied.
|
||
func applyNoteRegex() throws -> String {
|
||
var modified = self
|
||
let note = try Regex("::: note\\n((.|\\n)*?)(\\n\\n)?")
|
||
modified = modified.replacing(note) { match in
|
||
"> [!NOTE]\n> \(match.output[1].substring ?? "")"
|
||
}
|
||
let warning = try Regex("::: warning\\n((.|\\n)*?)(\\n\\n)?")
|
||
modified = modified.replacing(warning) { match in
|
||
"> [!WARNING]\n> \(match.output[1].substring ?? "")"
|
||
}
|
||
return modified
|
||
}
|
||
|
||
}
|