# LCEssentials — Extensions Foundation, value-type, string, collection, numeric, date, and crypto helpers, plus the `LCEssentials` namespace itself. UIKit extensions live in [UIKit.md](UIKit.md); SwiftUI helpers in [SwiftUI.md](SwiftUI.md). Every section is a collapsible block — click a heading to expand it. ## Contents - [API & Networking](#api--networking) - [Strings & Text](#strings--text) - [Collections & Sequences](#collections--sequences) - [Numbers & Geometry](#numbers--geometry) - [Date, Data & Files](#date-data--files) - [Encoding & Errors](#encoding--errors) - [Crypto](#crypto) - [Core — the `LCEssentials` namespace](#core--the-lcessentials-namespace) --- ## API & Networking `API` is an `actor` wrapping `URLSession` for typed JSON requests and multipart uploads. This is a summary — the **[full guide is in API.md](API.md)** (all parameters, error model, client certificates, custom body types, and the rationale vs. a hand-rolled `URLSession`).
API — typed async requests & uploads ### `API.shared` The shared `actor` instance. Every call is `await`; nothing runs on the main thread unless you hop there yourself. ```swift struct User: Decodable, Sendable { let id: Int; let name: String } let user: User = try await API.shared.request( url: "https://api.example.com/users/{id}", method: .get, pathParams: ["id": "42"] ) ``` ### `request(url:method:body:pathParams:headers:debug:timeoutInterval:networkServiceType:persistConnection:)` Sends a request and decodes the JSON response into `T: Decodable & Sendable`. Non-2xx responses throw an `NSError` whose `code` is the HTTP status and whose `localizedFailureReason` is the response body. When `T == String` the raw body is returned without JSON decoding. ```swift struct CreateUser: Encodable, Sendable { let name: String } // JSON body let created: User = try await API.shared.request( url: "https://api.example.com/users", method: .post, body: jsonBody(CreateUser(name: "Ana")) ) // form-url-encoded body let token: Token = try await API.shared.request( url: "https://api.example.com/oauth/token", method: .post, body: .form(["grant_type": "password", "username": "ana"]) ) ``` ### `upload(url:method:form:pathParams:headers:debug:timeoutInterval:networkServiceType:)` and its `onProgress:` overload Uploads a `multipart/form-data` body serialised to a temp file (removed afterwards) and streamed from disk, so large files never fully load into memory. ```swift var form = MultipartForm() form.field("caption", "Sunset") form.file("photo", data: jpegData, filename: "p.jpg") form.file("video", url: localVideoURL) // streamed from disk let result: UploadResult = try await API.shared.upload( url: "https://api.example.com/media", form: form, onProgress: { fraction in Task { @MainActor in progressView.progress = Float(fraction) } } ) ``` ### Body types — `HTTPBody` `jsonBody(_:)` wraps any `Encodable & Sendable`; `FormURLEncodedBody` (a.k.a. `.form([:])`) percent-escapes every value and never drops one; `RawBody` lets you supply the bytes and `Content-Type` yourself. Conform your own type to `HTTPBody` and `API` accepts it with no change. ```swift struct CSVBody: HTTPBody { let rows: [[String]] func encoded() throws -> (data: Data, contentType: String) { let text = rows.map { $0.joined(separator: ",") }.joined(separator: "\n") return (Data(text.utf8), "text/csv; charset=UTF-8") } } ``` ### `await API.shared.setupCertification(certData:password:)` Registers a client certificate (`.p12`) for mutual-TLS on subsequent requests. ```swift let p12 = try Data(contentsOf: certURL) await API.shared.setupCertification(certData: p12, password: "cert-pw") ```
## Strings & Text
String — validation, parsing, formatting, masks, HTML, dates ### URLs #### `var isValidUrl: Bool` / `var isValidHttpsUrl: Bool` / `var isValidHttpUrl: Bool` `isValidUrl` is true when `URL(string:)` succeeds; the other two additionally require the `https` / `http` scheme. ```swift "https://google.com".isValidUrl // true "https://google.com".isValidHttpsUrl // true "http://google.com".isValidHttpsUrl // false ``` #### `var urlEncoded: String` / `var urlDecoded: String` Percent-encode (host-allowed set) / decode. `urlDecoded` returns the original string when it is not encoded. ```swift "it's easy".urlEncoded // "it's%20easy" "it's%20easy".urlDecoded // "it's easy" ``` #### `mutating func urlEncode() -> String` / `mutating func urlDecode() -> String` In-place variants; also return the new value (`@discardableResult`). ```swift var s = "a b"; s.urlEncode() // s == "a%20b" ``` #### `func stringByAddingPercentEncodingForRFC3986() -> String` Percent-encodes for use as a query key/value, escaping `;/?:@&=+$,` and space. ```swift "a&b=c".stringByAddingPercentEncodingForRFC3986() // "a%26b%3Dc" ``` #### `var url: String?` First URL detected **inside** the string (via `NSDataDetector`), or `nil`. ```swift "visit www.site.com.br now".url // "www.site.com.br" ``` #### `var toURL: NSURL?` `NSURL(string:)` wrapper. ```swift "https://x.com".toURL // NSURL ``` ### Validation #### `var isEmail: Bool` Regex check for a syntactically valid email (TLD 2–20 chars). ```swift "user@example.com".isEmail // true "nope".isEmail // false ``` #### `var isCPF: Bool` Validates a Brazilian CPF including both check digits. Strips formatting first (`onlyNumbers`), requires 11 digits. ```swift "123.456.789-09".isCPF // true when the check digits match ``` #### `var isValidCNPJ: Bool` Validates a Brazilian CNPJ (14 digits, both check digits, rejects all-same-digit). ```swift "11.222.333/0001-81".isValidCNPJ // true when valid ``` #### `var isAlphabetic: Bool` Letters only, no digits. ```swift "abc".isAlphabetic // true "123abc".isAlphabetic // false ``` #### `var isAlphaNumeric: Bool` Contains at least one letter **and** one digit and nothing else — handy for password rules. ```swift "123abc".isAlphaNumeric // true "abc".isAlphaNumeric // false ``` #### `var isHTML: Bool` True if the string contains an HTML tag. ```swift "hi".isHTML // true ``` #### `func validateBolean(comparingBoolean: Bool = true) -> Bool` Loose truthy/falsy check against a large set of EN/PT words. With `comparingBoolean: true` returns whether the string means "true" (`YES`, `ON`, `SIM`, `ATIVO`, `1`, `T`, …); with `false`, whether it means "false". ```swift "SIM".validateBolean() // true "nao".validateBolean(comparingBoolean: false) // true ``` ### Conversion #### `var bool: Bool?` `"true"/"yes"/"1"` → `true`, `"false"/"no"/"0"` → `false`, else `nil` (trimmed, case-insensitive). ```swift " YES ".bool // true "maybe".bool // nil ``` #### `var int: Int?` / `var float: Float?` / `var double: Double?` Plain `Int(self)` / `Float(self)` / `Double(self)`. ```swift "101".int // 101 "1.5".double // 1.5 "x".int // nil ``` #### `func float(locale: Locale = .current) -> Float?` / `func double(locale:) -> Double?` Locale-aware parsing via `NumberFormatter` (accepts grouping separators). ```swift "1,5".double(locale: Locale(identifier: "pt_BR")) // 1.5 ``` #### `var currencyStringToDouble: Double` Parses a `pt_BR` currency string to `Double`, `0.0` on failure. ```swift "R$ 1.234,56".currencyStringToDouble // 1234.56 ``` #### `var btcToSats: Int` / `var bitcoinToSatoshis: Int` Multiplies a BTC amount string by 100,000,000. `bitcoinToSatoshis` is an alias. ```swift "0.0001".btcToSats // 10000 ``` #### `var data: Data` UTF-8 bytes. ```swift "hi".data // 2 bytes ``` #### `var nsString: NSString` / `var fullNSRange: NSRange` Bridge to `NSString`; `NSRange` spanning the whole string (UTF-16 aware). ```swift "café".fullNSRange // {0, 4} ``` #### `func nsRange(from range: Range) -> NSRange?` Convert a Swift `Range` to an `NSRange` in the UTF-16 view. #### `var base64Encode: String?` / `var base64Decode: String?` Base64 encode the UTF-8 bytes / decode a Base64 string back to text. ```swift "hi".base64Encode // "aGk=" "aGk=".base64Decode // "hi" ``` #### `func date(withCurrFormatt:localeIdentifier:timeZone:) -> Date?` Parse the string to `Date` using the given input format (default `"yyyy-MM-dd HH:mm:ss"`, locale `pt-BR`, current time zone). A `" 0000"` suffix is normalised to `" +0000"`. ```swift "2026-08-29 14:30:00".date() // Date ``` #### `func date(withCurrFormatt:newFormatt:localeIdentifier:timeZone:) -> Date?` Parse with one format and round-trip through another (normalises the value). #### `var currentTimeZone: String` Current time-zone offset string, e.g. `"-0300"`. ### Cleaning & filtering #### `var withoutSpacesAndNewLines: String` Removes every space and `\n`. ```swift " a \n b ".withoutSpacesAndNewLines // "ab" ``` #### `var onlyNumbers: String` / `var numbers: String` Digits only. `onlyNumbers` uses a `\D` regex; `numbers` uses `decimalDigits`. ```swift "(11) 98765-4321".onlyNumbers // "11987654321" ``` #### `var letters: String` / `var lettersWithWhiteSpace: String` Keep only letters (optionally keeping spaces). ```swift "a1 b2".letters // "ab" "a1 b2".lettersWithWhiteSpace // "a b" ``` #### `var alphanumeric: String` / `var alphanumericWithWhiteSpace: String` Keep only alphanumerics (optionally keeping spaces). ```swift "a-b_c 1".alphanumeric // "abc1" ``` #### `var removeSpecialChars: String` Keeps `[A-Za-z0-9 -]` only. ```swift "a@b#c".removeSpecialChars // "abc" ``` #### `var removeHTMLTags: String` / `var removeEmoji: String` Strip HTML tags / strip emoji (`CharacterSet.symbols`). ```swift "

