Initial Commit

This commit is contained in:
2025-09-23 20:22:59 -04:00
commit 743fc51873
135 changed files with 12240 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
//
// AppError.swift
// HRW
//
// Created by Isaac Paul on 10/13/24.
// Non-commercial license, see LICENSE.MD in the project root for details
//
import Foundation
final class AppError: LocalizedError, Sendable {
let message: String
init(_ message: String) {
self.message = message
}
init(_ message: String, _ error:Error) {
self.message = "\(message) : \(error.localizedDescription)"
}
static func failure<T>(_ message: String) -> Result<T, AppError> {
return .failure(AppError(message))
}
var errorDescription: String? {
get {
return message
}
}
}

View File

@@ -0,0 +1,80 @@
/**
* Plot
* Copyright (c) John Sundell 2021
* MIT license, see LICENSE file for details
*/
/*
internal final class ElementRenderingBuffer {
var containsChildElements = false
private let element: AnyElement
private let indentation: Indentation?
private var body = ""
private var attributes = [AnyAttribute]()
private var attributeIndexes = [String : Int]()
init(element: AnyElement, indentation: Indentation?) {
self.element = element
self.indentation = indentation
}
func add(_ attribute: AnyAttribute) {
if let existingIndex = attributeIndexes[attribute.name] {
if attribute.replaceExisting {
attributes[existingIndex].value = attribute.value
} else if let newValue = attribute.nonEmptyValue {
if let existingValue = attributes[existingIndex].nonEmptyValue {
attributes[existingIndex].value = existingValue + " " + newValue
} else {
attributes[existingIndex].value = newValue
}
}
} else {
attributeIndexes[attribute.name] = attributes.count
attributes.append(attribute)
}
}
func add(_ text: String, isPlainText: Bool) {
if !isPlainText, indentation != nil {
body.append("\n")
}
body.append(text)
}
func flush() -> String {
guard !element.name.isEmpty else { return body }
let whitespace = indentation?.string ?? ""
let padding = element.paddingCharacter.map(String.init) ?? ""
var openingTag = "\(whitespace)<\(padding)\(element.name)"
for attribute in attributes {
let string = attribute.render()
if !string.isEmpty {
openingTag.append(" " + string)
}
}
let openingTagSuffix = padding + ">"
switch element.closingMode {
case .standard,
.selfClosing where containsChildElements:
var string = openingTag + openingTagSuffix + body
if indentation != nil && containsChildElements {
string.append("\n\(whitespace)")
}
return string + "</\(element.name)>"
case .neverClosed:
return openingTag + openingTagSuffix + body
case .selfClosing:
return openingTag + "/" + openingTagSuffix
}
}
}
*/

View File

@@ -0,0 +1,45 @@
//
// GlobalAttributeKey.swift
// HRW
//
// Created by Isaac Paul on 10/15/24.
// Non-commercial license, see LICENSE.MD in the project root for details
//
public protocol IGlobalAttributeContainer {
var globalAttributes:Dictionary<GlobalAttributeKey, String> { get set }
var dataAttributes:Dictionary<String, String> { get set }
}
public enum GlobalAttributeKey: String {
case class_ = "class"
case id
case slot
case accesskey
case autocapitalize
case autocorrect
case autofocus
case contenteditable
case dir
case draggable
case enterkeyhint
case hidden
case inert
case inputmode
case is_ = "is"
case itemid
case itemprop
case itemref
case itemscope
case itemtype
case lang
case nonce
case popover
case spellcheck
case style
case tabindex
case title
case translate
case writingsuggestions
}

View File

