Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ jobs:
- '.ci/changed-file-filters.yml'
- '.github/workflows/ci.yml'
scripts:
- 'platforms/swift/Scripts/api'
- 'platforms/swift/Scripts/normalize-api.jq'
- 'scripts/lib/**'
- 'scripts/test_ruby'
- 'scripts/test/**'
Expand Down
14 changes: 12 additions & 2 deletions platforms/swift/Scripts/api
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,14 @@ dump_module() {
-abort-on-module-fail \
-avoid-location \
-avoid-tool-args \
-o "$out_path"
-o "$DERIVED_DATA/$module.raw.json"

normalize_module "$DERIVED_DATA/$module.raw.json" "$out_path"
}

normalize_module() {
# dump and check use the same canonical representation, including nested types.
jq -f "$SCRIPT_DIR/normalize-api.jq" "$1" > "$2"
}

diagnose_module() {
Expand Down Expand Up @@ -120,7 +127,10 @@ case "$SUBCOMMAND" in

dump_module "$module" "$current"

if ! diff -u "$committed" "$current"; then
normalized_committed="$TMP_OUT/$module.committed.normalized.json"
normalize_module "$committed" "$normalized_committed"

if ! diff -u "$normalized_committed" "$current"; then
failed_modules+=("$module")
echo ""
echo "── swift-api-digester -diagnose-sdk ($module) ──"
Expand Down
18 changes: 18 additions & 0 deletions platforms/swift/Scripts/normalize-api.jq
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# swift-api-digester visits declarations from separate files/extensions in build
# order. Canonicalize declaration lists at the module and every nested type.
# Stored properties and enum cases retain their relative order; their layout can
# matter. Unknown node kinds also retain their order rather than assuming safety.
# Never sort type/parameter children, conformances, or other metadata arrays.
def unordered_declaration:
.hasStorage != true and .declKind != "EnumElement" and
(.kind | IN("Constructor", "Function", "TypeAlias", "TypeDecl", "Var"));

walk(
if type == "object" and (.kind == "Root" or .kind == "TypeDecl") and
(.children | type) == "array" then
.children |= (
map(select(unordered_declaration | not)) +
(map(select(unordered_declaration)) | sort_by(.kind, .printedName, .usr))
)
else . end
)
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ extension CheckoutError {
CheckoutError(code: .unknown, message: message, underlyingError: underlyingError)
}

internal static func terminalProtocol(error: ErrorResponse) -> CheckoutError {
internal static func terminalProtocol(error: EmbeddedCheckoutProtocol.ErrorResponse) -> CheckoutError {
let representative = error.messages.first {
$0.type == .error && $0.severity == .unrecoverable
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ class CheckoutWebView: WKWebView {
)
}
.on(CheckoutProtocol.ready) { _ in
ReadyResult(checkout: nil, credential: nil, ucp: .success(), upgrade: nil, continueURL: nil, messages: nil)
EmbeddedCheckoutProtocol.ReadyResult(checkout: nil, credential: nil, ucp: .success(), upgrade: nil, continueURL: nil, messages: nil)
}
.on(CheckoutProtocol.complete) { [weak self] _ in
guard let self else { return }
Expand Down Expand Up @@ -805,7 +805,7 @@ extension CheckoutWebView: WKScriptMessageHandler {
}

private struct TerminalErrorNotification: Decodable {
let params: JSONRPCErrorParams
let params: EmbeddedCheckoutProtocol.JSONRPCErrorParams
}

extension UIApplication {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,28 +99,28 @@ struct WindowOpenDelegationTests {

@Test func requestPayloadDecodesValidURL() throws {
let payload = try JSONDecoder().decode(
WindowOpenRequest.self,
EmbeddedCheckoutProtocol.WindowOpenRequest.self,
from: Data(#"{"url":"https://example.com/terms"}"#.utf8)
)
#expect(payload.url == "https://example.com/terms")
#expect(payload.parsedURL == URL(string: "https://example.com/terms"))
}

@Test func parsedURLIsNilForEmptyURL() {
#expect(WindowOpenRequest(url: "").parsedURL == nil)
#expect(EmbeddedCheckoutProtocol.WindowOpenRequest(url: "").parsedURL == nil)
}

@Test func requestPayloadRejectsMissingURL() {
#expect((try? JSONDecoder().decode(WindowOpenRequest.self, from: Data("{}".utf8))) == nil)
#expect((try? JSONDecoder().decode(EmbeddedCheckoutProtocol.WindowOpenRequest.self, from: Data("{}".utf8))) == nil)
}

@Test func requestPayloadRejectsNullURL() {
#expect((try? JSONDecoder().decode(WindowOpenRequest.self, from: Data(#"{"url":null}"#.utf8))) == nil)
#expect((try? JSONDecoder().decode(EmbeddedCheckoutProtocol.WindowOpenRequest.self, from: Data(#"{"url":null}"#.utf8))) == nil)
}

private struct EncodingFailure: Error {}

private func encode(_ result: WindowOpenResult) throws -> [String: Any] {
private func encode(_ result: EmbeddedCheckoutProtocol.WindowOpenResult) throws -> [String: Any] {
let encoder = JSONEncoder()
encoder.outputFormatting = [.sortedKeys]
let data = try encoder.encode(result)
Expand Down
Loading
Loading