// // 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(".*?") 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 } }