@@ -0,0 +1,124 @@
//
// GlobalEnums.swift
// HRW
//
// Created by Isaac Paul on 10/19/24.
// Non-commercial license, see LICENSE.MD in the project root for details
//
import Foundation
//Some bike shedding to avoid allocations
struct ComponentsIterator: IteratorProtocol {
let string: String
let splitCharacter: Character
var currentIndex: String.Index
init(_ string: String, separatedBy: Character) {
self.string = string
self.splitCharacter = separatedBy
self.currentIndex = string.startIndex
}
mutating func next() -> Substring? {
// Skip any leading split characters
while currentIndex < string.endIndex && string[currentIndex] == splitCharacter {
currentIndex = string.index(after: currentIndex)
}
// Check if we've reached the end of the string
if currentIndex >= string.endIndex {
return nil
}
let start = currentIndex
while currentIndex < string.endIndex && string[currentIndex] != splitCharacter {
currentIndex = string.index(after: currentIndex)
}
return string[start..<currentIndex]
}
}
extension IteratorProtocol {
mutating func map<R>(_ block: (_ input:Element) throws -> R) rethrows -> [R] {
var result:[R] = []
while let item = self.next() {
result.append(try block(item))
}
return result
}
}
extension String {
func componentsIterator(separatedBy: Character) -> ComponentsIterator {
return ComponentsIterator(self, separatedBy: separatedBy)
}
func componentsIterator(separatedBy: String) -> ComponentsIterator {
return ComponentsIterator(self, separatedBy: separatedBy.first!)
}
}
public enum ShadowRootMode : Substring {
case open = "open" ///The template element represents an open declarative shadow root.
case close = "close" ///The template element represents a closed declarative shadow root.
public init?(rawValue: String) {
self.init(rawValue: rawValue.asSubstring())
}
}
public enum Blocking : Substring {
case render = "render"
static func parseList(_ value:String?) throws -> [Blocking] {
guard let value = value else { return [] }
var iterator = value.componentsIterator(separatedBy: " ")
let result = try iterator.map { input in
return try expect(Blocking(rawValue: input), "unexpected value for blocking: \(input)")
}
return result
}
}
public enum FetchPriority : Substring {
case high = "high"
case low = "low"
case auto = "auto"
public init?(rawValue: String) {
self.init(rawValue: rawValue.asSubstring())
}
public init(expect: String) throws {
guard let _ = FetchPriority(rawValue: expect) else {
throw AppError("Unexpected value for Fetch Priority: \(expect)")
}
self.init(rawValue: expect.asSubstring())!
}
}
public enum Preload : Substring {
case none = "none"
case auto = "auto"
case metadata = "metadata"
public init?(rawValue: String) {
self.init(rawValue: rawValue.asSubstring())
}
public init(expect: String) throws {
let strToUse:String
if (expect.count == 0) {
strToUse = "auto"
} else {
strToUse = expect
}
guard let _ = Preload(rawValue: strToUse) else {
throw AppError("Unexpected value for Preload \(strToUse)")
}
self.init(rawValue: strToUse.asSubstring())!
}
}

View File

@@ -0,0 +1,92 @@
//
// GlobalEventKey.swift
// HRW
//
// Created by Isaac Paul on 10/22/24.
// Non-commercial license, see LICENSE.MD in the project root for details
//
public protocol IGlobalEventContainer {
var globalEvents:Dictionary<GlobalEventKey, String> { get set }
}
///While these attributes apply to all elements, they are not useful on all elements. For example, only media elements will ever receive a volumechange event fired by the user agent.
public enum GlobalEventKey: Substring {
case onauxclick
case onbeforeinput
case onbeforematch
case onbeforetoggle
/// when specified on body elements it exposes event handlers of the Window object with the same names.
case onblur
case oncancel
case oncanplay
case oncanplaythrough
case onchange
case onclick
case onclose
case oncontextlost
case oncontextmenu
case oncontextrestored
case oncopy
case oncuechange
case oncut
case ondblclick
case ondrag
case ondragend
case ondragenter
case ondragleave
case ondragover
case ondragstart
case ondrop
case ondurationchange
case onemptied
case onended
/// when specified on body elements it exposes event handlers of the Window object with the same names.
case onerror
/// when specified on body elements it exposes event handlers of the Window object with the same names.
case onfocus
case onformdata
case oninput
case oninvalid
case onkeydown
case onkeypress
case onkeyup
/// when specified on body elements it exposes event handlers of the Window object with the same names.
case onload
case onloadeddata
case onloadedmetadata
case onloadstart
case onmousedown
case onmouseenter
case onmouseleave
case onmousemove
case onmouseout
case onmouseover
case onmouseup
case onpaste
case onpause
case onplay
case onplaying
case onprogress
case onratechange
case onreset
/// when specified on body elements it exposes event handlers of the Window object with the same names.
case onresize
/// when specified on body elements it exposes event handlers of the Window object with the same names.
case onscroll
/// when specified on body elements it exposes event handlers of the Window object with the same names.
case onscrollend
case onsecuritypolicyviolation
case onseeked
case onseeking
case onselect
case onslotchange
case onstalled
case onsubmit
case onsuspend
case ontimeupdate
case ontoggle
case onvolumechange
case onwaiting
case onwheel
}