hi

".removeHTMLTags // "hi" "hi 😀".removeEmoji // "hi " ``` ### Slicing & padding #### `var first: String` / `var last: String` First / last character **as a String** (`""` when empty). #### `var uppercaseFirst: String` Capitalises the first character only. ```swift "hello".uppercaseFirst // "Hello" ``` #### `var firstCharacterAsString: String?` / `var lastCharacterAsString: String?` Optional variants — `nil` when empty. #### `func paddingStart(_ length: Int, with: String = " ") -> String` / `func paddingEnd(...)` Pad to `length` with a repeating pad string at the start / end. No-op if already long enough. ```swift "hue".paddingStart(10) // " hue" "hue".paddingEnd(10, with: "br") // "huebrbrbrb" ``` #### `func truncated(toLength: Int, trailing: String? = "...") -> String` Non-mutating truncation. ```swift "This is long".truncated(toLength: 7) // "This is..." ``` #### `mutating func truncate(toLength: Int, trailing: String? = "...") -> String` In-place truncation (`@discardableResult`). #### `mutating func trim() -> String` Trim leading/trailing whitespace and newlines, in place (`@discardableResult`). ```swift var s = " hi \n"; s.trim() // s == "hi" ``` #### `mutating func reverse() -> String` Reverse in place (`@discardableResult`). #### `mutating func insertAtIndexEnd(string:ind:)` / `insertAtIndexStart(string:ind:)` Insert `string` at an offset measured from `endIndex` (negative `ind` moves left). ```swift var s = "abcd"; s.insertAtIndexEnd(string: "-", ind: -1) // "abc-d" ``` ### Replacing #### `func replace(from:to:)` / `func findAndReplace(from:to:)` Simple substring replacement (`findAndReplace` is generic over `StringProtocol`). ```swift "a.b.c".replace(from: ".", to: "-") // "a-b-c" ``` #### `func replacing(range: CountableClosedRange, with: String) -> String` Replace by integer character range. ```swift "abcdef".replacing(range: 1...3, with: "X") // "aXef" ``` #### `func replacingLastOccurrenceOfString(_:with:caseInsensitive: Bool = true) -> String` Replace only the last match. ```swift "a-b-c".replacingLastOccurrenceOfString("-", with: "+") // "a-b+c" ``` #### `func replaceAll(of pattern: String, with: String, options: = []) -> String` Regex replace-all; returns the original on a bad pattern. ```swift "a1b2c3".replaceAll(of: "[0-9]", with: "#") // "a#b#c#" ``` #### `@discardableResult func replaceURL(_ withDict: [String: Any]) -> String` Substitute `{key}` placeholders — used by `API.request(pathParams:)`. ```swift "/users/{id}/posts/{p}".replaceURL(["id": 7, "p": "x"]) // "/users/7/posts/x" ``` ### Words & search #### `func words() -> [String]` / `func wordCount() -> Int` Split on whitespace + punctuation, dropping empties. ```swift "Swift is amazing".words() // ["Swift", "is", "amazing"] "Swift is amazing".wordCount() // 3 ``` #### `func contains(_:caseSensitive: Bool = true) -> Bool` Substring check with optional case-insensitivity. ```swift "Hello".contains("ell") // true "Hello".contains("HELLO", caseSensitive: false) // true ``` ### Formatting helpers #### `func applyMask(toText: String, mask: String) -> String` Apply a `#`-placeholder mask; literal characters in the mask are inserted. ```swift "11987654321".applyMask(toText: "11987654321", mask: "(##) #####-####") // "(11) 98765-4321" ``` #### `func exponentize(str: String) -> String` Turn `^`-prefixed digits into Unicode superscripts. ```swift "x^2 + y^3".exponentize(str: "x^2 + y^3") // "x² + y³" ``` #### `func stringFromTimeInterval(_ interval: TimeInterval) -> NSString` Format a `TimeInterval` as `HH:MM:SS.mmm`. ```swift "".stringFromTimeInterval(3661.5) // "01:01:01.500" ``` #### `func toSlug() -> String` Lowercase, de-accent, spaces → `-`, strip other punctuation. ```swift "Olá Mundo!".toSlug() // "ola-mundo" ``` #### `func localized(comment: String = "") -> String` `NSLocalizedString(self, comment:)`. ```swift "welcome_title".localized() ``` ### Generators & misc #### `static func loremIpsum(ofLength length: Int = 445) -> String` Lorem-ipsum text truncated to `length` (max 445). ```swift String.loremIpsum(ofLength: 20) // "Lorem ipsum dolor si" ``` #### `func randomString(length: Int) -> String` Random `[A-Za-z0-9]` string. (Instance method — the receiver is ignored.) ```swift "".randomString(length: 8) // e.g. "a9Fk2Lp0" ``` #### `var JSONStringToDictionary: [String: Any]?` Parse a JSON object string to a dictionary (`nil` + logs on failure). ```swift #"{"a":1}"#.JSONStringToDictionary // ["a": 1] ``` #### `var convertToHTML: NSAttributedString?` Render an HTML string to `NSAttributedString` (UIKit path uses the CSS converter below). #### `func convertHtmlToAttributedStringWithCSS(font:csscolor:lineheight:csstextalign:customCSS:) -> NSAttributedString?` — *UIKit only* HTML → `NSAttributedString` with an injected `