mirror of
https://github.com/wu736139669/hapi.git
synced 2026-10-08 19:12:28 +00:00
ios/scripts/linux-test.sh stages HapiKit + shared/fixtures at repo depth
into a persistent tmp dir and runs swift test in swift:6.1-noble; the
manifest drops HapiUI (SwiftUI/swift-markdown/Highlightr) under
#if os(Linux). 458 tests green, including all 48 chat and 11 pagination
golden fixtures.
Fixes that fell out of the first real compile of the blind-written port:
- ChatTypes.CodexReview.wireValue + SummaryPatching legacy id fallback:
split expressions that exceeded the Swift 6 type-checker budget
- FileEndpointsTests: raw string containing "# terminated the literal
early (never compiled anywhere) — now ##-delimited
- SSEClient.backoffSleep: Task { try? ... } inferred Task<()?, Never>
- Darwin gates: Security/Keychain behind canImport(Security) (tests use
InMemoryCredentialStore via CredentialStoring), CryptoKit digest with
FNV-1a filename fallback, FoundationNetworking imports for URLSession
types, corelibs URLCache diskPath: initializer, get-only
waitsForConnectivity, delegate-based SSE transport where
URLSession.bytes(for:) does not exist
56 lines
2.3 KiB
Swift
56 lines
2.3 KiB
Swift
import Foundation
|
|
#if canImport(FoundationNetworking)
|
|
import FoundationNetworking // URLSession types live here on Linux
|
|
#endif
|
|
|
|
/// URL assembly shared by `APIClient` and `AuthManager`.
|
|
///
|
|
/// Percent-encoding is done by hand with the RFC 3986 unreserved set (the
|
|
/// strictest choice) so that path components and query values match what the
|
|
/// web client produces via `encodeURIComponent`/`URLSearchParams` — notably
|
|
/// `+` is encoded as `%2B`, which `URLComponents.queryItems` would leave
|
|
/// literal (and the hub would decode as a space).
|
|
enum HubRequestURL {
|
|
/// RFC 3986 unreserved characters — everything else is percent-encoded.
|
|
static let unreserved = CharacterSet(
|
|
charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
|
|
)
|
|
|
|
/// Builds `origin(baseURL) + path + query`. `path` must be an absolute,
|
|
/// already-percent-encoded path (compose dynamic segments with
|
|
/// ``encodePathComponent(_:)``); any path on `baseURL` itself is replaced,
|
|
/// matching the web client's `new URL(path, baseUrl)` for absolute paths.
|
|
static func make(baseURL: URL, path: String, query: [URLQueryItem]) throws -> URL {
|
|
guard var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: true) else {
|
|
throw URLError(.badURL)
|
|
}
|
|
components.percentEncodedPath = path
|
|
components.fragment = nil
|
|
components.percentEncodedQuery = query.isEmpty ? nil : encodeQuery(query)
|
|
guard let url = components.url else {
|
|
throw URLError(.badURL)
|
|
}
|
|
return url
|
|
}
|
|
|
|
/// Joins items in the given order as `name=value`, both strictly encoded.
|
|
static func encodeQuery(_ items: [URLQueryItem]) -> String {
|
|
items.map { item in
|
|
let name = encodeComponent(item.name)
|
|
guard let value = item.value else { return name }
|
|
return "\(name)=\(encodeComponent(value))"
|
|
}
|
|
.joined(separator: "&")
|
|
}
|
|
|
|
static func encodeComponent(_ value: String) -> String {
|
|
value.addingPercentEncoding(withAllowedCharacters: unreserved) ?? value
|
|
}
|
|
}
|
|
|
|
/// Percent-encodes one path segment (the `encodeURIComponent` equivalent used
|
|
/// for `:id`-style params throughout the endpoint layer).
|
|
func encodePathComponent(_ value: String) -> String {
|
|
HubRequestURL.encodeComponent(value)
|
|
}
|