View File

@@ -0,0 +1,171 @@
/**
* Plot
* Copyright (c) John Sundell 2019
* MIT license, see LICENSE file for details
*/
import Foundation
/// let someUrl:URL = try URL("hello") ?! AppError("What")
infix operator ?!: NilCoalescingPrecedence
public func ?!<T>(value: T?, error: @autoclosure () -> Error) throws -> T {
if let value = value { return value }
throw error()
}
internal extension String {
func asSubstring() -> Substring {
return self[self.startIndex..<self.endIndex]
}
func escaped() -> String {
var pendingAmpersandString: String?
func flushPendingAmpersandString(
withSuffix suffix: String? = nil,
resettingTo newValue: String? = nil
) -> String {
let pending = pendingAmpersandString
pendingAmpersandString = newValue
return pending.map { "&amp;\($0)\(suffix ?? "")" } ?? suffix ?? ""
}
return String(flatMap { character -> String in
switch character {
case "<":
return flushPendingAmpersandString(withSuffix: "&lt;")
case ">":
return flushPendingAmpersandString(withSuffix: "&gt;")
case "&":
return flushPendingAmpersandString(resettingTo: "")
case ";":
let pending = pendingAmpersandString.map { "&\($0);" }
pendingAmpersandString = nil
return pending ?? ";"
case "#" where pendingAmpersandString?.isEmpty == true:
pendingAmpersandString = "#"
return ""
default:
if let pending = pendingAmpersandString {
guard character.isLetter || character.isNumber else {
return flushPendingAmpersandString(withSuffix: String(character))
}
pendingAmpersandString = "\(pending)\(character)"
return ""
}
return "\(character)"
}
}) + flushPendingAmpersandString()
}
static func parseList(_ value:String?, _ separator:String = " ") throws -> [String] {
guard let value = value else { return [] }
var iterator = value.componentsIterator(separatedBy: separator)
return iterator.map({String($0)})
}
}
extension Array where Element: RawRepresentable, Element.RawValue == String {
/// Converts an array of String-backed enums to an array of their raw string values.
func toStringList(_ seperator:String) -> String {
let strList = self.map { $0.rawValue }
return strList.joined(separator: seperator)
}
}
extension Array where Element == String {
/// Converts an array of String-backed enums to an array of their raw string values.
func toStringList(_ seperator:String) -> String {
let strList = self.map { $0 }
return strList.joined(separator: seperator)
}
}
extension Array where Element == URL {
/// Converts an array of String-backed enums to an array of their raw string values.
func toStringList(_ seperator:String) -> String {
let strList = self.map { $0.absoluteString }
return strList.joined(separator: seperator)
}
}
extension Array where Element == Float {
/// Converts an array of String-backed enums to an array of their raw string values.
func toStringList(_ seperator:String) -> String {
let strList = self.map { String($0) }
return strList.joined(separator: seperator)
}
}
extension Set where Element: RawRepresentable, Element.RawValue == String {
/// Converts an array of String-backed enums to an array of their raw string values.
func toStringList(_ seperator:String) -> String {
let strList = self.map { $0.rawValue }
return strList.joined(separator: seperator)
}
}
extension Float {
static func parseList(_ value:String?, _ separator:String = " ") throws -> [Float] {
guard let value = value else { return [] }
var iterator = value.componentsIterator(separatedBy: separator)
return try iterator.map({ try Float.expect($0) })
}
static func expect(_ value:String) throws -> Float {
if let result = Float(value) {
return result
}
throw AppError("Unable to map value to float")
}
static func expect(_ value:Substring) throws -> Float {
if let result = Float(value) {
return result
}
throw AppError("Unable to map value to float")
}
}
extension URL {
static func parseList(_ value:String?, _ separator:String = " ") throws -> [URL] {
guard let value = value else { return [] }
var iterator = value.componentsIterator(separatedBy: separator)
return try iterator.map({
guard let result = URL(string:String($0)) else {
throw AppError("Invalid URL: \(String($0))")
}
return result
})
}
}
extension Bool {
public init(expect: String) throws {
if (expect == "true") {
self = true
return
}
if (expect == "false") {
self = false
return
}
throw AppError("Unexpected value for bool: \(expect)")
}
public init(expectYesOrNo: String) throws {
if (expectYesOrNo == "yes") {
self = true
return
}
if (expectYesOrNo == "no") {
self = false
return
}
throw AppError("Unexpected value for bool: \(expectYesOrNo)")
}
}

