From d5a51f1f0fc7820bcd437417129715f552d0f15c Mon Sep 17 00:00:00 2001 From: Jay Herron Date: Sun, 5 Apr 2026 01:51:25 -0600 Subject: [PATCH 1/2] chore: Add swift-format file --- .swift-format | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .swift-format diff --git a/.swift-format b/.swift-format new file mode 100644 index 0000000..1ffdbf5 --- /dev/null +++ b/.swift-format @@ -0,0 +1,7 @@ +{ + "version": 1, + "indentation" : { + "spaces" : 4 + }, + "lineBreakBeforeEachArgument": true +} From 14e441e0ea4c5e0ca3d45abbd3157cd197f3b733 Mon Sep 17 00:00:00 2001 From: Jay Herron Date: Sun, 5 Apr 2026 02:12:36 -0600 Subject: [PATCH 2/2] refactor: Applies formatter --- Examples/HelloWorldServer/Package.swift | 4 +- .../Sources/HelloWorldServer/Resolvers.swift | 59 +- .../HelloWorldServerTests.swift | 123 +-- Examples/StarWars/Package.swift | 8 +- .../Sources/StarWars/GraphQL/Relay.swift | 253 ++++-- .../Sources/StarWars/GraphQL/Resolvers.swift | 763 ++++++++++++++---- .../Sources/StarWars/SWAPI/SwapiClient.swift | 18 +- .../Tests/StarWarsTests/StarWarsTests.swift | 73 +- Package.swift | 10 +- Plugins/GraphQLGeneratorPlugin.swift | 28 +- .../BuildGraphQLSchemaGenerator.swift | 133 +-- .../Generator/CodeGenerator.swift | 4 +- .../Generator/GraphQLRawSDLGenerator.swift | 12 +- .../Generator/GraphQLTypesGenerator.swift | 267 +++--- .../Utilities/SafeNameGenerator.swift | 43 +- .../Utilities/swiftTypeName.swift | 46 +- .../GraphQLGeneratorMacros.swift | 9 +- .../GraphQLResolverMacro.swift | 42 +- .../AnyAsyncSequence.swift | 5 +- .../GraphQLScalar.swift | 4 +- .../IndentTests.swift | 9 +- .../SchemaGeneratorTests.swift | 265 +++--- .../TypeGeneratorTests.swift | 151 ++-- .../GraphQLResolverMacroTests.swift | 225 +++--- 24 files changed, 1648 insertions(+), 906 deletions(-) diff --git a/Examples/HelloWorldServer/Package.swift b/Examples/HelloWorldServer/Package.swift index 493d404..ac2d818 100644 --- a/Examples/HelloWorldServer/Package.swift +++ b/Examples/HelloWorldServer/Package.swift @@ -5,7 +5,7 @@ import PackageDescription let package = Package( name: "HelloWorldServer", platforms: [ - .macOS(.v13), + .macOS(.v13) ], dependencies: [ .package(name: "graphql-generator", path: "../.."), @@ -20,7 +20,7 @@ let package = Package( .product(name: "GraphQLGeneratorRuntime", package: "graphql-generator"), ], plugins: [ - .plugin(name: "GraphQLGeneratorPlugin", package: "graphql-generator"), + .plugin(name: "GraphQLGeneratorPlugin", package: "graphql-generator") ] ), .testTarget( diff --git a/Examples/HelloWorldServer/Sources/HelloWorldServer/Resolvers.swift b/Examples/HelloWorldServer/Sources/HelloWorldServer/Resolvers.swift index 8a99459..e25dc08 100644 --- a/Examples/HelloWorldServer/Sources/HelloWorldServer/Resolvers.swift +++ b/Examples/HelloWorldServer/Sources/HelloWorldServer/Resolvers.swift @@ -52,7 +52,9 @@ extension GraphQLScalars { case .string: return map default: - throw GraphQLError(message: "EmailAddress cannot represent non-string value: \(map)") + throw GraphQLError( + message: "EmailAddress cannot represent non-string value: \(map)" + ) } } @@ -89,7 +91,9 @@ struct User: GraphQLGenerated.User { // Can't use @graphQLResolver macro because we must convert from String to GraphQLScalars.EmailAddress let email: String - func email(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> GraphQLScalars.EmailAddress { + func email(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> GraphQLScalars.EmailAddress + { return .init(email: email) } } @@ -99,7 +103,10 @@ struct Contact: GraphQLGenerated.Contact { /// Required implementations let email: String - func email(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> GraphQLScalars.EmailAddress { + func email( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> GraphQLScalars.EmailAddress { return .init(email: email) } } @@ -113,37 +120,63 @@ struct Post: GraphQLGenerated.Post { /// Required implementations let authorId: String - func author(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> any GraphQLGenerated.User { + func author( + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> any GraphQLGenerated.User { return context.users[authorId]! } } struct Query: GraphQLGenerated.Query { /// Required implementations - static func user(id: String, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.User)? { + static func user( + id: String, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.User)? { return context.users[id] } - static func users(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.User] { + static func users( + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.User] { return context.users.values.map { $0 as any GraphQLGenerated.User } } - static func post(id: String, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Post)? { + static func post( + id: String, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.Post)? { return context.posts[id] } - static func posts(limit _: Int?, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Post] { + static func posts( + limit _: Int?, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Post] { return context.posts.values.map { $0 as any GraphQLGenerated.Post } } - static func userOrPost(id: String, context: GraphQLContext, info _: GraphQLResolveInfo) async throws -> (any GraphQLGenerated.UserOrPost)? { + static func userOrPost( + id: String, + context: GraphQLContext, + info _: GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.UserOrPost)? { return context.users[id] ?? context.posts[id] } } struct Mutation: GraphQLGenerated.Mutation { /// Required implementations - static func upsertUser(userInfo: GraphQLGenerated.UserInfo, context: GraphQLContext, info _: GraphQLResolveInfo) -> any GraphQLGenerated.User { + static func upsertUser( + userInfo: GraphQLGenerated.UserInfo, + context: GraphQLContext, + info _: GraphQLResolveInfo + ) -> any GraphQLGenerated.User { let user = User( id: userInfo.id, name: userInfo.name, @@ -158,7 +191,11 @@ struct Mutation: GraphQLGenerated.Mutation { struct Subscription: GraphQLGenerated.Subscription { /// Required implementations - static func watchUser(id: String, context: GraphQLContext, info _: GraphQLResolveInfo) async throws -> AnyAsyncSequence<(any GraphQLGenerated.User)?> { + static func watchUser( + id: String, + context: GraphQLContext, + info _: GraphQLResolveInfo + ) async throws -> AnyAsyncSequence<(any GraphQLGenerated.User)?> { return AsyncStream<(any GraphQLGenerated.User)?> { continuation in context.onTriggerWatch = { [weak context] in continuation.yield(context?.users[id]) diff --git a/Examples/HelloWorldServer/Tests/HelloWorldServerTests/HelloWorldServerTests.swift b/Examples/HelloWorldServer/Tests/HelloWorldServerTests/HelloWorldServerTests.swift index 035c7f8..4df8e48 100644 --- a/Examples/HelloWorldServer/Tests/HelloWorldServerTests/HelloWorldServerTests.swift +++ b/Examples/HelloWorldServer/Tests/HelloWorldServerTests/HelloWorldServerTests.swift @@ -1,33 +1,36 @@ import GraphQL -@testable import HelloWorldServer import Testing +@testable import HelloWorldServer + @Suite struct HelloWorldServerTests { @Test func query() async throws { let schema = try buildGraphQLSchema(resolvers: Resolvers.self) let context = GraphQLContext( - users: ["1": .init(id: "1", name: "John", age: 18, role: .user, email: "john@example.com")], + users: [ + "1": .init(id: "1", name: "John", age: 18, role: .user, email: "john@example.com") + ], posts: ["1": .init(id: "1", title: "Foo", content: "bar", authorId: "1")] ) let actual = try await graphql( schema: schema, request: """ - { - posts { - id - title - content - author { + { + posts { id - name - email - age - role + title + content + author { + id + name + email + age + role + } } } - } - """, + """, context: context ) let expected = GraphQLResult( @@ -44,8 +47,8 @@ struct HelloWorldServerTests { "age": 18, "role": "USER", ], - ], - ], + ] + ] ] ) #expect(actual == expected) @@ -60,16 +63,16 @@ struct HelloWorldServerTests { let actual = try await graphql( schema: schema, request: """ - mutation { - upsertUser(userInfo: {id: "2", name: "Jane", email: "jane@example.com"}) { - id - name - email - age - role + mutation { + upsertUser(userInfo: {id: "2", name: "Jane", email: "jane@example.com"}) { + id + name + email + age + role + } } - } - """, + """, context: context ) let expected = GraphQLResult( @@ -80,7 +83,7 @@ struct HelloWorldServerTests { "email": "jane@example.com", "age": nil, "role": "USER", - ], + ] ] ) #expect(actual == expected) @@ -89,22 +92,24 @@ struct HelloWorldServerTests { @Test func subscription() async throws { let schema = try buildGraphQLSchema(resolvers: Resolvers.self) let context = GraphQLContext( - users: ["1": .init(id: "1", name: "John", age: 18, role: .user, email: "john@example.com")], + users: [ + "1": .init(id: "1", name: "John", age: 18, role: .user, email: "john@example.com") + ], posts: [:] ) let stream = try await graphqlSubscribe( schema: schema, request: """ - subscription { - watchUser(id: "1") { - id - name - email - age - role + subscription { + watchUser(id: "1") { + id + name + email + age + role + } } - } - """, + """, context: context ).get() @@ -112,32 +117,34 @@ struct HelloWorldServerTests { context.triggerWatch() #expect( - try await iterator.next() == GraphQLResult( - data: [ - "watchUser": [ - "id": "1", - "name": "John", - "email": "john@example.com", - "age": 18, - "role": "USER", - ], - ] - ) + try await iterator.next() + == GraphQLResult( + data: [ + "watchUser": [ + "id": "1", + "name": "John", + "email": "john@example.com", + "age": 18, + "role": "USER", + ] + ] + ) ) context.triggerWatch() #expect( - try await iterator.next() == GraphQLResult( - data: [ - "watchUser": [ - "id": "1", - "name": "John", - "email": "john@example.com", - "age": 18, - "role": "USER", - ], - ] - ) + try await iterator.next() + == GraphQLResult( + data: [ + "watchUser": [ + "id": "1", + "name": "John", + "email": "john@example.com", + "age": 18, + "role": "USER", + ] + ] + ) ) } } diff --git a/Examples/StarWars/Package.swift b/Examples/StarWars/Package.swift index bd263c6..e01584e 100644 --- a/Examples/StarWars/Package.swift +++ b/Examples/StarWars/Package.swift @@ -5,13 +5,13 @@ import PackageDescription let package = Package( name: "StarWars", platforms: [ - .macOS(.v13), + .macOS(.v13) ], products: [ .library( name: "StarWars", targets: ["StarWars"] - ), + ) ], dependencies: [ .package(name: "graphql-generator", path: "../.."), @@ -30,13 +30,13 @@ let package = Package( .product(name: "GraphQLGeneratorRuntime", package: "graphql-generator"), ], plugins: [ - .plugin(name: "GraphQLGeneratorPlugin", package: "graphql-generator"), + .plugin(name: "GraphQLGeneratorPlugin", package: "graphql-generator") ] ), .testTarget( name: "StarWarsTests", dependencies: [ - "StarWars", + "StarWars" ] ), ] diff --git a/Examples/StarWars/Sources/StarWars/GraphQL/Relay.swift b/Examples/StarWars/Sources/StarWars/GraphQL/Relay.swift index 6462b55..777daaf 100644 --- a/Examples/StarWars/Sources/StarWars/GraphQL/Relay.swift +++ b/Examples/StarWars/Sources/StarWars/GraphQL/Relay.swift @@ -67,7 +67,7 @@ struct Connection: Sendable { if let last { startIndex = max(endIndex - last, startIndex) } - let pageIds = ids[startIndex ... endIndex] + let pageIds = ids[startIndex...endIndex] pageInfo = PageInfo( hasNextPage: endIndex < ids.count - 1, @@ -87,37 +87,60 @@ extension Connection: GraphQLGenerated.SpeciesFilmsConnection, GraphQLGenerated.StarshipFilmsConnection, GraphQLGenerated.VehicleFilmsConnection - where T: GraphQLGenerated.Film -{ - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.FilmsEdge]? { +where T: GraphQLGenerated.Film { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.FilmsEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.PersonFilmsEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.PersonFilmsEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.PlanetFilmsEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.PlanetFilmsEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.SpeciesFilmsEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.SpeciesFilmsEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.StarshipFilmsEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.StarshipFilmsEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.VehicleFilmsEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.VehicleFilmsEdge]? { return edges } - func films(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Film]? { + func films( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Film]? { return try await nodes(context: context, info: info) } - private func nodes(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Film]? { + private func nodes( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Film]? { var nodes = [GraphQLGenerated.Film]() for edge in edges { if let node = try await edge.node(context: context, info: info) { @@ -135,49 +158,81 @@ extension Connection: GraphQLGenerated.SpeciesPeopleConnection, GraphQLGenerated.StarshipPilotsConnection, GraphQLGenerated.VehiclePilotsConnection - where T: GraphQLGenerated.Person -{ - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.PeopleEdge]? { +where T: GraphQLGenerated.Person { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.PeopleEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.FilmCharactersEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.FilmCharactersEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.PlanetResidentsEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.PlanetResidentsEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.SpeciesPeopleEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.SpeciesPeopleEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.StarshipPilotsEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.StarshipPilotsEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.VehiclePilotsEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.VehiclePilotsEdge]? { return edges } - func people(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Person]? { + func people( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Person]? { return try await nodes(context: context, info: info) } - func characters(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Person]? { + func characters( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Person]? { return try await nodes(context: context, info: info) } - func residents(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Person]? { + func residents( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Person]? { return try await nodes(context: context, info: info) } - func pilots(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Person]? { + func pilots( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Person]? { return try await nodes(context: context, info: info) } - private func nodes(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Person]? { + private func nodes( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Person]? { var nodes = [GraphQLGenerated.Person]() for edge in edges { if let node = try await edge.node(context: context, info: info) { @@ -191,21 +246,32 @@ extension Connection: extension Connection: GraphQLGenerated.PlanetsConnection, GraphQLGenerated.FilmPlanetsConnection - where T: GraphQLGenerated.Planet -{ - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.PlanetsEdge]? { +where T: GraphQLGenerated.Planet { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.PlanetsEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.FilmPlanetsEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.FilmPlanetsEdge]? { return edges } - func planets(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Planet]? { + func planets( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Planet]? { return try await nodes(context: context, info: info) } - private func nodes(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Planet]? { + private func nodes( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Planet]? { var nodes = [GraphQLGenerated.Planet]() for edge in edges { if let node = try await edge.node(context: context, info: info) { @@ -219,21 +285,32 @@ extension Connection: extension Connection: GraphQLGenerated.SpeciesConnection, GraphQLGenerated.FilmSpeciesConnection - where T: GraphQLGenerated.Species -{ - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.SpeciesEdge]? { +where T: GraphQLGenerated.Species { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.SpeciesEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.FilmSpeciesEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.FilmSpeciesEdge]? { return edges } - func species(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Species]? { + func species( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Species]? { return try await nodes(context: context, info: info) } - private func nodes(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Species]? { + private func nodes( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Species]? { var nodes = [GraphQLGenerated.Species]() for edge in edges { if let node = try await edge.node(context: context, info: info) { @@ -248,25 +325,39 @@ extension Connection: GraphQLGenerated.StarshipsConnection, GraphQLGenerated.FilmStarshipsConnection, GraphQLGenerated.PersonStarshipsConnection - where T: GraphQLGenerated.Starship -{ - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.StarshipsEdge]? { +where T: GraphQLGenerated.Starship { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.StarshipsEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.FilmStarshipsEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.FilmStarshipsEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.PersonStarshipsEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.PersonStarshipsEdge]? { return edges } - func starships(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Starship]? { + func starships( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Starship]? { return try await nodes(context: context, info: info) } - private func nodes(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Starship]? { + private func nodes( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Starship]? { var nodes = [GraphQLGenerated.Starship]() for edge in edges { if let node = try await edge.node(context: context, info: info) { @@ -281,25 +372,39 @@ extension Connection: GraphQLGenerated.VehiclesConnection, GraphQLGenerated.FilmVehiclesConnection, GraphQLGenerated.PersonVehiclesConnection - where T: GraphQLGenerated.Vehicle -{ - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.VehiclesEdge]? { +where T: GraphQLGenerated.Vehicle { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.VehiclesEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.FilmVehiclesEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.FilmVehiclesEdge]? { return edges } - func edges(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.PersonVehiclesEdge]? { + func edges( + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.PersonVehiclesEdge]? { return edges } - func vehicles(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Vehicle]? { + func vehicles( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Vehicle]? { return try await nodes(context: context, info: info) } - private func nodes(context: GraphQLContext, info: GraphQL.GraphQLResolveInfo) async throws -> [any GraphQLGenerated.Vehicle]? { + private func nodes( + context: GraphQLContext, + info: GraphQL.GraphQLResolveInfo + ) async throws -> [any GraphQLGenerated.Vehicle]? { var nodes = [GraphQLGenerated.Vehicle]() for edge in edges { if let node = try await edge.node(context: context, info: info) { @@ -321,9 +426,11 @@ extension Edge: GraphQLGenerated.SpeciesFilmsEdge, GraphQLGenerated.StarshipFilmsEdge, GraphQLGenerated.VehicleFilmsEdge - where T: GraphQLGenerated.Film -{ - func node(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Film)? { +where T: GraphQLGenerated.Film { + func node( + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.Film)? { let (_, id) = decodeID(cursor) return try await context.client.get(type: Film.self, id: id) } @@ -336,9 +443,11 @@ extension Edge: GraphQLGenerated.SpeciesPeopleEdge, GraphQLGenerated.StarshipPilotsEdge, GraphQLGenerated.VehiclePilotsEdge - where T: GraphQLGenerated.Person -{ - func node(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Person)? { +where T: GraphQLGenerated.Person { + func node( + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.Person)? { let (_, id) = decodeID(cursor) return try await context.client.get(type: Person.self, id: id) } @@ -347,9 +456,11 @@ extension Edge: extension Edge: GraphQLGenerated.PlanetsEdge, GraphQLGenerated.FilmPlanetsEdge - where T: GraphQLGenerated.Planet -{ - func node(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Planet)? { +where T: GraphQLGenerated.Planet { + func node( + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.Planet)? { let (_, id) = decodeID(cursor) return try await context.client.get(type: Planet.self, id: id) } @@ -358,9 +469,11 @@ extension Edge: extension Edge: GraphQLGenerated.SpeciesEdge, GraphQLGenerated.FilmSpeciesEdge - where T: GraphQLGenerated.Species -{ - func node(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Species)? { +where T: GraphQLGenerated.Species { + func node( + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.Species)? { let (_, id) = decodeID(cursor) return try await context.client.get(type: Species.self, id: id) } @@ -370,9 +483,11 @@ extension Edge: GraphQLGenerated.StarshipsEdge, GraphQLGenerated.FilmStarshipsEdge, GraphQLGenerated.PersonStarshipsEdge - where T: GraphQLGenerated.Starship -{ - func node(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Starship)? { +where T: GraphQLGenerated.Starship { + func node( + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.Starship)? { let (_, id) = decodeID(cursor) return try await context.client.get(type: Starship.self, id: id) } @@ -382,9 +497,11 @@ extension Edge: GraphQLGenerated.VehiclesEdge, GraphQLGenerated.FilmVehiclesEdge, GraphQLGenerated.PersonVehiclesEdge - where T: GraphQLGenerated.Vehicle -{ - func node(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Vehicle)? { +where T: GraphQLGenerated.Vehicle { + func node( + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.Vehicle)? { let (_, id) = decodeID(cursor) return try await context.client.get(type: Vehicle.self, id: id) } diff --git a/Examples/StarWars/Sources/StarWars/GraphQL/Resolvers.swift b/Examples/StarWars/Sources/StarWars/GraphQL/Resolvers.swift index 446aa11..c6a476a 100644 --- a/Examples/StarWars/Sources/StarWars/GraphQL/Resolvers.swift +++ b/Examples/StarWars/Sources/StarWars/GraphQL/Resolvers.swift @@ -15,12 +15,24 @@ struct Resolvers: GraphQLGenerated.Resolvers { } struct Root: GraphQLGenerated.Root { - static func allFilms(after: String?, first: Int?, before: String?, last: Int?, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.FilmsConnection)? { + static func allFilms( + after: String?, + first: Int?, + before: String?, + last: Int?, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.FilmsConnection)? { let allIDs = try await context.client.getAllIDs(type: Film.self) return Connection(ids: allIDs, after: after, first: first, before: before, last: last) } - static func film(id: String?, filmID: String?, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Film)? { + static func film( + id: String?, + filmID: String?, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.Film)? { if let filmID { return try await context.client.get(type: Film.self, id: filmID) } else if let id { @@ -31,12 +43,30 @@ struct Root: GraphQLGenerated.Root { } } - static func allPeople(after: String?, first: Int?, before: String?, last: Int?, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.PeopleConnection)? { + static func allPeople( + after: String?, + first: Int?, + before: String?, + last: Int?, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.PeopleConnection)? { let allIDs = try await context.client.getAllIDs(type: Person.self) - return Connection(ids: allIDs, after: after, first: first, before: before, last: last) - } - - static func person(id: String?, personID: String?, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Person)? { + return Connection( + ids: allIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + static func person( + id: String?, + personID: String?, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.Person)? { if let personID { return try await context.client.get(type: Person.self, id: personID) } else if let id { @@ -47,12 +77,30 @@ struct Root: GraphQLGenerated.Root { } } - static func allPlanets(after: String?, first: Int?, before: String?, last: Int?, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.PlanetsConnection)? { + static func allPlanets( + after: String?, + first: Int?, + before: String?, + last: Int?, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.PlanetsConnection)? { let allIDs = try await context.client.getAllIDs(type: Planet.self) - return Connection(ids: allIDs, after: after, first: first, before: before, last: last) - } - - static func planet(id: String?, planetID: String?, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Planet)? { + return Connection( + ids: allIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + static func planet( + id: String?, + planetID: String?, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.Planet)? { if let planetID { return try await context.client.get(type: Planet.self, id: planetID) } else if let id { @@ -63,12 +111,30 @@ struct Root: GraphQLGenerated.Root { } } - static func allSpecies(after: String?, first: Int?, before: String?, last: Int?, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.SpeciesConnection)? { + static func allSpecies( + after: String?, + first: Int?, + before: String?, + last: Int?, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.SpeciesConnection)? { let allIDs = try await context.client.getAllIDs(type: Species.self) - return Connection(ids: allIDs, after: after, first: first, before: before, last: last) - } - - static func species(id: String?, speciesID: String?, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Species)? { + return Connection( + ids: allIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + static func species( + id: String?, + speciesID: String?, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.Species)? { if let speciesID { return try await context.client.get(type: Species.self, id: speciesID) } else if let id { @@ -79,12 +145,30 @@ struct Root: GraphQLGenerated.Root { } } - static func allStarships(after: String?, first: Int?, before: String?, last: Int?, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.StarshipsConnection)? { + static func allStarships( + after: String?, + first: Int?, + before: String?, + last: Int?, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.StarshipsConnection)? { let allIDs = try await context.client.getAllIDs(type: Starship.self) - return Connection(ids: allIDs, after: after, first: first, before: before, last: last) - } - - static func starship(id: String?, starshipID: String?, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Starship)? { + return Connection( + ids: allIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + static func starship( + id: String?, + starshipID: String?, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.Starship)? { if let starshipID { return try await context.client.get(type: Starship.self, id: starshipID) } else if let id { @@ -95,12 +179,30 @@ struct Root: GraphQLGenerated.Root { } } - static func allVehicles(after: String?, first: Int?, before: String?, last: Int?, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.VehiclesConnection)? { + static func allVehicles( + after: String?, + first: Int?, + before: String?, + last: Int?, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.VehiclesConnection)? { let allIDs = try await context.client.getAllIDs(type: Vehicle.self) - return Connection(ids: allIDs, after: after, first: first, before: before, last: last) - } - - static func vehicle(id: String?, vehicleID: String?, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Vehicle)? { + return Connection( + ids: allIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + static func vehicle( + id: String?, + vehicleID: String?, + context: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.Vehicle)? { if let vehicleID { return try await context.client.get(type: Vehicle.self, id: vehicleID) } else if let id { @@ -111,7 +213,9 @@ struct Root: GraphQLGenerated.Root { } } - static func node(id: String, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Node)? { + static func node(id: String, context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) + async throws -> (any GraphQLGenerated.Node)? + { let (type, itemID) = decodeID(id) switch type { case .films: @@ -135,61 +239,142 @@ extension Film: GraphQLGenerated.Film { return encodeID(type: Film.self, id: urlToID(url)) } - func title(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func title(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return title } - func episodeID(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Int? { + func episodeID(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Int? + { return episode_id } - func openingCrawl(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func openingCrawl(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return opening_crawl } - func director(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func director(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return director } - func producers(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [String]? { + func producers(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> [String]? + { return producer.split(separator: ",").map { String($0) } } - func releaseDate(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func releaseDate(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return release_date } - func created(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func created(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return created } - func edited(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func edited(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return edited } - func speciesConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.FilmSpeciesConnection)? { + func speciesConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.FilmSpeciesConnection)? { let filteredIDs = species.map { encodeID(type: Film.self, id: urlToID($0)) } - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func starshipConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.FilmStarshipsConnection)? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func starshipConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.FilmStarshipsConnection)? { let filteredIDs = starships.map { encodeID(type: Starship.self, id: urlToID($0)) } - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func vehicleConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.FilmVehiclesConnection)? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func vehicleConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.FilmVehiclesConnection)? { let filteredIDs = vehicles.map { encodeID(type: Vehicle.self, id: urlToID($0)) } - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func characterConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.FilmCharactersConnection)? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func characterConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.FilmCharactersConnection)? { let filteredIDs = characters.map { encodeID(type: Person.self, id: urlToID($0)) } - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func planetConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.FilmPlanetsConnection)? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func planetConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.FilmPlanetsConnection)? { let filteredIDs = planets.map { encodeID(type: Planet.self, id: urlToID($0)) } - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) } } @@ -198,69 +383,129 @@ extension Person: GraphQLGenerated.Person { return encodeID(type: Person.self, id: urlToID(url)) } - func name(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func name(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? + { return name } - func birthYear(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func birthYear(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return birth_year } - func eyeColor(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func eyeColor(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return eye_color } - func gender(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func gender(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return gender } - func hairColor(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func hairColor(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return hair_color } - func height(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Int? { + func height(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Int? + { return Int(height) } - func mass(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Double? { + func mass(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Double? + { return Double(mass) } - func skinColor(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func skinColor(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return skin_color } - func homeworld(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Planet)? { + func homeworld(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> ( + any GraphQLGenerated.Planet + )? { try await context.client.get(type: Planet.self, id: urlToID(homeworld)) } - func filmConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.PersonFilmsConnection)? { + func filmConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.PersonFilmsConnection)? { let filteredIDs = films.map { encodeID(type: Film.self, id: urlToID($0)) } - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func species(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Species)? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func species(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> ( + any GraphQLGenerated.Species + )? { guard let firstSpecies = species?.first else { return nil } return try await context.client.get(type: Species.self, id: urlToID(firstSpecies)) } - func starshipConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.PersonStarshipsConnection)? { + func starshipConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.PersonStarshipsConnection)? { let filteredIDs = starships.map { encodeID(type: Starship.self, id: urlToID($0)) } - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func vehicleConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.PersonVehiclesConnection)? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func vehicleConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.PersonVehiclesConnection)? { let filteredIDs = vehicles.map { encodeID(type: Vehicle.self, id: urlToID($0)) } - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func created(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func created(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return created } - func edited(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func edited(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return edited } } @@ -270,57 +515,104 @@ extension Planet: GraphQLGenerated.Planet { return encodeID(type: Planet.self, id: urlToID(url)) } - func name(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func name(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? + { return name } - func diameter(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Int? { + func diameter(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Int? + { return Int(diameter) } - func rotationPeriod(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Int? { + func rotationPeriod(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Int? + { return Int(rotation_period) } - func orbitalPeriod(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Int? { + func orbitalPeriod(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Int? + { return Int(orbital_period) } - func gravity(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func gravity(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return gravity } - func population(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Double? { + func population(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Double? + { return Double(population) } - func climates(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [String]? { + func climates(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> [String]? + { return climate.split(separator: ",").map { String($0) } } - func terrains(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [String]? { + func terrains(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> [String]? + { return terrain.split(separator: ",").map { String($0) } } - func surfaceWater(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Double? { + func surfaceWater(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Double? + { return Double(surface_water) } - func residentConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.PlanetResidentsConnection)? { + func residentConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.PlanetResidentsConnection)? { let filteredIDs = residents?.map { encodeID(type: Person.self, id: urlToID($0)) } ?? [] - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func filmConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.PlanetFilmsConnection)? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func filmConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.PlanetFilmsConnection)? { let filteredIDs = films?.map { encodeID(type: Film.self, id: urlToID($0)) } ?? [] - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func created(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func created(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return created } - func edited(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func edited(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return edited } } @@ -330,61 +622,110 @@ extension Species: GraphQLGenerated.Species { return encodeID(type: Species.self, id: urlToID(url)) } - func name(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func name(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? + { return name } - func classification(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func classification(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return classification } - func designation(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func designation(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return designation } - func averageHeight(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Double? { + func averageHeight(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Double? + { return Double(average_height) } - func averageLifespan(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Int? { + func averageLifespan(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Int? + { return Int(average_lifespan) } - func eyeColors(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [String]? { + func eyeColors(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> [String]? + { return eye_colors.split(separator: ",").map { String($0) } } - func hairColors(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [String]? { + func hairColors(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> [String]? + { return hair_colors.split(separator: ",").map { String($0) } } - func skinColors(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [String]? { + func skinColors(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> [String]? + { return skin_colors.split(separator: ",").map { String($0) } } - func language(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func language(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return language } - func homeworld(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.Planet)? { + func homeworld(context: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> ( + any GraphQLGenerated.Planet + )? { return try await context.client.get(type: Planet.self, id: urlToID(homeworld)) } - func personConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.SpeciesPeopleConnection)? { + func personConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.SpeciesPeopleConnection)? { let filteredIDs = people.map { encodeID(type: Person.self, id: urlToID($0)) } - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func filmConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.SpeciesFilmsConnection)? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func filmConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.SpeciesFilmsConnection)? { let filteredIDs = films?.map { encodeID(type: Film.self, id: urlToID($0)) } ?? [] - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func created(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func created(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return created } - func edited(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func edited(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return edited } } @@ -394,43 +735,61 @@ extension Starship: GraphQLGenerated.Starship { return encodeID(type: Starship.self, id: urlToID(url)) } - func name(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func name(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? + { return name } - func model(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func model(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return model } - func starshipClass(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func starshipClass(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return starship_class } - func manufacturers(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [String]? { + func manufacturers(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> [String]? + { return manufacturer.split(separator: ",").map { String($0) } } - func costInCredits(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Double? { + func costInCredits(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Double? + { return Double(cost_in_credits) } - func length(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Double? { + func length(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Double? + { return Double(length) } - func crew(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func crew(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? + { return crew } - func passengers(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func passengers(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return passengers } - func maxAtmospheringSpeed(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Int? { + func maxAtmospheringSpeed(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) + async throws -> Int? + { return Int(max_atmosphering_speed) } - func hyperdriveRating(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Double? { + func hyperdriveRating(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) + async throws -> Double? + { return Double(hyperdrive_rating) } @@ -438,29 +797,63 @@ extension Starship: GraphQLGenerated.Starship { return Int(MGLT) } - func cargoCapacity(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Double? { + func cargoCapacity(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Double? + { return Double(cargo_capacity) } - func consumables(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func consumables(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return consumables } - func pilotConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.StarshipPilotsConnection)? { + func pilotConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.StarshipPilotsConnection)? { let filteredIDs = pilots.map { encodeID(type: Person.self, id: urlToID($0)) } - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func filmConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.StarshipFilmsConnection)? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func filmConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.StarshipFilmsConnection)? { let filteredIDs = films.map { encodeID(type: Film.self, id: urlToID($0)) } - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func created(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func created(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return created } - func edited(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func edited(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return edited } } @@ -470,65 +863,115 @@ extension Vehicle: GraphQLGenerated.Vehicle { return encodeID(type: Vehicle.self, id: urlToID(url)) } - func name(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func name(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? + { return name } - func model(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func model(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return model } - func vehicleClass(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func vehicleClass(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return vehicle_class } - func manufacturers(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> [String]? { + func manufacturers(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> [String]? + { return manufacturer.split(separator: ",").map { String($0) } } - func costInCredits(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Double? { + func costInCredits(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Double? + { return Double(cost_in_credits) } - func length(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Double? { + func length(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Double? + { return Double(length) } - func crew(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func crew(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? + { return crew } - func passengers(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func passengers(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return passengers } - func maxAtmospheringSpeed(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Int? { + func maxAtmospheringSpeed(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) + async throws -> Int? + { return Int(max_atmosphering_speed) } - func cargoCapacity(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> Double? { + func cargoCapacity(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> Double? + { return Double(cargo_capacity) } - func consumables(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func consumables(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return consumables } - func pilotConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.VehiclePilotsConnection)? { + func pilotConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.VehiclePilotsConnection)? { let filteredIDs = pilots.map { encodeID(type: Person.self, id: urlToID($0)) } - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func filmConnection(after: String?, first: Int?, before: String?, last: Int?, context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> (any GraphQLGenerated.VehicleFilmsConnection)? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func filmConnection( + after: String?, + first: Int?, + before: String?, + last: Int?, + context _: GraphQLContext, + info _: GraphQL.GraphQLResolveInfo + ) async throws -> (any GraphQLGenerated.VehicleFilmsConnection)? { let filteredIDs = films.map { encodeID(type: Film.self, id: urlToID($0)) } - return Connection(ids: filteredIDs, after: after, first: first, before: before, last: last) - } - - func created(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + return Connection( + ids: filteredIDs, + after: after, + first: first, + before: before, + last: last + ) + } + + func created(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return created } - func edited(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws -> String? { + func edited(context _: GraphQLContext, info _: GraphQL.GraphQLResolveInfo) async throws + -> String? + { return edited } } diff --git a/Examples/StarWars/Sources/StarWars/SWAPI/SwapiClient.swift b/Examples/StarWars/Sources/StarWars/SWAPI/SwapiClient.swift index f201163..59ceb2d 100644 --- a/Examples/StarWars/Sources/StarWars/SWAPI/SwapiClient.swift +++ b/Examples/StarWars/Sources/StarWars/SWAPI/SwapiClient.swift @@ -36,12 +36,13 @@ struct SwapiClient { } } for await result in group { - results[result.0] = switch result.1 { - case let .success(response): - .success(response) - case let .failure(error): - .failure(error) - } + results[result.0] = + switch result.1 { + case .success(let response): + .success(response) + case .failure(let error): + .failure(error) + } } return results } @@ -49,7 +50,10 @@ struct SwapiClient { } func get(type: T.Type, id: String) async throws -> T? { - let instance = try await get(url: "\(rootUrl)/\(type.type.rawValue)/\(id)", as: InstanceResponse.self) + let instance = try await get( + url: "\(rootUrl)/\(type.type.rawValue)/\(id)", + as: InstanceResponse.self + ) return instance?.result.properties } diff --git a/Examples/StarWars/Tests/StarWarsTests/StarWarsTests.swift b/Examples/StarWars/Tests/StarWarsTests/StarWarsTests.swift index 1f8b49c..913ce90 100644 --- a/Examples/StarWars/Tests/StarWarsTests/StarWarsTests.swift +++ b/Examples/StarWars/Tests/StarWarsTests/StarWarsTests.swift @@ -1,7 +1,8 @@ import GraphQL -@testable import StarWars import Testing +@testable import StarWars + @Suite("display name") struct StarWarsTests { @Test func film() async throws { @@ -13,32 +14,32 @@ struct StarWarsTests { graphql( schema: schema, request: """ - { - film(filmID: 1) { - title - planetConnection(first: 2) { - totalCount - edges { - node { - id - name - diameter + { + film(filmID: 1) { + title + planetConnection(first: 2) { + totalCount + edges { + node { + id + name + diameter + } } } - } - vehicleConnection(first: 2) { - totalCount - edges { - node { - id - name - costInCredits + vehicleConnection(first: 2) { + totalCount + edges { + node { + id + name + costInCredits + } } } } } - } - """, + """, context: context ) ) @@ -53,27 +54,27 @@ struct StarWarsTests { graphql( schema: schema, request: """ - { - allPeople(first: 3) { - totalCount - edges { - node { - id - name - starshipConnection { - totalCount - edges { - node { - id - name + { + allPeople(first: 3) { + totalCount + edges { + node { + id + name + starshipConnection { + totalCount + edges { + node { + id + name + } } } } } } } - } - """, + """, context: context ) ) diff --git a/Package.swift b/Package.swift index 678c611..d0f7fa6 100644 --- a/Package.swift +++ b/Package.swift @@ -28,7 +28,7 @@ let package = Package( dependencies: [ .package(url: "https://github.com/GraphQLSwift/GraphQL.git", from: "4.1.0"), .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.3.0"), - .package(url: "https://github.com/apple/swift-syntax.git", "600.0.1" ..< "603.0.0"), + .package(url: "https://github.com/apple/swift-syntax.git", "600.0.1"..<"603.0.0"), ], targets: [ // Build plugin @@ -47,19 +47,19 @@ let package = Package( .target( name: "GraphQLGeneratorCore", dependencies: [ - .product(name: "GraphQL", package: "GraphQL"), + .product(name: "GraphQL", package: "GraphQL") ] ), .target( name: "GraphQLGeneratorRuntime", dependencies: [ - .product(name: "GraphQL", package: "GraphQL"), + .product(name: "GraphQL", package: "GraphQL") ] ), .testTarget( name: "GraphQLGeneratorCoreTests", dependencies: [ - "GraphQLGeneratorCore", + "GraphQLGeneratorCore" ] ), @@ -74,7 +74,7 @@ let package = Package( .target( name: "GraphQLGeneratorMacros", dependencies: [ - "GraphQLGeneratorMacrosBackend", + "GraphQLGeneratorMacrosBackend" ] ), .testTarget( diff --git a/Plugins/GraphQLGeneratorPlugin.swift b/Plugins/GraphQLGeneratorPlugin.swift index d708420..2efc561 100644 --- a/Plugins/GraphQLGeneratorPlugin.swift +++ b/Plugins/GraphQLGeneratorPlugin.swift @@ -32,18 +32,20 @@ struct GraphQLGeneratorPlugin: BuildToolPlugin { outputDirectory.appendingPathComponent("GraphQLTypes.swift"), ] - let arguments = schemaInputs.flatMap { ["\($0.path)"] } + [ - "--output-directory", outputDirectory.path, - ] + let arguments = + schemaInputs.flatMap { ["\($0.path)"] } + [ + "--output-directory", outputDirectory.path, + ] return [ .buildCommand( - displayName: "Generating GraphQL Swift code from \(schemaFiles.count) schema file(s)", + displayName: + "Generating GraphQL Swift code from \(schemaFiles.count) schema file(s)", executable: generatorTool.url, arguments: arguments, inputFiles: schemaInputs, outputFiles: outputFiles - ), + ) ] } } @@ -53,7 +55,9 @@ struct GraphQLGeneratorPlugin: BuildToolPlugin { extension GraphQLGeneratorPlugin: XcodeBuildToolPlugin { /// Entry point for creating build commands for targets in Xcode projects. - func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { + func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws + -> [Command] + { // Find GraphQL schema files let schemaFiles = target.inputFiles.filter { file in file.url.pathExtension == "graphql" || file.url.pathExtension == "gql" @@ -75,18 +79,20 @@ struct GraphQLGeneratorPlugin: BuildToolPlugin { outputDirectory.appendingPathComponent("Schema.swift"), ] - let arguments = schemaInputs.flatMap { ["\($0.path)"] } + [ - "--output-directory", outputDirectory.path, - ] + let arguments = + schemaInputs.flatMap { ["\($0.path)"] } + [ + "--output-directory", outputDirectory.path, + ] return [ .buildCommand( - displayName: "Generating GraphQL Swift code from \(schemaFiles.count) schema file(s)", + displayName: + "Generating GraphQL Swift code from \(schemaFiles.count) schema file(s)", executable: generatorTool.url, arguments: arguments, inputFiles: schemaInputs, outputFiles: outputFiles - ), + ) ] } } diff --git a/Sources/GraphQLGeneratorCore/Generator/BuildGraphQLSchemaGenerator.swift b/Sources/GraphQLGeneratorCore/Generator/BuildGraphQLSchemaGenerator.swift index 9a7d60c..9f7f751 100644 --- a/Sources/GraphQLGeneratorCore/Generator/BuildGraphQLSchemaGenerator.swift +++ b/Sources/GraphQLGeneratorCore/Generator/BuildGraphQLSchemaGenerator.swift @@ -7,21 +7,21 @@ package struct BuildGraphQLSchemaGenerator { package func generate(schema: GraphQLSchema) throws -> String { var output = """ - // Generated by GraphQL Generator - // DO NOT EDIT - This file is automatically generated + // Generated by GraphQL Generator + // DO NOT EDIT - This file is automatically generated - import Foundation - import GraphQL - import GraphQLGeneratorRuntime + import Foundation + import GraphQL + import GraphQLGeneratorRuntime - /// Build a GraphQL schema with the provided resolvers - func buildGraphQLSchema( - resolvers: Resolvers.Type, - decoder: MapDecoder = .init() - ) throws -> GraphQLSchema { + /// Build a GraphQL schema with the provided resolvers + func buildGraphQLSchema( + resolvers: Resolvers.Type, + decoder: MapDecoder = .init() + ) throws -> GraphQLSchema { - let schema = try GraphQL.buildSchema(source: graphQLRawSDL) - """ + let schema = try GraphQL.buildSchema(source: graphQLRawSDL) + """ // Ignore any internal types (which have prefix "__") let types = schema.typeMap.values.filter { @@ -33,7 +33,7 @@ package struct BuildGraphQLSchemaGenerator { $0 as? GraphQLInterfaceType } for interfaceType in interfaceTypes { - output += try""" + output += try """ \(generateInterfaceType(for: interfaceType).indent(1)) @@ -45,12 +45,11 @@ package struct BuildGraphQLSchemaGenerator { $0 as? GraphQLObjectType }.filter { // Skip root operation types - $0.name != schema.queryType?.name && - $0.name != schema.mutationType?.name && - $0.name != schema.subscriptionType?.name + $0.name != schema.queryType?.name && $0.name != schema.mutationType?.name + && $0.name != schema.subscriptionType?.name } for objectType in objectTypes { - output += try""" + output += try """ \(generateObjectType(for: objectType, target: .parent).indent(1)) @@ -59,7 +58,7 @@ package struct BuildGraphQLSchemaGenerator { // Generate Query type if let queryType = schema.queryType { - output += try""" + output += try """ \(generateObjectType(for: queryType, target: .query).indent(1)) @@ -68,7 +67,7 @@ package struct BuildGraphQLSchemaGenerator { // Generate Mutation type if it exists if let mutationType = schema.mutationType { - output += try""" + output += try """ \(generateObjectType(for: mutationType, target: .mutation).indent(1)) @@ -77,7 +76,7 @@ package struct BuildGraphQLSchemaGenerator { // Generate Subscription type if it exists if let subscriptionType = schema.subscriptionType { - output += try""" + output += try """ \(generateObjectType(for: subscriptionType, target: .subscription).indent(1)) @@ -87,10 +86,10 @@ package struct BuildGraphQLSchemaGenerator { output += """ - return schema - } + return schema + } - """ + """ return output } @@ -101,9 +100,9 @@ package struct BuildGraphQLSchemaGenerator { var output = """ - let \(typeName) = schema.typeMap["\(type.name)"] as? GraphQLObjectType - let \(variableName) = try \(typeName)?.fields() ?? [:] - """ + let \(typeName) = schema.typeMap["\(type.name)"] as? GraphQLObjectType + let \(variableName) = try \(typeName)?.fields() ?? [:] + """ // Generate fields let fields = try type.fields() @@ -122,10 +121,10 @@ package struct BuildGraphQLSchemaGenerator { output += """ - \(typeName)?.fields = { - return \(variableName) - } - """ + \(typeName)?.fields = { + return \(variableName) + } + """ return output } @@ -146,9 +145,9 @@ package struct BuildGraphQLSchemaGenerator { var output = """ - let \(typeName) = schema.typeMap["\(type.name)"] as? GraphQLObjectType - let \(variableName) = try \(typeName)?.fields() ?? [:] - """ + let \(typeName) = schema.typeMap["\(type.name)"] as? GraphQLObjectType + let \(variableName) = try \(typeName)?.fields() ?? [:] + """ // Generate fields let fields = try type.fields() @@ -167,10 +166,10 @@ package struct BuildGraphQLSchemaGenerator { output += """ - \(typeName)?.fields = { - return \(variableName) - } - """ + \(typeName)?.fields = { + return \(variableName) + } + """ return output } @@ -187,15 +186,15 @@ package struct BuildGraphQLSchemaGenerator { // TODO: Swift 6.0 requires `@Sendable` explicitly here. We can remove it when we drop 6.0 support. if target == .subscription { output += """ - \(variableName)["\(fieldName)"]?.resolve = { @Sendable source, _, _, _ in - return source - } - \(variableName)["\(fieldName)"]?.subscribe = { @Sendable source, args, context, info in - """ + \(variableName)["\(fieldName)"]?.resolve = { @Sendable source, _, _, _ in + return source + } + \(variableName)["\(fieldName)"]?.subscribe = { @Sendable source, args, context, info in + """ } else { output += """ - \(variableName)["\(fieldName)"]?.resolve = { @Sendable source, args, context, info in - """ + \(variableName)["\(fieldName)"]?.resolve = { @Sendable source, args, context, info in + """ } // Build argument list @@ -205,53 +204,63 @@ package struct BuildGraphQLSchemaGenerator { // For nested resolvers, we decode and call the method on the parent instance // We use the type Declaration name, since this should always be a non-list, non-nullable instance, // and add 'any' because all intermediate types are represented as protocols - let parentCastType = try swiftTypeDeclaration(for: parentType, includeNamespace: true, nameGenerator: nameGenerator) + let parentCastType = try swiftTypeDeclaration( + for: parentType, + includeNamespace: true, + nameGenerator: nameGenerator + ) output += """ - let parent = try cast(source, to: (any \(parentCastType)).self) - """ + let parent = try cast(source, to: (any \(parentCastType)).self) + """ } // Add field arguments for (argName, arg) in field.args { let safeArgName = nameGenerator.swiftMemberName(for: argName) - let swiftType = try swiftTypeReference(for: arg.type, includeNamespace: true, nameGenerator: nameGenerator) + let swiftType = try swiftTypeReference( + for: arg.type, + includeNamespace: true, + nameGenerator: nameGenerator + ) // Extract value from Map based on type - var decodeStatement = "try decoder.decode((\(swiftType)).self, from: args[\"\(argName)\"])" + var decodeStatement = + "try decoder.decode((\(swiftType)).self, from: args[\"\(argName)\"])" if !(arg.type is GraphQLNonNull) { // If the arg is nullable, we get errors if we try to decode an `undefined` map. This protects against that. decodeStatement = "args[\"\(argName)\"] != .undefined ? \(decodeStatement) : nil" } output += """ - let \(safeArgName) = \(decodeStatement) - """ + let \(safeArgName) = \(decodeStatement) + """ argsList.append("\(safeArgName): \(safeArgName)") } // Add context output += """ - let context = try cast(context, to: GraphQLContext.self) - """ + let context = try cast(context, to: GraphQLContext.self) + """ argsList.append("context: context") // Add resolver info argsList.append("info: info") // Call the resolver - let targetName = switch target { - case .parent: "parent" - case .query: "Resolvers.Query" - case .mutation: "Resolvers.Mutation" - case .subscription: "Resolvers.Subscription" - } + let targetName = + switch target { + case .parent: "parent" + case .query: "Resolvers.Query" + case .mutation: "Resolvers.Mutation" + case .subscription: "Resolvers.Subscription" + } let functionName = nameGenerator.swiftMemberName(for: fieldName) output += """ - return try await \(targetName).\(functionName)(\(argsList.joined(separator: ", "))) - } - """ + return try await \(targetName).\(functionName)(\(argsList.joined(separator: ", "))) + } + """ return output } diff --git a/Sources/GraphQLGeneratorCore/Generator/CodeGenerator.swift b/Sources/GraphQLGeneratorCore/Generator/CodeGenerator.swift index d1f2b24..5ff74f2 100644 --- a/Sources/GraphQLGeneratorCore/Generator/CodeGenerator.swift +++ b/Sources/GraphQLGeneratorCore/Generator/CodeGenerator.swift @@ -11,7 +11,9 @@ package struct CodeGenerator { let schema = try GraphQL.buildSchema(source: source) var files: [String: String] = [:] - files["BuildGraphQLSchema.swift"] = try BuildGraphQLSchemaGenerator().generate(schema: schema) + files["BuildGraphQLSchema.swift"] = try BuildGraphQLSchemaGenerator().generate( + schema: schema + ) files["GraphQLRawSDL.swift"] = try GraphQLRawSDLGenerator().generate(source: source) files["GraphQLTypes.swift"] = try GraphQLTypesGenerator().generate(schema: schema) diff --git a/Sources/GraphQLGeneratorCore/Generator/GraphQLRawSDLGenerator.swift b/Sources/GraphQLGeneratorCore/Generator/GraphQLRawSDLGenerator.swift index 6679386..5f23d3c 100644 --- a/Sources/GraphQLGeneratorCore/Generator/GraphQLRawSDLGenerator.swift +++ b/Sources/GraphQLGeneratorCore/Generator/GraphQLRawSDLGenerator.swift @@ -5,12 +5,12 @@ import GraphQL package struct GraphQLRawSDLGenerator { package func generate(source: String) throws -> String { return """ - // Generated by GraphQL Generator - // DO NOT EDIT - This file is automatically generated + // Generated by GraphQL Generator + // DO NOT EDIT - This file is automatically generated - let graphQLRawSDL = #\"\"\" - \(source) - \"\"\"# - """ + let graphQLRawSDL = #\"\"\" + \(source) + \"\"\"# + """ } } diff --git a/Sources/GraphQLGeneratorCore/Generator/GraphQLTypesGenerator.swift b/Sources/GraphQLGeneratorCore/Generator/GraphQLTypesGenerator.swift index 56081d7..533b6c9 100644 --- a/Sources/GraphQLGeneratorCore/Generator/GraphQLTypesGenerator.swift +++ b/Sources/GraphQLGeneratorCore/Generator/GraphQLTypesGenerator.swift @@ -7,40 +7,40 @@ package struct GraphQLTypesGenerator { package func generate(schema: GraphQLSchema) throws -> String { var output = """ - // Generated by GraphQL Generator - // DO NOT EDIT - This file is automatically generated + // Generated by GraphQL Generator + // DO NOT EDIT - This file is automatically generated - import Foundation - import GraphQL - import GraphQLGeneratorRuntime + import Foundation + import GraphQL + import GraphQLGeneratorRuntime - enum GraphQLScalars { } + enum GraphQLScalars { } - enum GraphQLGenerated { - protocol Resolvers: Sendable { - """ + enum GraphQLGenerated { + protocol Resolvers: Sendable { + """ if let queryType = schema.queryType { try output += """ - associatedtype Query: \(swiftTypeDeclaration(for: queryType, includeNamespace: true, nameGenerator: nameGenerator)) - """ + associatedtype Query: \(swiftTypeDeclaration(for: queryType, includeNamespace: true, nameGenerator: nameGenerator)) + """ } if let mutationType = schema.mutationType { try output += """ - associatedtype Mutation: \(swiftTypeDeclaration(for: mutationType, includeNamespace: true, nameGenerator: nameGenerator)) - """ + associatedtype Mutation: \(swiftTypeDeclaration(for: mutationType, includeNamespace: true, nameGenerator: nameGenerator)) + """ } if let subscriptionType = schema.subscriptionType { try output += """ - associatedtype Subscription: \(swiftTypeDeclaration(for: subscriptionType, includeNamespace: true, nameGenerator: nameGenerator)) - """ + associatedtype Subscription: \(swiftTypeDeclaration(for: subscriptionType, includeNamespace: true, nameGenerator: nameGenerator)) + """ } output += """ - } - """ + } + """ // Ignore any internal types (which have prefix "__") let types = schema.typeMap.values.filter { @@ -52,7 +52,7 @@ package struct GraphQLTypesGenerator { $0 as? GraphQLEnumType } for type in enumTypes { - output += try""" + output += try """ \(generateEnum(for: type).indent(1, includeFirst: true)) """ @@ -63,7 +63,7 @@ package struct GraphQLTypesGenerator { $0 as? GraphQLInputObjectType } for type in inputTypes { - output += try""" + output += try """ \(generateInputStruct(for: type).indent(1, includeFirst: true)) """ @@ -81,14 +81,18 @@ package struct GraphQLTypesGenerator { if let description = type.description { output += """ - \(description.docComment().indent(1, includeFirst: true)) - """ + \(description.docComment().indent(1, includeFirst: true)) + """ } - let swiftTypeName = try swiftTypeDeclaration(for: type, includeNamespace: false, nameGenerator: nameGenerator) + let swiftTypeName = try swiftTypeDeclaration( + for: type, + includeNamespace: false, + nameGenerator: nameGenerator + ) output += """ - protocol \(swiftTypeName): Sendable {} - """ + protocol \(swiftTypeName): Sendable {} + """ // Record which types need to be conformed for conformingType in try type.types() { @@ -105,7 +109,7 @@ package struct GraphQLTypesGenerator { $0 as? GraphQLInterfaceType } for type in interfaceTypes { - output += try""" + output += try """ \(generateInterfaceProtocol(for: type).indent(1, includeFirst: true)) """ @@ -116,12 +120,11 @@ package struct GraphQLTypesGenerator { $0 as? GraphQLObjectType }.filter { // Skip root operation types - $0.name != schema.queryType?.name && - $0.name != schema.mutationType?.name && - $0.name != schema.subscriptionType?.name + $0.name != schema.queryType?.name && $0.name != schema.mutationType?.name + && $0.name != schema.subscriptionType?.name } for type in objectTypes { - output += try""" + output += try """ \(generateTypeProtocol(for: type, unionTypeMap: unionTypeMap).indent(1, includeFirst: true)) """ @@ -129,7 +132,7 @@ package struct GraphQLTypesGenerator { // Generate Query type if let queryType = schema.queryType { - output += try""" + output += try """ \(generateRootTypeProtocol(for: queryType).indent(1, includeFirst: true)) """ @@ -137,7 +140,7 @@ package struct GraphQLTypesGenerator { // Generate Mutation type if let mutationType = schema.mutationType { - output += try""" + output += try """ \(generateRootTypeProtocol(for: mutationType).indent(1, includeFirst: true)) """ @@ -145,15 +148,15 @@ package struct GraphQLTypesGenerator { // Generate Mutation type if let subscriptionType = schema.subscriptionType { - output += try""" + output += try """ \(generateRootTypeProtocol(for: subscriptionType).indent(1, includeFirst: true)) """ } output += """ - } - """ + } + """ return output } @@ -165,36 +168,40 @@ package struct GraphQLTypesGenerator { if let description = type.description { output += """ - \(description.docComment()) - """ + \(description.docComment()) + """ } - let swiftTypeName = try swiftTypeDeclaration(for: type, includeNamespace: false, nameGenerator: nameGenerator) + let swiftTypeName = try swiftTypeDeclaration( + for: type, + includeNamespace: false, + nameGenerator: nameGenerator + ) output += """ - enum \(swiftTypeName): String, Codable, Sendable { - """ + enum \(swiftTypeName): String, Codable, Sendable { + """ // Generate cases for value in type.values { if let description = value.description { output += """ - \(description.docComment().indent(1, includeFirst: false)) - """ + \(description.docComment().indent(1, includeFirst: false)) + """ } // Use safe name generator for case names let safeCaseName = nameGenerator.swiftMemberName(for: value.name) output += """ - case \(safeCaseName) = "\(value.name)" - """ + case \(safeCaseName) = "\(value.name)" + """ } output += """ - } - """ + } + """ return output } @@ -206,15 +213,19 @@ package struct GraphQLTypesGenerator { if let description = type.description { output += """ - \(description.docComment()) - """ + \(description.docComment()) + """ } - let swiftTypeName = try swiftTypeDeclaration(for: type, includeNamespace: false, nameGenerator: nameGenerator) + let swiftTypeName = try swiftTypeDeclaration( + for: type, + includeNamespace: false, + nameGenerator: nameGenerator + ) output += """ - struct \(swiftTypeName): Codable, Sendable { - """ + struct \(swiftTypeName): Codable, Sendable { + """ // Generate properties let fields = try type.fields() @@ -222,23 +233,27 @@ package struct GraphQLTypesGenerator { if let description = field.description { output += """ - \(description.docComment().indent(1, includeFirst: false)) - """ + \(description.docComment().indent(1, includeFirst: false)) + """ } - let returnType = try swiftTypeReference(for: field.type, includeNamespace: false, nameGenerator: nameGenerator) + let returnType = try swiftTypeReference( + for: field.type, + includeNamespace: false, + nameGenerator: nameGenerator + ) output += """ - let \(nameGenerator.swiftMemberName(for: fieldName)): \(returnType) - """ + let \(nameGenerator.swiftMemberName(for: fieldName)): \(returnType) + """ } // Swift auto-generates memberwise initializers for structs, so we don't need to generate one output += """ - } - """ + } + """ return output } @@ -250,19 +265,24 @@ package struct GraphQLTypesGenerator { if let description = type.description { output += """ - \(description.docComment()) - """ + \(description.docComment()) + """ } let interfaces = try type.interfaces().map { - try swiftTypeDeclaration(for: $0, includeNamespace: false, nameGenerator: nameGenerator) + ", " + try swiftTypeDeclaration(for: $0, includeNamespace: false, nameGenerator: nameGenerator) + + ", " }.joined(separator: "") - let swiftTypeName = try swiftTypeDeclaration(for: type, includeNamespace: false, nameGenerator: nameGenerator) + let swiftTypeName = try swiftTypeDeclaration( + for: type, + includeNamespace: false, + nameGenerator: nameGenerator + ) output += """ - protocol \(swiftTypeName): \(interfaces)Sendable { - """ + protocol \(swiftTypeName): \(interfaces)Sendable { + """ // Generate properties let fields = try type.fields() @@ -270,17 +290,25 @@ package struct GraphQLTypesGenerator { if let description = field.description { output += """ - \(description.docComment().indent(1, includeFirst: false)) - """ + \(description.docComment().indent(1, includeFirst: false)) + """ } - let returnType = try swiftTypeReference(for: field.type, includeNamespace: false, nameGenerator: nameGenerator) + let returnType = try swiftTypeReference( + for: field.type, + includeNamespace: false, + nameGenerator: nameGenerator + ) var params: [String] = [] // Add arguments if any for (argName, arg) in field.args { - let argType = try swiftTypeReference(for: arg.type, includeNamespace: false, nameGenerator: nameGenerator) + let argType = try swiftTypeReference( + for: arg.type, + includeNamespace: false, + nameGenerator: nameGenerator + ) params.append("\(argName): \(argType)") } @@ -294,43 +322,56 @@ package struct GraphQLTypesGenerator { output += """ - func \(nameGenerator.swiftMemberName(for: fieldName))(\(paramString)) async throws -> \(returnType) + func \(nameGenerator.swiftMemberName(for: fieldName))(\(paramString)) async throws -> \(returnType) - """ + """ } output += """ - } - """ + } + """ return output } - func generateTypeProtocol(for type: GraphQLObjectType, unionTypeMap: [String: [GraphQLUnionType]]) throws -> String { + func generateTypeProtocol( + for type: GraphQLObjectType, + unionTypeMap: [String: [GraphQLUnionType]] + ) throws -> String { var output = "" // Add description if available if let description = type.description { output += """ - \(description.docComment()) - """ + \(description.docComment()) + """ } - let unions = try unionTypeMap[type.name]?.map { - try swiftTypeDeclaration(for: $0, includeNamespace: false, nameGenerator: nameGenerator) + ", " - }.joined(separator: "") ?? "" + let unions = + try unionTypeMap[type.name]?.map { + try swiftTypeDeclaration( + for: $0, + includeNamespace: false, + nameGenerator: nameGenerator + ) + ", " + }.joined(separator: "") ?? "" let interfaces = try type.interfaces().map { - try swiftTypeDeclaration(for: $0, includeNamespace: false, nameGenerator: nameGenerator) + ", " + try swiftTypeDeclaration(for: $0, includeNamespace: false, nameGenerator: nameGenerator) + + ", " }.joined(separator: "") - let swiftTypeName = try swiftTypeDeclaration(for: type, includeNamespace: false, nameGenerator: nameGenerator) + let swiftTypeName = try swiftTypeDeclaration( + for: type, + includeNamespace: false, + nameGenerator: nameGenerator + ) output += """ - protocol \(swiftTypeName): \(unions)\(interfaces)Sendable { - """ + protocol \(swiftTypeName): \(unions)\(interfaces)Sendable { + """ // Generate properties let fields = try type.fields() @@ -338,17 +379,25 @@ package struct GraphQLTypesGenerator { if let description = field.description { output += """ - \(description.docComment().indent(1, includeFirst: false)) - """ + \(description.docComment().indent(1, includeFirst: false)) + """ } - let returnType = try swiftTypeReference(for: field.type, includeNamespace: false, nameGenerator: nameGenerator) + let returnType = try swiftTypeReference( + for: field.type, + includeNamespace: false, + nameGenerator: nameGenerator + ) var params: [String] = [] // Add arguments if any for (argName, arg) in field.args { - let argType = try swiftTypeReference(for: arg.type, includeNamespace: false, nameGenerator: nameGenerator) + let argType = try swiftTypeReference( + for: arg.type, + includeNamespace: false, + nameGenerator: nameGenerator + ) params.append("\(argName): \(argType)") } @@ -362,15 +411,15 @@ package struct GraphQLTypesGenerator { output += """ - func \(nameGenerator.swiftMemberName(for: fieldName))(\(paramString)) async throws -> \(returnType) + func \(nameGenerator.swiftMemberName(for: fieldName))(\(paramString)) async throws -> \(returnType) - """ + """ } output += """ - } - """ + } + """ return output } @@ -384,15 +433,19 @@ package struct GraphQLTypesGenerator { if let description = type.description { output += """ - \(description.docComment()) - """ + \(description.docComment()) + """ } - let swiftTypeName = try swiftTypeDeclaration(for: type, includeNamespace: false, nameGenerator: nameGenerator) + let swiftTypeName = try swiftTypeDeclaration( + for: type, + includeNamespace: false, + nameGenerator: nameGenerator + ) output += """ - protocol \(swiftTypeName): Sendable { - """ + protocol \(swiftTypeName): Sendable { + """ // Generate properties let fields = try type.fields() @@ -400,11 +453,15 @@ package struct GraphQLTypesGenerator { if let description = field.description { output += """ - \(description.docComment().indent(1, includeFirst: false)) - """ + \(description.docComment().indent(1, includeFirst: false)) + """ } - var returnType = try swiftTypeReference(for: field.type, includeNamespace: false, nameGenerator: nameGenerator) + var returnType = try swiftTypeReference( + for: field.type, + includeNamespace: false, + nameGenerator: nameGenerator + ) if type.name == "Subscription" { returnType = "AnyAsyncSequence<\(returnType)>" } @@ -413,7 +470,11 @@ package struct GraphQLTypesGenerator { // Add arguments if any for (argName, arg) in field.args { - let argType = try swiftTypeReference(for: arg.type, includeNamespace: false, nameGenerator: nameGenerator) + let argType = try swiftTypeReference( + for: arg.type, + includeNamespace: false, + nameGenerator: nameGenerator + ) params.append("\(argName): \(argType)") } @@ -427,15 +488,15 @@ package struct GraphQLTypesGenerator { output += """ - static func \(nameGenerator.swiftMemberName(for: fieldName))(\(paramString)) async throws -> \(returnType) + static func \(nameGenerator.swiftMemberName(for: fieldName))(\(paramString)) async throws -> \(returnType) - """ + """ } output += """ - } - """ + } + """ return output } @@ -446,7 +507,7 @@ package enum GeneratorError: Error, CustomStringConvertible { package var description: String { switch self { - case let .unsupportedType(message): + case .unsupportedType(let message): return "Unsupported type: \(message)" } } diff --git a/Sources/GraphQLGeneratorCore/Utilities/SafeNameGenerator.swift b/Sources/GraphQLGeneratorCore/Utilities/SafeNameGenerator.swift index ad189ae..818c5bd 100644 --- a/Sources/GraphQLGeneratorCore/Utilities/SafeNameGenerator.swift +++ b/Sources/GraphQLGeneratorCore/Utilities/SafeNameGenerator.swift @@ -97,20 +97,29 @@ struct DefensiveSafeNameGenerator: SafeNameGenerator { /// /// Copied from SwiftSyntax/TokenKind.swift private static let keywords: Set = [ - "associatedtype", "class", "deinit", "enum", "extension", "func", "import", "init", "inout", "let", "operator", - "precedencegroup", "protocol", "struct", "subscript", "typealias", "var", "fileprivate", "internal", "private", - "public", "static", "defer", "if", "guard", "do", "repeat", "else", "for", "in", "while", "return", "break", - "continue", "fallthrough", "switch", "case", "default", "where", "catch", "throw", "as", "Any", "false", "is", - "nil", "rethrows", "super", "self", "Self", "true", "try", "throws", "yield", "String", "Error", "Int", "Bool", + "associatedtype", "class", "deinit", "enum", "extension", "func", "import", "init", "inout", + "let", "operator", + "precedencegroup", "protocol", "struct", "subscript", "typealias", "var", "fileprivate", + "internal", "private", + "public", "static", "defer", "if", "guard", "do", "repeat", "else", "for", "in", "while", + "return", "break", + "continue", "fallthrough", "switch", "case", "default", "where", "catch", "throw", "as", + "Any", "false", "is", + "nil", "rethrows", "super", "self", "Self", "true", "try", "throws", "yield", "String", + "Error", "Int", "Bool", "Array", "Type", "type", "Protocol", "await", ] /// A map of ASCII printable characters to their HTML entity names. Used to reduce collisions in generated names. private static let specialCharsMap: [Unicode.Scalar: String] = [ - " ": "space", "!": "excl", "\"": "quot", "#": "num", "$": "dollar", "%": "percnt", "&": "amp", "'": "apos", - "(": "lpar", ")": "rpar", "*": "ast", "+": "plus", ",": "comma", "-": "hyphen", ".": "period", "/": "sol", - ":": "colon", ";": "semi", "<": "lt", "=": "equals", ">": "gt", "?": "quest", "@": "commat", "[": "lbrack", - "\\": "bsol", "]": "rbrack", "^": "hat", "`": "grave", "{": "lcub", "|": "verbar", "}": "rcub", "~": "tilde", + " ": "space", "!": "excl", "\"": "quot", "#": "num", "$": "dollar", "%": "percnt", + "&": "amp", "'": "apos", + "(": "lpar", ")": "rpar", "*": "ast", "+": "plus", ",": "comma", "-": "hyphen", + ".": "period", "/": "sol", + ":": "colon", ";": "semi", "<": "lt", "=": "equals", ">": "gt", "?": "quest", "@": "commat", + "[": "lbrack", + "\\": "bsol", "]": "rbrack", "^": "hat", "`": "grave", "{": "lcub", "|": "verbar", + "}": "rcub", "~": "tilde", ] } @@ -160,7 +169,9 @@ struct IdiomaticSafeNameGenerator: SafeNameGenerator { enum State: Equatable { case modifying case preFirstWord - struct AccumulatingFirstWordContext: Equatable { var isAccumulatingInitialUppercase: Bool } + struct AccumulatingFirstWordContext: Equatable { + var isAccumulatingInitialUppercase: Bool + } case accumulatingFirstWord(AccumulatingFirstWordContext) case accumulatingWord case waitingForWordStarter @@ -191,7 +202,7 @@ struct IdiomaticSafeNameGenerator: SafeNameGenerator { state = .accumulatingFirstWord(.init(isAccumulatingInitialUppercase: false)) buffer.append(char) } - case var .accumulatingFirstWord(context): + case .accumulatingFirstWord(var context): if char.isLetter || char.isNumber { if isAllUppercase { buffer.append(contentsOf: char.lowercased()) @@ -209,7 +220,9 @@ struct IdiomaticSafeNameGenerator: SafeNameGenerator { buffer.append(char) context.isAccumulatingInitialUppercase = false } else { - let suffix = documentedName.suffix(from: documentedName.index(after: index)) + let suffix = documentedName.suffix( + from: documentedName.index(after: index) + ) if suffix.count >= 2 { let next = suffix.first! let secondNext = suffix.dropFirst().first! @@ -259,7 +272,11 @@ struct IdiomaticSafeNameGenerator: SafeNameGenerator { } case .accumulatingWord: if char.isLetter || char.isNumber { - if isAllUppercase { buffer.append(contentsOf: char.lowercased()) } else { buffer.append(char) } + if isAllUppercase { + buffer.append(contentsOf: char.lowercased()) + } else { + buffer.append(char) + } state = .accumulatingWord } else if Self.wordSeparators.contains(char) { // In the middle of an identifier, these are considered diff --git a/Sources/GraphQLGeneratorCore/Utilities/swiftTypeName.swift b/Sources/GraphQLGeneratorCore/Utilities/swiftTypeName.swift index 97c9d8f..1bb2219 100644 --- a/Sources/GraphQLGeneratorCore/Utilities/swiftTypeName.swift +++ b/Sources/GraphQLGeneratorCore/Utilities/swiftTypeName.swift @@ -6,9 +6,17 @@ import GraphQL /// - type: The GraphQL Type to generate a reference to /// - includeNamespace: Whether to include the `GraphQLGenerated` type namespace in the result /// - nameGenerator: The name generator -func swiftTypeReference(for type: GraphQLType, includeNamespace: Bool, nameGenerator: SafeNameGenerator) throws -> String { +func swiftTypeReference( + for type: GraphQLType, + includeNamespace: Bool, + nameGenerator: SafeNameGenerator +) throws -> String { if let nonNull = type as? GraphQLNonNull { - let innerType = try swiftTypeReference(for: nonNull.ofType, includeNamespace: includeNamespace, nameGenerator: nameGenerator) + let innerType = try swiftTypeReference( + for: nonNull.ofType, + includeNamespace: includeNamespace, + nameGenerator: nameGenerator + ) // Remove the optional marker if present if innerType.hasSuffix("?") { if innerType.hasPrefix("(") { @@ -22,7 +30,11 @@ func swiftTypeReference(for type: GraphQLType, includeNamespace: Bool, nameGener } if let list = type as? GraphQLList { - let innerType = try swiftTypeReference(for: list.ofType, includeNamespace: includeNamespace, nameGenerator: nameGenerator) + let innerType = try swiftTypeReference( + for: list.ofType, + includeNamespace: includeNamespace, + nameGenerator: nameGenerator + ) if innerType.hasSuffix("?") { let baseType = String(innerType.dropLast()) return "[\(baseType)]?" @@ -31,10 +43,16 @@ func swiftTypeReference(for type: GraphQLType, includeNamespace: Bool, nameGener } if let namedType = type as? GraphQLNamedType { - let baseName = try swiftTypeDeclaration(for: namedType, includeNamespace: includeNamespace, nameGenerator: nameGenerator) + let baseName = try swiftTypeDeclaration( + for: namedType, + includeNamespace: includeNamespace, + nameGenerator: nameGenerator + ) // By default, GraphQL fields are nullable, so add "?" - if namedType is GraphQLUnionType || namedType is GraphQLInterfaceType || namedType is GraphQLObjectType { + if namedType is GraphQLUnionType || namedType is GraphQLInterfaceType + || namedType is GraphQLObjectType + { // These are all interfaces, so we must wrap them in 'any' and parentheses for optionals. return "(any \(baseName))?" } @@ -53,15 +71,27 @@ func swiftTypeReference(for type: GraphQLType, includeNamespace: Bool, nameGener /// - type: The GraphQL Type to generate a reference to /// - includeNamespace: Whether to include the `GraphQLGenerated` type namespace in the result /// - nameGenerator: The name generator -func swiftTypeDeclaration(for type: GraphQLType, includeNamespace: Bool, nameGenerator: SafeNameGenerator) throws -> String { +func swiftTypeDeclaration( + for type: GraphQLType, + includeNamespace: Bool, + nameGenerator: SafeNameGenerator +) throws -> String { if let nonNull = type as? GraphQLNonNull { // Declarations must be for non-nulls, so just pass through - return try swiftTypeDeclaration(for: nonNull.ofType, includeNamespace: includeNamespace, nameGenerator: nameGenerator) + return try swiftTypeDeclaration( + for: nonNull.ofType, + includeNamespace: includeNamespace, + nameGenerator: nameGenerator + ) } if let list = type as? GraphQLList { // Declarations must be for non-lists, so just pass through - return try swiftTypeDeclaration(for: list.ofType, includeNamespace: includeNamespace, nameGenerator: nameGenerator) + return try swiftTypeDeclaration( + for: list.ofType, + includeNamespace: includeNamespace, + nameGenerator: nameGenerator + ) } if let namedType = type as? GraphQLNamedType { diff --git a/Sources/GraphQLGeneratorMacros/GraphQLGeneratorMacros.swift b/Sources/GraphQLGeneratorMacros/GraphQLGeneratorMacros.swift index 10d7db5..676b459 100644 --- a/Sources/GraphQLGeneratorMacros/GraphQLGeneratorMacros.swift +++ b/Sources/GraphQLGeneratorMacros/GraphQLGeneratorMacros.swift @@ -53,7 +53,8 @@ /// - Parameters: /// - name: Optional. The GraphQL field name. If omitted, the property name is used. @attached(peer, names: arbitrary) -public macro graphQLResolver(name: String? = nil) = #externalMacro( - module: "GraphQLGeneratorMacrosBackend", - type: "GraphQLResolverMacro" -) +public macro graphQLResolver(name: String? = nil) = + #externalMacro( + module: "GraphQLGeneratorMacrosBackend", + type: "GraphQLResolverMacro" + ) diff --git a/Sources/GraphQLGeneratorMacrosBackend/GraphQLResolverMacro.swift b/Sources/GraphQLGeneratorMacrosBackend/GraphQLResolverMacro.swift index 0bcb621..a1d176a 100644 --- a/Sources/GraphQLGeneratorMacrosBackend/GraphQLResolverMacro.swift +++ b/Sources/GraphQLGeneratorMacrosBackend/GraphQLResolverMacro.swift @@ -18,16 +18,17 @@ public struct GraphQLResolverMacro: PeerMacro { } // Validate that it's a stored property (has 'let' or 'var') - guard varDecl.bindingSpecifier.tokenKind == .keyword(.let) || - varDecl.bindingSpecifier.tokenKind == .keyword(.var) + guard + varDecl.bindingSpecifier.tokenKind == .keyword(.let) + || varDecl.bindingSpecifier.tokenKind == .keyword(.var) else { throw MacroError.invalidPropertyDeclaration } // Extract the property name and type guard let binding = varDecl.bindings.first, - let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier, - let type = binding.typeAnnotation?.type + let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier, + let type = binding.typeAnnotation?.type else { throw MacroError.invalidPropertyDeclaration } @@ -36,24 +37,28 @@ public struct GraphQLResolverMacro: PeerMacro { let propertyType = type.trimmedDescription // Check if the property has a throwing getter - let hasThrows = binding.accessorBlock?.accessors.as(AccessorDeclListSyntax.self)?.contains { accessor in - accessor.accessorSpecifier.tokenKind == .keyword(.get) && accessor.effectSpecifiers?.throwsClause != nil - } ?? false + let hasThrows = + binding.accessorBlock?.accessors.as(AccessorDeclListSyntax.self)?.contains { accessor in + accessor.accessorSpecifier.tokenKind == .keyword(.get) + && accessor.effectSpecifiers?.throwsClause != nil + } ?? false // Check if the property has an async getter - let hasAsync = binding.accessorBlock?.accessors.as(AccessorDeclListSyntax.self)?.contains { accessor in - accessor.accessorSpecifier.tokenKind == .keyword(.get) && accessor.effectSpecifiers?.asyncSpecifier != nil - } ?? false + let hasAsync = + binding.accessorBlock?.accessors.as(AccessorDeclListSyntax.self)?.contains { accessor in + accessor.accessorSpecifier.tokenKind == .keyword(.get) + && accessor.effectSpecifiers?.asyncSpecifier != nil + } ?? false // Set argument defaults var graphQLFieldName = propertyName // Override if arguments are provided - if case let .argumentList(arguments) = node.arguments { + if case .argumentList(let arguments) = node.arguments { if let nameArg = arguments.first(where: { $0.label?.text == "name" }) { guard let fieldName = nameArg.expression.as(StringLiteralExprSyntax.self)? - .segments.first?.as(StringSegmentSyntax.self)?.content.text + .segments.first?.as(StringSegmentSyntax.self)?.content.text else { // Invalid name argument throw MacroError.invalidArguments @@ -64,10 +69,10 @@ public struct GraphQLResolverMacro: PeerMacro { // Generate the resolver method let resolverMethod: DeclSyntax = """ - func \(raw: graphQLFieldName)(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> \(raw: propertyType) { - return \(raw: hasThrows ? "try " : "")\(raw: hasAsync ? "await " : "")\(raw: propertyName) - } - """ + func \(raw: graphQLFieldName)(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> \(raw: propertyType) { + return \(raw: hasThrows ? "try " : "")\(raw: hasAsync ? "await " : "")\(raw: propertyName) + } + """ return [resolverMethod] } @@ -84,7 +89,8 @@ enum MacroError: Error, CustomStringConvertible { case .notAttachedToProperty: return "@graphQLResolver can only be applied to properties" case .invalidPropertyDeclaration: - return "@graphQLResolver requires a stored property (let/var) with an explicit type annotation" + return + "@graphQLResolver requires a stored property (let/var) with an explicit type annotation" case .invalidArguments: return "@graphQLResolver accepts either no arguments or a 'name' string argument" } @@ -95,6 +101,6 @@ enum MacroError: Error, CustomStringConvertible { @main struct GraphQLGeneratorMacrosPlugin: CompilerPlugin { let providingMacros: [Macro.Type] = [ - GraphQLResolverMacro.self, + GraphQLResolverMacro.self ] } diff --git a/Sources/GraphQLGeneratorRuntime/AnyAsyncSequence.swift b/Sources/GraphQLGeneratorRuntime/AnyAsyncSequence.swift index bef9c0f..06ff1f9 100644 --- a/Sources/GraphQLGeneratorRuntime/AnyAsyncSequence.swift +++ b/Sources/GraphQLGeneratorRuntime/AnyAsyncSequence.swift @@ -1,4 +1,3 @@ - /// A type-erased AsyncSequence. This exists because we cannot qualify `AsyncSequence` opaque types with `Element` /// constraints in our SubscriptionProtocol. public struct AnyAsyncSequence: AsyncSequence, Sendable { @@ -31,9 +30,9 @@ public struct AnyAsyncSequence: AsyncSequence, Sendable { } } -public extension AsyncSequence where Self: Sendable, Element: Sendable { +extension AsyncSequence where Self: Sendable, Element: Sendable { /// Create a type erased version of this sequence - func any() -> AnyAsyncSequence { + public func any() -> AnyAsyncSequence { AnyAsyncSequence(self) } } diff --git a/Sources/GraphQLGeneratorRuntime/GraphQLScalar.swift b/Sources/GraphQLGeneratorRuntime/GraphQLScalar.swift index 207f9be..6aa0db1 100644 --- a/Sources/GraphQLGeneratorRuntime/GraphQLScalar.swift +++ b/Sources/GraphQLGeneratorRuntime/GraphQLScalar.swift @@ -17,9 +17,9 @@ public protocol GraphQLScalar: Sendable, Codable { // somewhat inefficient. They typically pass through a full serialize/deserialize step on each call. // Because of this, we have chosen not to vend defaults to force the user to implement more performant versions. -public extension GraphQLScalar { +extension GraphQLScalar { /// This wraps the GraphQLScalar definition in a type-safe one - static func serialize(any: Any) throws -> Map { + public static func serialize(any: Any) throws -> Map { // We should always get a value of `Self` for custom scalars. guard let scalar = any as? Self else { throw GraphQLError( diff --git a/Tests/GraphQLGeneratorCoreTests/IndentTests.swift b/Tests/GraphQLGeneratorCoreTests/IndentTests.swift index 0e48605..7d80d40 100644 --- a/Tests/GraphQLGeneratorCoreTests/IndentTests.swift +++ b/Tests/GraphQLGeneratorCoreTests/IndentTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQLGeneratorCore import Testing +@testable import GraphQLGeneratorCore + @Suite struct IndentTests { @Test func singleLine() { @@ -15,8 +16,7 @@ struct IndentTests { abc def """.indent(1, includeFirst: false) - == - """ + == """ abc def """ @@ -26,8 +26,7 @@ struct IndentTests { abc def """.indent(1, includeFirst: true) - == - """ + == """ abc def """ diff --git a/Tests/GraphQLGeneratorCoreTests/SchemaGeneratorTests.swift b/Tests/GraphQLGeneratorCoreTests/SchemaGeneratorTests.swift index bbb74a4..f9baee9 100644 --- a/Tests/GraphQLGeneratorCoreTests/SchemaGeneratorTests.swift +++ b/Tests/GraphQLGeneratorCoreTests/SchemaGeneratorTests.swift @@ -1,7 +1,8 @@ import GraphQL -@testable import GraphQLGeneratorCore import Testing +@testable import GraphQLGeneratorCore + @Suite struct SchemaGeneratorTests { let generator = BuildGraphQLSchemaGenerator() @@ -14,7 +15,7 @@ struct SchemaGeneratorTests { "foo": .init( type: GraphQLString, description: "foo" - ), + ) ] ) let schema = try GraphQLSchema( @@ -32,55 +33,55 @@ struct SchemaGeneratorTests { ] ), types: [ - bar, + bar ] ) let actual = try generator.generate(schema: schema) let expected = #""" - // Generated by GraphQL Generator - // DO NOT EDIT - This file is automatically generated - - import Foundation - import GraphQL - import GraphQLGeneratorRuntime - - /// Build a GraphQL schema with the provided resolvers - func buildGraphQLSchema( - resolvers: Resolvers.Type, - decoder: MapDecoder = .init() - ) throws -> GraphQLSchema { - - let schema = try GraphQL.buildSchema(source: graphQLRawSDL) - - let bar = schema.typeMap["Bar"] as? GraphQLObjectType - let barFields = try bar?.fields() ?? [:] - barFields["foo"]?.resolve = { @Sendable source, args, context, info in - let parent = try cast(source, to: (any GraphQLGenerated.Bar).self) - let context = try cast(context, to: GraphQLContext.self) - return try await parent.foo(context: context, info: info) - } - bar?.fields = { - return barFields + // Generated by GraphQL Generator + // DO NOT EDIT - This file is automatically generated + + import Foundation + import GraphQL + import GraphQLGeneratorRuntime + + /// Build a GraphQL schema with the provided resolvers + func buildGraphQLSchema( + resolvers: Resolvers.Type, + decoder: MapDecoder = .init() + ) throws -> GraphQLSchema { + + let schema = try GraphQL.buildSchema(source: graphQLRawSDL) + + let bar = schema.typeMap["Bar"] as? GraphQLObjectType + let barFields = try bar?.fields() ?? [:] + barFields["foo"]?.resolve = { @Sendable source, args, context, info in + let parent = try cast(source, to: (any GraphQLGenerated.Bar).self) + let context = try cast(context, to: GraphQLContext.self) + return try await parent.foo(context: context, info: info) + } + bar?.fields = { + return barFields + } + + let query = schema.typeMap["Query"] as? GraphQLObjectType + let queryFields = try query?.fields() ?? [:] + queryFields["foo"]?.resolve = { @Sendable source, args, context, info in + let context = try cast(context, to: GraphQLContext.self) + return try await Resolvers.Query.foo(context: context, info: info) + } + queryFields["bar"]?.resolve = { @Sendable source, args, context, info in + let context = try cast(context, to: GraphQLContext.self) + return try await Resolvers.Query.bar(context: context, info: info) + } + query?.fields = { + return queryFields + } + + return schema } - let query = schema.typeMap["Query"] as? GraphQLObjectType - let queryFields = try query?.fields() ?? [:] - queryFields["foo"]?.resolve = { @Sendable source, args, context, info in - let context = try cast(context, to: GraphQLContext.self) - return try await Resolvers.Query.foo(context: context, info: info) - } - queryFields["bar"]?.resolve = { @Sendable source, args, context, info in - let context = try cast(context, to: GraphQLContext.self) - return try await Resolvers.Query.bar(context: context, info: info) - } - query?.fields = { - return queryFields - } - - return schema - } - - """# + """# #expect( actual == expected ) @@ -93,7 +94,7 @@ struct SchemaGeneratorTests { "id": GraphQLField( type: GraphQLNonNull(GraphQLID), description: "The ID of the node" - ), + ) ] ) @@ -101,17 +102,17 @@ struct SchemaGeneratorTests { let expected = """ - let node = schema.typeMap["Node"] as? GraphQLObjectType - let nodeFields = try node?.fields() ?? [:] - nodeFields["id"]?.resolve = { @Sendable source, args, context, info in - let parent = try cast(source, to: (any GraphQLGenerated.Node).self) - let context = try cast(context, to: GraphQLContext.self) - return try await parent.id(context: context, info: info) - } - node?.fields = { - return nodeFields - } - """ + let node = schema.typeMap["Node"] as? GraphQLObjectType + let nodeFields = try node?.fields() ?? [:] + nodeFields["id"]?.resolve = { @Sendable source, args, context, info in + let parent = try cast(source, to: (any GraphQLGenerated.Node).self) + let context = try cast(context, to: GraphQLContext.self) + return try await parent.id(context: context, info: info) + } + node?.fields = { + return nodeFields + } + """ #expect(result == expected) } @@ -134,22 +135,22 @@ struct SchemaGeneratorTests { let expected = """ - let book = schema.typeMap["Book"] as? GraphQLObjectType - let bookFields = try book?.fields() ?? [:] - bookFields["title"]?.resolve = { @Sendable source, args, context, info in - let parent = try cast(source, to: (any GraphQLGenerated.Book).self) - let context = try cast(context, to: GraphQLContext.self) - return try await parent.title(context: context, info: info) - } - bookFields["author"]?.resolve = { @Sendable source, args, context, info in - let parent = try cast(source, to: (any GraphQLGenerated.Book).self) - let context = try cast(context, to: GraphQLContext.self) - return try await parent.author(context: context, info: info) - } - book?.fields = { - return bookFields - } - """ + let book = schema.typeMap["Book"] as? GraphQLObjectType + let bookFields = try book?.fields() ?? [:] + bookFields["title"]?.resolve = { @Sendable source, args, context, info in + let parent = try cast(source, to: (any GraphQLGenerated.Book).self) + let context = try cast(context, to: GraphQLContext.self) + return try await parent.title(context: context, info: info) + } + bookFields["author"]?.resolve = { @Sendable source, args, context, info in + let parent = try cast(source, to: (any GraphQLGenerated.Book).self) + let context = try cast(context, to: GraphQLContext.self) + return try await parent.author(context: context, info: info) + } + book?.fields = { + return bookFields + } + """ #expect(result == expected) } @@ -162,7 +163,7 @@ struct SchemaGeneratorTests { "user": GraphQLField( type: GraphQLString, description: "Get a user" - ), + ) ] ) @@ -170,16 +171,16 @@ struct SchemaGeneratorTests { let expected = """ - let query = schema.typeMap["Query"] as? GraphQLObjectType - let queryFields = try query?.fields() ?? [:] - queryFields["user"]?.resolve = { @Sendable source, args, context, info in - let context = try cast(context, to: GraphQLContext.self) - return try await Resolvers.Query.user(context: context, info: info) - } - query?.fields = { - return queryFields - } - """ + let query = schema.typeMap["Query"] as? GraphQLObjectType + let queryFields = try query?.fields() ?? [:] + queryFields["user"]?.resolve = { @Sendable source, args, context, info in + let context = try cast(context, to: GraphQLContext.self) + return try await Resolvers.Query.user(context: context, info: info) + } + query?.fields = { + return queryFields + } + """ #expect(result == expected) } @@ -191,7 +192,7 @@ struct SchemaGeneratorTests { "createUser": GraphQLField( type: GraphQLString, description: "Create a user" - ), + ) ] ) @@ -199,16 +200,16 @@ struct SchemaGeneratorTests { let expected = """ - let mutation = schema.typeMap["Mutation"] as? GraphQLObjectType - let mutationFields = try mutation?.fields() ?? [:] - mutationFields["createUser"]?.resolve = { @Sendable source, args, context, info in - let context = try cast(context, to: GraphQLContext.self) - return try await Resolvers.Mutation.createUser(context: context, info: info) - } - mutation?.fields = { - return mutationFields - } - """ + let mutation = schema.typeMap["Mutation"] as? GraphQLObjectType + let mutationFields = try mutation?.fields() ?? [:] + mutationFields["createUser"]?.resolve = { @Sendable source, args, context, info in + let context = try cast(context, to: GraphQLContext.self) + return try await Resolvers.Mutation.createUser(context: context, info: info) + } + mutation?.fields = { + return mutationFields + } + """ #expect(result == expected) } @@ -220,7 +221,7 @@ struct SchemaGeneratorTests { "userUpdated": GraphQLField( type: GraphQLString, description: "Subscribe to user updates" - ), + ) ] ) @@ -228,19 +229,19 @@ struct SchemaGeneratorTests { let expected = """ - let subscription = schema.typeMap["Subscription"] as? GraphQLObjectType - let subscriptionFields = try subscription?.fields() ?? [:] - subscriptionFields["userUpdated"]?.resolve = { @Sendable source, _, _, _ in - return source - } - subscriptionFields["userUpdated"]?.subscribe = { @Sendable source, args, context, info in - let context = try cast(context, to: GraphQLContext.self) - return try await Resolvers.Subscription.userUpdated(context: context, info: info) - } - subscription?.fields = { - return subscriptionFields - } - """ + let subscription = schema.typeMap["Subscription"] as? GraphQLObjectType + let subscriptionFields = try subscription?.fields() ?? [:] + subscriptionFields["userUpdated"]?.resolve = { @Sendable source, _, _, _ in + return source + } + subscriptionFields["userUpdated"]?.subscribe = { @Sendable source, args, context, info in + let context = try cast(context, to: GraphQLContext.self) + return try await Resolvers.Subscription.userUpdated(context: context, info: info) + } + subscription?.fields = { + return subscriptionFields + } + """ #expect(result == expected) } @@ -268,14 +269,14 @@ struct SchemaGeneratorTests { ) let expected = """ - queryFields["posts"]?.resolve = { @Sendable source, args, context, info in - let parent = try cast(source, to: (any GraphQLGenerated.User).self) - let filter = args["filter"] != .undefined ? try decoder.decode((String?).self, from: args["filter"]) : nil - let scalar = try decoder.decode((GraphQLScalars.Scalar).self, from: args["scalar"]) - let context = try cast(context, to: GraphQLContext.self) - return try await parent.posts(filter: filter, scalar: scalar, context: context, info: info) - } - """ + queryFields["posts"]?.resolve = { @Sendable source, args, context, info in + let parent = try cast(source, to: (any GraphQLGenerated.User).self) + let filter = args["filter"] != .undefined ? try decoder.decode((String?).self, from: args["filter"]) : nil + let scalar = try decoder.decode((GraphQLScalars.Scalar).self, from: args["scalar"]) + let context = try cast(context, to: GraphQLContext.self) + return try await parent.posts(filter: filter, scalar: scalar, context: context, info: info) + } + """ #expect(result == expected) } @@ -284,7 +285,7 @@ struct SchemaGeneratorTests { let field = GraphQLField( type: GraphQLString, args: [ - "id": GraphQLArgument(type: GraphQLNonNull(GraphQLID)), + "id": GraphQLArgument(type: GraphQLNonNull(GraphQLID)) ] ) @@ -299,12 +300,12 @@ struct SchemaGeneratorTests { ) let expected = """ - queryFields["user"]?.resolve = { @Sendable source, args, context, info in - let id = try decoder.decode((String).self, from: args["id"]) - let context = try cast(context, to: GraphQLContext.self) - return try await Resolvers.Query.user(id: id, context: context, info: info) - } - """ + queryFields["user"]?.resolve = { @Sendable source, args, context, info in + let id = try decoder.decode((String).self, from: args["id"]) + let context = try cast(context, to: GraphQLContext.self) + return try await Resolvers.Query.user(id: id, context: context, info: info) + } + """ #expect(result == expected) } @@ -325,14 +326,14 @@ struct SchemaGeneratorTests { ) let expected = """ - subscriptionFields["messageAdded"]?.resolve = { @Sendable source, _, _, _ in - return source - } - subscriptionFields["messageAdded"]?.subscribe = { @Sendable source, args, context, info in - let context = try cast(context, to: GraphQLContext.self) - return try await Resolvers.Subscription.messageAdded(context: context, info: info) - } - """ + subscriptionFields["messageAdded"]?.resolve = { @Sendable source, _, _, _ in + return source + } + subscriptionFields["messageAdded"]?.subscribe = { @Sendable source, args, context, info in + let context = try cast(context, to: GraphQLContext.self) + return try await Resolvers.Subscription.messageAdded(context: context, info: info) + } + """ #expect(result == expected) } diff --git a/Tests/GraphQLGeneratorCoreTests/TypeGeneratorTests.swift b/Tests/GraphQLGeneratorCoreTests/TypeGeneratorTests.swift index 1dcce0f..f15d995 100644 --- a/Tests/GraphQLGeneratorCoreTests/TypeGeneratorTests.swift +++ b/Tests/GraphQLGeneratorCoreTests/TypeGeneratorTests.swift @@ -1,7 +1,8 @@ import GraphQL -@testable import GraphQLGeneratorCore import Testing +@testable import GraphQLGeneratorCore + @Suite struct TypeGeneratorTests { let generator = GraphQLTypesGenerator() @@ -31,15 +32,15 @@ struct TypeGeneratorTests { #expect( actual == """ - /// foo - enum Foo: String, Codable, Sendable { /// foo - case foo = "foo" - /// bar - case bar = "bar" - case baz = "baz" - } - """ + enum Foo: String, Codable, Sendable { + /// foo + case foo = "foo" + /// bar + case bar = "bar" + case baz = "baz" + } + """ ) } @@ -66,15 +67,15 @@ struct TypeGeneratorTests { let expected = """ - /// Input for creating a new user - struct CreateUserInput: Codable, Sendable { - /// User's full name - let name: String - let email: String - /// User's age - let age: Int? - } - """ + /// Input for creating a new user + struct CreateUserInput: Codable, Sendable { + /// User's full name + let name: String + let email: String + /// User's age + let age: Int? + } + """ #expect(result == expected) } @@ -98,12 +99,12 @@ struct TypeGeneratorTests { let expected = """ - struct PersonInput: Codable, Sendable { - let name: String - let address: AddressInput? - let friends: [PersonInput]? - } - """ + struct PersonInput: Codable, Sendable { + let name: String + let address: AddressInput? + let friends: [PersonInput]? + } + """ #expect(result == expected) } @@ -127,12 +128,12 @@ struct TypeGeneratorTests { let expected = """ - struct PersonInput: Codable, Sendable { - let cellPhone: GraphQLScalars.PhoneNumber - let homePhone: GraphQLScalars.PhoneNumber? - let familyPhones: [GraphQLScalars.PhoneNumber]? - } - """ + struct PersonInput: Codable, Sendable { + let cellPhone: GraphQLScalars.PhoneNumber + let homePhone: GraphQLScalars.PhoneNumber? + let familyPhones: [GraphQLScalars.PhoneNumber]? + } + """ #expect(result == expected) } @@ -146,7 +147,7 @@ struct TypeGeneratorTests { name: "B", description: "B", interfaces: [ - interfaceA, + interfaceA ], fields: [ "foo": .init( @@ -171,16 +172,16 @@ struct TypeGeneratorTests { #expect( actual == """ - /// B - protocol B: A, Sendable { - /// foo - func foo(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String + /// B + protocol B: A, Sendable { + /// foo + func foo(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String - /// baz - func baz(arg1: String, arg2: Int?, context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String? + /// baz + func baz(arg1: String, arg2: Int?, context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String? - } - """ + } + """ ) } @@ -217,7 +218,7 @@ struct TypeGeneratorTests { args: [ "baz": .init( type: GraphQLNonNull(scalar) - ), + ) ] ), ], @@ -226,25 +227,25 @@ struct TypeGeneratorTests { let actual = try GraphQLTypesGenerator().generateTypeProtocol( for: typeFoo, unionTypeMap: [ - "Foo": [GraphQLUnionType(name: "X", types: [typeFoo])], + "Foo": [GraphQLUnionType(name: "X", types: [typeFoo])] ] ) #expect( actual == """ - /// Foo - protocol Foo: X, A, Sendable { - /// foo - func foo(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String + /// Foo + protocol Foo: X, A, Sendable { + /// foo + func foo(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String - /// bar - func bar(foo: String, bar: String?, context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String? + /// bar + func bar(foo: String, bar: String?, context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String? - /// baz - func baz(baz: GraphQLScalars.Scalar, context: GraphQLContext, info: GraphQLResolveInfo) async throws -> GraphQLScalars.Scalar? + /// baz + func baz(baz: GraphQLScalars.Scalar, context: GraphQLContext, info: GraphQLResolveInfo) async throws -> GraphQLScalars.Scalar? - } - """ + } + """ ) } @@ -256,7 +257,7 @@ struct TypeGeneratorTests { "foo": .init( type: GraphQLString, description: "foo" - ), + ) ] ) let query = try GraphQLObjectType( @@ -276,15 +277,15 @@ struct TypeGeneratorTests { #expect( actual == """ - protocol Query: Sendable { - /// foo - static func foo(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String? + protocol Query: Sendable { + /// foo + static func foo(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String? - /// bar - static func bar(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> (any Bar)? + /// bar + static func bar(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> (any Bar)? - } - """ + } + """ ) } @@ -305,7 +306,7 @@ struct TypeGeneratorTests { type: GraphQLBoolean, description: "Delete a user", args: [ - "id": GraphQLArgument(type: GraphQLNonNull(GraphQLID)), + "id": GraphQLArgument(type: GraphQLNonNull(GraphQLID)) ] ), ] @@ -315,16 +316,16 @@ struct TypeGeneratorTests { let expected = """ - /// Mutations - protocol Mutation: Sendable { - /// Create a new user - static func createUser(name: String, email: String, context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String? + /// Mutations + protocol Mutation: Sendable { + /// Create a new user + static func createUser(name: String, email: String, context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String? - /// Delete a user - static func deleteUser(id: String, context: GraphQLContext, info: GraphQLResolveInfo) async throws -> Bool? + /// Delete a user + static func deleteUser(id: String, context: GraphQLContext, info: GraphQLResolveInfo) async throws -> Bool? - } - """ + } + """ #expect(result == expected) } @@ -339,21 +340,21 @@ struct TypeGeneratorTests { args: [ "id": .init( type: GraphQLString - ), + ) ] - ), + ) ] ) let actual = try generator.generateRootTypeProtocol(for: subscription) #expect( actual == """ - protocol Subscription: Sendable { - /// foo - static func watchThis(id: String?, context: GraphQLContext, info: GraphQLResolveInfo) async throws -> AnyAsyncSequence + protocol Subscription: Sendable { + /// foo + static func watchThis(id: String?, context: GraphQLContext, info: GraphQLResolveInfo) async throws -> AnyAsyncSequence - } - """ + } + """ ) } } diff --git a/Tests/GraphQLGeneratorMacrosTests/GraphQLResolverMacroTests.swift b/Tests/GraphQLGeneratorMacrosTests/GraphQLResolverMacroTests.swift index 57c2956..10a35db 100644 --- a/Tests/GraphQLGeneratorMacrosTests/GraphQLResolverMacroTests.swift +++ b/Tests/GraphQLGeneratorMacrosTests/GraphQLResolverMacroTests.swift @@ -5,7 +5,7 @@ import XCTest final class GraphQLResolverMacroTests: XCTestCase { let testMacros: [String: Macro.Type] = [ - "graphQLResolver": GraphQLResolverMacro.self, + "graphQLResolver": GraphQLResolverMacro.self ] func testSimpleField() { @@ -17,14 +17,14 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct User { - let id: String + struct User { + let id: String - func id(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { - return id + func id(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { + return id + } } - } - """, + """, macros: testMacros ) } @@ -44,24 +44,24 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct User { - let id: String + struct User { + let id: String - func id(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { - return id - } - let name: String + func id(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { + return id + } + let name: String - func name(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { - return name - } - let age: Int? + func name(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { + return name + } + let age: Int? - func age(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> Int? { - return age + func age(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> Int? { + return age + } } - } - """, + """, macros: testMacros ) } @@ -75,14 +75,14 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct User { - let email: String + struct User { + let email: String - func emailAddress(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { - return email + func emailAddress(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { + return email + } } - } - """, + """, macros: testMacros ) } @@ -99,19 +99,19 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct User { - let id: String + struct User { + let id: String - func id(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { - return id - } - let name: String + func id(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { + return id + } + let name: String - func fullName(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { - return name + func fullName(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { + return name + } } - } - """, + """, macros: testMacros ) } @@ -125,14 +125,14 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct User { - let email: String? + struct User { + let email: String? - func email(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String? { - return email + func email(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String? { + return email + } } - } - """, + """, macros: testMacros ) } @@ -146,14 +146,14 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct Query { - let users: [User] + struct Query { + let users: [User] - func users(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> [User] { - return users + func users(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> [User] { + return users + } } - } - """, + """, macros: testMacros ) } @@ -167,14 +167,14 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct User { - let email: GraphQLScalars.EmailAddress + struct User { + let email: GraphQLScalars.EmailAddress - func email(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> GraphQLScalars.EmailAddress { - return email + func email(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> GraphQLScalars.EmailAddress { + return email + } } - } - """, + """, macros: testMacros ) } @@ -188,14 +188,14 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct Query { - let user: (any User)? + struct Query { + let user: (any User)? - func user(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> (any User)? { - return user + func user(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> (any User)? { + return user + } } - } - """, + """, macros: testMacros ) } @@ -209,14 +209,14 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct User { - var name: String + struct User { + var name: String - func name(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { - return name + func name(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { + return name + } } - } - """, + """, macros: testMacros ) } @@ -230,16 +230,17 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct User { - let id = "123" - } - """, + struct User { + let id = "123" + } + """, diagnostics: [ DiagnosticSpec( - message: "@graphQLResolver requires a stored property (let/var) with an explicit type annotation", + message: + "@graphQLResolver requires a stored property (let/var) with an explicit type annotation", line: 2, column: 5 - ), + ) ], macros: testMacros ) @@ -252,14 +253,14 @@ final class GraphQLResolverMacroTests: XCTestCase { func someFunction() {} """, expandedSource: """ - func someFunction() {} - """, + func someFunction() {} + """, diagnostics: [ DiagnosticSpec( message: "@graphQLResolver can only be applied to properties", line: 1, column: 1 - ), + ) ], macros: testMacros ) @@ -278,18 +279,18 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct User { - var name: String { - get { - return "Test" + struct User { + var name: String { + get { + return "Test" + } } - } - func name(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { - return name + func name(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { + return name + } } - } - """, + """, macros: testMacros ) } @@ -307,18 +308,18 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct User { - var id: String { - get throws { - try property.getID() + struct User { + var id: String { + get throws { + try property.getID() + } } - } - func id(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { - return try id + func id(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { + return try id + } } - } - """, + """, macros: testMacros ) } @@ -336,18 +337,18 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct User { - var id: String { - get async { - await property.getID() + struct User { + var id: String { + get async { + await property.getID() + } } - } - func id(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { - return await id + func id(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { + return await id + } } - } - """, + """, macros: testMacros ) } @@ -365,18 +366,18 @@ final class GraphQLResolverMacroTests: XCTestCase { } """, expandedSource: """ - struct User { - var id: String { - get async throws { - try await property.getID() + struct User { + var id: String { + get async throws { + try await property.getID() + } } - } - func id(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { - return try await id + func id(context: GraphQLContext, info: GraphQLResolveInfo) async throws -> String { + return try await id + } } - } - """, + """, macros: testMacros ) }