View File

@@ -0,0 +1,419 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftCertificates open source project
//
// Copyright (c) 2023 Apple Inc. and the SwiftCertificates project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftCertificates project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
//Taken from: https://github.com/apple/swift-certificates
/// ``_TinyArray`` is a ``RandomAccessCollection`` optimised to store zero or one ``Element``.
/// It supports arbitrary many elements but if only up to one ``Element`` is stored it does **not** allocate separate storage on the heap
/// and instead stores the ``Element`` inline.
public struct _TinyArray<Element> {
@usableFromInline
enum Storage {
case one(Element)
case arbitrary([Element])
}
@usableFromInline
var storage: Storage
}
// MARK: - TinyArray "public" interface
extension _TinyArray: Equatable where Element: Equatable {}
extension _TinyArray: Hashable where Element: Hashable {}
extension _TinyArray: Sendable where Element: Sendable {}
extension _TinyArray: ExpressibleByArrayLiteral {
@inlinable
public init(arrayLiteral elements: Element...) {
switch elements.count {
case 0:
self = .init()
case 1:
self = .init(CollectionOfOne(elements[0]))
default:
self = .init(elements)
}
}
}
extension _TinyArray: RandomAccessCollection {
public typealias Element = Element
public typealias Index = Int
@inlinable
public subscript(position: Int) -> Element {
get {
self.storage[position]
}
set {
self.storage[position] = newValue
}
}
@inlinable
public var startIndex: Int {
self.storage.startIndex
}
@inlinable
public var endIndex: Int {
self.storage.endIndex
}
}
extension _TinyArray {
@inlinable
public init(_ elements: some Sequence<Element>) {
self.storage = .init(elements)
}
@inlinable
public init(_ elements: some Sequence<Result<Element, some Error>>) throws {
self.storage = try .init(elements)
}
@inlinable
public init() {
self.storage = .init()
}
@inlinable
public mutating func append(_ newElement: Element) {
self.storage.append(newElement)
}
@inlinable
public mutating func append(contentsOf newElements: some Sequence<Element>) {
self.storage.append(contentsOf: newElements)
}
@discardableResult
@inlinable
public mutating func remove(at index: Int) -> Element {
self.storage.remove(at: index)
}
@inlinable
public mutating func removeAll(where shouldBeRemoved: (Element) throws -> Bool) rethrows {
try self.storage.removeAll(where: shouldBeRemoved)
}
@inlinable
public mutating func sort(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows {
try self.storage.sort(by: areInIncreasingOrder)
}
@inlinable
public func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> _TinyArray<SegmentOfResult.Element> where SegmentOfResult : Sequence {
try self.storage.flatMap(transform)
}
@inlinable
public func flatMap<NEWTYPE>(_ transform: (Element) throws -> _TinyArray<NEWTYPE>) rethrows -> _TinyArray<NEWTYPE> where Element == _TinyArray<NEWTYPE> {
try self.storage.flatMap(transform)
}
@inlinable
public func flatMap<NEWTYPE>() -> _TinyArray<NEWTYPE> where Element == _TinyArray<NEWTYPE> {
self.storage.flatMap()
}
}
// MARK: - TinyArray.Storage "private" implementation
extension _TinyArray.Storage: Equatable where Element: Equatable {
@inlinable
static func == (lhs: Self, rhs: Self) -> Bool {
switch (lhs, rhs) {
case (.one(let lhs), .one(let rhs)):
return lhs == rhs
case (.arbitrary(let lhs), .arbitrary(let rhs)):
// we don't use lhs.elementsEqual(rhs) so we can hit the fast path from Array
// if both arrays share the same underlying storage: https://github.com/apple/swift/blob/b42019005988b2d13398025883e285a81d323efa/stdlib/public/core/Array.swift#L1775
return lhs == rhs
case (.one(let element), .arbitrary(let array)),
(.arbitrary(let array), .one(let element)):
guard array.count == 1 else {
return false
}
return element == array[0]
}
}
}
extension _TinyArray.Storage: Hashable where Element: Hashable {
@inlinable
func hash(into hasher: inout Hasher) {
// same strategy as Array: https://github.com/apple/swift/blob/b42019005988b2d13398025883e285a81d323efa/stdlib/public/core/Array.swift#L1801
hasher.combine(count)
for element in self {
hasher.combine(element)
}
}
}
extension _TinyArray.Storage: Sendable where Element: Sendable {}
extension _TinyArray.Storage: RandomAccessCollection {
@inlinable
subscript(position: Int) -> Element {
get {
switch self {
case .one(let element):
guard position == 0 else {
fatalError("index \(position) out of bounds")
}
return element
case .arbitrary(let elements):
return elements[position]
}
}
set {
switch self {
case .one:
guard position == 0 else {
fatalError("index \(position) out of bounds")
}
self = .one(newValue)
case .arbitrary(var elements):
elements[position] = newValue
self = .arbitrary(elements)
}
}
}
@inlinable
var startIndex: Int {
0
}
@inlinable
var endIndex: Int {
switch self {
case .one: return 1
case .arbitrary(let elements): return elements.endIndex
}
}
}
extension _TinyArray.Storage {
@inlinable
init(_ elements: some Sequence<Element>) {
self = .arbitrary([])
self.append(contentsOf: elements)
}
@inlinable
init(_ newElements: some Sequence<Result<Element, some Error>>) throws {
var iterator = newElements.makeIterator()
guard let firstElement = try iterator.next()?.get() else {
self = .arbitrary([])
return
}
guard let secondElement = try iterator.next()?.get() else {
// newElements just contains a single element
// and we hit the fast path
self = .one(firstElement)
return
}
var elements: [Element] = []
elements.reserveCapacity(newElements.underestimatedCount)
elements.append(firstElement)
elements.append(secondElement)
while let nextElement = try iterator.next()?.get() {
elements.append(nextElement)
}
self = .arbitrary(elements)
}
@inlinable
init() {
self = .arbitrary([])
}
@inlinable
mutating func append(_ newElement: Element) {
self.append(contentsOf: CollectionOfOne(newElement))
}
@inlinable
mutating func append(contentsOf newElements: some Sequence<Element>) {
switch self {
case .one(let firstElement):
var iterator = newElements.makeIterator()
guard let secondElement = iterator.next() else {
// newElements is empty, nothing to do
return
}
var elements: [Element] = []
elements.reserveCapacity(1 + newElements.underestimatedCount)
elements.append(firstElement)
elements.append(secondElement)
elements.appendRemainingElements(from: &iterator)
self = .arbitrary(elements)
case .arbitrary(var elements):
if elements.isEmpty {
// if `self` is currently empty and `newElements` just contains a single
// element, we skip allocating an array and set `self` to `.one(firstElement)`
var iterator = newElements.makeIterator()
guard let firstElement = iterator.next() else {
// newElements is empty, nothing to do
return
}
guard let secondElement = iterator.next() else {
// newElements just contains a single element
// and we hit the fast path
self = .one(firstElement)
return
}
elements.reserveCapacity(elements.count + newElements.underestimatedCount)
elements.append(firstElement)
elements.append(secondElement)
elements.appendRemainingElements(from: &iterator)
self = .arbitrary(elements)
} else {
elements.append(contentsOf: newElements)
self = .arbitrary(elements)
}
}
}
@discardableResult
@inlinable
mutating func remove(at index: Int) -> Element {
switch self {
case .one(let oldElement):
guard index == 0 else {
fatalError("index \(index) out of bounds")
}
self = .arbitrary([])
return oldElement
case .arbitrary(var elements):
defer {
self = .arbitrary(elements)
}
return elements.remove(at: index)
}
}
@inlinable
mutating func removeAll(where shouldBeRemoved: (Element) throws -> Bool) rethrows {
switch self {
case .one(let oldElement):
if try shouldBeRemoved(oldElement) {
self = .arbitrary([])
}
case .arbitrary(var elements):
defer {
self = .arbitrary(elements)
}
return try elements.removeAll(where: shouldBeRemoved)
}
}
@inlinable
mutating func sort(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows {
switch self {
case .one:
// a collection of just one element is always sorted, nothing to do
break
case .arbitrary(var elements):
defer {
self = .arbitrary(elements)
}
try elements.sort(by: areInIncreasingOrder)
}
}
@inlinable
func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> _TinyArray<SegmentOfResult.Element> where SegmentOfResult : Sequence {
switch self {
case .one(let element):
let sequence:SegmentOfResult = try transform(element)
let result:_TinyArray<SegmentOfResult.Element> = _TinyArray<SegmentOfResult.Element>(sequence)
return result
case .arbitrary(let elements):
let seq:Array<SegmentOfResult.Element> = try elements.flatMap({ try transform($0) })
let result:_TinyArray<SegmentOfResult.Element> = _TinyArray<SegmentOfResult.Element>(seq)
return result
}
}
@inlinable
func flatMap<NEWTYPE>(_ transform: (Element) throws -> _TinyArray<NEWTYPE>) rethrows -> _TinyArray<NEWTYPE> where Element == _TinyArray<NEWTYPE> {
switch self {
case .one(let element):
let test:_TinyArray<NEWTYPE> = element
let sequence:_TinyArray<NEWTYPE> = try transform(element)
return sequence
case .arbitrary(let elements):
let seq:Array<NEWTYPE> = try elements.flatMap({ try transform($0) })
let result:_TinyArray<NEWTYPE> = _TinyArray<NEWTYPE>(seq)
return result
}
}
@inlinable
func flatMap<NEWTYPE>() -> _TinyArray<NEWTYPE> where Element == _TinyArray<NEWTYPE> {
switch self {
case .one(let element):
return element
case .arbitrary(let elements):
let seq:Array<NEWTYPE> = elements.flatMap({ $0 })
let result:_TinyArray<NEWTYPE> = _TinyArray<NEWTYPE>(seq)
return result
}
}
}
extension Array {
@inlinable
func flatMap<NEWTYPE>() -> Array<NEWTYPE> where Element == Array<NEWTYPE> {
if (self.count == 1) {
return self.first!
} else {
let arr = self.flatMap { $0 }
return arr
}
}
@inlinable
mutating func appendRemainingElements(from iterator: inout some IteratorProtocol<Element>) {
while let nextElement = iterator.next() {
append(nextElement)
}
}
@inlinable
func flatMapToTiny<NEWTYPE>() -> _TinyArray<NEWTYPE> where Element == _TinyArray<NEWTYPE> {
if (self.count == 1) {
return self.first!
} else {
let arr = self.flatMap({ $0 })
return _TinyArray(arr)
}
}
}

View File

@@ -0,0 +1,19 @@
//
// Url+Expect.swift
// HRW
//
// Created by Isaac Paul on 7/5/25.
// Non-commercial license, see LICENSE.MD in the project root for details
//
import Foundation
extension URL {
init(expect: String) throws {
if let result2 = URL(string: expect) {
self = result2
return
}
throw AppError("Could not convert to url: \(expect)")
}
}

View File

@@ -0,0 +1,22 @@
//
// Util.swift
// HRW
//
// Created by Isaac Paul on 10/15/24.
// Non-commercial license, see LICENSE.MD in the project root for details
//
@inline(__always)
internal func expect<T>(_ item:T?, _ error:String) throws -> T {
if let item = item {
return item
}
throw AppError(error)
}
/*
internal func parseBool(_ item:String?) throws -> Bool? {
if let item = item {
return item
}
return nil
}*/