From ffed0da8c900161bb4320295df428a35efb4998c Mon Sep 17 00:00:00 2001 From: Jay Herron Date: Sun, 5 Apr 2026 00:02:10 -0600 Subject: [PATCH 1/3] 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 00000000..1ffdbf5f --- /dev/null +++ b/.swift-format @@ -0,0 +1,7 @@ +{ + "version": 1, + "indentation" : { + "spaces" : 4 + }, + "lineBreakBeforeEachArgument": true +} From ad214203a24bf0e5bd336c976270fa4074f99f4d Mon Sep 17 00:00:00 2001 From: Jay Herron Date: Sun, 5 Apr 2026 00:06:06 -0600 Subject: [PATCH 2/3] refactor: Applies formatter --- Benchmarks/Benchmarks/GraphQLBenchmarks.swift | 14 +- Benchmarks/Benchmarks/StarWarsData.swift | 20 +- Benchmarks/Benchmarks/StarWarsSchema.swift | 168 +- Benchmarks/Package.swift | 4 +- Package.swift | 6 +- Sources/GraphQL/Error/GraphQLError.swift | 28 +- Sources/GraphQL/Error/LocatedError.swift | 8 +- Sources/GraphQL/Error/SyntaxError.swift | 24 +- Sources/GraphQL/Execution/Execute.swift | 267 +- Sources/GraphQL/Execution/Values.swift | 56 +- Sources/GraphQL/GraphQL.swift | 7 +- Sources/GraphQL/Language/AST.swift | 217 +- Sources/GraphQL/Language/BlockString.swift | 77 +- .../GraphQL/Language/CharacterClasses.swift | 14 +- Sources/GraphQL/Language/Lexer.swift | 252 +- Sources/GraphQL/Language/Location.swift | 8 +- Sources/GraphQL/Language/Parser.swift | 513 +-- Sources/GraphQL/Language/Predicates.swift | 29 +- Sources/GraphQL/Language/PrintString.swift | 25 +- Sources/GraphQL/Language/Printer.swift | 96 +- Sources/GraphQL/Language/Source.swift | 16 +- Sources/GraphQL/Language/Visitor.swift | 116 +- Sources/GraphQL/Map/AnyCoder.swift | 460 +- Sources/GraphQL/Map/AnySerialization.swift | 3 +- Sources/GraphQL/Map/GraphQLJSONEncoder.swift | 174 +- Sources/GraphQL/Map/Map.swift | 242 +- Sources/GraphQL/Map/MapCoder.swift | 475 ++- Sources/GraphQL/Map/MapSerialization.swift | 22 +- Sources/GraphQL/Subscription/Subscribe.swift | 95 +- .../GraphQL/SwiftUtilities/DidYouMean.swift | 2 +- .../GraphQL/SwiftUtilities/FormatList.swift | 2 +- Sources/GraphQL/SwiftUtilities/KeyMap.swift | 37 +- .../SwiftUtilities/SuggestionList.swift | 38 +- Sources/GraphQL/Type/Definition.swift | 446 +- Sources/GraphQL/Type/Directives.swift | 63 +- Sources/GraphQL/Type/Introspection.swift | 334 +- Sources/GraphQL/Type/Scalars.swift | 70 +- Sources/GraphQL/Type/Schema.swift | 95 +- Sources/GraphQL/Type/Validation.swift | 126 +- Sources/GraphQL/Utilities/ASTFromValue.swift | 51 +- .../GraphQL/Utilities/AssertValidName.swift | 4 +- .../GraphQL/Utilities/BuildASTSchema.swift | 50 +- Sources/GraphQL/Utilities/ConcatAST.swift | 8 +- Sources/GraphQL/Utilities/ExtendSchema.swift | 62 +- Sources/GraphQL/Utilities/IsValidValue.swift | 12 +- Sources/GraphQL/Utilities/PrintSchema.swift | 141 +- .../GraphQL/Utilities/TypeComparators.swift | 35 +- Sources/GraphQL/Utilities/TypeInfo.swift | 23 +- Sources/GraphQL/Utilities/ValueFromAST.swift | 37 +- .../Utilities/ValueFromASTUntyped.swift | 41 +- .../Rules/Custom/NoDeprecatedCustomRule.swift | 49 +- .../NoSchemaIntrospectionCustomRule.swift | 25 +- .../Rules/ExecutableDefinitionsRule.swift | 25 +- .../Rules/FieldsOnCorrectTypeRule.swift | 64 +- .../Rules/FragmentsOnCompositeTypesRule.swift | 21 +- .../KnownArgumentNamesOnDirectivesRule.swift | 5 +- .../Rules/KnownArgumentNamesRule.swift | 23 +- .../Rules/KnownDirectivesRule.swift | 22 +- .../Rules/KnownFragmentNamesRule.swift | 24 +- .../Validation/Rules/KnownTypeNamesRule.swift | 26 +- .../Rules/LoneAnonymousOperationRule.swift | 15 +- .../Rules/LoneSchemaDefinitionRule.swift | 15 +- .../Rules/NoFragmentCyclesRule.swift | 23 +- .../Rules/NoUndefinedVariablesRule.swift | 15 +- .../Rules/NoUnusedFragmentsRule.swift | 15 +- .../Rules/NoUnusedVariablesRule.swift | 18 +- .../Rules/PossibleFragmentSpreadsRule.swift | 18 +- .../Rules/PossibleTypeExtensionsRule.swift | 21 +- ...dedRequiredArgumentsOnDirectivesRule.swift | 4 +- .../Rules/ProvidedRequiredArgumentsRule.swift | 32 +- .../Validation/Rules/ScalarLeafsRule.swift | 18 +- .../UniqueArgumentDefinitionNamesRule.swift | 14 +- .../Rules/UniqueArgumentNamesRule.swift | 15 +- .../Rules/UniqueDirectiveNamesRule.swift | 12 +- .../UniqueDirectivesPerLocationRule.swift | 29 +- .../Rules/UniqueEnumValueNamesRule.swift | 18 +- .../UniqueFieldDefinitionNamesRule.swift | 21 +- .../Rules/UniqueFragmentNamesRule.swift | 16 +- .../Rules/UniqueInputFieldNamesRule.swift | 15 +- .../Rules/UniqueOperationNamesRule.swift | 16 +- .../Rules/UniqueOperationTypesRule.swift | 12 +- .../Rules/UniqueTypeNamesRule.swift | 12 +- .../Rules/UniqueVariableNamesRule.swift | 12 +- .../Rules/ValuesOfCorrectTypeRule.swift | 54 +- .../Rules/VariablesAreInputTypesRule.swift | 18 +- .../VariablesInAllowedPositionRule.swift | 48 +- .../GraphQL/Validation/SpecifiedRules.swift | 18 +- Sources/GraphQL/Validation/Validate.swift | 58 +- .../Validation/ValidationContext.swift | 44 +- .../ExecutionTests/OneOfTests.swift | 146 +- .../FederationTests/FederationTests.swift | 388 +- .../HelloWorldTests/HelloWorldTests.swift | 7 +- .../GraphQLTests/InputTests/InputTests.swift | 908 ++-- .../LanguageTests/BlockStringTests.swift | 43 +- .../LanguageTests/LexerTests.swift | 320 +- .../LanguageTests/ParserTests.swift | 238 +- .../LanguageTests/PrintStringTests.swift | 65 +- .../LanguageTests/PrinterTests.swift | 34 +- .../LanguageTests/SchemaParserTests.swift | 632 +-- .../LanguageTests/SchemaPrinterTests.swift | 219 +- .../LanguageTests/VisitorTests.swift | 534 +-- Tests/GraphQLTests/MapTests/MapTests.swift | 21 +- .../PersistedQueriesTests.swift | 268 +- .../StarWarsTests/StarWarsData.swift | 20 +- .../StarWarsIntrospectionTests.swift | 200 +- .../StarWarsTests/StarWarsQueryTests.swift | 217 +- .../StarWarsTests/StarWarsSchema.swift | 168 +- .../StarWarsValidationTests.swift | 89 +- .../SubscriptionSchema.swift | 8 +- .../SubscriptionTests/SubscriptionTests.swift | 969 +++-- .../SwiftUtilitiesTests/DidYouMeanTests.swift | 3 +- .../GraphQLArgumentDefinitionTests.swift | 3 +- .../TypeTests/GraphQLSchemaTests.swift | 36 +- .../TypeTests/IntrospectionTests.swift | 97 +- .../GraphQLTests/TypeTests/ScalarTests.swift | 53 +- .../TypeTests/ValidateSchemaTests.swift | 3730 +++++++++-------- .../UtilitiesTests/BuildASTSchemaTests.swift | 1065 ++--- .../UtilitiesTests/ConcatASTTests.swift | 41 +- .../UtilitiesTests/ExtendSchemaTests.swift | 1433 ++++--- .../UtilitiesTests/PrintSchemaTests.swift | 1265 +++--- .../ValidationTests/ExampleSchema.swift | 30 +- .../ExecutableDefinitionsRuleTests.swift | 43 +- .../FieldsOnCorrectTypeTests.swift | 129 +- .../FragmentsOnCompositeTypesRuleTests.swift | 56 +- ...wnArgumentNamesOnDirectivesRuleTests.swift | 51 +- .../KnownArgumentNamesTests.swift | 17 +- .../KnownDirectivesRuleTests.swift | 142 +- .../KnownFragmentNamesTests.swift | 29 +- .../KnownTypeNamesRuleTests.swift | 25 +- .../LoneAnonymousOperationRuleTests.swift | 51 +- .../LoneSchemaDefinitionRuleTests.swift | 79 +- .../NoDeprecatedCustomRuleTests.swift | 193 +- .../NoFragmentCyclesRuleTests.swift | 107 +- .../NoUndefinedVariablesRuleTests.swift | 185 +- .../NoUnusedFragmentsRuleTests.swift | 153 +- .../NoUnusedVariablesRuleTests.swift | 173 +- ...PossibleFragmentSpreadsRuleRuleTests.swift | 274 +- .../PossibleTypeExtensionsRuleTests.swift | 117 +- ...quiredArgumentsOnDirectivesRuleTests.swift | 64 +- .../ProvidedRequiredArgumentsRuleTests.swift | 81 +- ...iqueArgumentDefinitionNamesRuleTests.swift | 6 +- .../UniqueArgumentNamesRuleTests.swift | 43 +- .../UniqueDirectiveNamesRuleTests.swift | 15 +- ...UniqueDirectivesPerLocationRuleTests.swift | 43 +- .../UniqueEnumValueNamesRuleTests.swift | 71 +- .../UniqueFieldDefinitionNamesRuleTests.swift | 179 +- .../UniqueFragmentNamesRuleTests.swift | 41 +- .../UniqueInputFieldNamesRuleTests.swift | 33 +- .../UniqueOperationNamesRuleTests.swift | 51 +- .../UniqueOperationTypesRuleTests.swift | 104 +- .../UniqueTypeNamesRuleTests.swift | 35 +- .../UniqueVariableNamesRuleTests.swift | 13 +- .../ValidationTests/ValidationTests.swift | 9 +- .../ValuesOfCorrectTypeRuleTests.swift | 706 ++-- .../VariablesAreInputTypesRuleTests.swift | 13 +- .../VariablesInAllowedPositionRuleTests.swift | 198 +- 156 files changed, 11753 insertions(+), 11049 deletions(-) diff --git a/Benchmarks/Benchmarks/GraphQLBenchmarks.swift b/Benchmarks/Benchmarks/GraphQLBenchmarks.swift index d4ffc955..129eef1d 100644 --- a/Benchmarks/Benchmarks/GraphQLBenchmarks.swift +++ b/Benchmarks/Benchmarks/GraphQLBenchmarks.swift @@ -6,19 +6,19 @@ let benchmarks: @Sendable () -> Void = { let result = try await graphql( schema: starWarsSchema, request: """ - query NestedQuery { - hero { - name - friends { + query NestedQuery { + hero { name - appearsIn friends { name + appearsIn + friends { + name + } } } } - } - """ + """ ) } } diff --git a/Benchmarks/Benchmarks/StarWarsData.swift b/Benchmarks/Benchmarks/StarWarsData.swift index 29b8bef7..d7b1a15c 100644 --- a/Benchmarks/Benchmarks/StarWarsData.swift +++ b/Benchmarks/Benchmarks/StarWarsData.swift @@ -126,16 +126,12 @@ let droidData: [String: Droid] = [ "2001": r2d2, ] -/** - * Helper function to get a character by ID. - */ +/// Helper function to get a character by ID. @Sendable func getCharacter(id: String) -> Character? { return humanData[id] ?? droidData[id] } -/** - * Allows us to query for a character"s friends. - */ +/// Allows us to query for a character"s friends. @Sendable func getFriends(character: Character) -> [Character] { return character.friends.reduce(into: []) { friends, friendID in if let friend = getCharacter(id: friendID) { @@ -144,9 +140,7 @@ let droidData: [String: Droid] = [ } } -/** - * Allows us to fetch the undisputed hero of the Star Wars trilogy, R2-D2. - */ +/// Allows us to fetch the undisputed hero of the Star Wars trilogy, R2-D2. @Sendable func getHero(episode: Episode?) -> Character { if episode == .empire { // Luke is the hero of Episode V. @@ -156,16 +150,12 @@ let droidData: [String: Droid] = [ return r2d2 } -/** - * Allows us to query for the human with the given id. - */ +/// Allows us to query for the human with the given id. @Sendable func getHuman(id: String) -> Human? { return humanData[id] } -/** - * Allows us to query for the droid with the given id. - */ +/// Allows us to query for the droid with the given id. @Sendable func getDroid(id: String) -> Droid? { return droidData[id] } diff --git a/Benchmarks/Benchmarks/StarWarsSchema.swift b/Benchmarks/Benchmarks/StarWarsSchema.swift index 781f4c7a..9397b53a 100644 --- a/Benchmarks/Benchmarks/StarWarsSchema.swift +++ b/Benchmarks/Benchmarks/StarWarsSchema.swift @@ -49,12 +49,10 @@ import GraphQL * We begin by setting up our schema. */ -/** - * The original trilogy consists of three movies. - * - * This implements the following type system shorthand: - * enum Episode { NEWHOPE, EMPIRE, JEDI } - */ +/// The original trilogy consists of three movies. +/// +/// This implements the following type system shorthand: +/// enum Episode { NEWHOPE, EMPIRE, JEDI } let EpisodeEnum = try! GraphQLEnumType( name: "Episode", description: "One of the films in the Star Wars Trilogy", @@ -74,43 +72,43 @@ let EpisodeEnum = try! GraphQLEnumType( ] ) -/** - * Characters in the Star Wars trilogy are either humans or droids. - * - * This implements the following type system shorthand: - * interface Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * secretBackstory: String - * } - */ +/// Characters in the Star Wars trilogy are either humans or droids. +/// +/// This implements the following type system shorthand: +/// interface Character { +/// id: String! +/// name: String +/// friends: [Character] +/// appearsIn: [Episode] +/// secretBackstory: String +/// } let CharacterInterface = try! GraphQLInterfaceType( name: "Character", description: "A character in the Star Wars Trilogy", - fields: { [ - "id": GraphQLField( - type: GraphQLNonNull(GraphQLString), - description: "The id of the character." - ), - "name": GraphQLField( - type: GraphQLString, - description: "The name of the character." - ), - "friends": GraphQLField( - type: GraphQLList(CharacterInterface), - description: "The friends of the character, or an empty list if they have none." - ), - "appearsIn": GraphQLField( - type: GraphQLList(EpisodeEnum), - description: "Which movies they appear in." - ), - "secretBackstory": GraphQLField( - type: GraphQLString, - description: "All secrets about their past." - ), - ] }, + fields: { + [ + "id": GraphQLField( + type: GraphQLNonNull(GraphQLString), + description: "The id of the character." + ), + "name": GraphQLField( + type: GraphQLString, + description: "The name of the character." + ), + "friends": GraphQLField( + type: GraphQLList(CharacterInterface), + description: "The friends of the character, or an empty list if they have none." + ), + "appearsIn": GraphQLField( + type: GraphQLList(EpisodeEnum), + description: "Which movies they appear in." + ), + "secretBackstory": GraphQLField( + type: GraphQLString, + description: "All secrets about their past." + ), + ] + }, resolveType: { character, _ in switch character { case is Human: @@ -121,18 +119,16 @@ let CharacterInterface = try! GraphQLInterfaceType( } ) -/** - * We define our human type, which implements the character interface. - * - * This implements the following type system shorthand: - * type Human : Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * secretBackstory: String - * } - */ +/// We define our human type, which implements the character interface. +/// +/// This implements the following type system shorthand: +/// type Human : Character { +/// id: String! +/// name: String +/// friends: [Character] +/// appearsIn: [Episode] +/// secretBackstory: String +/// } let HumanType = try! GraphQLObjectType( name: "Human", description: "A humanoid creature in the Star Wars universe.", @@ -147,8 +143,7 @@ let HumanType = try! GraphQLObjectType( ), "friends": GraphQLField( type: GraphQLList(CharacterInterface), - description: "The friends of the human, or an empty list if they " + - "have none.", + description: "The friends of the human, or an empty list if they " + "have none.", resolve: { human, _, _, _ in getFriends(character: human as! Human) } @@ -179,19 +174,17 @@ let HumanType = try! GraphQLObjectType( } ) -/** - * The other type of character in Star Wars is a droid. - * - * This implements the following type system shorthand: - * type Droid : Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * secretBackstory: String - * primaryFunction: String - * } - */ +/// The other type of character in Star Wars is a droid. +/// +/// This implements the following type system shorthand: +/// type Droid : Character { +/// id: String! +/// name: String +/// friends: [Character] +/// appearsIn: [Episode] +/// secretBackstory: String +/// primaryFunction: String +/// } let DroidType = try! GraphQLObjectType( name: "Droid", description: "A mechanical creature in the Star Wars universe.", @@ -237,20 +230,17 @@ let DroidType = try! GraphQLObjectType( } ) -/** - * This is the type that will be the root of our query, and the - * entry point into our schema. It gives us the ability to fetch - * objects by their IDs, as well as to fetch the undisputed hero - * of the Star Wars trilogy, R2-D2, directly. - * - * This implements the following type system shorthand: - * type Query { - * hero(episode: Episode): Character - * human(id: String!): Human - * droid(id: String!): Droid - * } - * - */ +/// This is the type that will be the root of our query, and the +/// entry point into our schema. It gives us the ability to fetch +/// objects by their IDs, as well as to fetch the undisputed hero +/// of the Star Wars trilogy, R2-D2, directly. +/// +/// This implements the following type system shorthand: +/// type Query { +/// hero(episode: Episode): Character +/// human(id: String!): Human +/// droid(id: String!): Droid +/// } let QueryType = try! GraphQLObjectType( name: "Query", fields: [ @@ -260,9 +250,9 @@ let QueryType = try! GraphQLObjectType( "episode": GraphQLArgument( type: EpisodeEnum, description: - "If omitted, returns the hero of the whole saga. If " + - "provided, returns the hero of that particular episode." - ), + "If omitted, returns the hero of the whole saga. If " + + "provided, returns the hero of that particular episode." + ) ], resolve: { _, arguments, _, _ in let episode = Episode(arguments["episode"].string) @@ -275,7 +265,7 @@ let QueryType = try! GraphQLObjectType( "id": GraphQLArgument( type: GraphQLNonNull(GraphQLString), description: "id of the human" - ), + ) ], resolve: { _, arguments, _, _ in getHuman(id: arguments["id"].string!) @@ -287,7 +277,7 @@ let QueryType = try! GraphQLObjectType( "id": GraphQLArgument( type: GraphQLNonNull(GraphQLString), description: "id of the droid" - ), + ) ], resolve: { _, arguments, _, _ in getDroid(id: arguments["id"].string!) @@ -296,10 +286,8 @@ let QueryType = try! GraphQLObjectType( ] ) -/** - * Finally, we construct our schema (whose starting query type is the query - * type we defined above) and export it. - */ +/// Finally, we construct our schema (whose starting query type is the query +/// type we defined above) and export it. let starWarsSchema = try! GraphQLSchema( query: QueryType, types: [HumanType, DroidType] diff --git a/Benchmarks/Package.swift b/Benchmarks/Package.swift index b0b4e67a..62402e44 100644 --- a/Benchmarks/Package.swift +++ b/Benchmarks/Package.swift @@ -20,9 +20,9 @@ let package = Package( ], path: "Benchmarks", plugins: [ - .plugin(name: "BenchmarkPlugin", package: "package-benchmark"), + .plugin(name: "BenchmarkPlugin", package: "package-benchmark") ] - ), + ) ], swiftLanguageVersions: [.v5, .version("6")] ) diff --git a/Package.swift b/Package.swift index bcc14305..163a75a3 100644 --- a/Package.swift +++ b/Package.swift @@ -5,16 +5,16 @@ let package = Package( name: "GraphQL", platforms: [.macOS(.v10_15), .iOS(.v13), .tvOS(.v13), .watchOS(.v6)], products: [ - .library(name: "GraphQL", targets: ["GraphQL"]), + .library(name: "GraphQL", targets: ["GraphQL"]) ], dependencies: [ - .package(url: "https://github.com/apple/swift-collections", .upToNextMajor(from: "1.0.0")), + .package(url: "https://github.com/apple/swift-collections", .upToNextMajor(from: "1.0.0")) ], targets: [ .target( name: "GraphQL", dependencies: [ - .product(name: "OrderedCollections", package: "swift-collections"), + .product(name: "OrderedCollections", package: "swift-collections") ] ), .testTarget( diff --git a/Sources/GraphQL/Error/GraphQLError.swift b/Sources/GraphQL/Error/GraphQLError.swift index 0ddb4d3b..3430e528 100644 --- a/Sources/GraphQL/Error/GraphQLError.swift +++ b/Sources/GraphQL/Error/GraphQLError.swift @@ -1,9 +1,7 @@ -/** - * A GraphQLError describes an Error found during the parse, validate, or - * execute phases of performing a GraphQL operation. In addition to a message - * it also includes information about the locations in a - * GraphQL document and/or execution result that correspond to the error. - */ +/// A GraphQLError describes an Error found during the parse, validate, or +/// execute phases of performing a GraphQL operation. In addition to a message +/// it also includes information about the locations in a +/// GraphQL document and/or execution result that correspond to the error. public struct GraphQLError: Error, Codable { enum CodingKeys: String, CodingKey { case message @@ -217,9 +215,9 @@ public enum IndexPathValue: Codable, Equatable, Sendable { var container = encoder.singleValueContainer() switch self { - case let .index(index): + case .index(let index): try container.encode(index) - case let .key(key): + case .key(let key): try container.encode(key) } } @@ -234,9 +232,9 @@ extension IndexPathValue: IndexPathElement { extension IndexPathValue: CustomStringConvertible { public var description: String { switch self { - case let .index(index): + case .index(let index): return index.description - case let .key(key): + case .key(let key): return key.description } } @@ -255,16 +253,16 @@ extension IndexPathElement { } } -public extension IndexPathElement { - var indexValue: Int? { - if case let .index(index) = indexPathValue { +extension IndexPathElement { + public var indexValue: Int? { + if case .index(let index) = indexPathValue { return index } return nil } - var keyValue: String? { - if case let .key(key) = indexPathValue { + public var keyValue: String? { + if case .key(let key) = indexPathValue { return key } return nil diff --git a/Sources/GraphQL/Error/LocatedError.swift b/Sources/GraphQL/Error/LocatedError.swift index 5407df30..97bb5c07 100644 --- a/Sources/GraphQL/Error/LocatedError.swift +++ b/Sources/GraphQL/Error/LocatedError.swift @@ -1,8 +1,6 @@ -/** - * Given an arbitrary Error, presumably thrown while attempting to execute a - * GraphQL operation, produce a new GraphQLError aware of the location in the - * document responsible for the original Error. - */ +/// Given an arbitrary Error, presumably thrown while attempting to execute a +/// GraphQL operation, produce a new GraphQLError aware of the location in the +/// document responsible for the original Error. func locatedError(originalError: Error, nodes: [Node], path: IndexPath) -> GraphQLError { // Note: this uses a brand-check to support GraphQL errors originating from // other contexts. diff --git a/Sources/GraphQL/Error/SyntaxError.swift b/Sources/GraphQL/Error/SyntaxError.swift index f7816e84..0efe4a3c 100644 --- a/Sources/GraphQL/Error/SyntaxError.swift +++ b/Sources/GraphQL/Error/SyntaxError.swift @@ -1,26 +1,22 @@ import Foundation -/** - * Produces a GraphQLError representing a syntax error, containing useful - * descriptive information about the syntax error's position in the source. - */ +/// Produces a GraphQLError representing a syntax error, containing useful +/// descriptive information about the syntax error's position in the source. func syntaxError(source: Source, position: Int, description: String) -> GraphQLError { let location = getLocation(source: source, position: position) return GraphQLError( message: - "Syntax Error \(source.name) (\(location.line):\(location.column)) " + - description + "\n\n" + - highlightSourceAtLocation(source: source, location: location), + "Syntax Error \(source.name) (\(location.line):\(location.column)) " + description + + "\n\n" + + highlightSourceAtLocation(source: source, location: location), source: source, positions: [position] ) } -/** - * Render a helpful description of the location of the error in the GraphQL - * Source document. - */ +/// Render a helpful description of the location of the error in the GraphQL +/// Source document. func highlightSourceAtLocation(source: Source, location: SourceLocation) -> String { let line = location.line let prevLineNum = (line - 1).description @@ -54,9 +50,9 @@ func splitLines(string: String) -> [String] { for match in newLineRegex.matches( in: string, options: [], - range: NSRange(0 ..< nsstring.length) + range: NSRange(0.. [String] { if lines.isEmpty { return [string] } else { - let range = NSRange(location ..< nsstring.length) + let range = NSRange(location.. OrderedDictionary { return try await withThrowingTaskGroup(of: (String, (any Sendable)?).self) { group in // preserve field order by assigning to null and filtering later - var results: OrderedDictionary = fields + var results: OrderedDictionary = + fields .mapValues { _ -> Any? in nil } for field in fields { group.addTask { let fieldASTs = field.value let fieldPath = path.appending(field.key) - let result = try await resolveField( - exeContext: exeContext, - parentType: parentType, - source: sourceValue, - fieldASTs: fieldASTs, - path: fieldPath - ) ?? Map.null + let result = + try await resolveField( + exeContext: exeContext, + parentType: parentType, + source: sourceValue, + fieldASTs: fieldASTs, + path: fieldPath + ) ?? Map.null return (field.key, result) } } @@ -172,12 +169,10 @@ public struct ConcurrentFieldExecutionStrategy: QueryFieldExecutionStrategy, } } -/** - * Implements the "Evaluating requests" section of the GraphQL specification. - * - * If the arguments to this func do not result in a legal execution context, - * a GraphQLError will be thrown immediately explaining the invalid input. - */ +/// Implements the "Evaluating requests" section of the GraphQL specification. +/// +/// If the arguments to this func do not result in a legal execution context, +/// a GraphQLError will be thrown immediately explaining the invalid input. public func execute( schema: GraphQLSchema, documentAST: Document, @@ -206,7 +201,7 @@ public func execute( } do { -// var executeErrors: [GraphQLError] = [] + // var executeErrors: [GraphQLError] = [] let data = try await executeOperation( exeContext: buildContext, operation: buildContext.operation, @@ -224,7 +219,7 @@ public func execute( result.errors = buildContext.errors } -// executeErrors = buildContext.errors + // executeErrors = buildContext.errors return result } catch let error as GraphQLError { return GraphQLResult(errors: [error]) @@ -233,12 +228,10 @@ public func execute( } } -/** - * Constructs a ExecutionContext object from the arguments passed to - * execute, which we will pass throughout the other execution methods. - * - * Throws a GraphQLError if a valid execution context cannot be created. - */ +/// Constructs a ExecutionContext object from the arguments passed to +/// execute, which we will pass throughout the other execution methods. +/// +/// Throws a GraphQLError if a valid execution context cannot be created. func buildExecutionContext( schema: GraphQLSchema, documentAST: Document, @@ -300,9 +293,7 @@ func buildExecutionContext( ) } -/** - * Implements the "Evaluating operations" section of the spec. - */ +/// Implements the "Evaluating operations" section of the spec. func executeOperation( exeContext: ExecutionContext, operation: OperationDefinition, @@ -340,9 +331,7 @@ func executeOperation( ) } -/** - * Extracts the root type of the operation from the schema. - */ +/// Extracts the root type of the operation from the schema. func getOperationRootType( schema: GraphQLSchema, operation: OperationDefinition @@ -378,14 +367,12 @@ func getOperationRootType( } } -/** - * Given a selectionSet, adds all of the fields in that selection to - * the passed in map of fields, and returns it at the end. - * - * CollectFields requires the "runtime type" of an object. For a field which - * returns and Interface or Union type, the "runtime type" will be the actual - * Object type returned by that field. - */ +/// Given a selectionSet, adds all of the fields in that selection to +/// the passed in map of fields, and returns it at the end. +/// +/// CollectFields requires the "runtime type" of an object. For a field which +/// returns and Interface or Union type, the "runtime type" will be the actual +/// Object type returned by that field. @discardableResult func collectFields( exeContext: ExecutionContext, @@ -481,10 +468,8 @@ func collectFields( return fields } -/** - * Determines if a field should be included based on the @include and @skip - * directives, where @skip has higher precidence than @include. - */ +/// Determines if a field should be included based on the @include and @skip +/// directives, where @skip has higher precidence than @include. func shouldIncludeNode(exeContext: ExecutionContext, directives: [Directive] = []) throws -> Bool { if let skipAST = directives.find({ $0.name.value == GraphQLSkipDirective.name }) { let skip = try getArgumentValues( @@ -513,9 +498,7 @@ func shouldIncludeNode(exeContext: ExecutionContext, directives: [Directive] = [ return true } -/** - * Determines if a fragment is applicable to the given type. - */ +/// Determines if a fragment is applicable to the given type. func doesFragmentConditionMatch( exeContext: ExecutionContext, fragment: HasTypeCondition, @@ -534,8 +517,7 @@ func doesFragmentConditionMatch( return true } - if - let conditionalType = conditionalType as? GraphQLObjectType, + if let conditionalType = conditionalType as? GraphQLObjectType, conditionalType.name == type.name { return true @@ -551,19 +533,15 @@ func doesFragmentConditionMatch( return false } -/** - * Implements the logic to compute the key of a given field's entry - */ +/// Implements the logic to compute the key of a given field's entry func getFieldEntryKey(node: Field) -> String { return node.alias?.value ?? node.name.value } -/** - * Resolves the field on the given source object. In particular, this - * figures out the value that the field returns by calling its resolve func, - * then calls completeValue to complete promises, serialize scalars, or execute - * the sub-selection-set for objects. - */ +/// Resolves the field on the given source object. In particular, this +/// figures out the value that the field returns by calling its resolve func, +/// then calls completeValue to complete promises, serialize scalars, or execute +/// the sub-selection-set for objects. public func resolveField( exeContext: ExecutionContext, parentType: GraphQLObjectType, @@ -721,27 +699,25 @@ func completeValueWithLocatedError( } } -/** - * Implements the instructions for completeValue as defined in the - * "Field entries" section of the spec. - * - * If the field type is Non-Null, then this recursively completes the value - * for the inner type. It throws a field error if that completion returns null, - * as per the "Nullability" section of the spec. - * - * If the field type is a List, then this recursively completes the value - * for the inner type on each item in the list. - * - * If the field type is a Scalar or Enum, ensures the completed value is a legal - * value of the type by calling the `serialize` method of GraphQL type - * definition. - * - * If the field is an abstract type, determine the runtime type of the value - * and then complete based on that type - * - * Otherwise, the field type expects a sub-selection set, and will complete the - * value by evaluating all sub-selections. - */ +/// Implements the instructions for completeValue as defined in the +/// "Field entries" section of the spec. +/// +/// If the field type is Non-Null, then this recursively completes the value +/// for the inner type. It throws a field error if that completion returns null, +/// as per the "Nullability" section of the spec. +/// +/// If the field type is a List, then this recursively completes the value +/// for the inner type on each item in the list. +/// +/// If the field type is a Scalar or Enum, ensures the completed value is a legal +/// value of the type by calling the `serialize` method of GraphQL type +/// definition. +/// +/// If the field is an abstract type, determine the runtime type of the value +/// and then complete based on that type +/// +/// Otherwise, the field type expects a sub-selection set, and will complete the +/// value by evaluating all sub-selections. func completeValue( exeContext: ExecutionContext, returnType: GraphQLType, @@ -751,9 +727,9 @@ func completeValue( result: Result<(any Sendable)?, Error> ) async throws -> (any Sendable)? { switch result { - case let .failure(error): + case .failure(let error): throw error - case let .success(result): + case .success(let result): // If field type is NonNull, complete for inner type, and throw field error // if result is nullish. if let returnType = returnType as? GraphQLNonNull { @@ -767,7 +743,8 @@ func completeValue( ) guard let value = value else { throw GraphQLError( - message: "Cannot return null for non-nullable field \(info.parentType.name).\(info.fieldName)." + message: + "Cannot return null for non-nullable field \(info.parentType.name).\(info.fieldName)." ) } @@ -829,10 +806,8 @@ func completeValue( } } -/** - * Complete a list value by completing each item in the list with the - * inner type - */ +/// Complete a list value by completing each item in the list with the +/// inner type func completeListValue( exeContext: ExecutionContext, returnType: GraphQLList, @@ -844,8 +819,8 @@ func completeListValue( guard let result = result as? [(any Sendable)?] else { throw GraphQLError( message: - "Expected array, but did not find one for field " + - "\(info.parentType.name).\(info.fieldName)." + "Expected array, but did not find one for field " + + "\(info.parentType.name).\(info.fieldName)." ) } @@ -878,10 +853,8 @@ func completeListValue( } } -/** - * Complete a Scalar or Enum by serializing to a valid value, returning - * .null if serialization is not possible. - */ +/// Complete a Scalar or Enum by serializing to a valid value, returning +/// .null if serialization is not possible. func completeLeafValue(returnType: GraphQLLeafType, result: (any Sendable)?) throws -> Map { guard let result = result else { return .null @@ -891,10 +864,8 @@ func completeLeafValue(returnType: GraphQLLeafType, result: (any Sendable)?) thr // Do not check for serialization to null here. Some scalars may model literals as `Map.null`. } -/** - * Complete a value of an abstract type by determining the runtime object type - * of that value, then complete the value for that type. - */ +/// Complete a value of an abstract type by determining the runtime object type +/// of that value, then complete the value for that type. func completeAbstractValue( exeContext: ExecutionContext, returnType: GraphQLAbstractType, @@ -906,11 +877,13 @@ func completeAbstractValue( var resolveRes = try returnType.resolveType?(result, info) .typeResolveResult - resolveRes = try resolveRes ?? defaultResolveType( - value: result, - info: info, - abstractType: returnType - ) + resolveRes = + try resolveRes + ?? defaultResolveType( + value: result, + info: info, + abstractType: returnType + ) guard let resolveResult = resolveRes else { throw GraphQLError( @@ -923,18 +896,18 @@ func completeAbstractValue( var runtimeType: GraphQLType? switch resolveResult { - case let .name(name): + case .name(let name): runtimeType = exeContext.schema.getType(name: name) - case let .type(type): + case .type(let type): runtimeType = type } guard let objectType = runtimeType as? GraphQLObjectType else { throw GraphQLError( message: - "Abstract type \(returnType.name) must resolve to an Object type at " + - "runtime for field \(info.parentType.name).\(info.fieldName) with " + - "value \"\(resolveResult)\", received \"\(String(describing: runtimeType))\".", + "Abstract type \(returnType.name) must resolve to an Object type at " + + "runtime for field \(info.parentType.name).\(info.fieldName) with " + + "value \"\(resolveResult)\", received \"\(String(describing: runtimeType))\".", nodes: fieldASTs ) } @@ -942,8 +915,8 @@ func completeAbstractValue( if !exeContext.schema.isSubType(abstractType: returnType, maybeSubType: objectType) { throw GraphQLError( message: - "Runtime Object type \"\(objectType.name)\" is not a possible type " + - "for \"\(returnType.name)\".", + "Runtime Object type \"\(objectType.name)\" is not a possible type " + + "for \"\(returnType.name)\".", nodes: fieldASTs ) } @@ -958,9 +931,7 @@ func completeAbstractValue( ) } -/** - * Complete an Object value by executing all sub-selections. - */ +/// Complete an Object value by executing all sub-selections. func completeObjectValue( exeContext: ExecutionContext, returnType: GraphQLObjectType, @@ -972,13 +943,12 @@ func completeObjectValue( // If there is an isTypeOf predicate func, call it with the // current result. If isTypeOf returns false, then raise an error rather // than continuing execution. - if - let isTypeOf = returnType.isTypeOf, + if let isTypeOf = returnType.isTypeOf, try !isTypeOf(result, info) { throw GraphQLError( message: - "Expected value of type \"\(returnType.name)\" but got: \(result).", + "Expected value of type \"\(returnType.name)\" but got: \(result).", nodes: fieldASTs ) } @@ -1008,11 +978,9 @@ func completeObjectValue( ) } -/** - * If a resolveType func is not given, then a default resolve behavior is - * used which tests each possible type for the abstract type by calling - * isTypeOf for the object being coerced, returning the first type that matches. - */ +/// If a resolveType func is not given, then a default resolve behavior is +/// used which tests each possible type for the abstract type by calling +/// isTypeOf for the object being coerced, returning the first type that matches. func defaultResolveType( value: any Sendable, info: GraphQLResolveInfo, @@ -1021,7 +989,8 @@ func defaultResolveType( let possibleTypes = info.schema.getPossibleTypes(abstractType: abstractType) guard - let type = try possibleTypes + let type = + try possibleTypes .find({ try $0.isTypeOf?(value, info) ?? false }) else { return nil @@ -1030,11 +999,9 @@ func defaultResolveType( return .type(type) } -/** - * If a resolve func is not given, then a default resolve behavior is used - * which takes the property of the source object of the same name as the field - * and returns it as the result. - */ +/// If a resolve func is not given, then a default resolve behavior is used +/// which takes the property of the source object of the same name as the field +/// and returns it as the result. func defaultResolve( source: any Sendable, args _: Map, @@ -1059,15 +1026,13 @@ func defaultResolve( return mirror.getValue(named: info.fieldName) } -/** - * This method looks up the field on the given type defintion. - * It has special casing for the two introspection fields, __schema - * and __typename. __typename is special because it can always be - * queried as a field, even in situations where no other fields - * are allowed, like on a Union. __schema could get automatically - * added to the query type, but that would require mutating type - * definitions, which would cause issues. - */ +/// This method looks up the field on the given type defintion. +/// It has special casing for the two introspection fields, __schema +/// and __typename. __typename is special because it can always be +/// queried as a field, even in situations where no other fields +/// are allowed, like on a Union. __schema could get automatically +/// added to the query type, but that would require mutating type +/// definitions, which would cause issues. func getFieldDef( schema: GraphQLSchema, parentType: GraphQLObjectType, diff --git a/Sources/GraphQL/Execution/Values.swift b/Sources/GraphQL/Execution/Values.swift index 64724c44..ae1d8475 100644 --- a/Sources/GraphQL/Execution/Values.swift +++ b/Sources/GraphQL/Execution/Values.swift @@ -1,11 +1,9 @@ import Foundation import OrderedCollections -/** - * Prepares an object map of variableValues of the correct type based on the - * provided variable definitions and arbitrary input. If the input cannot be - * parsed to match the variable definitions, a GraphQLError will be thrown. - */ +/// Prepares an object map of variableValues of the correct type based on the +/// provided variable definitions and arbitrary input. If the input cannot be +/// parsed to match the variable definitions, a GraphQLError will be thrown. func getVariableValues( schema: GraphQLSchema, definitionASTs: [VariableDefinition], @@ -31,10 +29,8 @@ func getVariableValues( return vars } -/** - * Prepares an object map of argument values given a list of argument - * definitions and list of argument AST nodes. - */ +/// Prepares an object map of argument values given a list of argument +/// definitions and list of argument AST nodes. func getArgumentValues( argDefs: [GraphQLArgumentDefinition], argASTs: [Argument]?, @@ -71,7 +67,7 @@ func getArgumentValues( let message = "\n" + errors.joined(separator: "\n") throw GraphQLError( message: - "Argument \"\(argName)\" got invalid value \(argValue).\(message)" // TODO: "\(JSON.stringify(input)).\(message)", + "Argument \"\(argName)\" got invalid value \(argValue).\(message)" // TODO: "\(JSON.stringify(input)).\(message)", ) } args[argName] = argValue @@ -79,10 +75,8 @@ func getArgumentValues( return .dictionary(args) } -/** - * Given a variable definition, and any value of input, return a value which - * adheres to the variable definition, or throw an error. - */ +/// Given a variable definition, and any value of input, return a value which +/// adheres to the variable definition, or throw an error. func getVariableValue( schema: GraphQLSchema, definitionAST: VariableDefinition, @@ -94,8 +88,8 @@ func getVariableValue( guard let inputType = type as? GraphQLInputType else { throw GraphQLError( message: - "Variable \"$\(variable.name.value)\" expected value of type " + - "\"\(definitionAST.type)\" which cannot be used as an input type.", + "Variable \"$\(variable.name.value)\" expected value of type " + + "\"\(definitionAST.type)\" which cannot be used as an input type.", nodes: [definitionAST] ) } @@ -110,7 +104,7 @@ func getVariableValue( let message = !errors.isEmpty ? "\n" + errors.joined(separator: "\n") : "" throw GraphQLError( message: - "Variable \"$\(variable.name.value)\" got invalid value \"\(toCoerce)\".\(message)", + "Variable \"$\(variable.name.value)\" got invalid value \"\(toCoerce)\".\(message)", // TODO: "\(JSON.stringify(input)).\(message)", nodes: [definitionAST] ) @@ -119,9 +113,7 @@ func getVariableValue( return try coerceValue(value: toCoerce, type: inputType) } -/** - * Given a type and any value, return a runtime value coerced to match the type. - */ +/// Given a type and any value, return a runtime value coerced to match the type. func coerceValue(value: Map, type: GraphQLInputType) throws -> Map { if let nonNull = type as? GraphQLNonNull { // Note: we're not checking that the result of coerceValue is non-null. @@ -141,7 +133,7 @@ func coerceValue(value: Map, type: GraphQLInputType) throws -> Map { throw GraphQLError(message: "Input list must wrap an input type") } - if case let .array(value) = value { + if case .array(let value) = value { let coercedValues = try value.map { item in try coerceValue(value: item, type: itemType) } @@ -153,7 +145,7 @@ func coerceValue(value: Map, type: GraphQLInputType) throws -> Map { } if let objectType = type as? GraphQLInputObjectType { - guard case let .dictionary(value) = value else { + guard case .dictionary(let value) = value else { throw GraphQLError(message: "Must be dictionary to extract to an input type") } @@ -185,17 +177,15 @@ func coerceValue(value: Map, type: GraphQLInputType) throws -> Map { throw GraphQLError(message: "Provided type is not an input type") } -/** - * Prepares an object map of argument values given a directive definition - * and a AST node which may contain directives. Optionally also accepts a map - * of variable values. - * - * If the directive does not exist on the node, returns undefined. - * - * Note: The returned value is a plain Object with a prototype, since it is - * exposed to user code. Care should be taken to not pull values from the - * Object prototype. - */ +/// Prepares an object map of argument values given a directive definition +/// and a AST node which may contain directives. Optionally also accepts a map +/// of variable values. +/// +/// If the directive does not exist on the node, returns undefined. +/// +/// Note: The returned value is a plain Object with a prototype, since it is +/// exposed to user code. Care should be taken to not pull values from the +/// Object prototype. func getDirectiveValues( directiveDef: GraphQLDirective, directives: [Directive], diff --git a/Sources/GraphQL/GraphQL.swift b/Sources/GraphQL/GraphQL.swift index cd66ba88..b57199e5 100644 --- a/Sources/GraphQL/GraphQL.swift +++ b/Sources/GraphQL/GraphQL.swift @@ -1,4 +1,3 @@ - public struct GraphQLResult: Equatable, Codable, Sendable, CustomStringConvertible { public var data: Map? public var errors: [GraphQLError] @@ -152,11 +151,11 @@ public func graphql( switch try queryRetrieval.lookup(queryId) { case .unknownId: throw GraphQLError(message: "Unknown query id") - case let .parseError(parseError): + case .parseError(let parseError): throw parseError - case let .validateErrors(_, validationErrors): + case .validateErrors(_, let validationErrors): return GraphQLResult(errors: validationErrors) - case let .result(schema, documentAST): + case .result(let schema, let documentAST): return try await execute( schema: schema, documentAST: documentAST, diff --git a/Sources/GraphQL/Language/AST.swift b/Sources/GraphQL/Language/AST.swift index 72ee37d8..1b6e4e58 100644 --- a/Sources/GraphQL/Language/AST.swift +++ b/Sources/GraphQL/Language/AST.swift @@ -1,7 +1,5 @@ -/** - * Contains a range of UTF-8 character offsets and token references that - * identify the region of the source from which the AST derived. - */ +/// Contains a range of UTF-8 character offsets and token references that +/// identify the region of the source from which the AST derived. public struct Location: Equatable, Sendable { /** * The character offset at which this Node begins. @@ -29,10 +27,8 @@ public struct Location: Equatable, Sendable { public let source: Source } -/** - * Represents a range of characters represented by a lexical token - * within a Source. - */ +/// Represents a range of characters represented by a lexical token +/// within a Source. public final class Token: @unchecked Sendable { /// Token is sendable because it is not mutated after being Lexed, which is controlled /// internally. @@ -121,12 +117,8 @@ public final class Token: @unchecked Sendable { extension Token: Equatable { public static func == (lhs: Token, rhs: Token) -> Bool { - return lhs.kind == rhs.kind && - lhs.start == rhs.start && - lhs.end == rhs.end && - lhs.line == rhs.line && - lhs.column == rhs.column && - lhs.value == rhs.value + return lhs.kind == rhs.kind && lhs.start == rhs.start && lhs.end == rhs.end + && lhs.line == rhs.line && lhs.column == rhs.column && lhs.value == rhs.value } } @@ -164,12 +156,12 @@ public enum NodeResult { func get(key: IndexPathElement) -> NodeResult? { switch self { - case let .node(node): + case .node(let node): guard let key = key.keyValue else { return nil } return node.get(key: key) - case let .array(array): + case .array(let array): guard let key = key.indexValue else { return nil } @@ -179,29 +171,27 @@ public enum NodeResult { func set(value: NodeResult, key: IndexPathElement) -> Self? { switch self { - case let .node(node): + case .node(let node): guard let key = key.keyValue else { return nil } return .node(node.set(value: value, key: key)) - case var .array(array): + case .array(var array): switch value { - case let .node(value): + case .node(let value): guard let key = key.indexValue else { return nil } array[key] = value return .array(array) - case let .array(value): + case .array(let value): return .array(value) } } } } -/** - * The list of all possible AST node types. - */ +/// The list of all possible AST node types. public protocol Node: Sendable { var kind: Kind { get } var loc: Location? { get } @@ -209,12 +199,12 @@ public protocol Node: Sendable { func set(value: NodeResult?, key: String) -> Self } -public extension Node { - func get(key _: String) -> NodeResult? { +extension Node { + public func get(key _: String) -> NodeResult? { return nil } - func set(value _: NodeResult?, key _: String) -> Self { + public func set(value _: NodeResult?, key _: String) -> Self { // This should be overridden by each type on which it should do something return self } @@ -305,7 +295,7 @@ public struct Document { switch key { case "definitions": guard - case let .array(values) = value, + case .array(let values) = value, let definitions = values as? [Definition] else { break @@ -418,7 +408,7 @@ public final class OperationDefinition { switch key { case "name": guard - case let .node(node) = value, + case .node(let node) = value, let name = node as? Name else { return self @@ -433,7 +423,7 @@ public final class OperationDefinition { ) case "variableDefinitions": guard - case let .array(values) = value, + case .array(let values) = value, let variableDefinitions = values as? [VariableDefinition] else { return self @@ -448,7 +438,7 @@ public final class OperationDefinition { ) case "directives": guard - case let .array(values) = value, + case .array(let values) = value, let directives = values as? [Directive] else { return self @@ -463,7 +453,7 @@ public final class OperationDefinition { ) case "selectionSet": guard - case let .node(value) = value, + case .node(let value) = value, let selectionSet = value as? SelectionSet else { return self @@ -488,11 +478,10 @@ extension OperationDefinition: Hashable { } public static func == (lhs: OperationDefinition, rhs: OperationDefinition) -> Bool { - return lhs.operation == rhs.operation && - lhs.name == rhs.name && - lhs.variableDefinitions == rhs.variableDefinitions && - lhs.directives == rhs.directives && - lhs.selectionSet == rhs.selectionSet + return lhs.operation == rhs.operation && lhs.name == rhs.name + && lhs.variableDefinitions == rhs.variableDefinitions + && lhs.directives == rhs.directives + && lhs.selectionSet == rhs.selectionSet } } @@ -544,7 +533,7 @@ public struct VariableDefinition { switch key { case "variable": guard - case let .node(node) = value, + case .node(let node) = value, let variable = node as? Variable else { break @@ -552,7 +541,7 @@ public struct VariableDefinition { new.variable = variable case "type": guard - case let .node(node) = value, + case .node(let node) = value, let type = node as? Type else { break @@ -560,7 +549,7 @@ public struct VariableDefinition { new.type = type case "defaultValue": guard - case let .node(node) = value, + case .node(let node) = value, let defaultValue = node as? Value? else { break @@ -568,7 +557,7 @@ public struct VariableDefinition { new.defaultValue = defaultValue case "directives": guard - case let .array(values) = value, + case .array(let values) = value, let directives = values as? [Directive] else { break @@ -630,7 +619,7 @@ public struct Variable { switch key { case "name": guard - case let .node(node) = value, + case .node(let node) = value, let name = node as? Name else { break @@ -678,7 +667,7 @@ public final class SelectionSet { switch key { case "selections": guard - case let .array(values) = value, + case .array(let values) = value, let selections = values as? [Selection] else { return self @@ -795,7 +784,7 @@ public struct Field { switch key { case "alias": guard - case let .node(node) = value, + case .node(let node) = value, let alias = node as? Name else { break @@ -803,7 +792,7 @@ public struct Field { new.alias = alias case "name": guard - case let .node(node) = value, + case .node(let node) = value, let name = node as? Name else { break @@ -811,7 +800,7 @@ public struct Field { new.name = name case "arguments": guard - case let .array(values) = value, + case .array(let values) = value, let arguments = values as? [Argument] else { break @@ -819,7 +808,7 @@ public struct Field { new.arguments = arguments case "directives": guard - case let .array(values) = value, + case .array(let values) = value, let directives = values as? [Directive] else { break @@ -827,7 +816,7 @@ public struct Field { new.directives = directives case "selectionSet": guard - case let .node(value) = value, + case .node(let value) = value, let selectionSet = value as? SelectionSet else { break @@ -842,11 +831,8 @@ public struct Field { extension Field: Equatable { public static func == (lhs: Field, rhs: Field) -> Bool { - return lhs.alias == rhs.alias && - lhs.name == rhs.name && - lhs.arguments == rhs.arguments && - lhs.directives == rhs.directives && - lhs.selectionSet == rhs.selectionSet + return lhs.alias == rhs.alias && lhs.name == rhs.name && lhs.arguments == rhs.arguments + && lhs.directives == rhs.directives && lhs.selectionSet == rhs.selectionSet } } @@ -881,7 +867,7 @@ public struct Argument { switch key { case "name": guard - case let .node(node) = value, + case .node(let node) = value, let name = node as? Name else { break @@ -889,7 +875,7 @@ public struct Argument { new.name = name case "value": guard - case let .node(node) = value, + case .node(let node) = value, let value = node as? Value else { break @@ -904,8 +890,7 @@ public struct Argument { extension Argument: Equatable { public static func == (lhs: Argument, rhs: Argument) -> Bool { - return lhs.name == rhs.name && - lhs.value == rhs.value + return lhs.name == rhs.name && lhs.value == rhs.value } } @@ -947,7 +932,7 @@ public struct FragmentSpread { switch key { case "name": guard - case let .node(node) = value, + case .node(let node) = value, let name = node as? Name else { break @@ -955,7 +940,7 @@ public struct FragmentSpread { new.name = name case "directives": guard - case let .array(values) = value, + case .array(let values) = value, let directives = values as? [Directive] else { break @@ -970,8 +955,7 @@ public struct FragmentSpread { extension FragmentSpread: Equatable { public static func == (lhs: FragmentSpread, rhs: FragmentSpread) -> Bool { - return lhs.name == rhs.name && - lhs.directives == rhs.directives + return lhs.name == rhs.name && lhs.directives == rhs.directives } } @@ -1034,7 +1018,7 @@ public struct InlineFragment { switch key { case "typeCondition": guard - case let .node(node) = value, + case .node(let node) = value, let typeCondition = node as? NamedType else { break @@ -1042,7 +1026,7 @@ public struct InlineFragment { new.typeCondition = typeCondition case "directives": guard - case let .array(values) = value, + case .array(let values) = value, let directives = values as? [Directive] else { break @@ -1050,7 +1034,7 @@ public struct InlineFragment { new.directives = directives case "selectionSet": guard - case let .node(value) = value, + case .node(let value) = value, let selectionSet = value as? SelectionSet else { break @@ -1065,9 +1049,8 @@ public struct InlineFragment { extension InlineFragment: Equatable { public static func == (lhs: InlineFragment, rhs: InlineFragment) -> Bool { - return lhs.typeCondition == rhs.typeCondition && - lhs.directives == rhs.directives && - lhs.selectionSet == rhs.selectionSet + return lhs.typeCondition == rhs.typeCondition && lhs.directives == rhs.directives + && lhs.selectionSet == rhs.selectionSet } } @@ -1118,7 +1101,7 @@ public final class FragmentDefinition { switch key { case "name": guard - case let .node(node) = value, + case .node(let node) = value, let name = node as? Name else { return self @@ -1132,7 +1115,7 @@ public final class FragmentDefinition { ) case "typeCondition": guard - case let .node(node) = value, + case .node(let node) = value, let typeCondition = node as? NamedType else { return self @@ -1146,7 +1129,7 @@ public final class FragmentDefinition { ) case "directives": guard - case let .array(values) = value, + case .array(let values) = value, let directives = values as? [Directive] else { return self @@ -1160,7 +1143,7 @@ public final class FragmentDefinition { ) case "selectionSet": guard - case let .node(value) = value, + case .node(let value) = value, let selectionSet = value as? SelectionSet else { return self @@ -1184,10 +1167,8 @@ extension FragmentDefinition: Hashable { } public static func == (lhs: FragmentDefinition, rhs: FragmentDefinition) -> Bool { - return lhs.name == rhs.name && - lhs.typeCondition == rhs.typeCondition && - lhs.directives == rhs.directives && - lhs.selectionSet == rhs.selectionSet + return lhs.name == rhs.name && lhs.typeCondition == rhs.typeCondition + && lhs.directives == rhs.directives && lhs.selectionSet == rhs.selectionSet } } @@ -1376,7 +1357,7 @@ public struct ListValue { switch key { case "values": guard - case let .array(values) = value, + case .array(let values) = value, let values = values as? [Value] else { break @@ -1432,7 +1413,7 @@ public struct ObjectValue { switch key { case "fields": guard - case let .array(values) = value, + case .array(let values) = value, let fields = values as? [ObjectField] else { break @@ -1482,7 +1463,7 @@ public struct ObjectField { switch key { case "name": guard - case let .node(node) = value, + case .node(let node) = value, let name = node as? Name else { break @@ -1490,7 +1471,7 @@ public struct ObjectField { new.name = name case "value": guard - case let .node(node) = value, + case .node(let node) = value, let value = node as? Value else { break @@ -1505,8 +1486,7 @@ public struct ObjectField { extension ObjectField: Equatable { public static func == (lhs: ObjectField, rhs: ObjectField) -> Bool { - return lhs.name == rhs.name && - lhs.value == rhs.value + return lhs.name == rhs.name && lhs.value == rhs.value } } @@ -1541,7 +1521,7 @@ public struct Directive: Sendable { switch key { case "name": guard - case let .node(node) = value, + case .node(let node) = value, let name = node as? Name else { break @@ -1549,7 +1529,7 @@ public struct Directive: Sendable { new.name = name case "arguments": guard - case let .array(nodes) = value, + case .array(let nodes) = value, let arguments = nodes as? [Argument] else { break @@ -1564,8 +1544,7 @@ public struct Directive: Sendable { extension Directive: Equatable { public static func == (lhs: Directive, rhs: Directive) -> Bool { - return lhs.name == rhs.name && - lhs.arguments == rhs.arguments + return lhs.name == rhs.name && lhs.arguments == rhs.arguments } } @@ -1622,7 +1601,7 @@ public struct NamedType { switch key { case "name": guard - case let .node(node) = value, + case .node(let node) = value, let name = node as? Name else { break @@ -1668,7 +1647,7 @@ public struct ListType { switch key { case "type": guard - case let .node(node) = value, + case .node(let node) = value, let type = node as? Type else { break @@ -1718,7 +1697,7 @@ public struct NonNullType { switch key { case "type": guard - case let .node(node) = value, + case .node(let node) = value, let type = node as? NonNullableType else { break @@ -1834,9 +1813,8 @@ public struct SchemaDefinition { extension SchemaDefinition: Equatable { public static func == (lhs: SchemaDefinition, rhs: SchemaDefinition) -> Bool { - return lhs.description == rhs.description && - lhs.directives == rhs.directives && - lhs.operationTypes == rhs.operationTypes + return lhs.description == rhs.description && lhs.directives == rhs.directives + && lhs.operationTypes == rhs.operationTypes } } @@ -1864,8 +1842,7 @@ public struct OperationTypeDefinition { extension OperationTypeDefinition: Equatable { public static func == (lhs: OperationTypeDefinition, rhs: OperationTypeDefinition) -> Bool { - return lhs.operation == rhs.operation && - lhs.type == rhs.type + return lhs.operation == rhs.operation && lhs.type == rhs.type } } @@ -1948,9 +1925,8 @@ public struct ScalarTypeDefinition: Sendable { extension ScalarTypeDefinition: Equatable { public static func == (lhs: ScalarTypeDefinition, rhs: ScalarTypeDefinition) -> Bool { - return lhs.description == rhs.description && - lhs.name == rhs.name && - lhs.directives == rhs.directives + return lhs.description == rhs.description && lhs.name == rhs.name + && lhs.directives == rhs.directives } } @@ -1999,11 +1975,9 @@ public struct ObjectTypeDefinition { extension ObjectTypeDefinition: Equatable { public static func == (lhs: ObjectTypeDefinition, rhs: ObjectTypeDefinition) -> Bool { - return lhs.description == rhs.description && - lhs.name == rhs.name && - lhs.interfaces == rhs.interfaces && - lhs.directives == rhs.directives && - lhs.fields == rhs.fields + return lhs.description == rhs.description && lhs.name == rhs.name + && lhs.interfaces == rhs.interfaces && lhs.directives == rhs.directives + && lhs.fields == rhs.fields } } @@ -2052,11 +2026,9 @@ public struct FieldDefinition { extension FieldDefinition: Equatable { public static func == (lhs: FieldDefinition, rhs: FieldDefinition) -> Bool { - return lhs.description == rhs.description && - lhs.name == rhs.name && - lhs.arguments == rhs.arguments && - lhs.type == rhs.type && - lhs.directives == rhs.directives + return lhs.description == rhs.description && lhs.name == rhs.name + && lhs.arguments == rhs.arguments && lhs.type == rhs.type + && lhs.directives == rhs.directives } } @@ -2174,10 +2146,8 @@ public struct InterfaceTypeDefinition { extension InterfaceTypeDefinition: Equatable { public static func == (lhs: InterfaceTypeDefinition, rhs: InterfaceTypeDefinition) -> Bool { - return lhs.description == rhs.description && - lhs.name == rhs.name && - lhs.directives == rhs.directives && - lhs.fields == rhs.fields + return lhs.description == rhs.description && lhs.name == rhs.name + && lhs.directives == rhs.directives && lhs.fields == rhs.fields } } @@ -2221,10 +2191,8 @@ public struct UnionTypeDefinition { extension UnionTypeDefinition: Equatable { public static func == (lhs: UnionTypeDefinition, rhs: UnionTypeDefinition) -> Bool { - return lhs.description == rhs.description && - lhs.name == rhs.name && - lhs.directives == rhs.directives && - lhs.types == rhs.types + return lhs.description == rhs.description && lhs.name == rhs.name + && lhs.directives == rhs.directives && lhs.types == rhs.types } } @@ -2268,10 +2236,8 @@ public struct EnumTypeDefinition: Sendable { extension EnumTypeDefinition: Equatable { public static func == (lhs: EnumTypeDefinition, rhs: EnumTypeDefinition) -> Bool { - return lhs.description == rhs.description && - lhs.name == rhs.name && - lhs.directives == rhs.directives && - lhs.values == rhs.values + return lhs.description == rhs.description && lhs.name == rhs.name + && lhs.directives == rhs.directives && lhs.values == rhs.values } } @@ -2310,9 +2276,8 @@ public struct EnumValueDefinition: Sendable { extension EnumValueDefinition: Equatable { public static func == (lhs: EnumValueDefinition, rhs: EnumValueDefinition) -> Bool { - return lhs.description == rhs.description && - lhs.name == rhs.name && - lhs.directives == rhs.directives + return lhs.description == rhs.description && lhs.name == rhs.name + && lhs.directives == rhs.directives } } @@ -2356,10 +2321,8 @@ public struct InputObjectTypeDefinition { extension InputObjectTypeDefinition: Equatable { public static func == (lhs: InputObjectTypeDefinition, rhs: InputObjectTypeDefinition) -> Bool { - return lhs.description == rhs.description && - lhs.name == rhs.name && - lhs.directives == rhs.directives && - lhs.fields == rhs.fields + return lhs.description == rhs.description && lhs.name == rhs.name + && lhs.directives == rhs.directives && lhs.fields == rhs.fields } } @@ -2596,9 +2559,7 @@ public struct DirectiveDefinition { extension DirectiveDefinition: Equatable { public static func == (lhs: DirectiveDefinition, rhs: DirectiveDefinition) -> Bool { - return lhs.description == rhs.description && - lhs.name == rhs.name && - lhs.arguments == rhs.arguments && - lhs.locations == rhs.locations + return lhs.description == rhs.description && lhs.name == rhs.name + && lhs.arguments == rhs.arguments && lhs.locations == rhs.locations } } diff --git a/Sources/GraphQL/Language/BlockString.swift b/Sources/GraphQL/Language/BlockString.swift index 8b10af6f..f7fe050e 100644 --- a/Sources/GraphQL/Language/BlockString.swift +++ b/Sources/GraphQL/Language/BlockString.swift @@ -2,7 +2,7 @@ import Foundation func isPrintableAsBlockString(_ value: String) -> Bool { if value == "" { - return true // empty string is printable + return true // empty string is printable } var isEmptyLine = true @@ -11,37 +11,37 @@ func isPrintableAsBlockString(_ value: String) -> Bool { var seenNonEmptyLine = false let scalars = Array(value.unicodeScalars) - for i in 0 ..< scalars.count { + for i in 0.. + case 9, // \t + 32: // if !hasIndent { hasIndent = isEmptyLine } @@ -55,23 +55,21 @@ func isPrintableAsBlockString(_ value: String) -> Bool { } if isEmptyLine { - return false // Has trailing empty lines + return false // Has trailing empty lines } if hasCommonIndent && seenNonEmptyLine { - return false // Has internal indent + return false // Has internal indent } return true } -/** - * Print a block string in the indented block form by adding a leading and - * trailing blank line. However, if a block string starts with whitespace and is - * a single-line, adding a leading blank line would strip that whitespace. - * - * @internal - */ +/// Print a block string in the indented block form by adding a leading and +/// trailing blank line. However, if a block string starts with whitespace and is +/// a single-line, adding a leading blank line would strip that whitespace. +/// +/// @internal func printBlockString( _ value: String, minimize: Bool = false @@ -84,8 +82,8 @@ func printBlockString( // If common indentation is found we can fix some of those cases by adding leading new line let forceLeadingNewLine = - lines.count > 1 && - lines[1 ... (lines.count - 1)].allSatisfy { line in + lines.count > 1 + && lines[1...(lines.count - 1)].allSatisfy { line in line.count == 0 || isWhiteSpace(line.charCode(at: 0)) } @@ -98,15 +96,10 @@ func printBlockString( let forceTrailingNewline = hasTrailingQuote || hasTrailingSlash let printAsMultipleLines = - !minimize && + !minimize // add leading and trailing new lines only if it improves readability - ( - !isSingleLine || - value.count > 70 || - forceTrailingNewline || - forceLeadingNewLine || - hasTrailingTripleQuotes - ) + && (!isSingleLine || value.count > 70 || forceTrailingNewline || forceLeadingNewLine + || hasTrailingTripleQuotes) var result = "" diff --git a/Sources/GraphQL/Language/CharacterClasses.swift b/Sources/GraphQL/Language/CharacterClasses.swift index e0b8a84e..16964780 100644 --- a/Sources/GraphQL/Language/CharacterClasses.swift +++ b/Sources/GraphQL/Language/CharacterClasses.swift @@ -1,11 +1,9 @@ -/** - * ``` - * WhiteSpace :: - * - "Horizontal Tab (U+0009)" - * - "Space (U+0020)" - * ``` - * @internal - */ +/// ``` +/// WhiteSpace :: +/// - "Horizontal Tab (U+0009)" +/// - "Space (U+0020)" +/// ``` +/// @internal func isWhiteSpace(_ code: UInt8?) -> Bool { guard let code = code else { return false diff --git a/Sources/GraphQL/Language/Lexer.swift b/Sources/GraphQL/Language/Lexer.swift index 4fcfebb3..26ff1324 100644 --- a/Sources/GraphQL/Language/Lexer.swift +++ b/Sources/GraphQL/Language/Lexer.swift @@ -1,11 +1,9 @@ -/** - * Given a Source object, this returns a Lexer for that source. - * A Lexer is a stateful stream generator in that every time - * it is advanced, it returns the next token in the Source. Assuming the - * source lexes, the final Token emitted by the lexer will be of kind - * EOF, after which the lexer will repeatedly return the same EOF token - * whenever called. - */ +/// Given a Source object, this returns a Lexer for that source. +/// A Lexer is a stateful stream generator in that every time +/// it is advanced, it returns the next token in the Source. Assuming the +/// source lexes, the final Token emitted by the lexer will be of kind +/// EOF, after which the lexer will repeatedly return the same EOF token +/// whenever called. func createLexer(source: Source, noLocation: Bool = false) -> Lexer { let startOfFileToken = Token( kind: .sof, @@ -44,11 +42,9 @@ func advanceLexer(lexer: Lexer) throws -> Token { return token } -/** - * Returns a non-empty list of parse nodes, determined by the parseFn. - * This list may begin with a lex token of delimiterKind followed by items separated by lex tokens of tokenKind. - * Advances the parser to the next lex token after last item in the list. - */ +/// Returns a non-empty list of parse nodes, determined by the parseFn. +/// This list may begin with a lex token of delimiterKind followed by items separated by lex tokens of tokenKind. +/// Advances the parser to the next lex token after last item in the list. func delimitedMany(lexer: Lexer, kind: Token.Kind, parseFn: (Lexer) throws -> T) throws -> [T] { _ = try expectOptional(lexer: lexer, kind: kind) @@ -60,9 +56,7 @@ func delimitedMany(lexer: Lexer, kind: Token.Kind, parseFn: (Lexer) throws -> return nodes } -/** - * The return type of createLexer. - */ +/// The return type of createLexer. final class Lexer { let source: Source let noLocation: Bool @@ -126,10 +120,12 @@ final class Lexer { guard startToken.kind != .eof else { return startToken } repeat { - startToken = try startToken.next ?? { - startToken.next = try readToken(lexer: self, prev: startToken) - return startToken.next! - }() + startToken = + try startToken.next + ?? { + startToken.next = try readToken(lexer: self, prev: startToken) + return startToken.next! + }() } while startToken.kind == .comment // restore these since both `positionAfterWhitespace` & `readBlockString` @@ -142,9 +138,7 @@ final class Lexer { } } -/** - * A helper function to describe a token as a string for debugging - */ +/// A helper function to describe a token as a string for debugging func getTokenDesc(_ token: Token) -> String { if let value = token.value { return "\(token.kind) \"\(value)\"" @@ -175,7 +169,7 @@ extension String { func slice(start: Int, end: Int) -> String { let startIndex = utf8.index(utf8.startIndex, offsetBy: start) let endIndex = utf8.index(utf8.startIndex, offsetBy: end) - var slice: [UInt8] = utf8[startIndex ..< endIndex] + [0] + var slice: [UInt8] = utf8[startIndex.. Character { return Character(UnicodeScalar(code)) } -/** - * Gets the next token from the source starting at the given position. - * - * This skips over whitespace and comments until it finds the next lexable - * token, then lexes punctuators immediately or calls the appropriate helper - * function for more complicated tokens. - */ +/// Gets the next token from the source starting at the given position. +/// +/// This skips over whitespace and comments until it finds the next lexable +/// token, then lexes punctuators immediately or calls the appropriate helper +/// function for more complicated tokens. func readToken(lexer: Lexer, prev: Token) throws -> Token { let source = lexer.source let body = source.body @@ -382,9 +374,9 @@ func readToken(lexer: Lexer, prev: Token) throws -> Token { ) // A-Z _ a-z case 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 95, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, - 113, 114, 115, 116, 117, 118, 119, 120, 121, 122: + 88, 89, 90, 95, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122: return readName( source: source, position: position, @@ -404,8 +396,7 @@ func readToken(lexer: Lexer, prev: Token) throws -> Token { ) // " case 34: - if - body.charCode(at: position + 1) == 34, + if body.charCode(at: position + 1) == 34, body.charCode(at: position + 2) == 34 { return try readBlockString( @@ -435,11 +426,9 @@ func readToken(lexer: Lexer, prev: Token) throws -> Token { ) } -/** - * Reads from body starting at startPosition until it finds a non-whitespace - * or commented character, then returns the position of that character for - * lexing. - */ +/// Reads from body starting at startPosition until it finds a non-whitespace +/// or commented character, then returns the position of that character for +/// lexing. func positionAfterWhitespace(body: String, startPosition: Int, lexer: Lexer) -> Int { let bodyLength = body.utf8.count var position = startPosition @@ -448,18 +437,18 @@ func positionAfterWhitespace(body: String, startPosition: Int, lexer: Lexer) -> let code = body.charCode(at: position) // BOM - if - code == 239 && body.charCode(at: position + 1) == 187 && body + if code == 239 && body.charCode(at: position + 1) == 187 + && body .charCode(at: position + 2) == 191 { position += 3 - } else if code == 9 || code == 32 || code == 44 { // tab | space | comma + } else if code == 9 || code == 32 || code == 44 { // tab | space | comma position += 1 - } else if code == 10 { // new line + } else if code == 10 { // new line position += 1 lexer.line += 1 lexer.lineStart = position - } else if code == 13 { // carriage return + } else if code == 13 { // carriage return if body.charCode(at: position + 1) == 10 { position += 2 } else { @@ -475,11 +464,9 @@ func positionAfterWhitespace(body: String, startPosition: Int, lexer: Lexer) -> return position } -/** - * Reads a comment token from the source file. - * - * #[\u0009\u0020-\uFFFF]* - */ +/// Reads a comment token from the source file. +/// +/// #[\u0009\u0020-\uFFFF]* func readComment(source: Source, start: Int, line: Int, col: Int, prev: Token) -> Token { let body = source.body var code: UInt8? @@ -508,13 +495,11 @@ func readComment(source: Source, start: Int, line: Int, col: Int, prev: Token) - ) } -/** - * Reads a number token from the source file, either a float - * or an int depending on whether a decimal point appears. - * - * Int: -?(0|[1-9][0-9]*) - * Float: -?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)? - */ +/// Reads a number token from the source file, either a float +/// or an int depending on whether a decimal point appears. +/// +/// Int: -?(0|[1-9][0-9]*) +/// Float: -?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)? func readNumber( source: Source, start: Int, @@ -528,12 +513,12 @@ func readNumber( var position = start var isFloat = false - if let c = code, c == 45 { // - + if let c = code, c == 45 { // - position += 1 code = body.charCode(at: position) } - if let c = code, c == 48 { // 0 + if let c = code, c == 48 { // 0 position += 1 code = body.charCode(at: position) @@ -549,7 +534,7 @@ func readNumber( code = body.charCode(at: position) } - if let c = code, c == 46 { // . + if let c = code, c == 46 { // . isFloat = true position += 1 code = body.charCode(at: position) @@ -566,12 +551,12 @@ func readNumber( } } - if let c = code, c == 69 || c == 101 { // E e + if let c = code, c == 69 || c == 101 { // E e isFloat = true position += 1 code = body.charCode(at: position) - if let c = code, c == 43 || c == 45 { // + - + if let c = code, c == 43 || c == 45 { // + - position += 1 code = body.charCode(at: position) } @@ -598,17 +583,15 @@ func readNumber( ) } -/** - * Returns the new position in the source after reading digits. - */ +/// Returns the new position in the source after reading digits. func readDigits(source: Source, start: Int, firstCode: UInt8) throws -> Int { let body = source.body var position = start - if firstCode >= 48, firstCode <= 57 { // 0 - 9 + if firstCode >= 48, firstCode <= 57 { // 0 - 9 while true { position += 1 - if let code = body.charCode(at: position), code >= 48, code <= 57 { // 0 - 9 + if let code = body.charCode(at: position), code >= 48, code <= 57 { // 0 - 9 continue } else { break @@ -625,11 +608,9 @@ func readDigits(source: Source, start: Int, firstCode: UInt8) throws -> Int { ) } -/** - * Reads a string token from the source file. - * - * "([^"\\\u000A\u000D]|(\\(u[0-9a-fA-F]{4}|["\\/bfnrt])))*" - */ +/// Reads a string token from the source file. +/// +/// "([^"\\\u000A\u000D]|(\\(u[0-9a-fA-F]{4}|["\\/bfnrt])))*" func readString(source: Source, start: Int, line: Int, col: Int, prev: Token) throws -> Token { let body = source.body var positionIndex = body.utf8.index(body.utf8.startIndex, offsetBy: start + 1) @@ -657,12 +638,13 @@ func readString(source: Source, start: Int, line: Int, col: Int, prev: Token) th let startIterationIndex = positionIndex positionIndex = body.utf8.index(after: positionIndex) - if code == 92 { // \ - guard let chunk = String(body.utf8[chunkStartIndex ..< startIterationIndex]) else { + if code == 92 { // \ + guard let chunk = String(body.utf8[chunkStartIndex.. 2, body.utf8[body.utf8.index(positionIndex, offsetBy: 1)] == 34, body.utf8[body.utf8.index(positionIndex, offsetBy: 2)] == 34 { - guard let chunk = String(body.utf8[chunkStartIndex ..< positionIndex]) else { + guard let chunk = String(body.utf8[chunkStartIndex.. 4, body.utf8[body.utf8.index(positionIndex, offsetBy: 1)] == 34, body.utf8[body.utf8.index(positionIndex, offsetBy: 2)] == 34, @@ -842,11 +820,12 @@ func readBlockString( { // escaped triple quote (\""") - guard let chunk = String(body.utf8[chunkStartIndex ..< positionIndex]) else { + guard let chunk = String(body.utf8[chunkStartIndex.. String { for idx in lines.indices { let line = lines[idx] - if - newLines.count == 0, + if newLines.count == 0, line.firstIndex(where: { $0 != 0x0009 && $0 != 0x0020 }) == nil { continue @@ -943,8 +921,7 @@ func blockStringValue(rawValue: String) -> String { newLines.removeAll() for idx in lines.indices.reversed() { let line = lines[idx] - if - newLines.count == 0, + if newLines.count == 0, line.firstIndex(where: { $0 != 0x0009 && $0 != 0x0020 }) == nil { continue @@ -966,54 +943,53 @@ func blockStringValue(rawValue: String) -> String { return String(result) } -/** - * Converts four hexidecimal chars to the integer that the - * string represents. For example, uniCharCode('0','0','0','f') - * will return 15, and uniCharCode('0','0','f','f') returns 255. - * - * Returns a negative number on error, if a char was invalid. - * - * This is implemented by noting that char2hex() returns -1 on error, - * which means the result of ORing the char2hex() will also be negative. - */ +/// Converts four hexidecimal chars to the integer that the +/// string represents. For example, uniCharCode('0','0','0','f') +/// will return 15, and uniCharCode('0','0','f','f') returns 255. +/// +/// Returns a negative number on error, if a char was invalid. +/// +/// This is implemented by noting that char2hex() returns -1 on error, +/// which means the result of ORing the char2hex() will also be negative. func uniCharCode(a: UInt8, b: UInt8, c: UInt8, d: UInt8) -> Int { return char2hex(a) << 12 | char2hex(b) << 8 | char2hex(c) << 4 | char2hex(d) } -/** - * Converts a hex character to its integer value. - * '0' becomes 0, '9' becomes 9 - * 'A' becomes 10, 'F' becomes 15 - * 'a' becomes 10, 'f' becomes 15 - * - * Returns -1 on error. - */ +/// Converts a hex character to its integer value. +/// '0' becomes 0, '9' becomes 9 +/// 'A' becomes 10, 'F' becomes 15 +/// 'a' becomes 10, 'f' becomes 15 +/// +/// Returns -1 on error. func char2hex(_ a: UInt8) -> Int { let a = Int(a) - return a >= 48 && a <= 57 ? a - 48 : // 0-9 - a >= 65 && a <= 70 ? a - 55 : // A-F - a >= 97 && a <= 102 ? a - 87 : // a-f - -1 + return a >= 48 && a <= 57 + ? a - 48 + : // 0-9 + a >= 65 && a <= 70 + ? a - 55 + : // A-F + a >= 97 && a <= 102 + ? a - 87 + : // a-f + -1 } -/** - * Reads an alphanumeric + underscore name from the source. - * - * [_A-Za-z][_0-9A-Za-z]* - */ +/// Reads an alphanumeric + underscore name from the source. +/// +/// [_A-Za-z][_0-9A-Za-z]* func readName(source: Source, position: Int, line: Int, col: Int, prev: Token) -> Token { let body = source.body let bodyLength = body.utf8.count var end = position + 1 - while - end != bodyLength, + while end != bodyLength, let code = body.charCode(at: end), - code == 95 || // _ - code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122 - { // a-z + code == 95 // _ + || code >= 48 && code <= 57 // 0-9 + || code >= 65 && code <= 90 // A-Z + || code >= 97 && code <= 122 + { // a-z end += 1 } diff --git a/Sources/GraphQL/Language/Location.swift b/Sources/GraphQL/Language/Location.swift index 660d8b53..fb1cff4a 100644 --- a/Sources/GraphQL/Language/Location.swift +++ b/Sources/GraphQL/Language/Location.swift @@ -10,10 +10,8 @@ public struct SourceLocation: Codable, Equatable, Sendable { } } -/** - * Takes a Source and a UTF-8 character offset, and returns the corresponding - * line and column as a SourceLocation. - */ +/// Takes a Source and a UTF-8 character offset, and returns the corresponding +/// line and column as a SourceLocation. func getLocation(source: Source, position: Int) -> SourceLocation { var line = 1 var column = position + 1 @@ -21,7 +19,7 @@ func getLocation(source: Source, position: Int) -> SourceLocation { let matches = newLineRegex.matches( in: source.body, options: [], - range: NSRange(0 ..< source.body.utf16.count) + range: NSRange(0.. Value { return try parseValue(source: Source(body: source), noLocation: noLocation) } -/** - * Given a string containing a GraphQL value (ex. `[42]`), parse the AST for - * that value. - * Throws GraphQLError if a syntax error is encountered. - * - * This is useful within tools that operate upon GraphQL Values directly and - * in isolation of complete GraphQL documents. - * - * Consider providing the results to the utility func: valueFromAST(). - */ +/// Given a string containing a GraphQL value (ex. `[42]`), parse the AST for +/// that value. +/// Throws GraphQLError if a syntax error is encountered. +/// +/// This is useful within tools that operate upon GraphQL Values directly and +/// in isolation of complete GraphQL documents. +/// +/// Consider providing the results to the utility func: valueFromAST(). func parseValue(source: Source, noLocation: Bool = false) throws -> Value { let lexer = createLexer(source: source, noLocation: noLocation) try expect(lexer: lexer, kind: .sof) @@ -60,30 +52,26 @@ func parseValue(source: Source, noLocation: Bool = false) throws -> Value { return value } -/** - * Given a string containing a GraphQL Type (ex. `[Int!]`), parse the AST for - * that type. - * Throws GraphQLError if a syntax error is encountered. - * - * This is useful within tools that operate upon GraphQL Types directly and - * in isolation of complete GraphQL documents. - * - * Consider providing the results to the utility func: typeFromAST(). - */ +/// Given a string containing a GraphQL Type (ex. `[Int!]`), parse the AST for +/// that type. +/// Throws GraphQLError if a syntax error is encountered. +/// +/// This is useful within tools that operate upon GraphQL Types directly and +/// in isolation of complete GraphQL documents. +/// +/// Consider providing the results to the utility func: typeFromAST(). func parseType(source: String, noLocation: Bool = false) throws -> Type { return try parseType(source: Source(body: source), noLocation: noLocation) } -/** - * Given a string containing a GraphQL Type (ex. `[Int!]`), parse the AST for - * that type. - * Throws GraphQLError if a syntax error is encountered. - * - * This is useful within tools that operate upon GraphQL Types directly and - * in isolation of complete GraphQL documents. - * - * Consider providing the results to the utility func: typeFromAST(). - */ +/// Given a string containing a GraphQL Type (ex. `[Int!]`), parse the AST for +/// that type. +/// Throws GraphQLError if a syntax error is encountered. +/// +/// This is useful within tools that operate upon GraphQL Types directly and +/// in isolation of complete GraphQL documents. +/// +/// Consider providing the results to the utility func: typeFromAST(). func parseType(source: Source, noLocation: Bool = false) throws -> Type { let lexer = createLexer(source: source, noLocation: noLocation) try expect(lexer: lexer, kind: .sof) @@ -92,9 +80,7 @@ func parseType(source: Source, noLocation: Bool = false) throws -> Type { return type } -/** - * Converts a name lex token into a name parse node. - */ +/// Converts a name lex token into a name parse node. func parseName(lexer: Lexer) throws -> Name { let token = try expect(lexer: lexer, kind: .name) guard let value = token.value else { @@ -123,9 +109,7 @@ func parseDescription(lexer: Lexer) throws -> StringValue? { // Implements the parsing rules in the Document section. -/** - * Document : Definition+ - */ +/// Document : Definition+ func parseDocument(lexer: Lexer) throws -> Document { let start = lexer.token try expect(lexer: lexer, kind: .sof) @@ -141,12 +125,10 @@ func parseDocument(lexer: Lexer) throws -> Document { ) } -/** - * Definition : - * - OperationDefinition - * - FragmentDefinition - * - TypeSystemDefinition - */ +/// Definition : +/// - OperationDefinition +/// - FragmentDefinition +/// - TypeSystemDefinition func parseDefinition(lexer: Lexer) throws -> Definition { if peek(lexer: lexer, kind: .openingBrace) { return try parseOperationDefinition(lexer: lexer) @@ -154,7 +136,8 @@ func parseDefinition(lexer: Lexer) throws -> Definition { // Many definitions begin with a description and require a lookahead. let hasDescription = peekDescription(lexer: lexer) - let keywordToken = hasDescription + let keywordToken = + hasDescription ? try lexer.lookahead() : lexer.token @@ -177,7 +160,8 @@ func parseDefinition(lexer: Lexer) throws -> Definition { throw syntaxError( source: lexer.source, position: lexer.token.start, - description: "Unexpected description, descriptions are supported only on type definitions." + description: + "Unexpected description, descriptions are supported only on type definitions." ) } switch value { @@ -198,11 +182,9 @@ func parseDefinition(lexer: Lexer) throws -> Definition { // Implements the parsing rules in the Operations section. -/** - * OperationDefinition : - * - SelectionSet - * - OperationType Name? VariableDefinitions? Directives? SelectionSet - */ +/// OperationDefinition : +/// - SelectionSet +/// - OperationType Name? VariableDefinitions? Directives? SelectionSet func parseOperationDefinition(lexer: Lexer) throws -> OperationDefinition { let start = lexer.token @@ -211,7 +193,7 @@ func parseOperationDefinition(lexer: Lexer) throws -> OperationDefinition { loc: loc(lexer: lexer, startToken: start), operation: .query, name: nil, - variableDefinitions: [], // nil + variableDefinitions: [], // nil directives: [], selectionSet: parseSelectionSet(lexer: lexer) ) @@ -235,9 +217,7 @@ func parseOperationDefinition(lexer: Lexer) throws -> OperationDefinition { ) } -/** - * OperationType : one of query mutation subscription - */ +/// OperationType : one of query mutation subscription func parseOperationType(lexer: Lexer) throws -> OperationType { let operationToken = try expect(lexer: lexer, kind: .name) guard let value = operationToken.value else { @@ -252,38 +232,31 @@ func parseOperationType(lexer: Lexer) throws -> OperationType { } } -/** - * VariableDefinitions : ( VariableDefinition+ ) - */ +/// VariableDefinitions : ( VariableDefinition+ ) func parseVariableDefinitions(lexer: Lexer) throws -> [VariableDefinition] { - return peek(lexer: lexer, kind: .openingParenthesis) ? - try many( + return peek(lexer: lexer, kind: .openingParenthesis) + ? try many( lexer: lexer, openKind: .openingParenthesis, closeKind: .closingParenthesis, parse: parseVariableDefinition - ) : - [] + ) : [] } -/** - * VariableDefinition : Variable : Type DefaultValue? - */ +/// VariableDefinition : Variable : Type DefaultValue? func parseVariableDefinition(lexer: Lexer) throws -> VariableDefinition { let start = lexer.token return try VariableDefinition( loc: loc(lexer: lexer, startToken: start), variable: parseVariable(lexer: lexer), type: (expect(lexer: lexer, kind: .colon), parseTypeReference(lexer: lexer)).1, - defaultValue: skip(lexer: lexer, kind: .equals) ? - parseValueLiteral(lexer: lexer, isConst: true) : nil, + defaultValue: skip(lexer: lexer, kind: .equals) + ? parseValueLiteral(lexer: lexer, isConst: true) : nil, directives: parseDirectives(lexer: lexer) ) } -/** - * Variable : $ Name - */ +/// Variable : $ Name func parseVariable(lexer: Lexer) throws -> Variable { let start = lexer.token try expect(lexer: lexer, kind: .dollar) @@ -293,9 +266,7 @@ func parseVariable(lexer: Lexer) throws -> Variable { ) } -/** - * SelectionSet : { Selection+ } - */ +/// SelectionSet : { Selection+ } func parseSelectionSet(lexer: Lexer) throws -> SelectionSet { let start = lexer.token return try SelectionSet( @@ -309,23 +280,18 @@ func parseSelectionSet(lexer: Lexer) throws -> SelectionSet { ) } -/** - * Selection : - * - Field - * - FragmentSpread - * - InlineFragment - */ +/// Selection : +/// - Field +/// - FragmentSpread +/// - InlineFragment func parseSelection(lexer: Lexer) throws -> Selection { - return peek(lexer: lexer, kind: .spread) ? - try parseFragment(lexer: lexer) : - try parseField(lexer: lexer) + return peek(lexer: lexer, kind: .spread) + ? try parseFragment(lexer: lexer) : try parseField(lexer: lexer) } -/** - * Field : Alias? Name Arguments? Directives? SelectionSet? - * - * Alias : Name : - */ +/// Field : Alias? Name Arguments? Directives? SelectionSet? +/// +/// Alias : Name : func parseField(lexer: Lexer) throws -> Field { let start = lexer.token @@ -347,18 +313,15 @@ func parseField(lexer: Lexer) throws -> Field { name: name, arguments: parseArguments(lexer: lexer), directives: parseDirectives(lexer: lexer), - selectionSet: peek(lexer: lexer, kind: .openingBrace) ? - parseSelectionSet(lexer: lexer) : - nil + selectionSet: peek(lexer: lexer, kind: .openingBrace) + ? parseSelectionSet(lexer: lexer) : nil ) } -/** - * Arguments : ( Argument+ ) - */ +/// Arguments : ( Argument+ ) func parseArguments(lexer: Lexer) throws -> [Argument] { - return peek(lexer: lexer, kind: .openingParenthesis) ? - try many( + return peek(lexer: lexer, kind: .openingParenthesis) + ? try many( lexer: lexer, openKind: .openingParenthesis, closeKind: .closingParenthesis, @@ -366,9 +329,7 @@ func parseArguments(lexer: Lexer) throws -> [Argument] { ) : [] } -/** - * Argument : Name : Value - */ +/// Argument : Name : Value func parseArgument(lexer: Lexer) throws -> Argument { let start = lexer.token return try Argument( @@ -383,13 +344,11 @@ func parseArgument(lexer: Lexer) throws -> Argument { // Implements the parsing rules in the Fragments section. -/** - * Corresponds to both FragmentSpread and InlineFragment in the spec. - * - * FragmentSpread : ... FragmentName Directives? - * - * InlineFragment : ... TypeCondition? Directives? SelectionSet - */ +/// Corresponds to both FragmentSpread and InlineFragment in the spec. +/// +/// FragmentSpread : ... FragmentName Directives? +/// +/// InlineFragment : ... TypeCondition? Directives? SelectionSet func parseFragment(lexer: Lexer) throws -> Fragment { let start = lexer.token try expect(lexer: lexer, kind: .spread) @@ -415,12 +374,10 @@ func parseFragment(lexer: Lexer) throws -> Fragment { ) } -/** - * FragmentDefinition : - * - fragment FragmentName on TypeCondition Directives? SelectionSet - * - * TypeCondition : NamedType - */ +/// FragmentDefinition : +/// - fragment FragmentName on TypeCondition Directives? SelectionSet +/// +/// TypeCondition : NamedType func parseFragmentDefinition(lexer: Lexer) throws -> FragmentDefinition { let start = lexer.token try expectKeyword(lexer: lexer, value: "fragment") @@ -436,9 +393,7 @@ func parseFragmentDefinition(lexer: Lexer) throws -> FragmentDefinition { ) } -/** - * FragmentName : Name but not `on` - */ +/// FragmentName : Name but not `on` func parseFragmentName(lexer: Lexer) throws -> Name { if lexer.token.value == "on" { throw unexpected(lexer: lexer) @@ -448,21 +403,19 @@ func parseFragmentName(lexer: Lexer) throws -> Name { // Implements the parsing rules in the Values section. -/** - * Value[Const] : - * - [~Const] Variable - * - IntValue - * - FloatValue - * - StringValue - * - BooleanValue - * - EnumValue - * - ListValue[?Const] - * - ObjectValue[?Const] - * - * BooleanValue : one of `true` `false` - * - * EnumValue : Name but not `true`, `false` or `null` - */ +/// Value[Const] : +/// - [~Const] Variable +/// - IntValue +/// - FloatValue +/// - StringValue +/// - BooleanValue +/// - EnumValue +/// - ListValue[?Const] +/// - ObjectValue[?Const] +/// +/// BooleanValue : one of `true` `false` +/// +/// EnumValue : Name but not `true`, `false` or `null` func parseValueLiteral(lexer: Lexer, isConst: Bool) throws -> Value { let token = lexer.token switch token.kind { @@ -531,11 +484,9 @@ func parseValueValue(lexer: Lexer) throws -> Value { return try parseValueLiteral(lexer: lexer, isConst: false) } -/** - * ListValue[Const] : - * - [ ] - * - [ Value[?Const]+ ] - */ +/// ListValue[Const] : +/// - [ ] +/// - [ Value[?Const]+ ] func parseList(lexer: Lexer, isConst: Bool) throws -> ListValue { let start = lexer.token let item = isConst ? parseConstValue : parseValueValue @@ -550,11 +501,9 @@ func parseList(lexer: Lexer, isConst: Bool) throws -> ListValue { ) } -/** - * ObjectValue[Const] : - * - { } - * - { ObjectField[?Const]+ } - */ +/// ObjectValue[Const] : +/// - { } +/// - { ObjectField[?Const]+ } func parseObject(lexer: Lexer, isConst: Bool) throws -> ObjectValue { let start = lexer.token try expect(lexer: lexer, kind: .openingBrace) @@ -570,9 +519,7 @@ func parseObject(lexer: Lexer, isConst: Bool) throws -> ObjectValue { ) } -/** - * ObjectField[Const] : Name : Value[?Const] - */ +/// ObjectField[Const] : Name : Value[?Const] func parseObjectField(lexer: Lexer, isConst: Bool) throws -> ObjectField { let start = lexer.token return try ObjectField( @@ -603,9 +550,7 @@ func parseStringLiteral(lexer: Lexer, startToken: Token) throws -> StringValue { // Implements the parsing rules in the Directives section. -/** - * Directives : Directive+ - */ +/// Directives : Directive+ func parseDirectives(lexer: Lexer) throws -> [Directive] { var directives: [Directive] = [] @@ -616,9 +561,7 @@ func parseDirectives(lexer: Lexer) throws -> [Directive] { return directives } -/** - * Directive : @ Name Arguments? - */ +/// Directive : @ Name Arguments? func parseDirective(lexer: Lexer) throws -> Directive { let start = lexer.token try expect(lexer: lexer, kind: .at) @@ -631,12 +574,10 @@ func parseDirective(lexer: Lexer) throws -> Directive { // Implements the parsing rules in the Types section. -/** - * Type : - * - NamedType - * - ListType - * - NonNullType - */ +/// Type : +/// - NamedType +/// - ListType +/// - NonNullType func parseTypeReference(lexer: Lexer) throws -> Type { let start = lexer.token var type: Type @@ -662,9 +603,7 @@ func parseTypeReference(lexer: Lexer) throws -> Type { return type } -/** - * NamedType : Name - */ +/// NamedType : Name func parseNamedType(lexer: Lexer) throws -> NamedType { let start = lexer.token return try NamedType( @@ -675,11 +614,9 @@ func parseNamedType(lexer: Lexer) throws -> NamedType { // Implements the parsing rules in the Type Definition section. -/** - * SchemaDefinition : schema Directives? { OperationTypeDefinition+ } - * - * OperationTypeDefinition : OperationType : NamedType - */ +/// SchemaDefinition : schema Directives? { OperationTypeDefinition+ } +/// +/// OperationTypeDefinition : OperationType : NamedType func parseSchemaDefinition(lexer: Lexer) throws -> SchemaDefinition { let start = lexer.token let description = try parseDescription(lexer: lexer) @@ -711,9 +648,7 @@ func parseOperationTypeDefinition(lexer: Lexer) throws -> OperationTypeDefinitio ) } -/** - * ScalarTypeDefinition : scalar Name Directives? - */ +/// ScalarTypeDefinition : scalar Name Directives? func parseScalarTypeDefinition(lexer: Lexer) throws -> ScalarTypeDefinition { let start = lexer.token let description = try parseDescription(lexer: lexer) @@ -728,11 +663,9 @@ func parseScalarTypeDefinition(lexer: Lexer) throws -> ScalarTypeDefinition { ) } -/** - * ObjectTypeDefinition : - * - type Name ImplementsInterfaces? Directives? { FieldDefinition+ } - * - type Name ImplementsInterfaces? Directives? - */ +/// ObjectTypeDefinition : +/// - type Name ImplementsInterfaces? Directives? { FieldDefinition+ } +/// - type Name ImplementsInterfaces? Directives? func parseObjectTypeDefinition(lexer: Lexer) throws -> ObjectTypeDefinition { let start = lexer.token let description = try parseDescription(lexer: lexer) @@ -756,20 +689,16 @@ func parseObjectTypeDefinition(lexer: Lexer) throws -> ObjectTypeDefinition { ) } -/** - * ImplementsInterfaces : - * - implements &? NamedType - * - ImplementsInterfaces & NamedType - */ +/// ImplementsInterfaces : +/// - implements &? NamedType +/// - ImplementsInterfaces & NamedType func parseImplementsInterfaces(lexer: Lexer) throws -> [NamedType] { try expectOptionalKeyword(lexer: lexer, value: "implements") ? delimitedMany(lexer: lexer, kind: .amp, parseFn: parseNamedType) : [] } -/** - * FieldDefinition : Name ArgumentsDefinition? : Type Directives? - */ +/// FieldDefinition : Name ArgumentsDefinition? : Type Directives? func parseFieldDefinition(lexer: Lexer) throws -> FieldDefinition { let start = lexer.token let description = try parseDescription(lexer: lexer) @@ -788,9 +717,7 @@ func parseFieldDefinition(lexer: Lexer) throws -> FieldDefinition { ) } -/** - * ArgumentsDefinition : ( InputValueDefinition+ ) - */ +/// ArgumentsDefinition : ( InputValueDefinition+ ) func parseArgumentDefs(lexer: Lexer) throws -> [InputValueDefinition] { if !peek(lexer: lexer, kind: .openingParenthesis) { return [] @@ -803,9 +730,7 @@ func parseArgumentDefs(lexer: Lexer) throws -> [InputValueDefinition] { ) } -/** - * InputValueDefinition : Name : Type DefaultValue? Directives? - */ +/// InputValueDefinition : Name : Type DefaultValue? Directives? func parseInputValueDef(lexer: Lexer) throws -> InputValueDefinition { let start = lexer.token let description = try parseDescription(lexer: lexer) @@ -830,11 +755,9 @@ func parseInputValueDef(lexer: Lexer) throws -> InputValueDefinition { ) } -/** - * InterfaceTypeDefinition : - * - interface Name Directives? { FieldDefinition+ } - * - interface Name Directives? - */ +/// InterfaceTypeDefinition : +/// - interface Name Directives? { FieldDefinition+ } +/// - interface Name Directives? func parseInterfaceTypeDefinition(lexer: Lexer) throws -> InterfaceTypeDefinition { let start = lexer.token let description = try parseDescription(lexer: lexer) @@ -858,11 +781,9 @@ func parseInterfaceTypeDefinition(lexer: Lexer) throws -> InterfaceTypeDefinitio ) } -/** - * UnionTypeDefinition : - * - union Name Directives? = UnionMembers - * - union Name Directives? - */ +/// UnionTypeDefinition : +/// - union Name Directives? = UnionMembers +/// - union Name Directives? func parseUnionTypeDefinition(lexer: Lexer) throws -> UnionTypeDefinition { let start = lexer.token let description = try parseDescription(lexer: lexer) @@ -878,22 +799,18 @@ func parseUnionTypeDefinition(lexer: Lexer) throws -> UnionTypeDefinition { ) } -/** - * UnionMembers : - * - = |? NamedType - * - UnionMemberTypes | NamedType - */ +/// UnionMembers : +/// - = |? NamedType +/// - UnionMemberTypes | NamedType func parseUnionMembers(lexer: Lexer) throws -> [NamedType] { try expectOptional(lexer: lexer, kind: .equals) != nil ? delimitedMany(lexer: lexer, kind: .pipe, parseFn: parseNamedType) : [] } -/** - * EnumTypeDefinition : - * - enum Name Directives? { EnumValueDefinition+ } - * - enum Name Directives? - */ +/// EnumTypeDefinition : +/// - enum Name Directives? { EnumValueDefinition+ } +/// - enum Name Directives? func parseEnumTypeDefinition(lexer: Lexer) throws -> EnumTypeDefinition { let start = lexer.token let description = try parseDescription(lexer: lexer) @@ -915,11 +832,9 @@ func parseEnumTypeDefinition(lexer: Lexer) throws -> EnumTypeDefinition { ) } -/** - * EnumValueDefinition : EnumValue Directives? - * - * EnumValue : Name - */ +/// EnumValueDefinition : EnumValue Directives? +/// +/// EnumValue : Name func parseEnumValueDefinition(lexer: Lexer) throws -> EnumValueDefinition { let start = lexer.token let description = try parseDescription(lexer: lexer) @@ -933,11 +848,9 @@ func parseEnumValueDefinition(lexer: Lexer) throws -> EnumValueDefinition { ) } -/** - * InputObjectTypeDefinition : - * - input Name Directives? { InputValueDefinition+ } - * - input Name Directives? - */ +/// InputObjectTypeDefinition : +/// - input Name Directives? { InputValueDefinition+ } +/// - input Name Directives? func parseInputObjectTypeDefinition(lexer: Lexer) throws -> InputObjectTypeDefinition { let start = lexer.token let description = try parseDescription(lexer: lexer) @@ -973,14 +886,13 @@ func parseExtensionDefinition(lexer: Lexer) throws -> TypeSystemDefinition { throw syntaxError( source: lexer.source, position: token.start, - description: "expected schema or type or interface or scalar or union or enum or input after extend" + description: + "expected schema or type or interface or scalar or union or enum or input after extend" ) } } -/** - * TypeExtensionDefinition : extend ObjectTypeDefinition - */ +/// TypeExtensionDefinition : extend ObjectTypeDefinition func parseTypeExtensionDefinition(lexer: Lexer) throws -> TypeExtensionDefinition { let start = lexer.token try expectKeyword(lexer: lexer, value: "extend") @@ -994,8 +906,7 @@ func parseTypeExtensionDefinition(lexer: Lexer) throws -> TypeExtensionDefinitio closeKind: .closingBrace, parse: parseFieldDefinition ) - if - interfaces.isEmpty, + if interfaces.isEmpty, directives.isEmpty, fields.isEmpty { @@ -1012,9 +923,7 @@ func parseTypeExtensionDefinition(lexer: Lexer) throws -> TypeExtensionDefinitio ) } -/** - * SchemaExtensionDefinition: extend SchemaExtensionDefinition - */ +/// SchemaExtensionDefinition: extend SchemaExtensionDefinition func parseSchemaExtensionDefinition(lexer: Lexer) throws -> SchemaExtensionDefinition { let start = lexer.token try expectKeyword(lexer: lexer, value: "extend") @@ -1040,9 +949,7 @@ func parseSchemaExtensionDefinition(lexer: Lexer) throws -> SchemaExtensionDefin ) } -/** - * InterfaceExtensionDefinition: extend InterfaceTypeDefinition - */ +/// InterfaceExtensionDefinition: extend InterfaceTypeDefinition func parseInterfaceExtensionDefinition(lexer: Lexer) throws -> InterfaceExtensionDefinition { let start = lexer.token try expectKeyword(lexer: lexer, value: "extend") @@ -1056,8 +963,7 @@ func parseInterfaceExtensionDefinition(lexer: Lexer) throws -> InterfaceExtensio closeKind: .closingBrace, parse: parseFieldDefinition ) - if - interfaces.isEmpty, + if interfaces.isEmpty, directives.isEmpty, fields.isEmpty { @@ -1074,9 +980,7 @@ func parseInterfaceExtensionDefinition(lexer: Lexer) throws -> InterfaceExtensio ) } -/** - * ScalarExtensionDefinition: extend InterfaceTypeDefinition - */ +/// ScalarExtensionDefinition: extend InterfaceTypeDefinition func parseScalarExtensionDefinition(lexer: Lexer) throws -> ScalarExtensionDefinition { let start = lexer.token try expectKeyword(lexer: lexer, value: "extend") @@ -1096,9 +1000,7 @@ func parseScalarExtensionDefinition(lexer: Lexer) throws -> ScalarExtensionDefin ) } -/** - * UnionExtensionDefinition: extend UnionTypeDefinition - */ +/// UnionExtensionDefinition: extend UnionTypeDefinition func parseUnionExtensionDefinition(lexer: Lexer) throws -> UnionExtensionDefinition { let start = lexer.token try expectKeyword(lexer: lexer, value: "extend") @@ -1106,8 +1008,7 @@ func parseUnionExtensionDefinition(lexer: Lexer) throws -> UnionExtensionDefinit let name = try parseName(lexer: lexer) let directives = try parseDirectives(lexer: lexer) let types = try parseUnionMembers(lexer: lexer) - if - directives.isEmpty, + if directives.isEmpty, types.isEmpty { throw unexpected(lexer: lexer) @@ -1123,9 +1024,7 @@ func parseUnionExtensionDefinition(lexer: Lexer) throws -> UnionExtensionDefinit ) } -/** - * EnumExtensionDefinition: extend EnumTypeDefinition - */ +/// EnumExtensionDefinition: extend EnumTypeDefinition func parseEnumExtensionDefinition(lexer: Lexer) throws -> EnumExtensionDefinition { let start = lexer.token try expectKeyword(lexer: lexer, value: "extend") @@ -1138,8 +1037,7 @@ func parseEnumExtensionDefinition(lexer: Lexer) throws -> EnumExtensionDefinitio closeKind: .closingBrace, parse: parseEnumValueDefinition ) - if - directives.isEmpty, + if directives.isEmpty, values.isEmpty { throw unexpected(lexer: lexer) @@ -1155,9 +1053,7 @@ func parseEnumExtensionDefinition(lexer: Lexer) throws -> EnumExtensionDefinitio ) } -/** - * InputObjectExtensionDefinition: extend InputObjectTypeDefinition - */ +/// InputObjectExtensionDefinition: extend InputObjectTypeDefinition func parseInputObjectExtensionDefinition(lexer: Lexer) throws -> InputObjectExtensionDefinition { let start = lexer.token try expectKeyword(lexer: lexer, value: "extend") @@ -1170,8 +1066,7 @@ func parseInputObjectExtensionDefinition(lexer: Lexer) throws -> InputObjectExte closeKind: .closingBrace, parse: parseInputValueDef ) - if - directives.isEmpty, + if directives.isEmpty, fields.isEmpty { throw unexpected(lexer: lexer) @@ -1187,10 +1082,8 @@ func parseInputObjectExtensionDefinition(lexer: Lexer) throws -> InputObjectExte ) } -/** - * DirectiveDefinition : - * - directive @ Name ArgumentsDefinition? repeatable? on DirectiveLocations - */ +/// DirectiveDefinition : +/// - directive @ Name ArgumentsDefinition? repeatable? on DirectiveLocations func parseDirectiveDefinition(lexer: Lexer) throws -> DirectiveDefinition { let start = lexer.token let description = try parseDescription(lexer: lexer) @@ -1212,21 +1105,17 @@ func parseDirectiveDefinition(lexer: Lexer) throws -> DirectiveDefinition { ) } -/** - * DirectiveLocations : - * - |? DirectiveLocation - * - DirectiveLocations | DirectiveLocation - */ +/// DirectiveLocations : +/// - |? DirectiveLocation +/// - DirectiveLocations | DirectiveLocation func parseDirectiveLocations(lexer: Lexer) throws -> [Name] { try delimitedMany(lexer: lexer, kind: .pipe, parseFn: parseName) } // Core parsing utility funcs -/** - * Returns a location object, used to identify the place in - * the source that created a given parsed object. - */ +/// Returns a location object, used to identify the place in +/// the source that created a given parsed object. func loc(lexer: Lexer, startToken: Token) -> Location? { if !lexer.noLocation { return location(startToken: startToken, endToken: lexer.lastToken, source: lexer.source) @@ -1244,17 +1133,13 @@ func location(startToken: Token, endToken: Token, source: Source) -> Location { ) } -/** - * Determines if the next token is of a given kind - */ +/// Determines if the next token is of a given kind func peek(lexer: Lexer, kind: Token.Kind) -> Bool { return lexer.token.kind == kind } -/** - * If the next token is of the given kind, return true after advancing - * the lexer. Otherwise, do not change the parser state and return false. - */ +/// If the next token is of the given kind, return true after advancing +/// the lexer. Otherwise, do not change the parser state and return false. func skip(lexer: Lexer, kind: Token.Kind) throws -> Bool { let match = lexer.token.kind == kind if match { @@ -1263,10 +1148,8 @@ func skip(lexer: Lexer, kind: Token.Kind) throws -> Bool { return match } -/** - * If the next token is of the given kind, return that token after advancing - * the lexer. Otherwise, do not change the parser state and throw an error. - */ +/// If the next token is of the given kind, return that token after advancing +/// the lexer. Otherwise, do not change the parser state and throw an error. @discardableResult func expect(lexer: Lexer, kind: Token.Kind) throws -> Token { let token = lexer.token @@ -1283,10 +1166,8 @@ func expect(lexer: Lexer, kind: Token.Kind) throws -> Token { return token } -/** - * If the next token is of the given kind, return that token after advancing - * the lexer. Otherwise, do not change the parser state and return nil. - */ +/// If the next token is of the given kind, return that token after advancing +/// the lexer. Otherwise, do not change the parser state and return nil. @discardableResult func expectOptional(lexer: Lexer, kind: Token.Kind) throws -> Token? { let token = lexer.token @@ -1297,11 +1178,9 @@ func expectOptional(lexer: Lexer, kind: Token.Kind) throws -> Token? { return nil } -/** - * If the next token is a keyword with the given value, return that token after - * advancing the lexer. Otherwise, do not change the parser state and return - * false. - */ +/// If the next token is a keyword with the given value, return that token after +/// advancing the lexer. Otherwise, do not change the parser state and return +/// false. @discardableResult func expectKeyword(lexer: Lexer, value: String) throws -> Token { let token = lexer.token @@ -1318,10 +1197,8 @@ func expectKeyword(lexer: Lexer, value: String) throws -> Token { return token } -/** - * If the next token is a given keyword, return "true" after advancing the lexer. - * Otherwise, do not change the parser state and return "false". - */ +/// If the next token is a given keyword, return "true" after advancing the lexer. +/// Otherwise, do not change the parser state and return "false". @discardableResult func expectOptionalKeyword(lexer: Lexer, value: String) throws -> Bool { let token = lexer.token @@ -1332,11 +1209,9 @@ func expectOptionalKeyword(lexer: Lexer, value: String) throws -> Bool { return true } -/** - * Helper func for creating an error when an unexpected lexed token - * is encountered. - */ -func unexpected(lexer: Lexer, atToken: Token? = nil) -> Error { // GraphQLError { +/// Helper func for creating an error when an unexpected lexed token +/// is encountered. +func unexpected(lexer: Lexer, atToken: Token? = nil) -> Error { // GraphQLError { let token = atToken ?? lexer.token return syntaxError( source: lexer.source, @@ -1345,12 +1220,10 @@ func unexpected(lexer: Lexer, atToken: Token? = nil) -> Error { // GraphQLError ) } -/** - * Returns a possibly empty list of parse nodes, determined by - * the parseFn. This list begins with a lex token of openKind - * and ends with a lex token of closeKind. Advances the parser - * to the next lex token after the closing token. - */ +/// Returns a possibly empty list of parse nodes, determined by +/// the parseFn. This list begins with a lex token of openKind +/// and ends with a lex token of closeKind. Advances the parser +/// to the next lex token after the closing token. func any( lexer: Lexer, openKind: Token.Kind, @@ -1367,12 +1240,10 @@ func any( return nodes } -/** - * Returns a list of parse nodes, determined by the parseFn. - * It can be empty only if open token is missing otherwise it will always return non-empty list - * that begins with a lex token of openKind and ends with a lex token of closeKind. - * Advances the parser to the next lex token after the closing token. - */ +/// Returns a list of parse nodes, determined by the parseFn. +/// It can be empty only if open token is missing otherwise it will always return non-empty list +/// that begins with a lex token of openKind and ends with a lex token of closeKind. +/// Advances the parser to the next lex token after the closing token. func optionalMany( lexer: Lexer, openKind: Token.Kind, @@ -1389,12 +1260,10 @@ func optionalMany( return nodes } -/** - * Returns a non-empty list of parse nodes, determined by - * the parseFn. This list begins with a lex token of openKind - * and ends with a lex token of closeKind. Advances the parser - * to the next lex token after the closing token. - */ +/// Returns a non-empty list of parse nodes, determined by +/// the parseFn. This list begins with a lex token of openKind +/// and ends with a lex token of closeKind. Advances the parser +/// to the next lex token after the closing token. func many( lexer: Lexer, openKind: Token.Kind, diff --git a/Sources/GraphQL/Language/Predicates.swift b/Sources/GraphQL/Language/Predicates.swift index 8c7c9f8f..ca81fc1d 100644 --- a/Sources/GraphQL/Language/Predicates.swift +++ b/Sources/GraphQL/Language/Predicates.swift @@ -1,41 +1,34 @@ - func isTypeSystemDefinitionNode( _ node: Node ) -> Bool { return - node.kind == Kind.schemaDefinition || - isTypeDefinitionNode(node) || - node.kind == Kind.directiveDefinition + node.kind == Kind.schemaDefinition || isTypeDefinitionNode(node) + || node.kind == Kind.directiveDefinition } func isTypeDefinitionNode( _ node: Node ) -> Bool { return - node.kind == Kind.scalarTypeDefinition || - node.kind == Kind.objectTypeDefinition || - node.kind == Kind.interfaceTypeDefinition || - node.kind == Kind.unionTypeDefinition || - node.kind == Kind.enumTypeDefinition || - node.kind == Kind.inputObjectTypeDefinition + node.kind == Kind.scalarTypeDefinition || node.kind == Kind.objectTypeDefinition + || node.kind == Kind.interfaceTypeDefinition || node.kind == Kind.unionTypeDefinition + || node.kind == Kind.enumTypeDefinition || node.kind == Kind.inputObjectTypeDefinition } func isTypeSystemExtensionNode( _ node: Node ) -> Bool { return - node.kind == Kind.schemaExtensionDefinition || - isTypeExtensionNode(node) + node.kind == Kind.schemaExtensionDefinition || isTypeExtensionNode(node) } func isTypeExtensionNode( _ node: Node ) -> Bool { return - node.kind == Kind.scalarExtensionDefinition || - node.kind == Kind.typeExtensionDefinition || - node.kind == Kind.interfaceExtensionDefinition || - node.kind == Kind.unionExtensionDefinition || - node.kind == Kind.enumExtensionDefinition || - node.kind == Kind.inputObjectExtensionDefinition + node.kind == Kind.scalarExtensionDefinition || node.kind == Kind.typeExtensionDefinition + || node.kind == Kind.interfaceExtensionDefinition + || node.kind == Kind.unionExtensionDefinition + || node.kind == Kind.enumExtensionDefinition + || node.kind == Kind.inputObjectExtensionDefinition } diff --git a/Sources/GraphQL/Language/PrintString.swift b/Sources/GraphQL/Language/PrintString.swift index 6b5c6389..91d98867 100644 --- a/Sources/GraphQL/Language/PrintString.swift +++ b/Sources/GraphQL/Language/PrintString.swift @@ -1,16 +1,13 @@ import Foundation -/** - * Prints a string as a GraphQL StringValue literal. Replaces control characters - * and excluded characters (" U+0022 and \\ U+005C) with escape sequences. - */ +/// Prints a string as a GraphQL StringValue literal. Replaces control characters +/// and excluded characters (" U+0022 and \\ U+005C) with escape sequences. func printString(_ str: String) -> String { let replacedString = str.unicodeScalars.map { char in - if - char.value <= 0x1F || // \x00-\x1f - char.value == 0x22 || // \x22 - char.value == 0x5C || // \x5c - (char.value >= 0x7F && char.value <= 0x9F) // \x7f-\x9f + if char.value <= 0x1F // \x00-\x1f + || char.value == 0x22 // \x22 + || char.value == 0x5C // \x5c + || (char.value >= 0x7F && char.value <= 0x9F) // \x7f-\x9f { return escapeSequences[Int(char.value)] } @@ -25,15 +22,15 @@ let escapeSequences = [ "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001A", "\\u001B", "\\u001C", "\\u001D", "\\u001E", "\\u001F", "", "", "\\\"", "", "", "", "", "", - "", "", "", "", "", "", "", "", // 2F + "", "", "", "", "", "", "", "", // 2F "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", // 3F + "", "", "", "", "", "", "", "", // 3F "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", // 4F + "", "", "", "", "", "", "", "", // 4F "", "", "", "", "", "", "", "", - "", "", "", "", "\\\\", "", "", "", // 5F + "", "", "", "", "\\\\", "", "", "", // 5F "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", // 6F + "", "", "", "", "", "", "", "", // 6F "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "\\u007F", "\\u0080", "\\u0081", "\\u0082", "\\u0083", "\\u0084", "\\u0085", "\\u0086", "\\u0087", diff --git a/Sources/GraphQL/Language/Printer.swift b/Sources/GraphQL/Language/Printer.swift index 3fd17914..0cec3dac 100644 --- a/Sources/GraphQL/Language/Printer.swift +++ b/Sources/GraphQL/Language/Printer.swift @@ -37,11 +37,14 @@ extension Document: Printable { extension OperationDefinition: Printable { var printed: String { let varDefs = wrap("(", join(variableDefinitions, ", "), ")") - let prefix = join([ - operation.rawValue, - join([name, varDefs]), - join(directives, " "), - ], " ") + let prefix = join( + [ + operation.rawValue, + join([name, varDefs]), + join(directives, " "), + ], + " " + ) // Anonymous queries with no directives or variable definitions can use // the query short form. @@ -119,19 +122,22 @@ extension FragmentSpread: Printable { extension InlineFragment: Printable { var printed: String { - join([ - "...", - wrap("on ", typeCondition), - join(directives, " "), - selectionSet, - ], " ") + join( + [ + "...", + wrap("on ", typeCondition), + join(directives, " "), + selectionSet, + ], + " " + ) } } extension FragmentDefinition: Printable { var printed: String { - "fragment " + name + " on " + typeCondition + " " + wrap("", join(directives, " "), " ") + - selectionSet + "fragment " + name + " on " + typeCondition + " " + wrap("", join(directives, " "), " ") + + selectionSet } } @@ -236,8 +242,8 @@ extension NonNullType: Printable { extension SchemaDefinition: Printable { var printed: String { - wrap("", description, "\n") + - join(["schema", join(directives, " "), block(operationTypes)], " ") + wrap("", description, "\n") + + join(["schema", join(directives, " "), block(operationTypes)], " ") } } @@ -249,15 +255,14 @@ extension OperationTypeDefinition: Printable { extension ScalarTypeDefinition: Printable { var printed: String { - wrap("", description, "\n") + - join(["scalar", name.printed, join(directives, " ")], " ") + wrap("", description, "\n") + join(["scalar", name.printed, join(directives, " ")], " ") } } extension ObjectTypeDefinition: Printable { var printed: String { - wrap("", description, "\n") + - join( + wrap("", description, "\n") + + join( [ "type", name, @@ -274,9 +279,10 @@ extension FieldDefinition: Printable { var printed: String { let prefix = wrap("", description, "\n") + name - let args = hasMultilineItems(arguments) ? - wrap("(\n", indent(join(arguments, "\n")), "\n)") : - wrap("(", join(arguments, ", "), ")") + let args = + hasMultilineItems(arguments) + ? wrap("(\n", indent(join(arguments, "\n")), "\n)") + : wrap("(", join(arguments, ", "), ")") return prefix + args + ": " + type.printed + wrap(" ", join(directives, " ")) } @@ -284,8 +290,8 @@ extension FieldDefinition: Printable { extension InputValueDefinition: Printable { var printed: String { - wrap("", description, "\n") + - join( + wrap("", description, "\n") + + join( [ name + ": " + type.printed, wrap("= ", defaultValue?.printed), @@ -298,8 +304,8 @@ extension InputValueDefinition: Printable { extension InterfaceTypeDefinition: Printable { var printed: String { - wrap("", description, "\n") + - join( + wrap("", description, "\n") + + join( [ "interface", name, @@ -314,29 +320,28 @@ extension InterfaceTypeDefinition: Printable { extension UnionTypeDefinition: Printable { var printed: String { - wrap("", description, "\n") + - join(["union", name, join(directives, " "), wrap("= ", join(types, " | "))], " ") + wrap("", description, "\n") + + join(["union", name, join(directives, " "), wrap("= ", join(types, " | "))], " ") } } extension EnumTypeDefinition: Printable { var printed: String { - wrap("", description, "\n") + - join(["enum", name, join(directives, " "), block(values)], " ") + wrap("", description, "\n") + + join(["enum", name, join(directives, " "), block(values)], " ") } } extension EnumValueDefinition: Printable { var printed: String { - wrap("", description, "\n") + - join([name, join(directives, " ")], " ") + wrap("", description, "\n") + join([name, join(directives, " ")], " ") } } extension InputObjectTypeDefinition: Printable { var printed: String { - wrap("", description, "\n") + - join(["input", name, join(directives, " "), block(fields)], " ") + wrap("", description, "\n") + + join(["input", name, join(directives, " "), block(fields)], " ") } } @@ -344,9 +349,10 @@ extension DirectiveDefinition: Printable { var printed: String { let prefix = wrap("", description, "\n") + "directive @" + name - let args = hasMultilineItems(arguments) ? - wrap("(\n", indent(join(arguments, "\n")), "\n)") : - wrap("(", join(arguments, ", "), ")") + let args = + hasMultilineItems(arguments) + ? wrap("(\n", indent(join(arguments, "\n")), "\n)") + : wrap("(", join(arguments, ", "), ")") return prefix + args + (repeatable ? " repeatable" : "") + " on " + join(locations, " | ") } @@ -456,26 +462,26 @@ extension String: Printable { } } -private extension Node { - var printed: String { +extension Node { + fileprivate var printed: String { (self as? Printable)?.printed ?? "UnknownNode" } } -private extension Value { - var printed: String { +extension Value { + fileprivate var printed: String { (self as? Printable)?.printed ?? "UnknownValue" } } -private extension Selection { - var printed: String { +extension Selection { + fileprivate var printed: String { (self as? Printable)?.printed ?? "UnknownSelection" } } -private extension Type { - var printed: String { +extension Type { + fileprivate var printed: String { (self as? Printable)?.printed ?? "UnknownType" } } diff --git a/Sources/GraphQL/Language/Source.swift b/Sources/GraphQL/Language/Source.swift index d5416bb6..5d200dbb 100644 --- a/Sources/GraphQL/Language/Source.swift +++ b/Sources/GraphQL/Language/Source.swift @@ -1,12 +1,10 @@ -/** - * A representation of source input to GraphQL. The name is optional, - * but is mostly useful for clients who store GraphQL documents in - * source files; for example, if the GraphQL input is in a file Foo.graphql, - * it might be useful for name to be "Foo.graphql". - * - * Note that since Source parsing is heavily UTF8 dependent, the body - * is converted into contiguous UTF8 bytes if necessary for optimal performance. - */ +/// A representation of source input to GraphQL. The name is optional, +/// but is mostly useful for clients who store GraphQL documents in +/// source files; for example, if the GraphQL input is in a file Foo.graphql, +/// it might be useful for name to be "Foo.graphql". +/// +/// Note that since Source parsing is heavily UTF8 dependent, the body +/// is converted into contiguous UTF8 bytes if necessary for optimal performance. public struct Source: Hashable, Equatable, Sendable { public let body: String public let name: String diff --git a/Sources/GraphQL/Language/Visitor.swift b/Sources/GraphQL/Language/Visitor.swift index e1cc1fba..c816da97 100644 --- a/Sources/GraphQL/Language/Visitor.swift +++ b/Sources/GraphQL/Language/Visitor.swift @@ -54,39 +54,37 @@ let QueryDocumentKeys: [Kind: [String]] = [ .inputObjectExtensionDefinition: ["name", "directives", "fields"], ] -/** - * visit() will walk through an AST using a depth first traversal, calling - * the visitor's enter function at each node in the traversal, and calling the - * leave function after visiting that node and all of its child nodes. - * - * By returning different values from the enter and leave functions, the - * behavior of the visitor can be altered, including skipping over a sub-tree of - * the AST (by returning `.skip`), editing the AST by returning a value or nil - * to remove the value, or to stop the whole traversal by returning `.break`. - * - * When using visit() to edit an AST, the original AST will not be modified, and - * a new version of the AST with the changes applied will be returned from the - * visit function. - * - * let editedAST = visit(ast, Visitor( - * enter: { node, key, parent, path, ancestors in - * return - * .continue: no action - * .skip: skip visiting this node - * .break: stop visiting altogether - * .node(nil): delete this node - * .node(newNode): replace this node with the returned value - * }, - * leave: { node, key, parent, path, ancestors in - * return - * .continue: no action - * .skip: no action - * .break: stop visiting altogether - * .node(nil): delete this node - * .node(newNode): replace this node with the returned value - * } - * )) - */ +/// visit() will walk through an AST using a depth first traversal, calling +/// the visitor's enter function at each node in the traversal, and calling the +/// leave function after visiting that node and all of its child nodes. +/// +/// By returning different values from the enter and leave functions, the +/// behavior of the visitor can be altered, including skipping over a sub-tree of +/// the AST (by returning `.skip`), editing the AST by returning a value or nil +/// to remove the value, or to stop the whole traversal by returning `.break`. +/// +/// When using visit() to edit an AST, the original AST will not be modified, and +/// a new version of the AST with the changes applied will be returned from the +/// visit function. +/// +/// let editedAST = visit(ast, Visitor( +/// enter: { node, key, parent, path, ancestors in +/// return +/// .continue: no action +/// .skip: skip visiting this node +/// .break: stop visiting altogether +/// .node(nil): delete this node +/// .node(newNode): replace this node with the returned value +/// }, +/// leave: { node, key, parent, path, ancestors in +/// return +/// .continue: no action +/// .skip: no action +/// .break: stop visiting altogether +/// .node(nil): delete this node +/// .node(newNode): replace this node with the returned value +/// } +/// )) @discardableResult func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node { let visitorKeys = keyMap.isEmpty ? QueryDocumentKeys : keyMap @@ -120,7 +118,7 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node let editKey = editKey.indexValue! let arrayKey = editKey - editOffset - if case var .array(n) = node { + if case .array(var n) = node { if let editValue = editValue { n[arrayKey] = editValue node = .array(n) @@ -132,7 +130,7 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node } } } else { - if case let .node(n) = node { + if case .node(let n) = node { var newNode = n for (editKey, editValue) in edits { if let editValue = editValue { @@ -159,7 +157,7 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node stack = stack!.prev // If parent has been edited, we must pass it up to the parent's parent and so on until // we get to the root (at which point stack has no .prev) - if parentEdited, case let .node(parent) = parent, let stackPrev = stack?.prev { + if parentEdited, case .node(let parent) = parent, let stackPrev = stack?.prev { edits.append((stackPrev.keys.last ?? "root", parent)) } } else if let parent = parent { @@ -171,8 +169,8 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node path.append(key!) } - var result: VisitResult = .break // placeholder - if case let .node(n) = node { + var result: VisitResult = .break // placeholder + if case .node(let n) = node { if !isLeaving { result = visitor.enter( node: n, @@ -198,7 +196,7 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node _ = path.popLast() continue } - } else if case let .node(resultNode) = result { + } else if case .node(let resultNode) = result { edits.append((key ?? "root", resultNode)) if !isLeaving { if let resultNode = resultNode { @@ -211,7 +209,7 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node } } - if case .continue = result, isEdited, case let .node(node) = node! { + if case .continue = result, isEdited, case .node(let node) = node! { edits.append((key!, node)) } @@ -220,12 +218,12 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node } else { stack = Stack(index: index, keys: keys, edits: edits, inArray: inArray, prev: stack) switch node! { - case let .node(node): + case .node(let node): inArray = false keys = visitorKeys[node.kind] ?? [] - case let .array(array): + case .array(let array): inArray = true - keys = Array(array.indices) // array.map { _ in "root" } + keys = Array(array.indices) // array.map { _ in "root" } } index = -1 edits = [] @@ -234,17 +232,16 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node } parent = node } - } while - stack != nil + } while stack != nil if !edits.isEmpty, let nextEditNode = edits[edits.count - 1].node { return nextEditNode } switch node! { - case let .node(root): // This should be equal to root, with any relevant edits + case .node(let root): // This should be equal to root, with any relevant edits return root - case let .array(array): // This should never occur + case .array(let array): // This should never occur return array[0] } } @@ -271,18 +268,16 @@ final class Stack { } } -/** - * Creates a new visitor instance which delegates to many visitors to run in - * parallel. Each visitor will be visited for each node before moving on. - * - * If a prior visitor edits a node, no following visitors will see that node. - */ +/// Creates a new visitor instance which delegates to many visitors to run in +/// parallel. Each visitor will be visited for each node before moving on. +/// +/// If a prior visitor edits a node, no following visitors will see that node. func visitInParallel(visitors: [Visitor]) -> Visitor { var skipping = [VisitResult?](repeating: nil, count: visitors.count) return Visitor( enter: { node, key, parent, path, ancestors in - for i in 0 ..< visitors.count { + for i in 0.. Visitor { return .continue }, leave: { node, key, parent, path, ancestors in - for i in 0 ..< visitors.count { + for i in 0.. Visitor { } else if case .node = result { return result } - } else if - case let .node(skippedNodeValue) = skipping[i], + } else if case .node(let skippedNodeValue) = skipping[i], let skippedNode = skippedNodeValue, skippedNode.kind == node.kind, skippedNode.loc == node.loc @@ -400,10 +394,8 @@ public func ignore( return .continue } -/** - * Creates a new visitor instance which maintains a provided TypeInfo instance - * along with visiting visitor. - */ +/// Creates a new visitor instance which maintains a provided TypeInfo instance +/// along with visiting visitor. func visitWithTypeInfo(typeInfo: TypeInfo, visitor: Visitor) -> Visitor { return Visitor( enter: { node, key, parent, path, ancestors in @@ -420,7 +412,7 @@ func visitWithTypeInfo(typeInfo: TypeInfo, visitor: Visitor) -> Visitor { if !result.isContinue { typeInfo.leave(node: node) - if case let .node(node) = result, let n = node { + if case .node(let node) = result, let n = node { typeInfo.enter(node: n) } } diff --git a/Sources/GraphQL/Map/AnyCoder.swift b/Sources/GraphQL/Map/AnyCoder.swift index d12fba04..8c8fb1bb 100644 --- a/Sources/GraphQL/Map/AnyCoder.swift +++ b/Sources/GraphQL/Map/AnyCoder.swift @@ -127,21 +127,19 @@ open class AnyEncoder { // // We assume, per Swift naming conventions, that the first character of the key is lowercase. var wordStart = stringKey.startIndex - var searchRange = stringKey.index(after: wordStart) ..< stringKey.endIndex + var searchRange = stringKey.index(after: wordStart)..1 capital letters. Turn those into a word, stopping at the capital before the lower case character. let beforeLowerIndex = stringKey.index(before: lowerCaseRange.lowerBound) - words.append(upperCaseRange.lowerBound ..< beforeLowerIndex) + words.append(upperCaseRange.lowerBound..: KeyedEncodingContainerP case .convertToSnakeCase: let newKeyString = AnyEncoder.KeyEncodingStrategy._convertToSnakeCase(key.stringValue) return _AnyKey(stringValue: newKeyString, intValue: key.intValue) - case let .custom(converter): + case .custom(let converter): return converter(codingPath + [key]) } } @@ -628,8 +626,7 @@ private struct _AnyUnkeyedEncodingContainer: UnkeyedEncodingContainer { } public mutating func nestedContainer( - keyedBy _: NestedKey - .Type + keyedBy _: NestedKey.Type ) -> KeyedEncodingContainer { codingPath.append(_AnyKey(index: count)) defer { self.codingPath.removeLast() } @@ -760,28 +757,28 @@ extension _AnyEncoder: SingleValueEncodingContainer { // MARK: - Concrete Value Representations -private extension _AnyEncoder { +extension _AnyEncoder { /// Returns the given value boxed in a container appropriate for pushing onto the container stack. - func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } - func box(_ value: Int) -> NSObject { return NSNumber(value: value) } - func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } - func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } - func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } - func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } - func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } - func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } - func box(_ value: UInt16) -> NSObject { return NSNumber(value: value) } - func box(_ value: UInt32) -> NSObject { return NSNumber(value: value) } - func box(_ value: UInt64) -> NSObject { return NSNumber(value: value) } - func box(_ value: String) -> NSObject { return NSString(string: value) } - - func box(_ float: Float) throws -> NSObject { + fileprivate func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt16) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt32) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt64) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: String) -> NSObject { return NSString(string: value) } + + fileprivate func box(_ float: Float) throws -> NSObject { guard !float.isInfinite, !float.isNaN else { guard - case let .convertToString( - positiveInfinity: posInfString, - negativeInfinity: negInfString, - nan: nanString + case .convertToString( + positiveInfinity: let posInfString, + negativeInfinity: let negInfString, + nan: let nanString ) = options.nonConformingFloatEncodingStrategy else { throw EncodingError._invalidFloatingPointValue(float, at: codingPath) @@ -799,13 +796,13 @@ private extension _AnyEncoder { return NSNumber(value: float) } - func box(_ double: Double) throws -> NSObject { + fileprivate func box(_ double: Double) throws -> NSObject { guard !double.isInfinite, !double.isNaN else { guard - case let .convertToString( - positiveInfinity: posInfString, - negativeInfinity: negInfString, - nan: nanString + case .convertToString( + positiveInfinity: let posInfString, + negativeInfinity: let negInfString, + nan: let nanString ) = options.nonConformingFloatEncodingStrategy else { throw EncodingError._invalidFloatingPointValue(double, at: codingPath) @@ -823,7 +820,7 @@ private extension _AnyEncoder { return NSNumber(value: double) } - func box(_ date: Date) throws -> NSObject { + fileprivate func box(_ date: Date) throws -> NSObject { switch options.dateEncodingStrategy { case .deferredToDate: // Must be called with a surrounding with(pushedKey:) call. @@ -844,10 +841,10 @@ private extension _AnyEncoder { fatalError("ISO8601DateFormatter is unavailable on this platform.") } - case let .formatted(formatter): + case .formatted(let formatter): return NSString(string: formatter.string(from: date)) - case let .custom(closure): + case .custom(let closure): let depth = storage.count do { try closure(date, self) @@ -869,7 +866,7 @@ private extension _AnyEncoder { } } - func box(_ data: Data) throws -> NSObject { + fileprivate func box(_ data: Data) throws -> NSObject { switch options.dataEncodingStrategy { case .deferredToData: // Must be called with a surrounding with(pushedKey:) call. @@ -889,7 +886,7 @@ private extension _AnyEncoder { case .base64: return NSString(string: data.base64EncodedString()) - case let .custom(closure): + case .custom(let closure): let depth = storage.count do { try closure(data, self) @@ -910,7 +907,7 @@ private extension _AnyEncoder { } } - func box(_ dict: [String: Encodable]) throws -> NSObject? { + fileprivate func box(_ dict: [String: Encodable]) throws -> NSObject? { let depth = storage.count let result = storage.pushKeyedContainer() do { @@ -936,12 +933,12 @@ private extension _AnyEncoder { return storage.popContainer() } - func box(_ value: Encodable) throws -> NSObject { + fileprivate func box(_ value: Encodable) throws -> NSObject { return try box_(value) ?? NSDictionary() } // This method is called "box_" instead of "box" to disambiguate it from the overloads. Because the return type here is different from all of the "box" overloads (and is more general), any "box" calls in here would call back into "box" recursively instead of calling the appropriate overload, which is not what we want. - func box_(_ value: Encodable) throws -> NSObject? { + fileprivate func box_(_ value: Encodable) throws -> NSObject? { let type = Swift.type(of: value) #if DEPLOYMENT_RUNTIME_SWIFT if type == Date.self { @@ -1072,10 +1069,10 @@ private class _AnyReferencingEncoder: _AnyEncoder { } switch self.reference { - case let .array(array, index): + case .array(let array, let index): array.insert(value, at: index) - case let .dictionary(dictionary, key): + case .dictionary(let dictionary, let key): dictionary[NSString(string: key)] = value } } @@ -1169,9 +1166,12 @@ open class AnyDecoder { stringKey.formIndex(before: &lastNonUnderscore) } - let keyRange = firstNonUnderscore ... lastNonUnderscore - let leadingUnderscoreRange = stringKey.startIndex ..< firstNonUnderscore - let trailingUnderscoreRange = stringKey.index(after: lastNonUnderscore) ..< stringKey + let keyRange = firstNonUnderscore...lastNonUnderscore + let leadingUnderscoreRange = stringKey.startIndex...self, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead." + debugDescription: + "Cannot get keyed decoding container -- found null value instead." ) ) } @@ -1336,7 +1338,8 @@ private class _AnyDecoder: Decoder { UnkeyedDecodingContainer.self, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get unkeyed decoding container -- found null value instead." + debugDescription: + "Cannot get unkeyed decoding container -- found null value instead." ) ) } @@ -1419,17 +1422,26 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP case .convertFromSnakeCase: // Convert the snake case keys in the container to camel case. // If we hit a duplicate key after conversion, then we'll use the first one we saw. Effectively an undefined behavior with Any dictionaries. - self.container = Dictionary(container.map { - key, value in (AnyDecoder.KeyDecodingStrategy._convertFromSnakeCase(key), value) - }, uniquingKeysWith: { first, _ in first }) - case let .custom(converter): - self.container = Dictionary(container.map { - key, value in ( - converter(decoder.codingPath + [_AnyKey(stringValue: key, intValue: nil)]) - .stringValue, - value - ) - }, uniquingKeysWith: { first, _ in first }) + self.container = Dictionary( + container.map { + key, + value in (AnyDecoder.KeyDecodingStrategy._convertFromSnakeCase(key), value) + }, + uniquingKeysWith: { first, _ in first } + ) + case .custom(let converter): + self.container = Dictionary( + container.map { + key, + value in + ( + converter(decoder.codingPath + [_AnyKey(stringValue: key, intValue: nil)]) + .stringValue, + value + ) + }, + uniquingKeysWith: { first, _ in first } + ) } codingPath = decoder.codingPath } @@ -1468,7 +1480,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1483,7 +1496,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1512,7 +1526,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1541,7 +1556,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1570,7 +1586,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1599,7 +1616,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1628,7 +1646,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1657,7 +1676,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1686,7 +1706,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1715,7 +1736,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1744,7 +1766,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1773,7 +1796,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1802,7 +1826,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1831,7 +1856,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1860,7 +1886,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1889,7 +1916,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1925,7 +1953,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP key, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \(_errorDescription(of: key))" + debugDescription: + "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \(_errorDescription(of: key))" ) ) } @@ -1954,7 +1983,8 @@ private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerP key, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get UnkeyedDecodingContainer -- no value found for key \(_errorDescription(of: key))" + debugDescription: + "Cannot get UnkeyedDecodingContainer -- no value found for key \(_errorDescription(of: key))" ) ) } @@ -2493,8 +2523,7 @@ private struct _AnyUnkeyedDecodingContainer: UnkeyedDecodingContainer { } public mutating func nestedContainer( - keyedBy _: NestedKey - .Type + keyedBy _: NestedKey.Type ) throws -> KeyedDecodingContainer { decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } @@ -2504,7 +2533,8 @@ private struct _AnyUnkeyedDecodingContainer: UnkeyedDecodingContainer { KeyedDecodingContainer.self, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get nested keyed container -- unkeyed container is at end." + debugDescription: + "Cannot get nested keyed container -- unkeyed container is at end." ) ) } @@ -2515,7 +2545,8 @@ private struct _AnyUnkeyedDecodingContainer: UnkeyedDecodingContainer { KeyedDecodingContainer.self, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead." + debugDescription: + "Cannot get keyed decoding container -- found null value instead." ) ) } @@ -2545,7 +2576,8 @@ private struct _AnyUnkeyedDecodingContainer: UnkeyedDecodingContainer { UnkeyedDecodingContainer.self, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get nested keyed container -- unkeyed container is at end." + debugDescription: + "Cannot get nested keyed container -- unkeyed container is at end." ) ) } @@ -2556,7 +2588,8 @@ private struct _AnyUnkeyedDecodingContainer: UnkeyedDecodingContainer { UnkeyedDecodingContainer.self, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead." + debugDescription: + "Cannot get keyed decoding container -- found null value instead." ) ) } @@ -2691,9 +2724,9 @@ extension _AnyDecoder: SingleValueDecodingContainer { // MARK: - Concrete Value Representations -private extension _AnyDecoder { +extension _AnyDecoder { /// Returns the given value unboxed from a container. - func unbox(_ value: Any, as type: Bool.Type) throws -> Bool? { + fileprivate func unbox(_ value: Any, as type: Bool.Type) throws -> Bool? { guard !(value is NSNull) else { return nil } #if DEPLOYMENT_RUNTIME_SWIFT || os(Linux) || os(Android) @@ -2727,7 +2760,7 @@ private extension _AnyDecoder { #endif } - func unbox(_ value: Any, as type: Int.Type) throws -> Int? { + fileprivate func unbox(_ value: Any, as type: Int.Type) throws -> Int? { guard !(value is NSNull) else { return nil } guard @@ -2739,16 +2772,18 @@ private extension _AnyDecoder { let int = number.intValue guard NSNumber(value: int) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." + ) + ) } return int } - func unbox(_ value: Any, as type: Int8.Type) throws -> Int8? { + fileprivate func unbox(_ value: Any, as type: Int8.Type) throws -> Int8? { guard !(value is NSNull) else { return nil } guard @@ -2760,16 +2795,18 @@ private extension _AnyDecoder { let int8 = number.int8Value guard NSNumber(value: int8) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." + ) + ) } return int8 } - func unbox(_ value: Any, as type: Int16.Type) throws -> Int16? { + fileprivate func unbox(_ value: Any, as type: Int16.Type) throws -> Int16? { guard !(value is NSNull) else { return nil } guard @@ -2781,16 +2818,18 @@ private extension _AnyDecoder { let int16 = number.int16Value guard NSNumber(value: int16) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." + ) + ) } return int16 } - func unbox(_ value: Any, as type: Int32.Type) throws -> Int32? { + fileprivate func unbox(_ value: Any, as type: Int32.Type) throws -> Int32? { guard !(value is NSNull) else { return nil } guard @@ -2802,16 +2841,18 @@ private extension _AnyDecoder { let int32 = number.int32Value guard NSNumber(value: int32) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." + ) + ) } return int32 } - func unbox(_ value: Any, as type: Int64.Type) throws -> Int64? { + fileprivate func unbox(_ value: Any, as type: Int64.Type) throws -> Int64? { guard !(value is NSNull) else { return nil } guard @@ -2823,16 +2864,18 @@ private extension _AnyDecoder { let int64 = number.int64Value guard NSNumber(value: int64) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." + ) + ) } return int64 } - func unbox(_ value: Any, as type: UInt.Type) throws -> UInt? { + fileprivate func unbox(_ value: Any, as type: UInt.Type) throws -> UInt? { guard !(value is NSNull) else { return nil } guard @@ -2844,16 +2887,18 @@ private extension _AnyDecoder { let uint = number.uintValue guard NSNumber(value: uint) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." + ) + ) } return uint } - func unbox(_ value: Any, as type: UInt8.Type) throws -> UInt8? { + fileprivate func unbox(_ value: Any, as type: UInt8.Type) throws -> UInt8? { guard !(value is NSNull) else { return nil } guard @@ -2865,16 +2910,18 @@ private extension _AnyDecoder { let uint8 = number.uint8Value guard NSNumber(value: uint8) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." + ) + ) } return uint8 } - func unbox(_ value: Any, as type: UInt16.Type) throws -> UInt16? { + fileprivate func unbox(_ value: Any, as type: UInt16.Type) throws -> UInt16? { guard !(value is NSNull) else { return nil } guard @@ -2886,16 +2933,18 @@ private extension _AnyDecoder { let uint16 = number.uint16Value guard NSNumber(value: uint16) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." + ) + ) } return uint16 } - func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? { + fileprivate func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? { guard !(value is NSNull) else { return nil } guard @@ -2907,16 +2956,18 @@ private extension _AnyDecoder { let uint32 = number.uint32Value guard NSNumber(value: uint32) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." + ) + ) } return uint32 } - func unbox(_ value: Any, as type: UInt64.Type) throws -> UInt64? { + fileprivate func unbox(_ value: Any, as type: UInt64.Type) throws -> UInt64? { guard !(value is NSNull) else { return nil } guard @@ -2928,20 +2979,21 @@ private extension _AnyDecoder { let uint64 = number.uint64Value guard NSNumber(value: uint64) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Any number <\(number)> does not fit in \(type)." + ) + ) } return uint64 } - func unbox(_ value: Any, as type: Float.Type) throws -> Float? { + fileprivate func unbox(_ value: Any, as type: Float.Type) throws -> Float? { guard !(value is NSNull) else { return nil } - if - let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + if let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse { // We are willing to return a Float by losing precision: @@ -2952,10 +3004,12 @@ private extension _AnyDecoder { // * If it was a Double or Decimal, you will get back the nearest approximation if it will fit let double = number.doubleValue guard abs(double) <= Double(Float.greatestFiniteMagnitude) else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Any number \(number) does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Any number \(number) does not fit in \(type)." + ) + ) } return Float(double) @@ -2970,13 +3024,12 @@ private extension _AnyDecoder { if let float = Float(exactly: int) { return float } - + overflow = true */ - } else if - let string = value as? String, - case let .convertFromString(posInfString, negInfString, nanString) = options + } else if let string = value as? String, + case .convertFromString(let posInfString, let negInfString, let nanString) = options .nonConformingFloatDecodingStrategy { if string == posInfString { @@ -2991,11 +3044,10 @@ private extension _AnyDecoder { throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } - func unbox(_ value: Any, as type: Double.Type) throws -> Double? { + fileprivate func unbox(_ value: Any, as type: Double.Type) throws -> Double? { guard !(value is NSNull) else { return nil } - if - let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + if let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse { // We are always willing to return the number as a Double: @@ -3011,13 +3063,12 @@ private extension _AnyDecoder { if let double = Double(exactly: int) { return double } - + overflow = true */ - } else if - let string = value as? String, - case let .convertFromString(posInfString, negInfString, nanString) = options + } else if let string = value as? String, + case .convertFromString(let posInfString, let negInfString, let nanString) = options .nonConformingFloatDecodingStrategy { if string == posInfString { @@ -3032,7 +3083,7 @@ private extension _AnyDecoder { throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } - func unbox(_ value: Any, as type: String.Type) throws -> String? { + fileprivate func unbox(_ value: Any, as type: String.Type) throws -> String? { guard !(value is NSNull) else { return nil } guard let string = value as? String else { @@ -3042,7 +3093,7 @@ private extension _AnyDecoder { return string } - func unbox(_ value: Any, as _: Date.Type) throws -> Date? { + fileprivate func unbox(_ value: Any, as _: Date.Type) throws -> Date? { guard !(value is NSNull) else { return nil } switch options.dateDecodingStrategy { @@ -3063,10 +3114,12 @@ private extension _AnyDecoder { if #available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { let string = try self.unbox(value, as: String.self)! guard let date = _iso8601Formatter().date(from: string) else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: self.codingPath, - debugDescription: "Expected date string to be ISO8601-formatted." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: self.codingPath, + debugDescription: "Expected date string to be ISO8601-formatted." + ) + ) } return date @@ -3074,25 +3127,27 @@ private extension _AnyDecoder { fatalError("ISO8601DateFormatter is unavailable on this platform.") } - case let .formatted(formatter): + case .formatted(let formatter): let string = try unbox(value, as: String.self)! guard let date = formatter.date(from: string) else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Date string does not match format expected by formatter." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Date string does not match format expected by formatter." + ) + ) } return date - case let .custom(closure): + case .custom(let closure): storage.push(container: value) defer { self.storage.popContainer() } return try closure(self) } } - func unbox(_ value: Any, as type: Data.Type) throws -> Data? { + fileprivate func unbox(_ value: Any, as type: Data.Type) throws -> Data? { guard !(value is NSNull) else { return nil } switch options.dataDecodingStrategy { @@ -3107,22 +3162,24 @@ private extension _AnyDecoder { } guard let data = Data(base64Encoded: string) else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Encountered Data is not valid Base64." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Encountered Data is not valid Base64." + ) + ) } return data - case let .custom(closure): + case .custom(let closure): storage.push(container: value) defer { self.storage.popContainer() } return try closure(self) } } - func unbox(_ value: Any, as _: Decimal.Type) throws -> Decimal? { + fileprivate func unbox(_ value: Any, as _: Decimal.Type) throws -> Decimal? { guard !(value is NSNull) else { return nil } // Attempt to bridge from NSDecimalNumber. @@ -3134,7 +3191,10 @@ private extension _AnyDecoder { } } - func unbox(_ value: Any, as type: _AnyStringDictionaryDecodableMarker.Type) throws -> T? { + fileprivate func unbox(_ value: Any, as type: _AnyStringDictionaryDecodableMarker.Type) + throws + -> T? + { guard !(value is NSNull) else { return nil } var result = [String: Any]() @@ -3153,11 +3213,11 @@ private extension _AnyDecoder { return result as? T } - func unbox(_ value: Any, as type: T.Type) throws -> T? { + fileprivate func unbox(_ value: Any, as type: T.Type) throws -> T? { return try unbox_(value, as: type) as? T } - func unbox_(_ value: Any, as type: Decodable.Type) throws -> Any? { + fileprivate func unbox_(_ value: Any, as type: Decodable.Type) throws -> Any? { #if DEPLOYMENT_RUNTIME_SWIFT // Bridging differences require us to split implementations here if type == Date.self { @@ -3172,10 +3232,12 @@ private extension _AnyDecoder { } guard let url = URL(string: urlString) else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Invalid URL string." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Invalid URL string." + ) + ) } return url } else if type == Decimal.self { @@ -3199,10 +3261,12 @@ private extension _AnyDecoder { } guard let url = URL(string: urlString) else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Invalid URL string." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Invalid URL string." + ) + ) } return url @@ -3265,14 +3329,14 @@ private func _iso8601Formatter() -> ISO8601DateFormatter { // Error Utilities //===----------------------------------------------------------------------===// -private extension EncodingError { +extension EncodingError { /// Returns a `.invalidValue` error describing the given invalid floating-point value. /// /// /// - parameter value: The value that was invalid to encode. /// - parameter path: The path of `CodingKey`s taken to encode this value. /// - returns: An `EncodingError` with the appropriate path and debug description. - static func _invalidFloatingPointValue( + fileprivate static func _invalidFloatingPointValue( _ value: T, at codingPath: [CodingKey] ) -> EncodingError { diff --git a/Sources/GraphQL/Map/AnySerialization.swift b/Sources/GraphQL/Map/AnySerialization.swift index 9520d9f3..fda05e94 100644 --- a/Sources/GraphQL/Map/AnySerialization.swift +++ b/Sources/GraphQL/Map/AnySerialization.swift @@ -11,7 +11,8 @@ public enum AnySerialization { map, EncodingError.Context( codingPath: [], - debugDescription: "Expected object input to be castable to NSObject: \(type(of: map))" + debugDescription: + "Expected object input to be castable to NSObject: \(type(of: map))" ) ) } diff --git a/Sources/GraphQL/Map/GraphQLJSONEncoder.swift b/Sources/GraphQL/Map/GraphQLJSONEncoder.swift index e709b012..d7cd763f 100644 --- a/Sources/GraphQL/Map/GraphQLJSONEncoder.swift +++ b/Sources/GraphQL/Map/GraphQLJSONEncoder.swift @@ -131,21 +131,19 @@ open class GraphQLJSONEncoder: @unchecked Sendable { // // We assume, per Swift naming conventions, that the first character of the key is lowercase. var wordStart = stringKey.startIndex - var searchRange = stringKey.index(after: wordStart) ..< stringKey.endIndex + var searchRange = stringKey.index(after: wordStart)..1 capital letters. Turn those into a word, stopping at the capital before the lower case character. let beforeLowerIndex = stringKey.index(before: lowerCaseRange.lowerBound) - words.append(upperCaseRange.lowerBound ..< beforeLowerIndex) + words.append(upperCaseRange.lowerBound.. JSONValue in switch future { - case let .value(value): + case .value(let value): return value - case let .nestedArray(array): + case .nestedArray(let array): return .array(array.values) - case let .nestedObject(object): + case .nestedObject(let object): return .object(object.values) - case let .encoder(encoder): + case .encoder(let encoder): return encoder.value ?? .object([:]) } } @@ -328,7 +326,7 @@ private enum JSONFuture { preconditionFailure( "For key \"\(key)\" a keyed container has already been created." ) - case let .nestedArray(array): + case .nestedArray(let array): return array case .none, .value: let array = RefArray() @@ -341,7 +339,7 @@ private enum JSONFuture { switch dict[key] { case .encoder: preconditionFailure("For key \"\(key)\" an encoder has already been created.") - case let .nestedObject(object): + case .nestedObject(let object): return object case .nestedArray: preconditionFailure( @@ -374,13 +372,13 @@ private enum JSONFuture { var values: OrderedDictionary { dict.mapValues { future -> JSONValue in switch future { - case let .value(value): + case .value(let value): return value - case let .nestedArray(array): + case .nestedArray(let array): return .array(array.values) - case let .nestedObject(object): + case .nestedObject(let object): return .object(object.values) - case let .encoder(encoder): + case .encoder(let encoder): return encoder.value ?? .object([:]) } } @@ -417,7 +415,7 @@ private class JSONEncoderImpl { extension JSONEncoderImpl: Encoder { func container(keyedBy _: Key.Type) -> KeyedEncodingContainer where Key: CodingKey { - if let _ = object { + if object != nil { let container = JSONKeyedEncodingContainer(impl: self, codingPath: codingPath) return KeyedEncodingContainer(container) } @@ -432,7 +430,7 @@ extension JSONEncoderImpl: Encoder { } func unkeyedContainer() -> UnkeyedEncodingContainer { - if let _ = array { + if array != nil { return JSONUnkeyedEncodingContainer(impl: self, codingPath: codingPath) } @@ -487,14 +485,13 @@ private protocol _SpecialTreatmentEncoder { } extension _SpecialTreatmentEncoder { - @inline(__always) fileprivate func wrapFloat< - F: FloatingPoint & - CustomStringConvertible + @inline(__always) + fileprivate func wrapFloat< + F: FloatingPoint & CustomStringConvertible >(_ float: F, for additionalKey: CodingKey?) throws -> JSONValue { guard !float.isNaN, !float.isInfinite else { - if - case let .convertToString(posInfString, negInfString, nanString) = options - .nonConformingFloatEncodingStrategy + if case .convertToString(let posInfString, let negInfString, let nanString) = options + .nonConformingFloatEncodingStrategy { switch float { case F.infinity: @@ -512,10 +509,13 @@ extension _SpecialTreatmentEncoder { path.append(additionalKey) } - throw EncodingError.invalidValue(float, .init( - codingPath: path, - debugDescription: "Unable to encode \(F.self).\(float) directly in JSON." - )) + throw EncodingError.invalidValue( + float, + .init( + codingPath: path, + debugDescription: "Unable to encode \(F.self).\(float) directly in JSON." + ) + ) } var string = float.description @@ -565,10 +565,10 @@ extension _SpecialTreatmentEncoder { fatalError("ISO8601DateFormatter is unavailable on this platform.") } - case let .formatted(formatter): + case .formatted(let formatter): return .string(formatter.string(from: date)) - case let .custom(closure): + case .custom(let closure): let encoder = getEncoder(for: additionalKey) try closure(date, encoder) // The closure didn't encode anything. Return the default keyed container. @@ -587,7 +587,7 @@ extension _SpecialTreatmentEncoder { let base64 = data.base64EncodedString() return .string(base64) - case let .custom(closure): + case .custom(let closure): let encoder = getEncoder(for: additionalKey) try closure(data, encoder) // The closure didn't encode anything. Return the default keyed container. @@ -663,7 +663,7 @@ private struct JSONKeyedEncodingContainer: KeyedEncodingContainerP let newKeyString = GraphQLJSONEncoder.KeyEncodingStrategy ._convertToSnakeCase(key.stringValue) return _JSONKey(stringValue: newKeyString, intValue: key.intValue) - case let .custom(converter): + case .custom(let converter): return converter(codingPath + [key]) } } @@ -734,8 +734,8 @@ private struct JSONKeyedEncodingContainer: KeyedEncodingContainerP object.set(encoded ?? .object([:]), for: convertedKey.stringValue) } - mutating func nestedContainer(keyedBy _: NestedKey.Type, forKey key: Self.Key) -> - KeyedEncodingContainer where NestedKey: CodingKey + mutating func nestedContainer(keyedBy _: NestedKey.Type, forKey key: Self.Key) + -> KeyedEncodingContainer where NestedKey: CodingKey { let convertedKey = _converted(key) let newPath = codingPath + [convertedKey] @@ -775,9 +775,9 @@ private struct JSONKeyedEncodingContainer: KeyedEncodingContainerP } extension JSONKeyedEncodingContainer { - @inline(__always) private mutating func encodeFloatingPoint< - F: FloatingPoint & - CustomStringConvertible + @inline(__always) + private mutating func encodeFloatingPoint< + F: FloatingPoint & CustomStringConvertible >(_ float: F, key: CodingKey) throws { let value = try wrapFloat(float, for: key) object.set(value, for: key.stringValue) @@ -884,9 +884,9 @@ private struct JSONUnkeyedEncodingContainer: UnkeyedEncodingContainer, _SpecialT array.append(encoded ?? .object([:])) } - mutating func nestedContainer(keyedBy _: NestedKey.Type) -> - KeyedEncodingContainer where NestedKey: CodingKey - { + mutating func nestedContainer(keyedBy _: NestedKey.Type) -> KeyedEncodingContainer< + NestedKey + > where NestedKey: CodingKey { let newPath = codingPath + [_JSONKey(index: count)] let object = array.appendObject() let nestedContainer = JSONKeyedEncodingContainer( @@ -916,13 +916,17 @@ private struct JSONUnkeyedEncodingContainer: UnkeyedEncodingContainer, _SpecialT } extension JSONUnkeyedEncodingContainer { - @inline(__always) private mutating func encodeFixedWidthInteger(_ value: N) throws { + @inline(__always) private mutating func encodeFixedWidthInteger( + _ value: N + ) + throws + { array.append(.number(value.description)) } - @inline(__always) private mutating func encodeFloatingPoint< - F: FloatingPoint & - CustomStringConvertible + @inline(__always) + private mutating func encodeFloatingPoint< + F: FloatingPoint & CustomStringConvertible >(_ float: F) throws { let value = try wrapFloat(float, for: _JSONKey(index: count)) array.append(value) @@ -1022,14 +1026,18 @@ private struct JSONSingleValueEncodingContainer: SingleValueEncodingContainer, } extension JSONSingleValueEncodingContainer { - @inline(__always) private mutating func encodeFixedWidthInteger(_ value: N) throws { + @inline(__always) private mutating func encodeFixedWidthInteger( + _ value: N + ) + throws + { preconditionCanEncodeNewValue() impl.singleValue = .number(value.description) } - @inline(__always) private mutating func encodeFloatingPoint< - F: FloatingPoint & - CustomStringConvertible + @inline(__always) + private mutating func encodeFloatingPoint< + F: FloatingPoint & CustomStringConvertible >(_ float: F) throws { preconditionCanEncodeNewValue() let value = try wrapFloat(float, for: nil) @@ -1037,8 +1045,8 @@ extension JSONSingleValueEncodingContainer { } } -private extension JSONValue { - struct Writer { +extension JSONValue { + fileprivate struct Writer { let options: GraphQLJSONEncoder.OutputFormatting init(options: GraphQLJSONEncoder.OutputFormatting) { @@ -1063,11 +1071,11 @@ private extension JSONValue { bytes.append(contentsOf: [UInt8]._true) case .bool(false): bytes.append(contentsOf: [UInt8]._false) - case let .string(string): + case .string(let string): encodeString(string, to: &bytes) - case let .number(string): + case .number(let string): bytes.append(contentsOf: string.utf8) - case let .array(array): + case .array(let array): var iterator = array.makeIterator() bytes.append(._openbracket) // we don't like branching, this is why we have this extra @@ -1079,7 +1087,7 @@ private extension JSONValue { writeValue(item, into: &bytes) } bytes.append(._closebracket) - case let .object(dict): + case .object(let dict): if #available(OSX 10.13, *), options.contains(.sortedKeys) { let sorted = dict.sorted { $0.key < $1.key } self.writeObject(sorted, into: &bytes) @@ -1094,8 +1102,7 @@ private extension JSONValue { into bytes: inout [UInt8], depth _: Int = 0 ) - where Object.Element == (key: String, value: JSONValue) - { + where Object.Element == (key: String, value: JSONValue) { var iterator = object.makeIterator() bytes.append(._openbrace) if let (key, value) = iterator.next() { @@ -1130,11 +1137,11 @@ private extension JSONValue { bytes.append(contentsOf: [UInt8]._true) case .bool(false): bytes.append(contentsOf: [UInt8]._false) - case let .string(string): + case .string(let string): encodeString(string, to: &bytes) - case let .number(string): + case .number(let string): bytes.append(contentsOf: string.utf8) - case let .array(array): + case .array(let array): var iterator = array.makeIterator() bytes.append(contentsOf: [._openbracket, ._newline]) if let first = iterator.next() { @@ -1149,7 +1156,7 @@ private extension JSONValue { bytes.append(._newline) addInset(to: &bytes, depth: depth) bytes.append(._closebracket) - case let .object(dict): + case .object(let dict): if #available(OSX 10.13, *), options.contains(.sortedKeys) { let sorted = dict.sorted { $0.key < $1.key } self.writePrettyObject(sorted, into: &bytes, depth: depth) @@ -1164,8 +1171,7 @@ private extension JSONValue { into bytes: inout [UInt8], depth: Int = 0 ) - where Object.Element == (key: String, value: JSONValue) - { + where Object.Element == (key: String, value: JSONValue) { var iterator = object.makeIterator() bytes.append(contentsOf: [._openbrace, ._newline]) if let (key, value) = iterator.next() { @@ -1196,7 +1202,7 @@ private extension JSONValue { while nextIndex != stringBytes.endIndex { switch stringBytes[nextIndex] { - case 0 ..< 32, UInt8(ascii: "\""), UInt8(ascii: "\\"): + case 0..<32, UInt8(ascii: "\""), UInt8(ascii: "\\"): // All Unicode characters may be placed within the // quotation marks, except for the characters that MUST be escaped: // quotation mark, reverse solidus, and the control characters (U+0000 @@ -1204,28 +1210,28 @@ private extension JSONValue { // https://tools.ietf.org/html/rfc8259#section-7 // copy the current range over - bytes.append(contentsOf: stringBytes[startCopyIndex ..< nextIndex]) + bytes.append(contentsOf: stringBytes[startCopyIndex.. UInt8 { switch value { - case 0 ... 9: + case 0...9: return value + UInt8(ascii: "0") - case 10 ... 15: + case 10...15: return value - 10 + UInt8(ascii: "a") default: preconditionFailure() @@ -1244,7 +1250,7 @@ private extension JSONValue { nextIndex = stringBytes.index(after: nextIndex) startCopyIndex = nextIndex case UInt8(ascii: "/") where options.contains(.withoutEscapingSlashes) == false: - bytes.append(contentsOf: stringBytes[startCopyIndex ..< nextIndex]) + bytes.append(contentsOf: stringBytes[startCopyIndex.. ISO8601DateFormatter { // Error Utilities //===----------------------------------------------------------------------===// -private extension EncodingError { +extension EncodingError { /// Returns a `.invalidValue` error describing the given invalid floating-point value. /// /// /// - parameter value: The value that was invalid to encode. /// - parameter path: The path of `CodingKey`s taken to encode this value. /// - returns: An `EncodingError` with the appropriate path and debug description. - static func _invalidFloatingPointValue( + fileprivate static func _invalidFloatingPointValue( _ value: T, at codingPath: [CodingKey] ) -> EncodingError { diff --git a/Sources/GraphQL/Map/Map.swift b/Sources/GraphQL/Map/Map.swift index fbe751bc..418444b3 100644 --- a/Sources/GraphQL/Map/Map.swift +++ b/Sources/GraphQL/Map/Map.swift @@ -31,66 +31,66 @@ public enum Map: Sendable { // MARK: Initializers -public extension Map { - static let encoder = MapEncoder() +extension Map { + public static let encoder = MapEncoder() - init(_ encodable: T, encoder: MapEncoder = Map.encoder) throws { + public init(_ encodable: T, encoder: MapEncoder = Map.encoder) throws { self = try encoder.encode(encodable) } - init(_ number: Number) { + public init(_ number: Number) { self = .number(number) } - init(_ bool: Bool) { + public init(_ bool: Bool) { self = .bool(bool) } - init(_ int: Int) { + public init(_ int: Int) { self.init(Number(int)) } - init(_ double: Double) { + public init(_ double: Double) { self.init(Number(double)) } - init(_ string: String) { + public init(_ string: String) { self = .string(string) } - init(_ array: [Map]) { + public init(_ array: [Map]) { self = .array(array) } - init(_ dictionary: OrderedDictionary) { + public init(_ dictionary: OrderedDictionary) { self = .dictionary(dictionary) } - init(_ number: Number?) { + public init(_ number: Number?) { self = number.map { Map($0) } ?? .null } - init(_ bool: Bool?) { + public init(_ bool: Bool?) { self.init(bool.map { Number($0) }) } - init(_ int: Int?) { + public init(_ int: Int?) { self.init(int.map { Number($0) }) } - init(_ double: Double?) { + public init(_ double: Double?) { self.init(double.map { Number($0) }) } - init(_ string: String?) { + public init(_ string: String?) { self = string.map { Map($0) } ?? .null } - init(_ array: [Map]?) { + public init(_ array: [Map]?) { self = array.map { Map($0) } ?? .null } - init(_ dictionary: OrderedDictionary?) { + public init(_ dictionary: OrderedDictionary?) { self = dictionary.map { Map($0) } ?? .null } } @@ -110,18 +110,20 @@ public func map(from value: Any?) throws -> Map { return map } - if - let value = value as? OrderedDictionary, - let dictionary: OrderedDictionary = try? value - .reduce(into: [:], { result, pair in - result[pair.key] = try map(from: pair.value) - }) + if let value = value as? OrderedDictionary, + let dictionary: OrderedDictionary = + try? value + .reduce( + into: [:], + { result, pair in + result[pair.key] = try map(from: pair.value) + } + ) { return .dictionary(dictionary) } - if - let value = value as? [Any], + if let value = value as? [Any], let array: [Map] = try? value.map({ value in try map(from: value) }) @@ -129,8 +131,7 @@ public func map(from value: Any?) throws -> Map { return .array(array) } - if - let value = value as? Encodable, + if let value = value as? Encodable, let map = try? Map(AnyEncodable(value)) { return map @@ -139,8 +140,8 @@ public func map(from value: Any?) throws -> Map { throw MapError.incompatibleType } -public extension Map { - init(any: Any?) throws { +extension Map { + public init(any: Any?) throws { switch any { case .none: self = .null @@ -166,43 +167,43 @@ public extension Map { // MARK: is -public extension Map { - var isUndefined: Bool { +extension Map { + public var isUndefined: Bool { if case .undefined = self { return true } return false } - var isNull: Bool { + public var isNull: Bool { if case .null = self { return true } return false } - var isNumber: Bool { + public var isNumber: Bool { if case .number = self { return true } return false } - var isString: Bool { + public var isString: Bool { if case .string = self { return true } return false } - var isArray: Bool { + public var isArray: Bool { if case .array = self { return true } return false } - var isDictionary: Bool { + public var isDictionary: Bool { if case .dictionary = self { return true } @@ -212,8 +213,8 @@ public extension Map { // MARK: is -public extension Map { - var typeDescription: String { +extension Map { + public var typeDescription: String { switch self { case .undefined: return "undefined" @@ -235,36 +236,36 @@ public extension Map { // MARK: as? -public extension Map { - var bool: Bool? { +extension Map { + public var bool: Bool? { return try? boolValue() } - var int: Int? { + public var int: Int? { return try? intValue() } - var double: Double? { + public var double: Double? { return try? doubleValue() } - var string: String? { + public var string: String? { return try? stringValue() } - var array: [Map]? { + public var array: [Map]? { return try? arrayValue() } - var dictionary: OrderedDictionary? { + public var dictionary: OrderedDictionary? { return try? dictionaryValue() } } // MARK: try as() -public extension Map { - func boolValue(converting: Bool = false) throws -> Bool { +extension Map { + public func boolValue(converting: Bool = false) throws -> Bool { guard converting else { return try get() } @@ -276,28 +277,28 @@ public extension Map { case .null: return false - case let .bool(value): + case .bool(let value): return value - case let .number(number): + case .number(let number): return number.boolValue - case let .string(value): + case .string(let value): switch value.lowercased() { case "true": return true case "false": return false default: throw MapError.incompatibleType } - case let .array(value): + case .array(let value): return !value.isEmpty - case let .dictionary(value): + case .dictionary(let value): return !value.isEmpty } } - func intValue(converting: Bool = false) throws -> Int { + public func intValue(converting: Bool = false) throws -> Int { guard converting else { return try (get() as Number).intValue } @@ -306,10 +307,10 @@ public extension Map { case .null: return 0 - case let .number(number): + case .number(let number): return number.intValue - case let .string(value): + case .string(let value): guard let value = Int(value) else { throw MapError.incompatibleType } @@ -321,7 +322,7 @@ public extension Map { } } - func doubleValue(converting: Bool = false) throws -> Double { + public func doubleValue(converting: Bool = false) throws -> Double { guard converting else { return try (get() as Number).doubleValue } @@ -330,10 +331,10 @@ public extension Map { case .null: return 0 - case let .number(number): + case .number(let number): return number.doubleValue - case let .string(value): + case .string(let value): guard let value = Double(value) else { throw MapError.incompatibleType } @@ -345,7 +346,7 @@ public extension Map { } } - func stringValue(converting: Bool = false) throws -> String { + public func stringValue(converting: Bool = false) throws -> String { guard converting else { return try get() } @@ -357,13 +358,13 @@ public extension Map { case .null: return "null" - case let .bool(value): + case .bool(let value): return "\(value)" - case let .number(number): + case .number(let number): return number.stringValue - case let .string(value): + case .string(let value): return value case .array: @@ -374,13 +375,13 @@ public extension Map { } } - func arrayValue(converting: Bool = false) throws -> [Map] { + public func arrayValue(converting: Bool = false) throws -> [Map] { guard converting else { return try get() } switch self { - case let .array(value): + case .array(let value): return value case .null: @@ -391,13 +392,13 @@ public extension Map { } } - func dictionaryValue(converting: Bool = false) throws -> OrderedDictionary { + public func dictionaryValue(converting: Bool = false) throws -> OrderedDictionary { guard converting else { return try get() } switch self { - case let .dictionary(value): + case .dictionary(let value): return value case .null: @@ -411,19 +412,19 @@ public extension Map { // MARK: Get -public extension Map { - func get(_ indexPath: IndexPathElement...) throws -> T { +extension Map { + public func get(_ indexPath: IndexPathElement...) throws -> T { if indexPath.isEmpty { switch self { - case let .number(value as T): + case .number(let value as T): return value - case let .bool(value as T): + case .bool(let value as T): return value - case let .string(value as T): + case .string(let value as T): return value - case let .array(value as T): + case .array(let value as T): return value - case let .dictionary(value as T): + case .dictionary(let value as T): return value default: throw MapError.incompatibleType @@ -433,16 +434,16 @@ public extension Map { return try get(IndexPath(indexPath)).get() } - func get(_ indexPath: IndexPathElement...) throws -> Map { + public func get(_ indexPath: IndexPathElement...) throws -> Map { return try get(IndexPath(indexPath)) } - func get(_ indexPath: IndexPath) throws -> Map { + public func get(_ indexPath: IndexPath) throws -> Map { var value: Map = self for element in indexPath.elements { switch element { - case let .index(index): + case .index(let index): let array = try value.arrayValue() if array.indices.contains(index) { @@ -451,7 +452,7 @@ public extension Map { throw MapError.outOfBounds } - case let .key(key): + case .key(let key): let dictionary = try value.dictionaryValue() if let newValue = dictionary[key] { @@ -468,12 +469,12 @@ public extension Map { // MARK: Set -public extension Map { - mutating func set(_ value: Map, for indexPath: IndexPathElement...) throws { +extension Map { + public mutating func set(_ value: Map, for indexPath: IndexPathElement...) throws { try set(value, for: indexPath) } - mutating func set(_ value: Map, for indexPath: [IndexPathElement]) throws { + public mutating func set(_ value: Map, for indexPath: [IndexPathElement]) throws { try set(value, for: IndexPath(indexPath), merging: true) } @@ -481,15 +482,16 @@ public extension Map { var elements = indexPath.elements guard let first = elements.first else { - return self = value + self = value + return } elements.removeFirst() if elements.isEmpty { switch first { - case let .index(index): - if case var .array(array) = self { + case .index(let index): + if case .array(var array) = self { if !array.indices.contains(index) { throw MapError.outOfBounds } @@ -499,12 +501,11 @@ public extension Map { } else { throw MapError.incompatibleType } - case let .key(key): - if case var .dictionary(dictionary) = self { + case .key(let key): + if case .dictionary(var dictionary) = self { let newValue = value - if - let existingDictionary = dictionary[key]?.dictionary, + if let existingDictionary = dictionary[key]?.dictionary, let newDictionary = newValue.dictionary, merging { @@ -538,24 +539,25 @@ public extension Map { // MARK: Remove -public extension Map { - mutating func remove(_ indexPath: IndexPathElement...) throws { +extension Map { + public mutating func remove(_ indexPath: IndexPathElement...) throws { try remove(indexPath) } - mutating func remove(_ indexPath: [IndexPathElement]) throws { + public mutating func remove(_ indexPath: [IndexPathElement]) throws { var indexPath = indexPath guard let first = indexPath.first else { - return self = .null + self = .null + return } indexPath.removeFirst() if indexPath.isEmpty { guard - case var .dictionary(dictionary) = self, - case let .key(key) = first.indexPathValue + case .dictionary(var dictionary) = self, + case .key(let key) = first.indexPathValue else { throw MapError.incompatibleType } @@ -574,8 +576,8 @@ public extension Map { // MARK: Subscripts -public extension Map { - subscript(indexPath: IndexPathElement...) -> Map { +extension Map { + public subscript(indexPath: IndexPathElement...) -> Map { get { return self[IndexPath(indexPath)] } @@ -585,7 +587,7 @@ public extension Map { } } - subscript(indexPath: IndexPath) -> Map { + public subscript(indexPath: IndexPath) -> Map { get { return (try? get(indexPath)) ?? nil } @@ -632,7 +634,7 @@ extension Map: Codable { self = .string(string) } else if let array = try? container.decode([Map].self) { self = .array(array) - } else if let _ = try? container.decode([String: Map].self) { + } else if (try? container.decode([String: Map].self)) != nil { // Override OrderedDictionary default (unkeyed alternating key-value) // Instead decode as a keyed container (like normal Dictionary) but use the order of the // input @@ -667,15 +669,15 @@ extension Map: Codable { ) case .null: try container.encodeNil() - case let .bool(value): + case .bool(let value): try container.encode(value) - case let .number(number): + case .number(let number): try container.encode(number.doubleValue) - case let .string(string): + case .string(let string): try container.encode(string) - case let .array(array): + case .array(let array): try container.encode(array) - case let .dictionary(dictionary): + case .dictionary(let dictionary): // Override OrderedDictionary default (unkeyed alternating key-value) // Instead decode as a keyed container (like normal Dictionary) in the order of our // OrderedDictionary @@ -727,15 +729,15 @@ public func == (lhs: Map, rhs: Map) -> Bool { return true case (.null, .null): return true - case let (.bool(l), .bool(r)) where l == r: + case (.bool(let l), .bool(let r)) where l == r: return true - case let (.number(l), .number(r)) where l == r: + case (.number(let l), .number(let r)) where l == r: return true - case let (.string(l), .string(r)) where l == r: + case (.string(let l), .string(let r)) where l == r: return true - case let (.array(l), .array(r)) where l == r: + case (.array(let l), .array(let r)) where l == r: return true - case let (.dictionary(l), .dictionary(r)) where l == r: + case (.dictionary(let l), .dictionary(let r)) where l == r: return true default: return false @@ -751,15 +753,15 @@ extension Map: Hashable { hasher.combine(0) case .null: hasher.combine(0) - case let .bool(value): + case .bool(let value): hasher.combine(value) - case let .number(number): + case .number(let number): hasher.combine(number) - case let .string(string): + case .string(let string): hasher.combine(string) - case let .array(array): + case .array(let array): hasher.combine(array) - case let .dictionary(dictionary): + case .dictionary(let dictionary): hasher.combine(dictionary) } } @@ -841,8 +843,8 @@ extension Map: CustomDebugStringConvertible { // MARK: Generic Description -public extension Map { - func description(debug: Bool) -> String { +extension Map { + public func description(debug: Bool) -> String { var indentLevel = 0 let escapeMapping: [Character: String] = [ @@ -879,15 +881,15 @@ public extension Map { return "undefined" case .null: return "null" - case let .bool(value): + case .bool(let value): return value.description - case let .number(number): + case .number(let number): return number.description - case let .string(string): + case .string(let string): return escape(string) - case let .array(array): + case .array(let array): return serialize(array: array) - case let .dictionary(dictionary): + case .dictionary(let dictionary): return serialize(dictionary: dictionary) } } @@ -899,7 +901,7 @@ public extension Map { indentLevel += 1 } - for index in 0 ..< array.count { + for index in 0..1 capital letters. Turn those into a word, stopping at the capital before the lower case character. let beforeLowerIndex = stringKey.index(before: lowerCaseRange.lowerBound) - words.append(upperCaseRange.lowerBound ..< beforeLowerIndex) + words.append(upperCaseRange.lowerBound..: KeyedEncodingContainerP case .convertToSnakeCase: let newKeyString = MapEncoder.KeyEncodingStrategy._convertToSnakeCase(key.stringValue) return _MapKey(stringValue: newKeyString, intValue: key.intValue) - case let .custom(converter): + case .custom(let converter): return converter(codingPath + [key]) } } @@ -636,8 +639,7 @@ private struct _MapUnkeyedEncodingContainer: UnkeyedEncodingContainer { } public mutating func nestedContainer( - keyedBy _: NestedKey - .Type + keyedBy _: NestedKey.Type ) -> KeyedEncodingContainer { codingPath.append(_MapKey(index: count)) defer { self.codingPath.removeLast() } @@ -768,28 +770,28 @@ extension _MapEncoder: SingleValueEncodingContainer { // MARK: - Concrete Value Representations -private extension _MapEncoder { +extension _MapEncoder { /// Returns the given value boxed in a container appropriate for pushing onto the container stack. - func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } - func box(_ value: Int) -> NSObject { return NSNumber(value: value) } - func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } - func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } - func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } - func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } - func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } - func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } - func box(_ value: UInt16) -> NSObject { return NSNumber(value: value) } - func box(_ value: UInt32) -> NSObject { return NSNumber(value: value) } - func box(_ value: UInt64) -> NSObject { return NSNumber(value: value) } - func box(_ value: String) -> NSObject { return NSString(string: value) } - - func box(_ float: Float) throws -> NSObject { + fileprivate func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt16) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt32) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt64) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: String) -> NSObject { return NSString(string: value) } + + fileprivate func box(_ float: Float) throws -> NSObject { guard !float.isInfinite, !float.isNaN else { guard - case let .convertToString( - positiveInfinity: posInfString, - negativeInfinity: negInfString, - nan: nanString + case .convertToString( + positiveInfinity: let posInfString, + negativeInfinity: let negInfString, + nan: let nanString ) = options.nonConformingFloatEncodingStrategy else { throw EncodingError._invalidFloatingPointValue(float, at: codingPath) @@ -807,13 +809,13 @@ private extension _MapEncoder { return NSNumber(value: float) } - func box(_ double: Double) throws -> NSObject { + fileprivate func box(_ double: Double) throws -> NSObject { guard !double.isInfinite, !double.isNaN else { guard - case let .convertToString( - positiveInfinity: posInfString, - negativeInfinity: negInfString, - nan: nanString + case .convertToString( + positiveInfinity: let posInfString, + negativeInfinity: let negInfString, + nan: let nanString ) = options.nonConformingFloatEncodingStrategy else { throw EncodingError._invalidFloatingPointValue(double, at: codingPath) @@ -831,7 +833,7 @@ private extension _MapEncoder { return NSNumber(value: double) } - func box(_ date: Date) throws -> NSObject { + fileprivate func box(_ date: Date) throws -> NSObject { switch options.dateEncodingStrategy { case .deferredToDate: // Must be called with a surrounding with(pushedKey:) call. @@ -852,10 +854,10 @@ private extension _MapEncoder { fatalError("ISO8601DateFormatter is unavailable on this platform.") } - case let .formatted(formatter): + case .formatted(let formatter): return NSString(string: formatter.string(from: date)) - case let .custom(closure): + case .custom(let closure): let depth = storage.count do { try closure(date, self) @@ -877,7 +879,7 @@ private extension _MapEncoder { } } - func box(_ data: Data) throws -> NSObject { + fileprivate func box(_ data: Data) throws -> NSObject { switch options.dataEncodingStrategy { case .deferredToData: // Must be called with a surrounding with(pushedKey:) call. @@ -897,7 +899,7 @@ private extension _MapEncoder { case .base64: return NSString(string: data.base64EncodedString()) - case let .custom(closure): + case .custom(let closure): let depth = storage.count do { try closure(data, self) @@ -918,7 +920,7 @@ private extension _MapEncoder { } } - func box(_ dict: OrderedDictionary) throws -> NSObject? { + fileprivate func box(_ dict: OrderedDictionary) throws -> NSObject? { let depth = storage.count let result = storage.pushKeyedContainer() do { @@ -944,12 +946,12 @@ private extension _MapEncoder { return storage.popContainer() } - func box(_ value: Encodable) throws -> NSObject { + fileprivate func box(_ value: Encodable) throws -> NSObject { return try box_(value) ?? NSDictionary() } // This method is called "box_" instead of "box" to disambiguate it from the overloads. Because the return type here is different from all of the "box" overloads (and is more general), any "box" calls in here would call back into "box" recursively instead of calling the appropriate overload, which is not what we want. - func box_(_ value: Encodable) throws -> NSObject? { + fileprivate func box_(_ value: Encodable) throws -> NSObject? { let type = Swift.type(of: value) #if DEPLOYMENT_RUNTIME_SWIFT if type == Date.self { @@ -1080,10 +1082,10 @@ private class _MapReferencingEncoder: _MapEncoder { } switch self.reference { - case let .array(array, index): + case .array(let array, let index): array.insert(value, at: index) - case let .dictionary(dictionary, key): + case .dictionary(let dictionary, let key): dictionary[NSString(string: key)] = value } } @@ -1177,9 +1179,12 @@ open class MapDecoder: @unchecked Sendable { stringKey.formIndex(before: &lastNonUnderscore) } - let keyRange = firstNonUnderscore ... lastNonUnderscore - let leadingUnderscoreRange = stringKey.startIndex ..< firstNonUnderscore - let trailingUnderscoreRange = stringKey.index(after: lastNonUnderscore) ..< stringKey + let keyRange = firstNonUnderscore...lastNonUnderscore + let leadingUnderscoreRange = stringKey.startIndex...self, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead." + debugDescription: + "Cannot get keyed decoding container -- found null value instead." ) ) } @@ -1344,7 +1351,8 @@ private class _MapDecoder: Decoder { UnkeyedDecodingContainer.self, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get unkeyed decoding container -- found null value instead." + debugDescription: + "Cannot get unkeyed decoding container -- found null value instead." ) ) } @@ -1427,17 +1435,26 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP case .convertFromSnakeCase: // Convert the snake case keys in the container to camel case. // If we hit a duplicate key after conversion, then we'll use the first one we saw. Effectively an undefined behavior with Map dictionaries. - self.container = Dictionary(container.map { - key, value in (MapDecoder.KeyDecodingStrategy._convertFromSnakeCase(key), value) - }, uniquingKeysWith: { first, _ in first }) - case let .custom(converter): - self.container = Dictionary(container.map { - key, value in ( - converter(decoder.codingPath + [_MapKey(stringValue: key, intValue: nil)]) - .stringValue, - value - ) - }, uniquingKeysWith: { first, _ in first }) + self.container = Dictionary( + container.map { + key, + value in (MapDecoder.KeyDecodingStrategy._convertFromSnakeCase(key), value) + }, + uniquingKeysWith: { first, _ in first } + ) + case .custom(let converter): + self.container = Dictionary( + container.map { + key, + value in + ( + converter(decoder.codingPath + [_MapKey(stringValue: key, intValue: nil)]) + .stringValue, + value + ) + }, + uniquingKeysWith: { first, _ in first } + ) } codingPath = decoder.codingPath } @@ -1476,7 +1493,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1491,7 +1509,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1520,7 +1539,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1549,7 +1569,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1578,7 +1599,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1607,7 +1629,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1636,7 +1659,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1665,7 +1689,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1694,7 +1719,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1723,7 +1749,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1752,7 +1779,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1781,7 +1809,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1810,7 +1839,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1839,7 +1869,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1868,7 +1899,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1897,7 +1929,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP DecodingError .Context( codingPath: decoder.codingPath, - debugDescription: "No value associated with key \(_errorDescription(of: key))." + debugDescription: + "No value associated with key \(_errorDescription(of: key))." ) ) } @@ -1933,7 +1966,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP key, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \(_errorDescription(of: key))" + debugDescription: + "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \(_errorDescription(of: key))" ) ) } @@ -1962,7 +1996,8 @@ private struct _MapKeyedDecodingContainer: KeyedDecodingContainerP key, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get UnkeyedDecodingContainer -- no value found for key \(_errorDescription(of: key))" + debugDescription: + "Cannot get UnkeyedDecodingContainer -- no value found for key \(_errorDescription(of: key))" ) ) } @@ -2501,8 +2536,7 @@ private struct _MapUnkeyedDecodingContainer: UnkeyedDecodingContainer { } public mutating func nestedContainer( - keyedBy _: NestedKey - .Type + keyedBy _: NestedKey.Type ) throws -> KeyedDecodingContainer { decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } @@ -2512,7 +2546,8 @@ private struct _MapUnkeyedDecodingContainer: UnkeyedDecodingContainer { KeyedDecodingContainer.self, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get nested keyed container -- unkeyed container is at end." + debugDescription: + "Cannot get nested keyed container -- unkeyed container is at end." ) ) } @@ -2523,7 +2558,8 @@ private struct _MapUnkeyedDecodingContainer: UnkeyedDecodingContainer { KeyedDecodingContainer.self, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead." + debugDescription: + "Cannot get keyed decoding container -- found null value instead." ) ) } @@ -2553,7 +2589,8 @@ private struct _MapUnkeyedDecodingContainer: UnkeyedDecodingContainer { UnkeyedDecodingContainer.self, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get nested keyed container -- unkeyed container is at end." + debugDescription: + "Cannot get nested keyed container -- unkeyed container is at end." ) ) } @@ -2564,7 +2601,8 @@ private struct _MapUnkeyedDecodingContainer: UnkeyedDecodingContainer { UnkeyedDecodingContainer.self, DecodingError.Context( codingPath: codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead." + debugDescription: + "Cannot get keyed decoding container -- found null value instead." ) ) } @@ -2699,9 +2737,9 @@ extension _MapDecoder: SingleValueDecodingContainer { // MARK: - Concrete Value Representations -private extension _MapDecoder { +extension _MapDecoder { /// Returns the given value unboxed from a container. - func unbox(_ value: Any, as type: Bool.Type) throws -> Bool? { + fileprivate func unbox(_ value: Any, as type: Bool.Type) throws -> Bool? { guard !(value is NSNull) else { return nil } #if DEPLOYMENT_RUNTIME_SWIFT || os(Linux) || os(Android) @@ -2735,7 +2773,7 @@ private extension _MapDecoder { #endif } - func unbox(_ value: Any, as type: Int.Type) throws -> Int? { + fileprivate func unbox(_ value: Any, as type: Int.Type) throws -> Int? { guard !(value is NSNull) else { return nil } guard @@ -2747,16 +2785,18 @@ private extension _MapDecoder { let int = number.intValue guard NSNumber(value: int) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." + ) + ) } return int } - func unbox(_ value: Any, as type: Int8.Type) throws -> Int8? { + fileprivate func unbox(_ value: Any, as type: Int8.Type) throws -> Int8? { guard !(value is NSNull) else { return nil } guard @@ -2768,16 +2808,18 @@ private extension _MapDecoder { let int8 = number.int8Value guard NSNumber(value: int8) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." + ) + ) } return int8 } - func unbox(_ value: Any, as type: Int16.Type) throws -> Int16? { + fileprivate func unbox(_ value: Any, as type: Int16.Type) throws -> Int16? { guard !(value is NSNull) else { return nil } guard @@ -2789,16 +2831,18 @@ private extension _MapDecoder { let int16 = number.int16Value guard NSNumber(value: int16) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." + ) + ) } return int16 } - func unbox(_ value: Any, as type: Int32.Type) throws -> Int32? { + fileprivate func unbox(_ value: Any, as type: Int32.Type) throws -> Int32? { guard !(value is NSNull) else { return nil } guard @@ -2810,16 +2854,18 @@ private extension _MapDecoder { let int32 = number.int32Value guard NSNumber(value: int32) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." + ) + ) } return int32 } - func unbox(_ value: Any, as type: Int64.Type) throws -> Int64? { + fileprivate func unbox(_ value: Any, as type: Int64.Type) throws -> Int64? { guard !(value is NSNull) else { return nil } guard @@ -2831,16 +2877,18 @@ private extension _MapDecoder { let int64 = number.int64Value guard NSNumber(value: int64) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." + ) + ) } return int64 } - func unbox(_ value: Any, as type: UInt.Type) throws -> UInt? { + fileprivate func unbox(_ value: Any, as type: UInt.Type) throws -> UInt? { guard !(value is NSNull) else { return nil } guard @@ -2852,16 +2900,18 @@ private extension _MapDecoder { let uint = number.uintValue guard NSNumber(value: uint) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." + ) + ) } return uint } - func unbox(_ value: Any, as type: UInt8.Type) throws -> UInt8? { + fileprivate func unbox(_ value: Any, as type: UInt8.Type) throws -> UInt8? { guard !(value is NSNull) else { return nil } guard @@ -2873,16 +2923,18 @@ private extension _MapDecoder { let uint8 = number.uint8Value guard NSNumber(value: uint8) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." + ) + ) } return uint8 } - func unbox(_ value: Any, as type: UInt16.Type) throws -> UInt16? { + fileprivate func unbox(_ value: Any, as type: UInt16.Type) throws -> UInt16? { guard !(value is NSNull) else { return nil } guard @@ -2894,16 +2946,18 @@ private extension _MapDecoder { let uint16 = number.uint16Value guard NSNumber(value: uint16) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." + ) + ) } return uint16 } - func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? { + fileprivate func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? { guard !(value is NSNull) else { return nil } guard @@ -2915,16 +2969,18 @@ private extension _MapDecoder { let uint32 = number.uint32Value guard NSNumber(value: uint32) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." + ) + ) } return uint32 } - func unbox(_ value: Any, as type: UInt64.Type) throws -> UInt64? { + fileprivate func unbox(_ value: Any, as type: UInt64.Type) throws -> UInt64? { guard !(value is NSNull) else { return nil } guard @@ -2936,20 +2992,21 @@ private extension _MapDecoder { let uint64 = number.uint64Value guard NSNumber(value: uint64) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Map number <\(number)> does not fit in \(type)." + ) + ) } return uint64 } - func unbox(_ value: Any, as type: Float.Type) throws -> Float? { + fileprivate func unbox(_ value: Any, as type: Float.Type) throws -> Float? { guard !(value is NSNull) else { return nil } - if - let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + if let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse { // We are willing to return a Float by losing precision: @@ -2960,10 +3017,12 @@ private extension _MapDecoder { // * If it was a Double or Decimal, you will get back the nearest approximation if it will fit let double = number.doubleValue guard abs(double) <= Double(Float.greatestFiniteMagnitude) else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Parsed Map number \(number) does not fit in \(type)." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Parsed Map number \(number) does not fit in \(type)." + ) + ) } return Float(double) @@ -2978,13 +3037,12 @@ private extension _MapDecoder { if let float = Float(exactly: int) { return float } - + overflow = true */ - } else if - let string = value as? String, - case let .convertFromString(posInfString, negInfString, nanString) = options + } else if let string = value as? String, + case .convertFromString(let posInfString, let negInfString, let nanString) = options .nonConformingFloatDecodingStrategy { if string == posInfString { @@ -2999,11 +3057,10 @@ private extension _MapDecoder { throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } - func unbox(_ value: Any, as type: Double.Type) throws -> Double? { + fileprivate func unbox(_ value: Any, as type: Double.Type) throws -> Double? { guard !(value is NSNull) else { return nil } - if - let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + if let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse { // We are always willing to return the number as a Double: @@ -3019,13 +3076,12 @@ private extension _MapDecoder { if let double = Double(exactly: int) { return double } - + overflow = true */ - } else if - let string = value as? String, - case let .convertFromString(posInfString, negInfString, nanString) = options + } else if let string = value as? String, + case .convertFromString(let posInfString, let negInfString, let nanString) = options .nonConformingFloatDecodingStrategy { if string == posInfString { @@ -3040,7 +3096,7 @@ private extension _MapDecoder { throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } - func unbox(_ value: Any, as type: String.Type) throws -> String? { + fileprivate func unbox(_ value: Any, as type: String.Type) throws -> String? { guard !(value is NSNull) else { return nil } guard let string = value as? String else { @@ -3050,7 +3106,7 @@ private extension _MapDecoder { return string } - func unbox(_ value: Any, as _: Date.Type) throws -> Date? { + fileprivate func unbox(_ value: Any, as _: Date.Type) throws -> Date? { guard !(value is NSNull) else { return nil } switch options.dateDecodingStrategy { @@ -3071,10 +3127,12 @@ private extension _MapDecoder { if #available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { let string = try self.unbox(value, as: String.self)! guard let date = _iso8601Formatter().date(from: string) else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: self.codingPath, - debugDescription: "Expected date string to be ISO8601-formatted." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: self.codingPath, + debugDescription: "Expected date string to be ISO8601-formatted." + ) + ) } return date @@ -3082,25 +3140,27 @@ private extension _MapDecoder { fatalError("ISO8601DateFormatter is unavailable on this platform.") } - case let .formatted(formatter): + case .formatted(let formatter): let string = try unbox(value, as: String.self)! guard let date = formatter.date(from: string) else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Date string does not match format expected by formatter." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Date string does not match format expected by formatter." + ) + ) } return date - case let .custom(closure): + case .custom(let closure): storage.push(container: value) defer { self.storage.popContainer() } return try closure(self) } } - func unbox(_ value: Any, as type: Data.Type) throws -> Data? { + fileprivate func unbox(_ value: Any, as type: Data.Type) throws -> Data? { guard !(value is NSNull) else { return nil } switch options.dataDecodingStrategy { @@ -3115,22 +3175,24 @@ private extension _MapDecoder { } guard let data = Data(base64Encoded: string) else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Encountered Data is not valid Base64." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Encountered Data is not valid Base64." + ) + ) } return data - case let .custom(closure): + case .custom(let closure): storage.push(container: value) defer { self.storage.popContainer() } return try closure(self) } } - func unbox(_ value: Any, as _: Decimal.Type) throws -> Decimal? { + fileprivate func unbox(_ value: Any, as _: Decimal.Type) throws -> Decimal? { guard !(value is NSNull) else { return nil } // Attempt to bridge from NSDecimalNumber. @@ -3142,7 +3204,10 @@ private extension _MapDecoder { } } - func unbox(_ value: Any, as type: _MapStringDictionaryDecodableMarker.Type) throws -> T? { + fileprivate func unbox(_ value: Any, as type: _MapStringDictionaryDecodableMarker.Type) + throws + -> T? + { guard !(value is NSNull) else { return nil } var result: OrderedDictionary = [:] @@ -3161,11 +3226,11 @@ private extension _MapDecoder { return result as? T } - func unbox(_ value: Any, as type: T.Type) throws -> T? { + fileprivate func unbox(_ value: Any, as type: T.Type) throws -> T? { return try unbox_(value, as: type) as? T } - func unbox_(_ value: Any, as type: Decodable.Type) throws -> Any? { + fileprivate func unbox_(_ value: Any, as type: Decodable.Type) throws -> Any? { #if DEPLOYMENT_RUNTIME_SWIFT // Bridging differences require us to split implementations here if type == Date.self { @@ -3180,10 +3245,12 @@ private extension _MapDecoder { } guard let url = URL(string: urlString) else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Invalid URL string." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Invalid URL string." + ) + ) } return url } else if type == Decimal.self { @@ -3207,10 +3274,12 @@ private extension _MapDecoder { } guard let url = URL(string: urlString) else { - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: codingPath, - debugDescription: "Invalid URL string." - )) + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Invalid URL string." + ) + ) } return url @@ -3273,14 +3342,14 @@ private func _iso8601Formatter() -> ISO8601DateFormatter { // Error Utilities //===----------------------------------------------------------------------===// -private extension EncodingError { +extension EncodingError { /// Returns a `.invalidValue` error describing the given invalid floating-point value. /// /// /// - parameter value: The value that was invalid to encode. /// - parameter path: The path of `CodingKey`s taken to encode this value. /// - returns: An `EncodingError` with the appropriate path and debug description. - static func _invalidFloatingPointValue( + fileprivate static func _invalidFloatingPointValue( _ value: T, at codingPath: [CodingKey] ) -> EncodingError { @@ -3327,7 +3396,9 @@ extension DecodingError { private static func _typeDescription(of value: Any) -> String { if value is NSNull { return "a null value" - } else if value is NSNumber /* FIXME: If swift-corelibs-foundation isn't updated to use NSNumber, this check will be necessary: || value is Int || value is Double */ { + } else if value + is NSNumber /* FIXME: If swift-corelibs-foundation isn't updated to use NSNumber, this check will be necessary: || value is Int || value is Double */ + { return "a number" } else if value is String { return "a string/data" diff --git a/Sources/GraphQL/Map/MapSerialization.swift b/Sources/GraphQL/Map/MapSerialization.swift index e4099cd8..54e8cbad 100644 --- a/Sources/GraphQL/Map/MapSerialization.swift +++ b/Sources/GraphQL/Map/MapSerialization.swift @@ -26,14 +26,16 @@ public struct MapSerialization { return .array(array) case let dictionary as NSDictionary: // Extract from an unordered dictionary, using NSDictionary extraction order - let orderedDictionary: OrderedDictionary = try dictionary + let orderedDictionary: OrderedDictionary = + try dictionary .reduce(into: [:]) { dictionary, pair in guard let key = pair.key as? String else { throw EncodingError.invalidValue( dictionary, EncodingError.Context( codingPath: [], - debugDescription: "Dictionary key was not string: \(pair.key) in \(dictionary)" + debugDescription: + "Dictionary key was not string: \(pair.key) in \(dictionary)" ) ) } @@ -42,7 +44,8 @@ public struct MapSerialization { dictionary, EncodingError.Context( codingPath: [], - debugDescription: "Dictionary value was not an object: \(key) in \(dictionary)" + debugDescription: + "Dictionary value was not an object: \(key) in \(dictionary)" ) ) } @@ -67,20 +70,21 @@ public struct MapSerialization { self, EncodingError.Context( codingPath: [], - debugDescription: "undefined values should have been excluded from serialization" + debugDescription: + "undefined values should have been excluded from serialization" ) ) case .null: return NSNull() - case let .bool(value): + case .bool(let value): return value as NSObject - case var .number(number): + case .number(var number): return number.number - case let .string(string): + case .string(let string): return string as NSString - case let .array(array): + case .array(let array): return try array.map { try object(with: $0) } as NSArray - case let .dictionary(dictionary): + case .dictionary(let dictionary): // Coerce to an unordered dictionary var unorderedDictionary: [String: NSObject] = [:] for (key, value) in dictionary { diff --git a/Sources/GraphQL/Subscription/Subscribe.swift b/Sources/GraphQL/Subscription/Subscribe.swift index 277c067f..327feeae 100644 --- a/Sources/GraphQL/Subscription/Subscribe.swift +++ b/Sources/GraphQL/Subscription/Subscribe.swift @@ -1,19 +1,17 @@ import OrderedCollections -/** - * Implements the "Subscribe" algorithm described in the GraphQL specification. - * - * Returns a `Result` that either succeeds with an `AsyncThrowingStream`, or fails with `GraphQLErrors`. - * - * If the client-provided arguments to this function do not result in a - * compliant subscription, the `Result` will fails with descriptive errors. - * - * If the source stream could not be created due to faulty subscription - * resolver logic or underlying systems, the `Result` will fail with errors. - * - * If the operation succeeded, the `Result` will succeed with an `AsyncThrowingStream` of `GraphQLResult`s - * representing the response stream. - */ +/// Implements the "Subscribe" algorithm described in the GraphQL specification. +/// +/// Returns a `Result` that either succeeds with an `AsyncThrowingStream`, or fails with `GraphQLErrors`. +/// +/// If the client-provided arguments to this function do not result in a +/// compliant subscription, the `Result` will fails with descriptive errors. +/// +/// If the source stream could not be created due to faulty subscription +/// resolver logic or underlying systems, the `Result` will fail with errors. +/// +/// If the operation succeeded, the `Result` will succeed with an `AsyncThrowingStream` of `GraphQLResult`s +/// representing the response stream. func subscribe( schema: GraphQLSchema, documentAST: Document, @@ -67,29 +65,27 @@ func subscribe( } } -/** - * Implements the "CreateSourceEventStream" algorithm described in the - * GraphQL specification, resolving the subscription source event stream. - * - * Returns a Result that either succeeds with an `AsyncSequence` or fails with `GraphQLErrors`. - * - * If the client-provided arguments to this function do not result in a - * compliant subscription, the `Result` will fail with descriptive errors. - * - * If the source stream could not be created due to faulty subscription - * resolver logic or underlying systems, the `Result` will fail with errors. - * - * If the operation succeeded, the `Result` will succeed with an AsyncSequence for the - * event stream returned by the resolver. - * - * A Source Event Stream represents a sequence of events, each of which triggers - * a GraphQL execution for that event. - * - * This may be useful when hosting the stateful subscription service in a - * different process or machine than the stateless GraphQL execution engine, - * or otherwise separating these two steps. For more on this, see the - * "Supporting Subscriptions at Scale" information in the GraphQL specification. - */ +/// Implements the "CreateSourceEventStream" algorithm described in the +/// GraphQL specification, resolving the subscription source event stream. +/// +/// Returns a Result that either succeeds with an `AsyncSequence` or fails with `GraphQLErrors`. +/// +/// If the client-provided arguments to this function do not result in a +/// compliant subscription, the `Result` will fail with descriptive errors. +/// +/// If the source stream could not be created due to faulty subscription +/// resolver logic or underlying systems, the `Result` will fail with errors. +/// +/// If the operation succeeded, the `Result` will succeed with an AsyncSequence for the +/// event stream returned by the resolver. +/// +/// A Source Event Stream represents a sequence of events, each of which triggers +/// a GraphQL execution for that event. +/// +/// This may be useful when hosting the stateful subscription service in a +/// different process or machine than the stateless GraphQL execution engine, +/// or otherwise separating these two steps. For more on this, see the +/// "Supporting Subscriptions at Scale" information in the GraphQL specification. func createSourceEventStream( schema: GraphQLSchema, documentAST: Document, @@ -204,13 +200,13 @@ func executeSubscription( let resolved: Any? switch resolvedOrError { - case let .failure(error): + case .failure(let error): if let graphQLError = error as? GraphQLError { throw graphQLError } else { throw GraphQLError(error) } - case let .success(success): + case .success(let success): resolved = success } if !context.errors.isEmpty { @@ -223,15 +219,20 @@ func executeSubscription( // return Sendable AsyncSequences. return .success(stream as! (any AsyncSequence & Sendable)) } else if resolved == nil { - return .failure(.init([ - GraphQLError(message: "Resolved subscription was nil"), - ])) + return .failure( + .init([ + GraphQLError(message: "Resolved subscription was nil") + ]) + ) } else { let resolvedObj = resolved as AnyObject - return .failure(.init([ - GraphQLError( - message: "Subscription field resolver must return an AsyncSequence. Received: '\(resolvedObj)'" - ), - ])) + return .failure( + .init([ + GraphQLError( + message: + "Subscription field resolver must return an AsyncSequence. Received: '\(resolvedObj)'" + ) + ]) + ) } } diff --git a/Sources/GraphQL/SwiftUtilities/DidYouMean.swift b/Sources/GraphQL/SwiftUtilities/DidYouMean.swift index 063b88c8..f0ef7e14 100644 --- a/Sources/GraphQL/SwiftUtilities/DidYouMean.swift +++ b/Sources/GraphQL/SwiftUtilities/DidYouMean.swift @@ -10,7 +10,7 @@ func didYouMean(_ submessage: String? = nil, suggestions: [String]) -> String { message.append("\(submessage) ") } - let suggestionList = suggestions[0 ... min(suggestions.count - 1, MAX_SUGGESTIONS - 1)] + let suggestionList = suggestions[0...min(suggestions.count - 1, MAX_SUGGESTIONS - 1)] .map { "\"\($0)\"" }.orList() return message + "\(suggestionList)?" } diff --git a/Sources/GraphQL/SwiftUtilities/FormatList.swift b/Sources/GraphQL/SwiftUtilities/FormatList.swift index a8215ac1..584dd839 100644 --- a/Sources/GraphQL/SwiftUtilities/FormatList.swift +++ b/Sources/GraphQL/SwiftUtilities/FormatList.swift @@ -18,7 +18,7 @@ extension Collection where Element == String, Index == Int { case 2: return joined(separator: " \(conjunction) ") default: - let allButLast = self[0 ... count - 2] + let allButLast = self[0...count - 2] let lastItem = self[count - 1] return allButLast.joined(separator: ", ") + ", \(conjunction) \(lastItem)" diff --git a/Sources/GraphQL/SwiftUtilities/KeyMap.swift b/Sources/GraphQL/SwiftUtilities/KeyMap.swift index 76c5046c..e03e9f29 100644 --- a/Sources/GraphQL/SwiftUtilities/KeyMap.swift +++ b/Sources/GraphQL/SwiftUtilities/KeyMap.swift @@ -1,23 +1,20 @@ -/** - * Creates a dictionary from an array, given a function to produce the keys - * for each value in the array. - * - * This provides a convenient lookup for the array items if the key function - * produces unique results. - * - * let phoneBook = [ - * ["name": "Jon", "num": "555-1234"], - * ["name": "Jenny", "num": "867-5309"], - * ] - * - * // ["Jon": ["name": "Jon", "num": "555-1234"], - * // Jenny: ["name": "Jenny", "num": "867-5309"]] - * let entriesByName = phoneBook.keyMap({ $0.name }) - * - * // ["name": "Jenny", "num": "857-6309"] - * let jennyEntry = entriesByName["Jenny"] - * - */ +/// Creates a dictionary from an array, given a function to produce the keys +/// for each value in the array. +/// +/// This provides a convenient lookup for the array items if the key function +/// produces unique results. +/// +/// let phoneBook = [ +/// ["name": "Jon", "num": "555-1234"], +/// ["name": "Jenny", "num": "867-5309"], +/// ] +/// +/// // ["Jon": ["name": "Jon", "num": "555-1234"], +/// // Jenny: ["name": "Jenny", "num": "867-5309"]] +/// let entriesByName = phoneBook.keyMap({ $0.name }) +/// +/// // ["name": "Jenny", "num": "857-6309"] +/// let jennyEntry = entriesByName["Jenny"] extension Array { func keyMap(_ keyFunction: (Element) -> String) -> [String: Element] { return reduce([:]) { map, item in diff --git a/Sources/GraphQL/SwiftUtilities/SuggestionList.swift b/Sources/GraphQL/SwiftUtilities/SuggestionList.swift index 8208735d..81ecc925 100644 --- a/Sources/GraphQL/SwiftUtilities/SuggestionList.swift +++ b/Sources/GraphQL/SwiftUtilities/SuggestionList.swift @@ -1,7 +1,5 @@ -/** - * Given an invalid input string and a list of valid options, returns a filtered - * list of valid options sorted based on their similarity with the input. - */ +/// Given an invalid input string and a list of valid options, returns a filtered +/// list of valid options sorted based on their similarity with the input. func suggestionList( input: String, options: [String] @@ -10,7 +8,7 @@ func suggestionList( let oLength = options.count let inputThreshold = input.utf8.count / 2 - for i in 0 ..< oLength { + for i in 0.. Int { let aLength = a.utf8.count let bLength = b.utf8.count var d = [[Int]](repeating: [Int](repeating: 0, count: bLength + 1), count: aLength + 1) - for i in 0 ... aLength { + for i in 0...aLength { d[i][0] = i } - for j in 1 ... bLength { + for j in 1...bLength { d[0][j] = j } - for i in 1 ... aLength { - for j in 1 ... bLength { + for i in 1...aLength { + for j in 1...bLength { let cost = a.charCode(at: i - 1) == b.charCode(at: j - 1) ? 0 : 1 let stupidCompiler = min(d[i][j - 1] + 1, d[i - 1][j - 1] + cost) d[i][j] = min(d[i - 1][j] + 1, stupidCompiler) - if - i > 1, j > 1, a.charCode(at: i - 1) == b.charCode(at: j - 2), + if i > 1, j > 1, a.charCode(at: i - 1) == b.charCode(at: j - 2), a.charCode(at: i - 2) == b.charCode(at: j - 1) { d[i][j] = min(d[i][j], d[i - 2][j - 2] + cost) diff --git a/Sources/GraphQL/Type/Definition.swift b/Sources/GraphQL/Type/Definition.swift index cb6f3b9d..4d7933e2 100644 --- a/Sources/GraphQL/Type/Definition.swift +++ b/Sources/GraphQL/Type/Definition.swift @@ -1,9 +1,7 @@ import Foundation import OrderedCollections -/** - * These are all of the possible kinds of types. - */ +/// These are all of the possible kinds of types. public protocol GraphQLType: CustomDebugStringConvertible, Sendable {} extension GraphQLScalarType: GraphQLType {} extension GraphQLObjectType: GraphQLType {} @@ -14,9 +12,7 @@ extension GraphQLInputObjectType: GraphQLType {} extension GraphQLList: GraphQLType {} extension GraphQLNonNull: GraphQLType {} -/** - * These types may be used as input types for arguments and directives. - */ +/// These types may be used as input types for arguments and directives. public protocol GraphQLInputType: GraphQLType {} extension GraphQLScalarType: GraphQLInputType {} extension GraphQLEnumType: GraphQLInputType {} @@ -33,9 +29,7 @@ func isInputType(type: GraphQLType?) -> Bool { return namedType is GraphQLInputType } -/** - * These types may be used as output types as the result of fields. - */ +/// These types may be used as output types as the result of fields. public protocol GraphQLOutputType: GraphQLType {} extension GraphQLScalarType: GraphQLOutputType {} extension GraphQLObjectType: GraphQLOutputType {} @@ -50,9 +44,7 @@ extension GraphQLNonNull: GraphQLOutputType {} // GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | // GraphQLList) {} -/** - * These types may describe types which may be leaf values. - */ +/// These types may describe types which may be leaf values. public protocol GraphQLLeafType: GraphQLNamedType { func serialize(value: Any) throws -> Map func parseValue(value: Map) throws -> Map @@ -64,21 +56,16 @@ extension GraphQLEnumType: GraphQLLeafType {} func isLeafType(type: GraphQLType?) -> Bool { let namedType = getNamedType(type: type) - return namedType is GraphQLScalarType || - namedType is GraphQLEnumType + return namedType is GraphQLScalarType || namedType is GraphQLEnumType } -/** - * These types may describe the parent context of a selection set. - */ +/// These types may describe the parent context of a selection set. public protocol GraphQLCompositeType: GraphQLNamedType, GraphQLOutputType {} extension GraphQLObjectType: GraphQLCompositeType {} extension GraphQLInterfaceType: GraphQLCompositeType {} extension GraphQLUnionType: GraphQLCompositeType {} -/** - * These types may describe the parent context of a selection set. - */ +/// These types may describe the parent context of a selection set. public protocol GraphQLAbstractType: GraphQLNamedType { var resolveType: GraphQLTypeResolve? { get } } @@ -86,9 +73,7 @@ public protocol GraphQLAbstractType: GraphQLNamedType { extension GraphQLInterfaceType: GraphQLAbstractType {} extension GraphQLUnionType: GraphQLAbstractType {} -/** - * These types can all accept null as a value. - */ +/// These types can all accept null as a value. public protocol GraphQLNullableType: GraphQLType {} extension GraphQLScalarType: GraphQLNullableType {} extension GraphQLObjectType: GraphQLNullableType {} @@ -106,9 +91,7 @@ func getNullableType(type: GraphQLType?) -> GraphQLNullableType? { return type as? GraphQLNullableType } -/** - * These named types do not include modifiers like List or NonNull. - */ +/// These named types do not include modifiers like List or NonNull. public protocol GraphQLNamedType: GraphQLNullableType { var name: String { get } } @@ -130,9 +113,7 @@ public func getNamedType(type: GraphQLType?) -> GraphQLNamedType? { return unmodifiedType as? GraphQLNamedType } -/** - * These types wrap other types. - */ +/// These types wrap other types. protocol GraphQLWrapperType: GraphQLType { var wrappedType: GraphQLType { get } } @@ -140,23 +121,20 @@ protocol GraphQLWrapperType: GraphQLType { extension GraphQLList: GraphQLWrapperType {} extension GraphQLNonNull: GraphQLWrapperType {} -/** - * Scalar Type Definition - * - * The leaf values of any request and input values to arguments are - * Scalars (or Enums) and are defined with a name and a series of functions - * used to parse input from ast or variables and to ensure validity. - * - * Example: - * - * let oddType = try ScalarType( - * name: "Bool", - * serialize: { - * try $0.map.asBool(converting: true) - * } - * ) - * - */ +/// Scalar Type Definition +/// +/// The leaf values of any request and input values to arguments are +/// Scalars (or Enums) and are defined with a name and a series of functions +/// used to parse input from ast or variables and to ensure validity. +/// +/// Example: +/// +/// let oddType = try ScalarType( +/// name: "Bool", +/// serialize: { +/// try $0.map.asBool(converting: true) +/// } +/// ) public final class GraphQLScalarType: Sendable { public let name: String public let description: String? @@ -230,48 +208,45 @@ extension GraphQLScalarType: Hashable { } } -/** - * Object Type Definition - * - * Almost all of the GraphQL types you define will be object types. Object types - * have a name, but most importantly describe their fields. - * - * Example: - * - * let AddressType = GraphQLObjectType( - * name: "Address", - * fields: [ - * "street": GraphQLField(type: GraphQLString), - * "number": GraphQLField(type: GraphQLInt), - * "formatted": GraphQLField( - * type: GraphQLString, - * resolve: { address, _, _, _ in - * guard let address = address as? Address { - * return Map.null - * } - * - * return "\(address.number) \(address.street)" - * } - * ) - * ] - * ) - * - * When two types need to refer to each other, or a type needs to refer to - * itself in a field, you can use a closure to supply the fields lazily. - * - * Example: - * - * let PersonType = GraphQLObjectType( - * name: "Person", - * fields: { - * [ - * "name": GraphQLField(type: GraphQLString), - * "bestFriend": GraphQLField(type: PersonType), - * ] - * } - * ) - * - */ +/// Object Type Definition +/// +/// Almost all of the GraphQL types you define will be object types. Object types +/// have a name, but most importantly describe their fields. +/// +/// Example: +/// +/// let AddressType = GraphQLObjectType( +/// name: "Address", +/// fields: [ +/// "street": GraphQLField(type: GraphQLString), +/// "number": GraphQLField(type: GraphQLInt), +/// "formatted": GraphQLField( +/// type: GraphQLString, +/// resolve: { address, _, _, _ in +/// guard let address = address as? Address { +/// return Map.null +/// } +/// +/// return "\(address.number) \(address.street)" +/// } +/// ) +/// ] +/// ) +/// +/// When two types need to refer to each other, or a type needs to refer to +/// itself in a field, you can use a closure to supply the fields lazily. +/// +/// Example: +/// +/// let PersonType = GraphQLObjectType( +/// name: "Person", +/// fields: { +/// [ +/// "name": GraphQLField(type: GraphQLString), +/// "bestFriend": GraphQLField(type: PersonType), +/// ] +/// } +/// ) public final class GraphQLObjectType: @unchecked Sendable { public let name: String public let description: String? @@ -468,29 +443,33 @@ public enum TypeResolveResult: Sendable { case name(String) } -public typealias GraphQLTypeResolve = @Sendable ( - _ value: any Sendable, - _ info: GraphQLResolveInfo -) throws -> TypeResolveResultRepresentable - -public typealias GraphQLIsTypeOf = @Sendable ( - _ source: any Sendable, - _ info: GraphQLResolveInfo -) throws -> Bool - -public typealias GraphQLFieldResolve = @Sendable ( - _ source: any Sendable, - _ args: Map, - _ context: any Sendable, - _ info: GraphQLResolveInfo -) async throws -> (any Sendable)? - -public typealias GraphQLFieldResolveInput = @Sendable ( - _ source: any Sendable, - _ args: Map, - _ context: any Sendable, - _ info: GraphQLResolveInfo -) throws -> (any Sendable)? +public typealias GraphQLTypeResolve = + @Sendable ( + _ value: any Sendable, + _ info: GraphQLResolveInfo + ) throws -> TypeResolveResultRepresentable + +public typealias GraphQLIsTypeOf = + @Sendable ( + _ source: any Sendable, + _ info: GraphQLResolveInfo + ) throws -> Bool + +public typealias GraphQLFieldResolve = + @Sendable ( + _ source: any Sendable, + _ args: Map, + _ context: any Sendable, + _ info: GraphQLResolveInfo + ) async throws -> (any Sendable)? + +public typealias GraphQLFieldResolveInput = + @Sendable ( + _ source: any Sendable, + _ args: Map, + _ context: any Sendable, + _ info: GraphQLResolveInfo + ) throws -> (any Sendable)? public struct GraphQLResolveInfo: Sendable { public let fieldName: String @@ -710,24 +689,21 @@ public func isRequiredArgument(_ arg: GraphQLArgumentDefinition) -> Bool { return arg.type is GraphQLNonNull && arg.defaultValue == nil } -/** - * Interface Type Definition - * - * When a field can return one of a heterogeneous set of types, a Interface type - * is used to describe what types are possible, what fields are in common across - * all types, as well as a function to determine which type is actually used - * when the field is resolved. - * - * Example: - * - * let EntityType = GraphQLInterfaceType( - * name: "Entity", - * fields: { - * "name": GraphQLField(type: GraphQLString) - * } - * ) - * - */ +/// Interface Type Definition +/// +/// When a field can return one of a heterogeneous set of types, a Interface type +/// is used to describe what types are possible, what fields are in common across +/// all types, as well as a function to determine which type is actually used +/// when the field is resolved. +/// +/// Example: +/// +/// let EntityType = GraphQLInterfaceType( +/// name: "Entity", +/// fields: { +/// "name": GraphQLField(type: GraphQLString) +/// } +/// ) public final class GraphQLInterfaceType: @unchecked Sendable { public let name: String public let description: String? @@ -863,31 +839,28 @@ extension GraphQLInterfaceType: Hashable { public typealias GraphQLUnionTypeExtensions = [String: String]? -/** - * Union Type Definition - * - * When a field can return one of a heterogeneous set of types, a Union type - * is used to describe what types are possible as well as providing a function - * to determine which type is actually used when the field is resolved. - * - * Example: - * - * let PetType = try GraphQLUnionType( - * name: "Pet", - * types: [DogType, CatType], - * resolveType: { value, context, info in - * switch value { - * case is Dog: - * return DogType - * case is Cat: - * return CatType - * default: - * return Map.null - * } - * } - * ) - * - */ +/// Union Type Definition +/// +/// When a field can return one of a heterogeneous set of types, a Union type +/// is used to describe what types are possible as well as providing a function +/// to determine which type is actually used when the field is resolved. +/// +/// Example: +/// +/// let PetType = try GraphQLUnionType( +/// name: "Pet", +/// types: [DogType, CatType], +/// resolveType: { value, context, info in +/// switch value { +/// case is Dog: +/// return DogType +/// case is Cat: +/// return CatType +/// default: +/// return Map.null +/// } +/// } +/// ) public final class GraphQLUnionType: @unchecked Sendable { public let kind: TypeKind = .union public let name: String @@ -969,27 +942,25 @@ extension GraphQLUnionType: Hashable { } } -/** - * Enum Type Definition - * - * Some leaf values of requests and input values are Enums. GraphQL serializes - * Enum values as strings, however internally Enums can be represented by any - * kind of type, often integers. - * - * Example: - * - * let RGBType = GraphQLEnumType( - * name: "RGB", - * values: { - * "RED": GraphQLEnumValue(value: 0), - * "GREEN": GraphQLEnumValue(value: 1), - * "BLUE": GraphQLEnumValue(value: 2) - * } - * ) - * - * Note: If a value is not provided in a definition, the name of the enum value - * will be used as its internal value. - */ +/// Enum Type Definition +/// +/// Some leaf values of requests and input values are Enums. GraphQL serializes +/// Enum values as strings, however internally Enums can be represented by any +/// kind of type, often integers. +/// +/// Example: +/// +/// let RGBType = GraphQLEnumType( +/// name: "RGB", +/// values: { +/// "RED": GraphQLEnumValue(value: 0), +/// "GREEN": GraphQLEnumValue(value: 1), +/// "BLUE": GraphQLEnumValue(value: 2) +/// } +/// ) +/// +/// Note: If a value is not provided in a definition, the name of the enum value +/// will be used as its internal value. public final class GraphQLEnumType: Sendable { public let name: String public let description: String? @@ -1044,14 +1015,14 @@ public final class GraphQLEnumType: Sendable { public func parseValue(value: Map) throws -> Map { guard let valueStr = value.string else { throw GraphQLError( - message: "Enum \"\(name)\" cannot represent non-string value: \(value)." + - didYouMeanEnumValue(unknownValueStr: value.description) + message: "Enum \"\(name)\" cannot represent non-string value: \(value)." + + didYouMeanEnumValue(unknownValueStr: value.description) ) } guard let enumValue = nameLookup[valueStr] else { throw GraphQLError( - message: "Value \"\(valueStr)\" does not exist in \"\(name)\" enum." + - didYouMeanEnumValue(unknownValueStr: valueStr) + message: "Value \"\(valueStr)\" does not exist in \"\(name)\" enum." + + didYouMeanEnumValue(unknownValueStr: valueStr) ) } return enumValue.value @@ -1060,15 +1031,16 @@ public final class GraphQLEnumType: Sendable { public func parseLiteral(valueAST: Value) throws -> Map { guard let enumNode = valueAST as? EnumValue else { throw GraphQLError( - message: "Enum \"\(name)\" cannot represent non-enum value: \(print(ast: valueAST))." + - didYouMeanEnumValue(unknownValueStr: print(ast: valueAST)), + message: + "Enum \"\(name)\" cannot represent non-enum value: \(print(ast: valueAST))." + + didYouMeanEnumValue(unknownValueStr: print(ast: valueAST)), nodes: [valueAST] ) } guard let enumValue = nameLookup[enumNode.value] else { throw GraphQLError( - message: "Value \"\(enumNode.value)\" does not exist in \"\(name)\" enum." + - didYouMeanEnumValue(unknownValueStr: enumNode.value), + message: "Value \"\(enumNode.value)\" does not exist in \"\(name)\" enum." + + didYouMeanEnumValue(unknownValueStr: enumNode.value), nodes: [valueAST] ) } @@ -1167,26 +1139,23 @@ public struct GraphQLEnumValueDefinition: Sendable { } } -/** - * Input Object Type Definition - * - * An input object defines a structured collection of fields which may be - * supplied to a field argument. - * - * Using `GraphQLNonNull` will ensure that a value must be provided by the query - * - * Example: - * - * let GeoPoint = GraphQLInputObjectType( - * name: "GeoPoint", - * fields: [ - * "lat": InputObjectField(type: GraphQLNonNull(GraphQLFloat)), - * "lon": InputObjectField(type: GraphQLNonNull(GraphQLFloat)), - * "alt": InputObjectField(type: GraphQLFloat, defaultValue: 0), - * ] - * ) - * - */ +/// Input Object Type Definition +/// +/// An input object defines a structured collection of fields which may be +/// supplied to a field argument. +/// +/// Using `GraphQLNonNull` will ensure that a value must be provided by the query +/// +/// Example: +/// +/// let GeoPoint = GraphQLInputObjectType( +/// name: "GeoPoint", +/// fields: [ +/// "lat": InputObjectField(type: GraphQLNonNull(GraphQLFloat)), +/// "lon": InputObjectField(type: GraphQLNonNull(GraphQLFloat)), +/// "alt": InputObjectField(type: GraphQLFloat, defaultValue: 0), +/// ] +/// ) public final class GraphQLInputObjectType: @unchecked Sendable { public let name: String public let description: String? @@ -1341,24 +1310,21 @@ public typealias InputObjectFieldDefinitionMap = OrderedDictionary< InputObjectFieldDefinition > -/** - * List Modifier - * - * A list is a kind of type marker, a wrapping type which points to another - * type. Lists are often created within the context of defining the fields of - * an object type. - * - * Example: - * - * let PersonType = GraphQLObjectType( - * name: "Person", - * fields: [ - * "parents": GraphQLField(type: GraphQLList("Person")), - * "children": GraphQLField(type: GraphQLList("Person")), - * ] - * ) - * - */ +/// List Modifier +/// +/// A list is a kind of type marker, a wrapping type which points to another +/// type. Lists are often created within the context of defining the fields of +/// an object type. +/// +/// Example: +/// +/// let PersonType = GraphQLObjectType( +/// name: "Person", +/// fields: [ +/// "parents": GraphQLField(type: GraphQLList("Person")), +/// "children": GraphQLField(type: GraphQLList("Person")), +/// ] +/// ) public final class GraphQLList { public let ofType: GraphQLType public let kind: TypeKind = .list @@ -1388,26 +1354,24 @@ extension GraphQLList: Hashable { } } -/** - * Non-Null Modifier - * - * A non-null is a kind of type marker, a wrapping type which points to another - * type. Non-null types enforce that their values are never null and can ensure - * an error is raised if this ever occurs during a request. It is useful for - * fields which you can make a strong guarantee on non-nullability, for example - * usually the id field of a database row will never be null. - * - * Example: - * - * let RowType = GraphQLObjectType( - * name: "Row", - * fields: [ - * "id": GraphQLField(type: GraphQLNonNull(GraphQLString)), - * ] - * ) - * - * Note: the enforcement of non-nullability occurs within the executor. - */ +/// Non-Null Modifier +/// +/// A non-null is a kind of type marker, a wrapping type which points to another +/// type. Non-null types enforce that their values are never null and can ensure +/// an error is raised if this ever occurs during a request. It is useful for +/// fields which you can make a strong guarantee on non-nullability, for example +/// usually the id field of a database row will never be null. +/// +/// Example: +/// +/// let RowType = GraphQLObjectType( +/// name: "Row", +/// fields: [ +/// "id": GraphQLField(type: GraphQLNonNull(GraphQLString)), +/// ] +/// ) +/// +/// Note: the enforcement of non-nullability occurs within the executor. public final class GraphQLNonNull { public let ofType: GraphQLNullableType public let kind: TypeKind = .nonNull diff --git a/Sources/GraphQL/Type/Directives.swift b/Sources/GraphQL/Type/Directives.swift index b4844027..3c9d0488 100644 --- a/Sources/GraphQL/Type/Directives.swift +++ b/Sources/GraphQL/Type/Directives.swift @@ -25,10 +25,8 @@ public enum DirectiveLocation: String, Encodable, Sendable { case inputFieldDefinition = "INPUT_FIELD_DEFINITION" } -/** - * Directives are used by the GraphQL runtime as a way of modifying execution - * behavior. Type system creators will usually not create these directly. - */ +/// Directives are used by the GraphQL runtime as a way of modifying execution +/// behavior. Type system creators will usually not create these directly. public final class GraphQLDirective: Sendable { public let name: String public let description: String? @@ -63,14 +61,12 @@ public final class GraphQLDirective: Sendable { } } -/** - * Used to conditionally include fields or fragments. - */ +/// Used to conditionally include fields or fragments. public let GraphQLIncludeDirective = try! GraphQLDirective( name: "include", description: - "Directs the executor to include this field or fragment only when " + - "the \\`if\\` argument is true.", + "Directs the executor to include this field or fragment only when " + + "the \\`if\\` argument is true.", locations: [ .field, .fragmentSpread, @@ -80,18 +76,16 @@ public let GraphQLIncludeDirective = try! GraphQLDirective( "if": GraphQLArgument( type: GraphQLNonNull(GraphQLBoolean), description: "Included when true." - ), + ) ] ) -/** - * Used to conditionally skip (exclude) fields or fragments. - */ +/// Used to conditionally skip (exclude) fields or fragments. public let GraphQLSkipDirective = try! GraphQLDirective( name: "skip", description: - "Directs the executor to skip this field or fragment when the \\`if\\` " + - "argument is true.", + "Directs the executor to skip this field or fragment when the \\`if\\` " + + "argument is true.", locations: [ .field, .fragmentSpread, @@ -101,22 +95,18 @@ public let GraphQLSkipDirective = try! GraphQLDirective( "if": GraphQLArgument( type: GraphQLNonNull(GraphQLBoolean), description: "Skipped when true." - ), + ) ] ) -/** - * Constant string used for default reason for a deprecation. - */ +/// Constant string used for default reason for a deprecation. let defaultDeprecationReason = "No longer supported" -/** - * Used to declare element of a GraphQL schema as deprecated. - */ +/// Used to declare element of a GraphQL schema as deprecated. public let GraphQLDeprecatedDirective = try! GraphQLDirective( name: "deprecated", description: - "Marks an element of a GraphQL schema as no longer supported.", + "Marks an element of a GraphQL schema as no longer supported.", locations: [ .fieldDefinition, .argumentDefinition, @@ -127,18 +117,16 @@ public let GraphQLDeprecatedDirective = try! GraphQLDirective( "reason": GraphQLArgument( type: GraphQLString, description: - "Explains why this element was deprecated, usually also including a " + - "suggestion for how to access supported similar data. Formatted " + - "using the Markdown syntax, as specified by [CommonMark]" + - "(https://commonmark.org/).", + "Explains why this element was deprecated, usually also including a " + + "suggestion for how to access supported similar data. Formatted " + + "using the Markdown syntax, as specified by [CommonMark]" + + "(https://commonmark.org/).", defaultValue: Map.string(defaultDeprecationReason) - ), + ) ] ) -/** - * Used to provide a URL for specifying the behavior of custom scalar definitions. - */ +/// Used to provide a URL for specifying the behavior of custom scalar definitions. public let GraphQLSpecifiedByDirective = try! GraphQLDirective( name: "specifiedBy", description: "Exposes a URL that specifies the behavior of this scalar.", @@ -147,23 +135,20 @@ public let GraphQLSpecifiedByDirective = try! GraphQLDirective( "url": GraphQLArgument( type: GraphQLNonNull(GraphQLString), description: "The URL that specifies the behavior of this scalar." - ), + ) ] ) -/** - * Used to indicate an Input Object is a OneOf Input Object. - */ +/// Used to indicate an Input Object is a OneOf Input Object. public let GraphQLOneOfDirective = try! GraphQLDirective( name: "oneOf", - description: "Indicates exactly one field must be supplied and this field must not be \\`null\\`.", + description: + "Indicates exactly one field must be supplied and this field must not be \\`null\\`.", locations: [.inputObject], args: [:] ) -/** - * The full list of specified directives. - */ +/// The full list of specified directives. let specifiedDirectives: [GraphQLDirective] = [ GraphQLIncludeDirective, GraphQLSkipDirective, diff --git a/Sources/GraphQL/Type/Introspection.swift b/Sources/GraphQL/Type/Introspection.swift index 1941e9a3..3aec74c9 100644 --- a/Sources/GraphQL/Type/Introspection.swift +++ b/Sources/GraphQL/Type/Introspection.swift @@ -1,10 +1,9 @@ - let __Schema = try! GraphQLObjectType( name: "__Schema", description: - "A GraphQL Schema defines the capabilities of a GraphQL server. It " + - "exposes all available types and directives on the server, as well as " + - "the entry points for query, mutation, and subscription operations.", + "A GraphQL Schema defines the capabilities of a GraphQL server. It " + + "exposes all available types and directives on the server, as well as " + + "the entry points for query, mutation, and subscription operations.", fields: [ "description": GraphQLField(type: GraphQLString), "types": GraphQLField( @@ -33,8 +32,8 @@ let __Schema = try! GraphQLObjectType( "mutationType": GraphQLField( type: __Type, description: - "If this server supports mutation, the type that " + - "mutation operations will be rooted at.", + "If this server supports mutation, the type that " + + "mutation operations will be rooted at.", resolve: { schema, _, _, _ -> GraphQLObjectType? in guard let schema = schema as? GraphQLSchema else { return nil @@ -46,8 +45,8 @@ let __Schema = try! GraphQLObjectType( "subscriptionType": GraphQLField( type: __Type, description: - "If this server support subscription, the type that " + - "subscription operations will be rooted at.", + "If this server support subscription, the type that " + + "subscription operations will be rooted at.", resolve: { schema, _, _, _ -> GraphQLObjectType? in guard let schema = schema as? GraphQLSchema else { return nil @@ -73,12 +72,12 @@ let __Schema = try! GraphQLObjectType( let __Directive = try! GraphQLObjectType( name: "__Directive", description: - "A Directive provides a way to describe alternate runtime execution and " + - "type validation behavior in a GraphQL document." + - "\n\nIn some cases, you need to provide options to alter GraphQL's " + - "execution behavior in ways field arguments will not suffice, such as " + - "conditionally including or skipping a field. Directives provide this by " + - "describing additional information to the executor.", + "A Directive provides a way to describe alternate runtime execution and " + + "type validation behavior in a GraphQL document." + + "\n\nIn some cases, you need to provide options to alter GraphQL's " + + "execution behavior in ways field arguments will not suffice, such as " + + "conditionally including or skipping a field. Directives provide this by " + + "describing additional information to the executor.", fields: [ "name": GraphQLField(type: GraphQLNonNull(GraphQLString)), "description": GraphQLField(type: GraphQLString), @@ -89,7 +88,7 @@ let __Directive = try! GraphQLObjectType( "args": GraphQLField( type: GraphQLNonNull(GraphQLList(GraphQLNonNull(__InputValue))), args: [ - "includeDeprecated": GraphQLArgument(type: GraphQLBoolean, defaultValue: false), + "includeDeprecated": GraphQLArgument(type: GraphQLBoolean, defaultValue: false) ], resolve: { directive, _, _, _ -> [GraphQLArgumentDefinition]? in guard let directive = directive as? GraphQLDirective else { @@ -105,8 +104,8 @@ let __Directive = try! GraphQLObjectType( let __DirectiveLocation = try! GraphQLEnumType( name: "__DirectiveLocation", description: - "A Directive can be adjacent to many parts of the GraphQL language, a " + - "__DirectiveLocation describes one such possible adjacencies.", + "A Directive can be adjacent to many parts of the GraphQL language, a " + + "__DirectiveLocation describes one such possible adjacencies.", values: [ "QUERY": GraphQLEnumValue( value: Map(DirectiveLocation.query.rawValue), @@ -195,167 +194,169 @@ let __Type: GraphQLObjectType = { let __Type = try! GraphQLObjectType( name: "__Type", description: - "The fundamental unit of any GraphQL Schema is the type. There are " + - "many kinds of types in GraphQL as represented by the \\`__TypeKind\\` enum." + - "\n\nDepending on the kind of a type, certain fields describe " + - "information about that type. Scalar types provide no information " + - "beyond a name, description and optional \\`specifiedByURL\\`, while Enum types provide their values. " + - "Object and Interface types provide the fields they describe. Abstract " + - "types, Union and Interface, provide the Object types possible " + - "at runtime. List and NonNull types compose other types." + "The fundamental unit of any GraphQL Schema is the type. There are " + + "many kinds of types in GraphQL as represented by the \\`__TypeKind\\` enum." + + "\n\nDepending on the kind of a type, certain fields describe " + + "information about that type. Scalar types provide no information " + + "beyond a name, description and optional \\`specifiedByURL\\`, while Enum types provide their values. " + + "Object and Interface types provide the fields they describe. Abstract " + + "types, Union and Interface, provide the Object types possible " + + "at runtime. List and NonNull types compose other types." ) - __Type.fields = { [ - "kind": GraphQLField( - type: GraphQLNonNull(__TypeKind), - resolve: { type, _, _, _ -> TypeKind? in - switch type { - case let type as GraphQLScalarType: - return TypeKind.scalar - case let type as GraphQLObjectType: - return TypeKind.object - case let type as GraphQLInterfaceType: - return TypeKind.interface - case let type as GraphQLUnionType: - return TypeKind.union - case let type as GraphQLEnumType: - return TypeKind.enum - case let type as GraphQLInputObjectType: - return TypeKind.inputObject - case let type as GraphQLList: - return TypeKind.list - case let type as GraphQLNonNull: - return TypeKind.nonNull - default: - throw GraphQLError(message: "Unknown kind of type: \(type)") + __Type.fields = { + [ + "kind": GraphQLField( + type: GraphQLNonNull(__TypeKind), + resolve: { type, _, _, _ -> TypeKind? in + switch type { + case let type as GraphQLScalarType: + return TypeKind.scalar + case let type as GraphQLObjectType: + return TypeKind.object + case let type as GraphQLInterfaceType: + return TypeKind.interface + case let type as GraphQLUnionType: + return TypeKind.union + case let type as GraphQLEnumType: + return TypeKind.enum + case let type as GraphQLInputObjectType: + return TypeKind.inputObject + case let type as GraphQLList: + return TypeKind.list + case let type as GraphQLNonNull: + return TypeKind.nonNull + default: + throw GraphQLError(message: "Unknown kind of type: \(type)") + } } - } - ), - "name": GraphQLField(type: GraphQLString), - "description": GraphQLField(type: GraphQLString), - "specifiedByURL": GraphQLField(type: GraphQLString), - "fields": GraphQLField( - type: GraphQLList(GraphQLNonNull(__Field)), - args: [ - "includeDeprecated": GraphQLArgument( - type: GraphQLBoolean, - defaultValue: false - ), - ], - resolve: { type, arguments, _, _ -> [GraphQLFieldDefinition]? in - if let type = type as? GraphQLObjectType { - let fieldMap = try type.getFields() - var fields = Array(fieldMap.values).sorted(by: { $0.name < $1.name }) - - if !(arguments["includeDeprecated"].bool ?? false) { - fields = fields.filter { !$0.isDeprecated } + ), + "name": GraphQLField(type: GraphQLString), + "description": GraphQLField(type: GraphQLString), + "specifiedByURL": GraphQLField(type: GraphQLString), + "fields": GraphQLField( + type: GraphQLList(GraphQLNonNull(__Field)), + args: [ + "includeDeprecated": GraphQLArgument( + type: GraphQLBoolean, + defaultValue: false + ) + ], + resolve: { type, arguments, _, _ -> [GraphQLFieldDefinition]? in + if let type = type as? GraphQLObjectType { + let fieldMap = try type.getFields() + var fields = Array(fieldMap.values).sorted(by: { $0.name < $1.name }) + + if !(arguments["includeDeprecated"].bool ?? false) { + fields = fields.filter { !$0.isDeprecated } + } + + return fields } - return fields - } + if let type = type as? GraphQLInterfaceType { + let fieldMap = try type.getFields() + var fields = Array(fieldMap.values).sorted(by: { $0.name < $1.name }) - if let type = type as? GraphQLInterfaceType { - let fieldMap = try type.getFields() - var fields = Array(fieldMap.values).sorted(by: { $0.name < $1.name }) + if !(arguments["includeDeprecated"].bool ?? false) { + fields = fields.filter { !$0.isDeprecated } + } - if !(arguments["includeDeprecated"].bool ?? false) { - fields = fields.filter { !$0.isDeprecated } + return fields } - return fields - } - - return nil - } - ), - "interfaces": GraphQLField( - type: GraphQLList(GraphQLNonNull(__Type)), - resolve: { type, _, _, _ -> [GraphQLInterfaceType]? in - if let type = type as? GraphQLObjectType { - return try type.getInterfaces() + return nil } + ), + "interfaces": GraphQLField( + type: GraphQLList(GraphQLNonNull(__Type)), + resolve: { type, _, _, _ -> [GraphQLInterfaceType]? in + if let type = type as? GraphQLObjectType { + return try type.getInterfaces() + } - if let type = type as? GraphQLInterfaceType { - return try type.getInterfaces() - } + if let type = type as? GraphQLInterfaceType { + return try type.getInterfaces() + } - return nil - } - ), - "possibleTypes": GraphQLField( - type: GraphQLList(GraphQLNonNull(__Type)), - resolve: { type, _, _, info -> [GraphQLObjectType]? in - guard let type = type as? GraphQLAbstractType else { return nil } + ), + "possibleTypes": GraphQLField( + type: GraphQLList(GraphQLNonNull(__Type)), + resolve: { type, _, _, info -> [GraphQLObjectType]? in + guard let type = type as? GraphQLAbstractType else { + return nil + } - return info.schema.getPossibleTypes(abstractType: type) - } - ), - "enumValues": GraphQLField( - type: GraphQLList(GraphQLNonNull(__EnumValue)), - args: [ - "includeDeprecated": GraphQLArgument( - type: GraphQLBoolean, - defaultValue: false - ), - ], - resolve: { type, arguments, _, _ -> [GraphQLEnumValueDefinition]? in - guard let type = type as? GraphQLEnumType else { - return nil + return info.schema.getPossibleTypes(abstractType: type) } + ), + "enumValues": GraphQLField( + type: GraphQLList(GraphQLNonNull(__EnumValue)), + args: [ + "includeDeprecated": GraphQLArgument( + type: GraphQLBoolean, + defaultValue: false + ) + ], + resolve: { type, arguments, _, _ -> [GraphQLEnumValueDefinition]? in + guard let type = type as? GraphQLEnumType else { + return nil + } - var values = type.values + var values = type.values - if !(arguments["includeDeprecated"].bool ?? false) { - values = values.filter { !$0.isDeprecated } - } + if !(arguments["includeDeprecated"].bool ?? false) { + values = values.filter { !$0.isDeprecated } + } - return values - } - ), - "inputFields": GraphQLField( - type: GraphQLList(GraphQLNonNull(__InputValue)), - args: [ - "includeDeprecated": GraphQLArgument( - type: GraphQLBoolean, - defaultValue: false - ), - ], - resolve: { type, _, _, _ -> [InputObjectFieldDefinition]? in - guard let type = type as? GraphQLInputObjectType else { - return nil + return values } + ), + "inputFields": GraphQLField( + type: GraphQLList(GraphQLNonNull(__InputValue)), + args: [ + "includeDeprecated": GraphQLArgument( + type: GraphQLBoolean, + defaultValue: false + ) + ], + resolve: { type, _, _, _ -> [InputObjectFieldDefinition]? in + guard let type = type as? GraphQLInputObjectType else { + return nil + } - let fieldMap = try type.getFields() - return Array(fieldMap.values).sorted(by: { $0.name < $1.name }) - } - ), - "ofType": GraphQLField(type: __Type), - "isOneOf": GraphQLField( - type: GraphQLBoolean, - resolve: { type, _, _, _ in - if let type = type as? GraphQLInputObjectType { - return type.isOneOf + let fieldMap = try type.getFields() + return Array(fieldMap.values).sorted(by: { $0.name < $1.name }) } - return false - } - ), - ] } + ), + "ofType": GraphQLField(type: __Type), + "isOneOf": GraphQLField( + type: GraphQLBoolean, + resolve: { type, _, _, _ in + if let type = type as? GraphQLInputObjectType { + return type.isOneOf + } + return false + } + ), + ] + } return __Type }() let __Field = try! GraphQLObjectType( name: "__Field", description: - "Object and Interface types are described by a list of Fields, each of " + - "which has a name, potentially a list of arguments, and a return type.", + "Object and Interface types are described by a list of Fields, each of " + + "which has a name, potentially a list of arguments, and a return type.", fields: [ "name": GraphQLField(type: GraphQLNonNull(GraphQLString)), "description": GraphQLField(type: GraphQLString), "args": GraphQLField( type: GraphQLNonNull(GraphQLList(GraphQLNonNull(__InputValue))), args: [ - "includeDeprecated": GraphQLArgument(type: GraphQLBoolean, defaultValue: false), + "includeDeprecated": GraphQLArgument(type: GraphQLBoolean, defaultValue: false) ], resolve: { field, _, _, _ -> [GraphQLArgumentDefinition]? in guard let field = field as? GraphQLFieldDefinition else { @@ -374,9 +375,9 @@ let __Field = try! GraphQLObjectType( let __InputValue = try! GraphQLObjectType( name: "__InputValue", description: - "Arguments provided to Fields or Directives and the input fields of an " + - "InputObject are represented as Input Values which describe their type " + - "and optionally a default value.", + "Arguments provided to Fields or Directives and the input fields of an " + + "InputObject are represented as Input Values which describe their type " + + "and optionally a default value.", fields: [ "name": GraphQLField(type: GraphQLNonNull(GraphQLString)), "description": GraphQLField(type: GraphQLString), @@ -384,8 +385,8 @@ let __InputValue = try! GraphQLObjectType( "defaultValue": GraphQLField( type: GraphQLString, description: - "A GraphQL-formatted string representing the default value for this " + - "input value.", + "A GraphQL-formatted string representing the default value for this " + + "input value.", resolve: { inputValue, _, _, _ -> Map? in guard let inputValue = inputValue as? GraphQLArgumentDefinition, @@ -414,9 +415,9 @@ let __InputValue = try! GraphQLObjectType( let __EnumValue = try! GraphQLObjectType( name: "__EnumValue", description: - "One possible value for a given Enum. Enum values are unique values, not " + - "a placeholder for a string or numeric value. However an Enum value is " + - "returned in a JSON response as a string.", + "One possible value for a given Enum. Enum values are unique values, not " + + "a placeholder for a string or numeric value. However an Enum value is " + + "returned in a JSON response as a string.", fields: [ "name": GraphQLField(type: GraphQLNonNull(GraphQLString)), "description": GraphQLField(type: GraphQLString), @@ -446,38 +447,35 @@ let __TypeKind = try! GraphQLEnumType( ), "OBJECT": GraphQLEnumValue( value: Map(TypeKind.object.rawValue), - description: "Indicates this type is an object. " + - "\\`fields\\` and \\`interfaces\\` are valid fields." + description: "Indicates this type is an object. " + + "\\`fields\\` and \\`interfaces\\` are valid fields." ), "INTERFACE": GraphQLEnumValue( value: Map(TypeKind.interface.rawValue), - description: "Indicates this type is an interface. " + - "\\`fields\\`, \\`interfaces\\`, and \\`possibleTypes\\` are valid fields." + description: "Indicates this type is an interface. " + + "\\`fields\\`, \\`interfaces\\`, and \\`possibleTypes\\` are valid fields." ), "UNION": GraphQLEnumValue( value: Map(TypeKind.union.rawValue), - description: "Indicates this type is a union. " + - "\\`possibleTypes\\` is a valid field." + description: "Indicates this type is a union. " + + "\\`possibleTypes\\` is a valid field." ), "ENUM": GraphQLEnumValue( value: Map(TypeKind.enum.rawValue), - description: "Indicates this type is an enum. " + - "\\`enumValues\\` is a valid field." + description: "Indicates this type is an enum. " + "\\`enumValues\\` is a valid field." ), "INPUT_OBJECT": GraphQLEnumValue( value: Map(TypeKind.inputObject.rawValue), - description: "Indicates this type is an input object. " + - "\\`inputFields\\` is a valid field." + description: "Indicates this type is an input object. " + + "\\`inputFields\\` is a valid field." ), "LIST": GraphQLEnumValue( value: Map(TypeKind.list.rawValue), - description: "Indicates this type is a list. " + - "\\`ofType\\` is a valid field." + description: "Indicates this type is a list. " + "\\`ofType\\` is a valid field." ), "NON_NULL": GraphQLEnumValue( value: Map(TypeKind.nonNull.rawValue), - description: "Indicates this type is a non-null. " + - "\\`ofType\\` is a valid field." + description: "Indicates this type is a non-null. " + "\\`ofType\\` is a valid field." ), ] ) @@ -504,7 +502,7 @@ let TypeMetaFieldDef = GraphQLFieldDefinition( GraphQLArgumentDefinition( name: "name", type: GraphQLNonNull(GraphQLString) - ), + ) ], resolve: { _, arguments, _, info in let name = arguments["name"].string! diff --git a/Sources/GraphQL/Type/Scalars.swift b/Sources/GraphQL/Type/Scalars.swift index 80225c67..acafdfd1 100644 --- a/Sources/GraphQL/Type/Scalars.swift +++ b/Sources/GraphQL/Type/Scalars.swift @@ -1,23 +1,19 @@ -/** - * Maximum possible Int value as per GraphQL Spec (32-bit signed integer). - * n.b. This differs from JavaScript's numbers that are IEEE 754 doubles safe up-to 2^53 - 1 - * */ +/// Maximum possible Int value as per GraphQL Spec (32-bit signed integer). +/// n.b. This differs from JavaScript's numbers that are IEEE 754 doubles safe up-to 2^53 - 1 let GRAPHQL_MAX_INT = 2_147_483_647 -/** - * Minimum possible Int value as per GraphQL Spec (32-bit signed integer). - * n.b. This differs from JavaScript's numbers that are IEEE 754 doubles safe starting at -(2^53 - 1) - * */ +/// Minimum possible Int value as per GraphQL Spec (32-bit signed integer). +/// n.b. This differs from JavaScript's numbers that are IEEE 754 doubles safe starting at -(2^53 - 1) let GRAPHQL_MIN_INT = -2_147_483_648 public let GraphQLInt = try! GraphQLScalarType( name: "Int", description: - "The `Int` scalar type represents non-fractional signed whole numeric " + - "values. Int can represent values between -(2^31) and 2^31 - 1.", + "The `Int` scalar type represents non-fractional signed whole numeric " + + "values. Int can represent values between -(2^31) and 2^31 - 1.", serialize: { outputValue in if let value = outputValue as? Map { - if case let .number(value) = value { + if case .number(let value) = value { return .int(value.intValue) } throw GraphQLError( @@ -30,8 +26,7 @@ public let GraphQLInt = try! GraphQLScalarType( if let value = outputValue as? String, value != "", let int = Int(value) { return .int(int) } - if - let value = outputValue as? Double, Double(GRAPHQL_MIN_INT) <= value, + if let value = outputValue as? Double, Double(GRAPHQL_MIN_INT) <= value, value <= Double(GRAPHQL_MAX_INT), value.isFinite { return .int(Int(value)) @@ -44,8 +39,7 @@ public let GraphQLInt = try! GraphQLScalarType( ) }, parseValue: { inputValue in - if - case let .number(value) = inputValue, Double(GRAPHQL_MIN_INT) <= value.doubleValue, + if case .number(let value) = inputValue, Double(GRAPHQL_MIN_INT) <= value.doubleValue, value.doubleValue <= Double(GRAPHQL_MAX_INT), value.doubleValue.isFinite { return .number(value) @@ -69,12 +63,12 @@ public let GraphQLInt = try! GraphQLScalarType( public let GraphQLFloat = try! GraphQLScalarType( name: "Float", description: - "The `Float` scalar type represents signed double-precision fractional " + - "values as specified by " + - "[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", + "The `Float` scalar type represents signed double-precision fractional " + + "values as specified by " + + "[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", serialize: { outputValue in if let value = outputValue as? Map { - if case let .number(value) = value { + if case .number(let value) = value { return .double(value.doubleValue) } throw GraphQLError( @@ -98,7 +92,7 @@ public let GraphQLFloat = try! GraphQLScalarType( ) }, parseValue: { inputValue in - if case let .number(value) = inputValue, value.doubleValue.isFinite { + if case .number(let value) = inputValue, value.doubleValue.isFinite { return .number(value) } throw GraphQLError( @@ -124,12 +118,12 @@ public let GraphQLFloat = try! GraphQLScalarType( public let GraphQLString = try! GraphQLScalarType( name: "String", description: - "The `String` scalar type represents textual data, represented as UTF-8 " + - "character sequences. The String type is most often used by GraphQL to " + - "represent free-form human-readable text.", + "The `String` scalar type represents textual data, represented as UTF-8 " + + "character sequences. The String type is most often used by GraphQL to " + + "represent free-form human-readable text.", serialize: { outputValue in if let value = outputValue as? Map { - if case let .string(value) = value { + if case .string(let value) = value { return .string(value) } throw GraphQLError( @@ -153,7 +147,7 @@ public let GraphQLString = try! GraphQLScalarType( ) }, parseValue: { outputValue in - if case let .string(value) = outputValue { + if case .string(let value) = outputValue { return .string(value) } throw GraphQLError( @@ -177,10 +171,10 @@ public let GraphQLBoolean = try! GraphQLScalarType( description: "The `Boolean` scalar type represents `true` or `false`.", serialize: { outputValue in if let value = outputValue as? Map { - if case let .bool(value) = value { + if case .bool(let value) = value { return .bool(value) } - if case let .number(value) = value { + if case .number(let value) = value { return .bool(value.intValue != 0) } throw GraphQLError( @@ -198,12 +192,12 @@ public let GraphQLBoolean = try! GraphQLScalarType( ) }, parseValue: { inputValue in - if case let .bool(value) = inputValue { + if case .bool(let value) = inputValue { return inputValue } // NOTE: We deviate from graphql-js and allow numeric conversions here because // the MapCoder's round-trip conversion to NSObject for Bool converts to 0/1 numbers. - if case let .number(value) = inputValue { + if case .number(let value) = inputValue { return .bool(value.intValue != 0) } throw GraphQLError( @@ -225,17 +219,17 @@ public let GraphQLBoolean = try! GraphQLScalarType( public let GraphQLID = try! GraphQLScalarType( name: "ID", description: - "The `ID` scalar type represents a unique identifier, often used to " + - "refetch an object or as key for a cache. The ID type appears in a JSON " + - "response as a String; however, it is not intended to be human-readable. " + - "When expected as an input type, any string (such as `\"4\"`) or integer " + - "(such as `4`) input value will be accepted as an ID.", + "The `ID` scalar type represents a unique identifier, often used to " + + "refetch an object or as key for a cache. The ID type appears in a JSON " + + "response as a String; however, it is not intended to be human-readable. " + + "When expected as an input type, any string (such as `\"4\"`) or integer " + + "(such as `4`) input value will be accepted as an ID.", serialize: { outputValue in if let value = outputValue as? Map { - if case let .string(value) = value { + if case .string(let value) = value { return .string(value) } - if case let .number(value) = value { + if case .number(let value) = value { return .string(value.description) } throw GraphQLError( @@ -251,10 +245,10 @@ public let GraphQLID = try! GraphQLScalarType( throw GraphQLError(message: "ID cannot represent value: \(outputValue)") }, parseValue: { inputValue in - if case let .string(value) = inputValue { + if case .string(let value) = inputValue { return inputValue } - if case let .number(value) = inputValue, value.storageType == .int { + if case .number(let value) = inputValue, value.storageType == .int { return .string(value.description) } throw GraphQLError(message: "ID cannot represent value: \(inputValue)") diff --git a/Sources/GraphQL/Type/Schema.swift b/Sources/GraphQL/Type/Schema.swift index 7026851b..9c07790b 100644 --- a/Sources/GraphQL/Type/Schema.swift +++ b/Sources/GraphQL/Type/Schema.swift @@ -1,33 +1,30 @@ import Dispatch import OrderedCollections -/** - * Schema Definition - * - * A Schema is created by supplying the root types of each type of operation, - * query and mutation (optional). A schema definition is then supplied to the - * validator and executor. - * - * Example: - * - * let MyAppSchema = GraphQLSchema( - * query: MyAppQueryRootType, - * mutation: MyAppMutationRootType, - * ) - * - * Note: If an array of `directives` are provided to GraphQLSchema, that will be - * the exact list of directives represented and allowed. If `directives` is not - * provided then a default set of the specified directives (e.g. @include and - * @skip) will be used. If you wish to provide *additional* directives to these - * specified directives, you must explicitly declare them. Example: - * - * let MyAppSchema = GraphQLSchema( - * ... - * directives: specifiedDirectives + [myCustomDirective], - * ... - * ) - * - */ +/// Schema Definition +/// +/// A Schema is created by supplying the root types of each type of operation, +/// query and mutation (optional). A schema definition is then supplied to the +/// validator and executor. +/// +/// Example: +/// +/// let MyAppSchema = GraphQLSchema( +/// query: MyAppQueryRootType, +/// mutation: MyAppMutationRootType, +/// ) +/// +/// Note: If an array of `directives` are provided to GraphQLSchema, that will be +/// the exact list of directives represented and allowed. If `directives` is not +/// provided then a default set of the specified directives (e.g. @include and +/// @skip) will be used. If you wish to provide *additional* directives to these +/// specified directives, you must explicitly declare them. Example: +/// +/// let MyAppSchema = GraphQLSchema( +/// ... +/// directives: specifiedDirectives + [myCustomDirective], +/// ... +/// ) public final class GraphQLSchema: @unchecked Sendable { let description: String? let extensions: [GraphQLSchemaExtensions] @@ -169,7 +166,7 @@ public final class GraphQLSchema: @unchecked Sendable { if typeMap[typeName] != nil { throw GraphQLError( message: - "Schema must contain uniquely named types but contains multiple types named \"\(typeName)\"." + "Schema must contain uniquely named types but contains multiple types named \"\(typeName)\"." ) } typeMap[typeName] = namedType @@ -177,10 +174,12 @@ public final class GraphQLSchema: @unchecked Sendable { if let namedType = namedType as? GraphQLInterfaceType { // Store implementations by interface. for iface in try namedType.getInterfaces() { - let implementation = implementations[iface.name] ?? .init( - objects: [], - interfaces: [] - ) + let implementation = + implementations[iface.name] + ?? .init( + objects: [], + interfaces: [] + ) var interfaces = implementation.interfaces interfaces.append(namedType) @@ -192,10 +191,12 @@ public final class GraphQLSchema: @unchecked Sendable { } else if let namedType = namedType as? GraphQLObjectType { // Store implementations by objects. for iface in try namedType.getInterfaces() { - let implementation = implementations[iface.name] ?? .init( - objects: [], - interfaces: [] - ) + let implementation = + implementations[iface.name] + ?? .init( + objects: [], + interfaces: [] + ) var objects = implementation.objects objects.append(namedType) @@ -342,15 +343,15 @@ func typeMapReducer(typeMap: TypeMap, type: GraphQLType) throws -> TypeMap { } guard let type = type as? GraphQLNamedType else { - return typeMap // Should never happen + return typeMap // Should never happen } if let existingType = typeMap[type.name] { if !(existingType == type) { throw GraphQLError( message: - "Schema must contain unique named types but contains multiple " + - "types named \"\(type.name)\"." + "Schema must contain unique named types but contains multiple " + + "types named \"\(type.name)\"." ) } else { // Otherwise, it's already been defined so short circuit @@ -436,13 +437,11 @@ class GraphQLSchemaNormalizedConfig { } } -/** - * Custom extensions - * - * @remarks - * Use a unique identifier name for your extension, for example the name of - * your library or project. Do not use a shortened identifier as this increases - * the risk of conflicts. We recommend you add at most one extension field, - * an object which can contain all the values you need. - */ +/// Custom extensions +/// +/// @remarks +/// Use a unique identifier name for your extension, for example the name of +/// your library or project. Do not use a shortened identifier as this increases +/// the risk of conflicts. We recommend you add at most one extension field, +/// an object which can contain all the values you need. public typealias GraphQLSchemaExtensions = [String: String]? diff --git a/Sources/GraphQL/Type/Validation.swift b/Sources/GraphQL/Type/Validation.swift index 605cc8a4..a2cb28bc 100644 --- a/Sources/GraphQL/Type/Validation.swift +++ b/Sources/GraphQL/Type/Validation.swift @@ -1,10 +1,8 @@ -/** - * Implements the "Type Validation" sub-sections of the specification's - * "Type System" section. - * - * Validation runs synchronously, returning an array of encountered errors, or - * an empty array if no errors were encountered and the Schema is valid. - */ +/// Implements the "Type Validation" sub-sections of the specification's +/// "Type System" section. +/// +/// Validation runs synchronously, returning an array of encountered errors, or +/// an empty array if no errors were encountered and the Schema is valid. public func validateSchema( schema: GraphQLSchema ) throws -> [GraphQLError] { @@ -26,10 +24,8 @@ public func validateSchema( return errors } -/** - * Utility function which asserts a schema is valid by throwing an error if - * it is invalid. - */ +/// Utility function which asserts a schema is valid by throwing an error if +/// it is invalid. func assertValidSchema(schema: GraphQLSchema) throws { let errors = try validateSchema(schema: schema) if !errors.isEmpty { @@ -102,7 +98,8 @@ func validateRootTypes(context: SchemaValidationContext) { if operationTypes.count > 1 { let operationList = operationTypes.map { $0.rawValue }.andList() context.reportError( - message: "All root types must be different, \"\(rootType)\" type is used as \(operationList) root types.", + message: + "All root types must be different, \"\(rootType)\" type is used as \(operationList) root types.", nodes: operationTypes.map { operationType in getOperationTypeNode(schema: schema, operation: operationType) } @@ -117,7 +114,7 @@ func getOperationTypeNode( ) -> Node? { let nodes: [SchemaDefinition?] = [schema.astNode] // TODO: Add schema operation extension support -// nodes.append(contentsOf: schema.extensionASTNodes) + // nodes.append(contentsOf: schema.extensionASTNodes) return nodes.flatMap { schemaNode in schemaNode?.operationTypes ?? [] }.find { operationNode in operationNode.operation == operation }?.type @@ -142,7 +139,8 @@ func validateDirectives(context: SchemaValidationContext) { if isRequiredArgument(arg), arg.deprecationReason != nil { context.reportError( - message: "Required argument @\(directive.name)(\(arg.name):) cannot be deprecated.", + message: + "Required argument @\(directive.name)(\(arg.name):) cannot be deprecated.", nodes: [ getDeprecatedDirectiveNode(directives: arg.astNode?.directives), arg.astNode?.type, @@ -161,7 +159,8 @@ func validateName( // Ensure names are valid, however introspection types opt out. if name.hasPrefix("__") { context.reportError( - message: "Name \"\(name)\" must not begin with \"__\", which is reserved by GraphQL introspection.", + message: + "Name \"\(name)\" must not begin with \"__\", which is reserved by GraphQL introspection.", node: astNode ) } @@ -246,15 +245,16 @@ func validateFields( // Ensure the type is an input type if !isInputType(type: arg.type) { context.reportError( - message: "The type of \(type).\(field.name)(\(argName):) must be Input " + - "Type but got: \(arg.type).", + message: "The type of \(type).\(field.name)(\(argName):) must be Input " + + "Type but got: \(arg.type).", node: arg.astNode?.type ) } if isRequiredArgument(arg), arg.deprecationReason != nil { context.reportError( - message: "Required argument \(type).\(field.name)(\(argName):) cannot be deprecated.", + message: + "Required argument \(type).\(field.name)(\(argName):) cannot be deprecated.", nodes: [ getDeprecatedDirectiveNode(directives: arg.astNode?.directives), arg.astNode?.type, @@ -292,15 +292,16 @@ func validateFields( // Ensure the type is an input type if !isInputType(type: arg.type) { context.reportError( - message: "The type of \(type).\(field.name)(\(argName):) must be Input " + - "Type but got: \(arg.type).", + message: "The type of \(type).\(field.name)(\(argName):) must be Input " + + "Type but got: \(arg.type).", node: arg.astNode?.type ) } if isRequiredArgument(arg), arg.deprecationReason != nil { context.reportError( - message: "Required argument \(type).\(field.name)(\(argName):) cannot be deprecated.", + message: + "Required argument \(type).\(field.name)(\(argName):) cannot be deprecated.", nodes: [ getDeprecatedDirectiveNode(directives: arg.astNode?.directives), arg.astNode?.type, @@ -319,7 +320,8 @@ func validateInterfaces( for iface in try type.getInterfaces() { if type == iface { context.reportError( - message: "Type \(type) cannot implement itself because it would create a circular reference.", + message: + "Type \(type) cannot implement itself because it would create a circular reference.", nodes: getAllImplementsInterfaceNodes(type: type, iface: iface) ) continue @@ -348,7 +350,8 @@ func validateInterfaces( for iface in try type.getInterfaces() { if type == iface { context.reportError( - message: "Type \(type) cannot implement itself because it would create a circular reference.", + message: + "Type \(type) cannot implement itself because it would create a circular reference.", nodes: getAllImplementsInterfaceNodes(type: type, iface: iface) ) continue @@ -386,7 +389,8 @@ func validateTypeImplementsInterface( var nodes: [Node?] = [ifaceField.astNode, type.astNode] nodes.append(contentsOf: type.extensionASTNodes) context.reportError( - message: "Interface field \(iface.name).\(fieldName) expected but \(type) does not provide it.", + message: + "Interface field \(iface.name).\(fieldName) expected but \(type) does not provide it.", nodes: nodes ) continue @@ -396,9 +400,8 @@ func validateTypeImplementsInterface( // a valid subtype. (covariant) if try !isTypeSubTypeOf(context.schema, typeField.type, ifaceField.type) { context.reportError( - message: "Interface field \(iface.name).\(fieldName) expects type " + - "\(ifaceField.type) but \(type).\(fieldName) " + - "is type \(typeField.type).", + message: "Interface field \(iface.name).\(fieldName) expects type " + + "\(ifaceField.type) but \(type).\(fieldName) " + "is type \(typeField.type).", nodes: [ifaceField.astNode?.type, typeField.astNode?.type] ) } @@ -411,7 +414,8 @@ func validateTypeImplementsInterface( // Assert interface field arg exists on object field. guard let typeArg = typeArg else { context.reportError( - message: "Interface field argument \(iface.name).\(fieldName)(\(argName):) expected but \(type).\(fieldName) does not provide it.", + message: + "Interface field argument \(iface.name).\(fieldName)(\(argName):) expected but \(type).\(fieldName) does not provide it.", nodes: [ifaceArg.astNode, typeField.astNode] ) continue @@ -422,10 +426,10 @@ func validateTypeImplementsInterface( // TODO: change to contravariant? if !isEqualType(ifaceArg.type, typeArg.type) { context.reportError( - message: "Interface field argument \(iface.name).\(fieldName)(\(argName):) " + - "expects type \(ifaceArg.type) but " + - "\(type).\(fieldName)(\(argName):) is type " + - "\(typeArg.type).", + message: "Interface field argument \(iface.name).\(fieldName)(\(argName):) " + + "expects type \(ifaceArg.type) but " + + "\(type).\(fieldName)(\(argName):) is type " + + "\(typeArg.type).", nodes: [ifaceArg.astNode?.type, typeArg.astNode?.type] ) } @@ -439,7 +443,8 @@ func validateTypeImplementsInterface( let ifaceArg = ifaceField.args.find { arg in arg.name == argName } if ifaceArg == nil, isRequiredArgument(typeArg) { context.reportError( - message: "Argument \"\(type).\(fieldName)(\(argName):)\" must not be required type \"\(typeArg.type)\" if not provided by the Interface field \"\(iface.name).\(fieldName)\".", + message: + "Argument \"\(type).\(fieldName)(\(argName):)\" must not be required type \"\(typeArg.type)\" if not provided by the Interface field \"\(iface.name).\(fieldName)\".", nodes: [typeArg.astNode, ifaceField.astNode] ) } @@ -464,7 +469,8 @@ func validateTypeImplementsInterface( var nodes: [Node?] = [ifaceField.astNode, type.astNode] nodes.append(contentsOf: type.extensionASTNodes) context.reportError( - message: "Interface field \(iface.name).\(fieldName) expected but \(type) does not provide it.", + message: + "Interface field \(iface.name).\(fieldName) expected but \(type) does not provide it.", nodes: nodes ) continue @@ -474,9 +480,8 @@ func validateTypeImplementsInterface( // a valid subtype. (covariant) if try !isTypeSubTypeOf(context.schema, typeField.type, ifaceField.type) { context.reportError( - message: "Interface field \(iface.name).\(fieldName) expects type " + - "\(ifaceField.type) but \(type).\(fieldName) " + - "is type \(typeField.type).", + message: "Interface field \(iface.name).\(fieldName) expects type " + + "\(ifaceField.type) but \(type).\(fieldName) " + "is type \(typeField.type).", nodes: [ifaceField.astNode?.type, typeField.astNode?.type] ) } @@ -489,7 +494,8 @@ func validateTypeImplementsInterface( // Assert interface field arg exists on object field. guard let typeArg = typeArg else { context.reportError( - message: "Interface field argument \(iface.name).\(fieldName)(\(argName):) expected but \(type).\(fieldName) does not provide it.", + message: + "Interface field argument \(iface.name).\(fieldName)(\(argName):) expected but \(type).\(fieldName) does not provide it.", nodes: [ifaceArg.astNode, typeField.astNode] ) continue @@ -500,10 +506,10 @@ func validateTypeImplementsInterface( // TODO: change to contravariant? if !isEqualType(ifaceArg.type, typeArg.type) { context.reportError( - message: "Interface field argument \(iface.name).\(fieldName)(\(argName):) " + - "expects type \(ifaceArg.type) but " + - "\(type).\(fieldName)(\(argName):) is type " + - "\(typeArg.type).", + message: "Interface field argument \(iface.name).\(fieldName)(\(argName):) " + + "expects type \(ifaceArg.type) but " + + "\(type).\(fieldName)(\(argName):) is type " + + "\(typeArg.type).", nodes: [ifaceArg.astNode?.type, typeArg.astNode?.type] ) } @@ -517,7 +523,8 @@ func validateTypeImplementsInterface( let ifaceArg = ifaceField.args.find { arg in arg.name == argName } if ifaceArg == nil, isRequiredArgument(typeArg) { context.reportError( - message: "Argument \"\(type).\(fieldName)(\(argName):)\" must not be required type \"\(typeArg.type)\" if not provided by the Interface field \"\(iface.name).\(fieldName)\".", + message: + "Argument \"\(type).\(fieldName)(\(argName):)\" must not be required type \"\(typeArg.type)\" if not provided by the Interface field \"\(iface.name).\(fieldName)\".", nodes: [typeArg.astNode, ifaceField.astNode] ) } @@ -537,10 +544,8 @@ func validateTypeImplementsAncestors( nodes.append(contentsOf: getAllImplementsInterfaceNodes(type: type, iface: iface)) context.reportError( message: transitive == type - ? - "Type \(type) cannot implement \(iface.name) because it would create a circular reference." - : - "Type \(type) must implement \(transitive.name) because it is implemented by \(iface.name).", + ? "Type \(type) cannot implement \(iface.name) because it would create a circular reference." + : "Type \(type) must implement \(transitive.name) because it is implemented by \(iface.name).", nodes: nodes ) } @@ -559,10 +564,8 @@ func validateTypeImplementsAncestors( nodes.append(contentsOf: getAllImplementsInterfaceNodes(type: type, iface: iface)) context.reportError( message: transitive == type - ? - "Type \(type) cannot implement \(iface.name) because it would create a circular reference." - : - "Type \(type) must implement \(transitive.name) because it is implemented by \(iface.name).", + ? "Type \(type) cannot implement \(iface.name) because it would create a circular reference." + : "Type \(type) must implement \(transitive.name) because it is implemented by \(iface.name).", nodes: nodes ) } @@ -641,15 +644,16 @@ func validateInputFields( // Ensure the type is an input type if !isInputType(type: field.type) { context.reportError( - message: "The type of \(inputObj.name).\(field.name) must be Input Type " + - "but got: \(field.type).", + message: "The type of \(inputObj.name).\(field.name) must be Input Type " + + "but got: \(field.type).", node: field.astNode?.type ) } if isRequiredInputField(field), field.deprecationReason != nil { context.reportError( - message: "Required input field \(inputObj.name).\(field.name) cannot be deprecated.", + message: + "Required input field \(inputObj.name).\(field.name) cannot be deprecated.", nodes: [ getDeprecatedDirectiveNode(directives: field.astNode?.directives), field.astNode?.type, @@ -712,18 +716,18 @@ func createInputObjectCircularRefsValidator( let fields = try inputObj.getFields().values for field in fields { - if - let nonNullType = field.type as? GraphQLNonNull, + if let nonNullType = field.type as? GraphQLNonNull, let fieldType = nonNullType.ofType as? GraphQLInputObjectType { let cycleIndex = fieldPathIndexByTypeName[fieldType.name] fieldPath.append(field) if let cycleIndex = cycleIndex { - let cyclePath = fieldPath[cycleIndex ..< fieldPath.count] + let cyclePath = fieldPath[cycleIndex.. Document { diff --git a/Sources/GraphQL/Utilities/ExtendSchema.swift b/Sources/GraphQL/Utilities/ExtendSchema.swift index ed9dff22..1799dc9a 100644 --- a/Sources/GraphQL/Utilities/ExtendSchema.swift +++ b/Sources/GraphQL/Utilities/ExtendSchema.swift @@ -1,17 +1,15 @@ import OrderedCollections -/** - * Produces a new schema given an existing schema and a document which may - * contain GraphQL type extensions and definitions. The original schema will - * remain unaltered. - * - * Because a schema represents a graph of references, a schema cannot be - * extended without effectively making an entire copy. We do not know until it's - * too late if subgraphs remain unchanged. - * - * This algorithm copies the provided schema, applying extensions while - * producing the copy. The original schema remains unaltered. - */ +/// Produces a new schema given an existing schema and a document which may +/// contain GraphQL type extensions and definitions. The original schema will +/// remain unaltered. +/// +/// Because a schema represents a graph of references, a schema cannot be +/// extended without effectively making an entire copy. We do not know until it's +/// too late if subgraphs remain unchanged. +/// +/// This algorithm copies the provided schema, applying extensions while +/// producing the copy. The original schema remains unaltered. public func extendSchema( schema: GraphQLSchema, documentAST: Document, @@ -63,14 +61,12 @@ func extendSchemaImpl( case .directiveDefinition: directiveDefs.append(def as! DirectiveDefinition) // Type Definitions - case - .scalarTypeDefinition, + case .scalarTypeDefinition, .objectTypeDefinition, .interfaceTypeDefinition, .unionTypeDefinition, .enumTypeDefinition, - .inputObjectTypeDefinition - : + .inputObjectTypeDefinition: typeDefs.append(def as! TypeDefinition) // Type System Extensions case .scalarExtensionDefinition: @@ -608,7 +604,8 @@ func extendSchemaImpl( } guard let type = wrappedType as? GraphQLOutputType, checkType is GraphQLOutputType else { throw GraphQLError( - message: "The type of \(typeName.printed).\(field.name.printed) must be Output Type but got: \(field.type)." + message: + "The type of \(typeName.printed).\(field.name.printed) must be Output Type but got: \(field.type)." ) } return type @@ -624,7 +621,8 @@ func extendSchemaImpl( for arg in argsNodes { guard let type = try getWrappedType(arg.type) as? GraphQLInputType else { throw GraphQLError( - message: "The type of \(methodFormat)(\(arg.name):) must be Input Type but got: \(print(ast: arg.type))." + message: + "The type of \(methodFormat)(\(arg.name):) must be Input Type but got: \(print(ast: arg.type))." ) } @@ -648,7 +646,8 @@ func extendSchemaImpl( let type = try getWrappedType(field.type) guard let type = type as? GraphQLInputType else { throw GraphQLError( - message: "The type of \(node.name.printed).\(field.name.printed) must be Input Type but got: \(type)." + message: + "The type of \(node.name.printed).\(field.name.printed) must be Input Type but got: \(type)." ) } @@ -677,7 +676,8 @@ func extendSchemaImpl( let type = try getWrappedType(field.type) guard let type = type as? GraphQLInputType else { throw GraphQLError( - message: "The type of \(node.name.printed).\(field.name.printed) must be Input Type but got: \(type)." + message: + "The type of \(node.name.printed).\(field.name.printed) must be Input Type but got: \(type)." ) } @@ -695,7 +695,7 @@ func extendSchemaImpl( } func buildEnumValueMap( - nodes: [EnumTypeDefinition] // | EnumTypeExtension], + nodes: [EnumTypeDefinition] // | EnumTypeExtension], ) throws -> GraphQLEnumValueMap { var enumValueMap = GraphQLEnumValueMap() for node in nodes { @@ -766,7 +766,8 @@ func extendSchemaImpl( let namedType = try getNamedType(interface) guard let checkedInterface = namedType as? GraphQLInterfaceType else { throw GraphQLError( - message: "Type \(type.name.printed) must only implement Interface types, it cannot implement \(namedType.name)." + message: + "Type \(type.name.printed) must only implement Interface types, it cannot implement \(namedType.name)." ) } interfaces.append(checkedInterface) @@ -780,7 +781,8 @@ func extendSchemaImpl( let namedType = try getNamedType(interface) guard let checkedInterface = namedType as? GraphQLInterfaceType else { throw GraphQLError( - message: "Type \(type.name.printed) must only implement Interface types, it cannot implement \(namedType.name)." + message: + "Type \(type.name.printed) must only implement Interface types, it cannot implement \(namedType.name)." ) } interfaces.append(checkedInterface) @@ -810,7 +812,8 @@ func extendSchemaImpl( let namedType = try getNamedType(type) guard let checkedType = namedType as? GraphQLObjectType else { throw GraphQLError( - message: "Union type \(type.name.printed) can only include Object types, it cannot include \(namedType.name)." + message: + "Union type \(type.name.printed) can only include Object types, it cannot include \(namedType.name)." ) } types.append(checkedType) @@ -939,7 +942,8 @@ func checkOperationType( let operationTypeStr = operationType.rawValue.capitalized let rootTypeStr = type.name guard let objectType = type as? GraphQLObjectType else { - let message = operationType == .query + let message = + operationType == .query ? "\(operationTypeStr) root type must be Object type, it cannot be \(rootTypeStr)." : "\(operationTypeStr) root type must be Object type, it cannot be \(rootTypeStr)." throw GraphQLError(message: message) @@ -994,9 +998,7 @@ func getDeprecationReason( return deprecated?.dictionary?["reason"]?.string } -/** - * Given a scalar node, returns the string value for the specifiedByURL. - */ +/// Given a scalar node, returns the string value for the specifiedByURL. func getSpecifiedByURL( node: ScalarTypeDefinition ) throws -> String? { @@ -1017,9 +1019,7 @@ func getSpecifiedByURL( return specifiedBy?.dictionary?["url"]?.string } -/** - * Given an input object node, returns if the node should be OneOf. - */ +/// Given an input object node, returns if the node should be OneOf. func isOneOf(node: InputObjectTypeDefinition) throws -> Bool { let isOneOf = try getDirectiveValues( directiveDef: GraphQLOneOfDirective, diff --git a/Sources/GraphQL/Utilities/IsValidValue.swift b/Sources/GraphQL/Utilities/IsValidValue.swift index 744b8386..c6a549a6 100644 --- a/Sources/GraphQL/Utilities/IsValidValue.swift +++ b/Sources/GraphQL/Utilities/IsValidValue.swift @@ -1,8 +1,6 @@ -/** - * Given a `Map` value and a GraphQL type, determine if the value will be - * accepted for that type. This is primarily useful for validating the - * runtime values of query variables. - */ +/// Given a `Map` value and a GraphQL type, determine if the value will be +/// accepted for that type. This is primarily useful for validating the +/// runtime values of query variables. func validate(value: Map, forType type: GraphQLInputType) throws -> [String] { // A value must be provided if the type is non-null. if let nonNullType = type as? GraphQLNonNull { @@ -31,7 +29,7 @@ func validate(value: Map, forType type: GraphQLInputType) throws -> [String] { throw GraphQLError(message: "Input list type must wrap another input type") } - if case let .array(values) = value { + if case .array(let values) = value { var errors: [String] = [] for (index, item) in values.enumerated() { @@ -49,7 +47,7 @@ func validate(value: Map, forType type: GraphQLInputType) throws -> [String] { // Input objects check each defined field. if let objectType = type as? GraphQLInputObjectType { - guard case let .dictionary(dictionary) = value else { + guard case .dictionary(let dictionary) = value else { return ["Expected \"\(objectType.name)\", found not an object."] } diff --git a/Sources/GraphQL/Utilities/PrintSchema.swift b/Sources/GraphQL/Utilities/PrintSchema.swift index e02fd983..40616101 100644 --- a/Sources/GraphQL/Utilities/PrintSchema.swift +++ b/Sources/GraphQL/Utilities/PrintSchema.swift @@ -50,8 +50,7 @@ func printSchemaDefinition(schema: GraphQLSchema) -> String? { // Only print a schema definition if there is a description or if it should // not be omitted because of having default type names. if schema.description != nil || !hasDefaultRootOperationTypes(schema: schema) { - var result = printDescription(schema.description) + - "schema {\n" + var result = printDescription(schema.description) + "schema {\n" if let queryType = queryType { result = result + " query: \(queryType.name)\n" } @@ -67,40 +66,37 @@ func printSchemaDefinition(schema: GraphQLSchema) -> String? { return nil } -/** - * GraphQL schema define root types for each type of operation. These types are - * the same as any other type and can be named in any manner, however there is - * a common naming convention: - * - * ```graphql - * schema { - * query: Query - * mutation: Mutation - * subscription: Subscription - * } - * ``` - * - * When using this naming convention, the schema description can be omitted so - * long as these names are only used for operation types. - * - * Note however that if any of these default names are used elsewhere in the - * schema but not as a root operation type, the schema definition must still - * be printed to avoid ambiguity. - */ +/// GraphQL schema define root types for each type of operation. These types are +/// the same as any other type and can be named in any manner, however there is +/// a common naming convention: +/// +/// ```graphql +/// schema { +/// query: Query +/// mutation: Mutation +/// subscription: Subscription +/// } +/// ``` +/// +/// When using this naming convention, the schema description can be omitted so +/// long as these names are only used for operation types. +/// +/// Note however that if any of these default names are used elsewhere in the +/// schema but not as a root operation type, the schema definition must still +/// be printed to avoid ambiguity. func hasDefaultRootOperationTypes(schema: GraphQLSchema) -> Bool { // The goal here is to check if a type was declared using the default names of "Query", // "Mutation" or "Subscription". We do so by comparing object IDs to determine if the // schema operation object is the same as the type object by that name. - return ( - schema.queryType.map { ObjectIdentifier($0) } - == (schema.getType(name: "Query") as? GraphQLObjectType).map { ObjectIdentifier($0) } && - schema.mutationType.map { ObjectIdentifier($0) } + return + (schema.queryType.map { ObjectIdentifier($0) } + == (schema.getType(name: "Query") as? GraphQLObjectType).map { ObjectIdentifier($0) } + && schema.mutationType.map { ObjectIdentifier($0) } == (schema.getType(name: "Mutation") as? GraphQLObjectType) - .map { ObjectIdentifier($0) } && - schema.subscriptionType.map { ObjectIdentifier($0) } - == (schema.getType(name: "Subscription") as? GraphQLObjectType) .map { ObjectIdentifier($0) } - ) + && schema.subscriptionType.map { ObjectIdentifier($0) } + == (schema.getType(name: "Subscription") as? GraphQLObjectType) + .map { ObjectIdentifier($0) }) } public func printType(type: GraphQLNamedType) -> String { @@ -128,9 +124,8 @@ public func printType(type: GraphQLNamedType) -> String { } func printScalar(type: GraphQLScalarType) -> String { - return printDescription(type.description) + - "scalar \(type.name)" + - printSpecifiedByURL(scalar: type) + return printDescription(type.description) + "scalar \(type.name)" + + printSpecifiedByURL(scalar: type) } func printImplementedInterfaces( @@ -143,34 +138,30 @@ func printImplementedInterfaces( func printObject(type: GraphQLObjectType) -> String { return - printDescription(type.description) + - "type \(type.name)" + - printImplementedInterfaces(interfaces: (try? type.getInterfaces()) ?? []) + - printFields(fields: (try? type.getFields()) ?? [:]) + printDescription(type.description) + "type \(type.name)" + + printImplementedInterfaces(interfaces: (try? type.getInterfaces()) ?? []) + + printFields(fields: (try? type.getFields()) ?? [:]) } func printInterface(type: GraphQLInterfaceType) -> String { return - printDescription(type.description) + - "interface \(type.name)" + - printImplementedInterfaces(interfaces: (try? type.getInterfaces()) ?? []) + - printFields(fields: (try? type.getFields()) ?? [:]) + printDescription(type.description) + "interface \(type.name)" + + printImplementedInterfaces(interfaces: (try? type.getInterfaces()) ?? []) + + printFields(fields: (try? type.getFields()) ?? [:]) } func printUnion(type: GraphQLUnionType) -> String { let types = (try? type.getTypes()) ?? [] return - printDescription(type.description) + - "union \(type.name)" + - (types.isEmpty ? "" : " = " + types.map { $0.name }.joined(separator: " | ")) + printDescription(type.description) + "union \(type.name)" + + (types.isEmpty ? "" : " = " + types.map { $0.name }.joined(separator: " | ")) } func printEnum(type: GraphQLEnumType) -> String { let values = type.values.enumerated().map { i, value in - printDescription(value.description, indentation: " ", firstInBlock: i == 0) + - " " + - value.name + - printDeprecated(reason: value.deprecationReason) + printDescription(value.description, indentation: " ", firstInBlock: i == 0) + " " + + value.name + + printDeprecated(reason: value.deprecationReason) } return printDescription(type.description) + "enum \(type.name)" + printBlock(items: values) @@ -179,26 +170,20 @@ func printEnum(type: GraphQLEnumType) -> String { func printInputObject(type: GraphQLInputObjectType) -> String { let inputFields = (try? type.getFields()) ?? [:] let fields = inputFields.values.enumerated().map { i, f in - printDescription(f.description, indentation: " ", firstInBlock: i == 0) + " " + - printInputValue(arg: f) + printDescription(f.description, indentation: " ", firstInBlock: i == 0) + " " + + printInputValue(arg: f) } return - printDescription(type.description) + - "input \(type.name)" + - (type.isOneOf ? " @oneOf" : "") + - printBlock(items: fields) + printDescription(type.description) + "input \(type.name)" + (type.isOneOf ? " @oneOf" : "") + + printBlock(items: fields) } func printFields(fields: GraphQLFieldDefinitionMap) -> String { let fields = fields.values.enumerated().map { i, f in - printDescription(f.description, indentation: " ", firstInBlock: i == 0) + - " " + - f.name + - printArgs(args: f.args, indentation: " ") + - ": " + - f.type.debugDescription + - printDeprecated(reason: f.deprecationReason) + printDescription(f.description, indentation: " ", firstInBlock: i == 0) + " " + f.name + + printArgs(args: f.args, indentation: " ") + ": " + f.type.debugDescription + + printDeprecated(reason: f.deprecationReason) } return printBlock(items: fields) } @@ -221,20 +206,14 @@ func printArgs( } return - "(\n" + - args.enumerated().map { i, arg in + "(\n" + + args.enumerated().map { i, arg in printDescription( arg.description, indentation: " " + indentation, firstInBlock: i == 0 - ) + - " " + - indentation + - printArgValue(arg: arg) - }.joined(separator: "\n") + - "\n" + - indentation + - ")" + ) + " " + indentation + printArgValue(arg: arg) + }.joined(separator: "\n") + "\n" + indentation + ")" } func printArgValue(arg: GraphQLArgumentDefinition) -> String { @@ -259,13 +238,9 @@ func printInputValue(arg: InputObjectFieldDefinition) -> String { public func printDirective(directive: GraphQLDirective) -> String { return - printDescription(directive.description) + - "directive @" + - directive.name + - printArgs(args: directive.args) + - (directive.isRepeatable ? " repeatable" : "") + - " on " + - directive.locations.map { $0.rawValue }.joined(separator: " | ") + printDescription(directive.description) + "directive @" + directive.name + + printArgs(args: directive.args) + (directive.isRepeatable ? " repeatable" : "") + " on " + + directive.locations.map { $0.rawValue }.joined(separator: " | ") } func printDeprecated(reason: String?) -> String { @@ -296,10 +271,12 @@ func printDescription( return "" } - let blockString = print(ast: StringValue( - value: description, - block: isPrintableAsBlockString(description) - )) + let blockString = print( + ast: StringValue( + value: description, + block: isPrintableAsBlockString(description) + ) + ) let prefix = (!indentation.isEmpty && !firstInBlock) ? "\n" + indentation : indentation diff --git a/Sources/GraphQL/Utilities/TypeComparators.swift b/Sources/GraphQL/Utilities/TypeComparators.swift index 1c00af26..c345262b 100644 --- a/Sources/GraphQL/Utilities/TypeComparators.swift +++ b/Sources/GraphQL/Utilities/TypeComparators.swift @@ -1,6 +1,4 @@ -/** - * Provided two types, return true if the types are equal (invariant). - */ +/// Provided two types, return true if the types are equal (invariant). func isEqualType(_ typeA: GraphQLType, _ typeB: GraphQLType) -> Bool { // Equivalent types are equal. if typeA == typeB { @@ -62,10 +60,8 @@ func == (lhs: GraphQLType, rhs: GraphQLType) -> Bool { return false } -/** - * Provided a type and a super type, return true if the first type is either - * equal or a subset of the second super type (covariant). - */ +/// Provided a type and a super type, return true if the first type is either +/// equal or a subset of the second super type (covariant). func isTypeSubTypeOf( _ schema: GraphQLSchema, _ maybeSubType: GraphQLType, @@ -101,8 +97,7 @@ func isTypeSubTypeOf( } // If superType type is an abstract type, check if it is super type of maybeSubType. - if - let superType = superType as? GraphQLAbstractType, + if let superType = superType as? GraphQLAbstractType, let maybeSubType = maybeSubType as? GraphQLObjectType, schema.isSubType( abstractType: superType, @@ -112,8 +107,7 @@ func isTypeSubTypeOf( return true } - if - let superType = superType as? GraphQLAbstractType, + if let superType = superType as? GraphQLAbstractType, let maybeSubType = maybeSubType as? GraphQLInterfaceType, schema.isSubType( abstractType: superType, @@ -127,15 +121,13 @@ func isTypeSubTypeOf( return false } -/** - * Provided two composite types, determine if they "overlap". Two composite - * types overlap when the Sets of possible concrete types for each intersect. - * - * This is often used to determine if a fragment of a given type could possibly - * be visited in a context of another type. - * - * This function is commutative. - */ +/// Provided two composite types, determine if they "overlap". Two composite +/// types overlap when the Sets of possible concrete types for each intersect. +/// +/// This is often used to determine if a fragment of a given type could possibly +/// be visited in a context of another type. +/// +/// This function is commutative. func doTypesOverlap( schema: GraphQLSchema, typeA: GraphQLCompositeType, @@ -167,8 +159,7 @@ func doTypesOverlap( } } - if - let typeA = typeA as? GraphQLObjectType, + if let typeA = typeA as? GraphQLObjectType, let typeB = typeB as? GraphQLAbstractType { // Determine if the former type is a possible concrete type of the latter. diff --git a/Sources/GraphQL/Utilities/TypeInfo.swift b/Sources/GraphQL/Utilities/TypeInfo.swift index 89e2a919..eac7d33f 100644 --- a/Sources/GraphQL/Utilities/TypeInfo.swift +++ b/Sources/GraphQL/Utilities/TypeInfo.swift @@ -1,8 +1,6 @@ -/** - * TypeInfo is a utility class which, given a GraphQL schema, can keep track - * of the current field and type definitions at any point in a GraphQL document - * AST during a recursive descent by calling `enter(node: node)` and `leave(node: node)`. - */ +/// TypeInfo is a utility class which, given a GraphQL schema, can keep track +/// of the current field and type definitions at any point in a GraphQL document +/// AST during a recursive descent by calling `enter(node: node)` and `leave(node: node)`. final class TypeInfo { let schema: GraphQLSchema var typeStack: [GraphQLOutputType?] @@ -226,11 +224,9 @@ final class TypeInfo { } } -/** - * Not exactly the same as the executor's definition of getFieldDef, in this - * statically evaluated environment we do not always have an Object type, - * and need to handle Interface and Union types. - */ +/// Not exactly the same as the executor's definition of getFieldDef, in this +/// statically evaluated environment we do not always have an Object type, +/// and need to handle Interface and Union types. func getFieldDef( schema: GraphQLSchema, parentType: GraphQLType, @@ -248,10 +244,9 @@ func getFieldDef( } } - if - name == TypeNameMetaFieldDef.name, parentType is GraphQLObjectType || - parentType is GraphQLInterfaceType || - parentType is GraphQLUnionType + if name == TypeNameMetaFieldDef.name, + parentType is GraphQLObjectType || parentType is GraphQLInterfaceType + || parentType is GraphQLUnionType { return TypeNameMetaFieldDef } diff --git a/Sources/GraphQL/Utilities/ValueFromAST.swift b/Sources/GraphQL/Utilities/ValueFromAST.swift index 114aae21..e8a1106c 100644 --- a/Sources/GraphQL/Utilities/ValueFromAST.swift +++ b/Sources/GraphQL/Utilities/ValueFromAST.swift @@ -1,22 +1,19 @@ import OrderedCollections -/** - * Produces a Map value given a GraphQL Value AST. - * - * A GraphQL type must be provided, which will be used to interpret different - * GraphQL Value literals. - * - * | GraphQL Value | Map Value | - * | -------------------- | ------------- | - * | Input Object | .dictionary | - * | List | .array | - * | Boolean | .bool | - * | String | .string | - * | Int | .int | - * | Float | .float | - * | Enum Value | .string | - * - */ +/// Produces a Map value given a GraphQL Value AST. +/// +/// A GraphQL type must be provided, which will be used to interpret different +/// GraphQL Value literals. +/// +/// | GraphQL Value | Map Value | +/// | -------------------- | ------------- | +/// | Input Object | .dictionary | +/// | List | .array | +/// | Boolean | .bool | +/// | String | .string | +/// | Int | .int | +/// | Float | .float | +/// | Enum Value | .string | func valueFromAST( valueAST: Value, type: GraphQLInputType, @@ -78,7 +75,7 @@ func valueFromAST( valueAST: valueAST, type: itemType, variables: variables - ), + ) ]) } @@ -111,11 +108,11 @@ func valueFromAST( if objectType.isOneOf { let keys = object.filter { $1 != .undefined }.keys if keys.count != 1 { - return .undefined // Invalid: not exactly one key, intentionally return no value. + return .undefined // Invalid: not exactly one key, intentionally return no value. } if object[keys[0]] == .null { - return .undefined // Invalid: value not non-null, intentionally return no value. + return .undefined // Invalid: value not non-null, intentionally return no value. } } diff --git a/Sources/GraphQL/Utilities/ValueFromASTUntyped.swift b/Sources/GraphQL/Utilities/ValueFromASTUntyped.swift index c1aa8bb6..9f6c9359 100644 --- a/Sources/GraphQL/Utilities/ValueFromASTUntyped.swift +++ b/Sources/GraphQL/Utilities/ValueFromASTUntyped.swift @@ -1,22 +1,19 @@ import OrderedCollections -/** - * Produces a JavaScript value given a GraphQL Value AST. - * - * Unlike `valueFromAST()`, no type is provided. The resulting map - * will reflect the provided GraphQL value AST. - * - * | GraphQL Value | Map Value | - * | -------------------- | ---------------- | - * | Input Object | .dictionary | - * | List | .array | - * | Boolean | .boolean | - * | String / Enum | .string | - * | Int | .int | - * | Float | .float | - * | Null | .null | - * - */ +/// Produces a JavaScript value given a GraphQL Value AST. +/// +/// Unlike `valueFromAST()`, no type is provided. The resulting map +/// will reflect the provided GraphQL value AST. +/// +/// | GraphQL Value | Map Value | +/// | -------------------- | ---------------- | +/// | Input Object | .dictionary | +/// | List | .array | +/// | Boolean | .boolean | +/// | String / Enum | .string | +/// | Int | .int | +/// | Float | .float | +/// | Null | .null | public func valueFromASTUntyped( valueAST: Value, variables: [String: Map] = [:] @@ -41,10 +38,12 @@ public func valueFromASTUntyped( case let value as BooleanValue: return .bool(value.value) case let value as ListValue: - let array = try value.values.map { try valueFromASTUntyped( - valueAST: $0, - variables: variables - ) } + let array = try value.values.map { + try valueFromASTUntyped( + valueAST: $0, + variables: variables + ) + } return .array(array) case let value as ObjectValue: var dictionary = OrderedDictionary() diff --git a/Sources/GraphQL/Validation/Rules/Custom/NoDeprecatedCustomRule.swift b/Sources/GraphQL/Validation/Rules/Custom/NoDeprecatedCustomRule.swift index 5dfc4f54..95b9f0bc 100644 --- a/Sources/GraphQL/Validation/Rules/Custom/NoDeprecatedCustomRule.swift +++ b/Sources/GraphQL/Validation/Rules/Custom/NoDeprecatedCustomRule.swift @@ -1,28 +1,25 @@ - -/** - * No deprecated - * - * A GraphQL document is only valid if all selected fields and all used enum values have not been - * deprecated. - * - * Note: This rule is optional and is not part of the Validation section of the GraphQL - * Specification. The main purpose of this rule is detection of deprecated usages and not - * necessarily to forbid their use when querying a service. - */ +/// No deprecated +/// +/// A GraphQL document is only valid if all selected fields and all used enum values have not been +/// deprecated. +/// +/// Note: This rule is optional and is not part of the Validation section of the GraphQL +/// Specification. The main purpose of this rule is detection of deprecated usages and not +/// necessarily to forbid their use when querying a service. public func NoDeprecatedCustomRule(context: ValidationContext) -> Visitor { return Visitor( enter: { node, _, _, _, _ in switch node.kind { case .field: let node = node as! Field - if - let fieldDef = context.fieldDef, + if let fieldDef = context.fieldDef, let deprecationReason = fieldDef.deprecationReason, let parentType = context.parentType { context.report( error: GraphQLError( - message: "The field \(parentType.name).\(fieldDef.name) is deprecated. \(deprecationReason)", + message: + "The field \(parentType.name).\(fieldDef.name) is deprecated. \(deprecationReason)", nodes: [node] ) ) @@ -30,24 +27,24 @@ public func NoDeprecatedCustomRule(context: ValidationContext) -> Visitor { return .continue case .argument: let node = node as! Argument - if - let argDef = context.argument, + if let argDef = context.argument, let deprecationReason = argDef.deprecationReason { if let directiveDef = context.typeInfo.directive { context.report( error: GraphQLError( - message: "Directive \"@\(directiveDef.name)\" argument \"\(argDef.name)\" is deprecated. \(deprecationReason)", + message: + "Directive \"@\(directiveDef.name)\" argument \"\(argDef.name)\" is deprecated. \(deprecationReason)", nodes: [node] ) ) - } else if - let fieldDef = context.fieldDef, + } else if let fieldDef = context.fieldDef, let parentType = context.parentType { context.report( error: GraphQLError( - message: "Field \"\(parentType.name).\(fieldDef.name)\" argument \"\(argDef.name)\" is deprecated. \(deprecationReason)", + message: + "Field \"\(parentType.name).\(fieldDef.name)\" argument \"\(argDef.name)\" is deprecated. \(deprecationReason)", nodes: [node] ) ) @@ -56,14 +53,14 @@ public func NoDeprecatedCustomRule(context: ValidationContext) -> Visitor { return .continue case .objectField: let node = node as! ObjectField - if - let inputObjectDef = context.parentInputType as? GraphQLInputObjectType, + if let inputObjectDef = context.parentInputType as? GraphQLInputObjectType, let inputFieldDef = try? inputObjectDef.getFields()[node.name.value], let deprecationReason = inputFieldDef.deprecationReason { context.report( error: GraphQLError( - message: "The input field \(inputObjectDef.name).\(inputFieldDef.name) is deprecated. \(deprecationReason)", + message: + "The input field \(inputObjectDef.name).\(inputFieldDef.name) is deprecated. \(deprecationReason)", nodes: [node] ) ) @@ -71,14 +68,14 @@ public func NoDeprecatedCustomRule(context: ValidationContext) -> Visitor { return .continue case .enumValue: let node = node as! EnumValue - if - let enumValueDef = context.typeInfo.enumValue, + if let enumValueDef = context.typeInfo.enumValue, let deprecationReason = enumValueDef.deprecationReason, let enumTypeDef = getNamedType(type: context.inputType) { context.report( error: GraphQLError( - message: "The enum value \"\(enumTypeDef.name).\(enumValueDef.name)\" is deprecated. \(deprecationReason)", + message: + "The enum value \"\(enumTypeDef.name).\(enumValueDef.name)\" is deprecated. \(deprecationReason)", nodes: [node] ) ) diff --git a/Sources/GraphQL/Validation/Rules/Custom/NoSchemaIntrospectionCustomRule.swift b/Sources/GraphQL/Validation/Rules/Custom/NoSchemaIntrospectionCustomRule.swift index df72d617..c5b38bc3 100644 --- a/Sources/GraphQL/Validation/Rules/Custom/NoSchemaIntrospectionCustomRule.swift +++ b/Sources/GraphQL/Validation/Rules/Custom/NoSchemaIntrospectionCustomRule.swift @@ -1,27 +1,24 @@ - -/** - * Prohibit introspection queries - * - * A GraphQL document is only valid if all fields selected are not fields that - * return an introspection type. - * - * Note: This rule is optional and is not part of the Validation section of the - * GraphQL Specification. This rule effectively disables introspection, which - * does not reflect best practices and should only be done if absolutely necessary. - */ +/// Prohibit introspection queries +/// +/// A GraphQL document is only valid if all fields selected are not fields that +/// return an introspection type. +/// +/// Note: This rule is optional and is not part of the Validation section of the +/// GraphQL Specification. This rule effectively disables introspection, which +/// does not reflect best practices and should only be done if absolutely necessary. public func NoSchemaIntrospectionCustomRule(context: ValidationContext) -> Visitor { return Visitor( enter: { node, _, _, _, _ in switch node.kind { case .field: let node = node as! Field - if - let type = getNamedType(type: context.type), + if let type = getNamedType(type: context.type), isIntrospectionType(type: type) { context.report( error: GraphQLError( - message: "GraphQL introspection has been disabled, but the requested query contained the field \(node.name.value)", + message: + "GraphQL introspection has been disabled, but the requested query contained the field \(node.name.value)", nodes: [node] ) ) diff --git a/Sources/GraphQL/Validation/Rules/ExecutableDefinitionsRule.swift b/Sources/GraphQL/Validation/Rules/ExecutableDefinitionsRule.swift index 2d4101f0..9b17567b 100644 --- a/Sources/GraphQL/Validation/Rules/ExecutableDefinitionsRule.swift +++ b/Sources/GraphQL/Validation/Rules/ExecutableDefinitionsRule.swift @@ -1,12 +1,9 @@ - -/** - * Executable definitions - * - * A GraphQL document is only valid for execution if all definitions are either - * operation or fragment definitions. - * - * See https://spec.graphql.org/draft/#sec-Executable-Definitions - */ +/// Executable definitions +/// +/// A GraphQL document is only valid for execution if all definitions are either +/// operation or fragment definitions. +/// +/// See https://spec.graphql.org/draft/#sec-Executable-Definitions func ExecutableDefinitionsRule(context: ValidationContext) -> Visitor { let definitions = context.ast.definitions let existingTypesMap = context.schema.typeMap @@ -16,10 +13,9 @@ func ExecutableDefinitionsRule(context: ValidationContext) -> Visitor { typeNames.insert(typeName) } for definition in definitions { - if - let type = definition as? TypeDefinition, + if let type = definition as? TypeDefinition, let nameResult = type.get(key: "name"), - case let .node(nameNode) = nameResult, + case .node(let nameNode) = nameResult, let name = nameNode as? Name { typeNames.insert(name.value) @@ -56,6 +52,7 @@ func ExecutableDefinitionsRule(context: ValidationContext) -> Visitor { } func isExecutable(_ definition: Definition) -> Bool { - definition.kind == .operationDefinition || definition - .kind == .fragmentDefinition + definition.kind == .operationDefinition + || definition + .kind == .fragmentDefinition } diff --git a/Sources/GraphQL/Validation/Rules/FieldsOnCorrectTypeRule.swift b/Sources/GraphQL/Validation/Rules/FieldsOnCorrectTypeRule.swift index 8567bac6..882fe66f 100644 --- a/Sources/GraphQL/Validation/Rules/FieldsOnCorrectTypeRule.swift +++ b/Sources/GraphQL/Validation/Rules/FieldsOnCorrectTypeRule.swift @@ -15,12 +15,10 @@ func undefinedFieldMessage( return message } -/** - * Fields on correct type - * - * A GraphQL document is only valid if all fields selected are defined by the - * parent type, or are an allowed meta field such as __typename. - */ +/// Fields on correct type +/// +/// A GraphQL document is only valid if all fields selected are defined by the +/// parent type, or are an allowed meta field such as __typename. func FieldsOnCorrectTypeRule(context: ValidationContext) -> Visitor { return Visitor( enter: { node, _, _, _, _ in @@ -35,30 +33,36 @@ func FieldsOnCorrectTypeRule(context: ValidationContext) -> Visitor { let fieldName = node.name.value // First determine if there are any suggested types to condition on. - let suggestedTypeNames = (try? getSuggestedTypeNames( - schema: schema, - type: type, - fieldName: fieldName - )) ?? [] + let suggestedTypeNames = + (try? getSuggestedTypeNames( + schema: schema, + type: type, + fieldName: fieldName + )) ?? [] // If there are no suggested types, then perhaps this was a typo? - let suggestedFieldNames = !suggestedTypeNames - .isEmpty ? [] : getSuggestedFieldNames( + let suggestedFieldNames = + !suggestedTypeNames + .isEmpty + ? [] + : getSuggestedFieldNames( schema: schema, type: type, fieldName: fieldName ) // Report an error, including helpful suggestions. - context.report(error: GraphQLError( - message: undefinedFieldMessage( - fieldName: fieldName, - type: type.name, - suggestedTypeNames: suggestedTypeNames, - suggestedFieldNames: suggestedFieldNames - ), - nodes: [node] - )) + context.report( + error: GraphQLError( + message: undefinedFieldMessage( + fieldName: fieldName, + type: type.name, + suggestedTypeNames: suggestedTypeNames, + suggestedFieldNames: suggestedFieldNames + ), + nodes: [node] + ) + ) } } return .continue @@ -69,12 +73,10 @@ func FieldsOnCorrectTypeRule(context: ValidationContext) -> Visitor { ) } -/** - * Go through all of the implementations of type, as well as the interfaces - * that they implement. If any of those types include the provided field, - * suggest them, sorted by how often the type is referenced, starting - * with Interfaces. - */ +/// Go through all of the implementations of type, as well as the interfaces +/// that they implement. If any of those types include the provided field, +/// suggest them, sorted by how often the type is referenced, starting +/// with Interfaces. func getSuggestedTypeNames( schema: GraphQLSchema, type: GraphQLOutputType, @@ -116,10 +118,8 @@ func getSuggestedTypeNames( return [] } -/** - * For the field name provided, determine if there are any similar field names - * that may be the result of a typo. - */ +/// For the field name provided, determine if there are any similar field names +/// that may be the result of a typo. func getSuggestedFieldNames( schema _: GraphQLSchema, type: GraphQLOutputType, diff --git a/Sources/GraphQL/Validation/Rules/FragmentsOnCompositeTypesRule.swift b/Sources/GraphQL/Validation/Rules/FragmentsOnCompositeTypesRule.swift index 359f9161..810f3911 100644 --- a/Sources/GraphQL/Validation/Rules/FragmentsOnCompositeTypesRule.swift +++ b/Sources/GraphQL/Validation/Rules/FragmentsOnCompositeTypesRule.swift @@ -1,13 +1,10 @@ - -/** - * Fragments on composite type - * - * Fragments use a type condition to determine if they apply, since fragments - * can only be spread into a composite type (object, interface, or union), the - * type condition must also be a composite type. - * - * See https://spec.graphql.org/draft/#sec-Fragments-On-Composite-Types - */ +/// Fragments on composite type +/// +/// Fragments use a type condition to determine if they apply, since fragments +/// can only be spread into a composite type (object, interface, or union), the +/// type condition must also be a composite type. +/// +/// See https://spec.graphql.org/draft/#sec-Fragments-On-Composite-Types func FragmentsOnCompositeTypesRule(context: ValidationContext) -> Visitor { return Visitor( enter: { node, _, _, _, _ in @@ -23,7 +20,7 @@ func FragmentsOnCompositeTypesRule(context: ValidationContext) -> Visitor { context.report( error: GraphQLError( message: - "Fragment cannot condition on non composite type \"\(typeStr)\".", + "Fragment cannot condition on non composite type \"\(typeStr)\".", nodes: [typeCondition] ) ) @@ -41,7 +38,7 @@ func FragmentsOnCompositeTypesRule(context: ValidationContext) -> Visitor { context.report( error: GraphQLError( message: - "Fragment \"\(fragment.name.value)\" cannot condition on non composite type \"\(typeStr)\".", + "Fragment \"\(fragment.name.value)\" cannot condition on non composite type \"\(typeStr)\".", nodes: [typeCondition] ) ) diff --git a/Sources/GraphQL/Validation/Rules/KnownArgumentNamesOnDirectivesRule.swift b/Sources/GraphQL/Validation/Rules/KnownArgumentNamesOnDirectivesRule.swift index 81ccb36f..02db757b 100644 --- a/Sources/GraphQL/Validation/Rules/KnownArgumentNamesOnDirectivesRule.swift +++ b/Sources/GraphQL/Validation/Rules/KnownArgumentNamesOnDirectivesRule.swift @@ -33,8 +33,9 @@ func KnownArgumentNamesOnDirectivesRule( let suggestions = suggestionList(input: argName, options: knownArgs) context.report( error: GraphQLError( - message: "Unknown argument \"\(argName)\" on directive \"@\(directiveName)\"." + - didYouMean(suggestions: suggestions), + message: + "Unknown argument \"\(argName)\" on directive \"@\(directiveName)\"." + + didYouMean(suggestions: suggestions), nodes: [argNode] ) ) diff --git a/Sources/GraphQL/Validation/Rules/KnownArgumentNamesRule.swift b/Sources/GraphQL/Validation/Rules/KnownArgumentNamesRule.swift index f390287e..4309105b 100644 --- a/Sources/GraphQL/Validation/Rules/KnownArgumentNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/KnownArgumentNamesRule.swift @@ -19,8 +19,7 @@ func undefinedArgumentMessage( func KnownArgumentNamesRule(context: ValidationContext) -> Visitor { return Visitor( enter: { node, _, _, _, _ in - if - let node = node as? Argument, context.argument == nil, let field = context.fieldDef, + if let node = node as? Argument, context.argument == nil, let field = context.fieldDef, let type = context.parentType { let argumentName = node.name.value @@ -30,15 +29,17 @@ func KnownArgumentNamesRule(context: ValidationContext) -> Visitor { argumentName: argumentName ) - context.report(error: GraphQLError( - message: undefinedArgumentMessage( - fieldName: field.name, - type: type.name, - argumentName: argumentName, - suggestedArgumentNames: suggestedArgumentNames - ), - nodes: [node] - )) + context.report( + error: GraphQLError( + message: undefinedArgumentMessage( + fieldName: field.name, + type: type.name, + argumentName: argumentName, + suggestedArgumentNames: suggestedArgumentNames + ), + nodes: [node] + ) + ) } return .continue diff --git a/Sources/GraphQL/Validation/Rules/KnownDirectivesRule.swift b/Sources/GraphQL/Validation/Rules/KnownDirectivesRule.swift index 8240fb1d..9c3c5a51 100644 --- a/Sources/GraphQL/Validation/Rules/KnownDirectivesRule.swift +++ b/Sources/GraphQL/Validation/Rules/KnownDirectivesRule.swift @@ -1,12 +1,9 @@ - -/** - * Known directives - * - * A GraphQL document is only valid if all `@directives` are known by the - * schema and legally positioned. - * - * See https://spec.graphql.org/draft/#sec-Directives-Are-Defined - */ +/// Known directives +/// +/// A GraphQL document is only valid if all `@directives` are known by the +/// schema and legally positioned. +/// +/// See https://spec.graphql.org/draft/#sec-Directives-Are-Defined func KnownDirectivesRule(context: SDLorNormalValidationContext) -> Visitor { var locationsMap = [String: [String]]() @@ -47,7 +44,8 @@ func KnownDirectivesRule(context: SDLorNormalValidationContext) -> Visitor { context.report( error: GraphQLError( - message: "Directive \"@\(name)\" may not be used on \(candidateLocation.rawValue).", + message: + "Directive \"@\(name)\" may not be used on \(candidateLocation.rawValue).", nodes: [node] ) ) @@ -58,7 +56,7 @@ func KnownDirectivesRule(context: SDLorNormalValidationContext) -> Visitor { } func getDirectiveLocationForASTPath(_ ancestors: [NodeResult]) -> DirectiveLocation? { - guard let last = ancestors.last, case let .node(appliedTo) = last else { + guard let last = ancestors.last, case .node(let appliedTo) = last else { return nil } @@ -98,7 +96,7 @@ func getDirectiveLocationForASTPath(_ ancestors: [NodeResult]) -> DirectiveLocat return nil } let parentNode = ancestors[ancestors.count - 3] - guard case let .node(parentNode) = parentNode else { + guard case .node(let parentNode) = parentNode else { return nil } return parentNode.kind == .inputObjectTypeDefinition diff --git a/Sources/GraphQL/Validation/Rules/KnownFragmentNamesRule.swift b/Sources/GraphQL/Validation/Rules/KnownFragmentNamesRule.swift index 6821b9f1..7a08cd24 100644 --- a/Sources/GraphQL/Validation/Rules/KnownFragmentNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/KnownFragmentNamesRule.swift @@ -1,13 +1,11 @@ import Foundation -/** - * Known fragment names - * - * A GraphQL document is only valid if all `...Fragment` fragment spreads refer - * to fragments defined in the same document. - * - * See https://spec.graphql.org/draft/#sec-Fragment-spread-target-defined - */ +/// Known fragment names +/// +/// A GraphQL document is only valid if all `...Fragment` fragment spreads refer +/// to fragments defined in the same document. +/// +/// See https://spec.graphql.org/draft/#sec-Fragment-spread-target-defined func KnownFragmentNamesRule(context: ValidationContext) -> Visitor { return Visitor( enter: { node, _, _, _, _ in @@ -18,10 +16,12 @@ func KnownFragmentNamesRule(context: ValidationContext) -> Visitor { let fragmentDefinition = context.getFragment(name: fragmentName) if fragmentDefinition == nil { - context.report(error: GraphQLError( - message: "Unknown fragment \"\(fragmentName)\".", - nodes: [fragmentReference.name] - )) + context.report( + error: GraphQLError( + message: "Unknown fragment \"\(fragmentName)\".", + nodes: [fragmentReference.name] + ) + ) } return .continue default: diff --git a/Sources/GraphQL/Validation/Rules/KnownTypeNamesRule.swift b/Sources/GraphQL/Validation/Rules/KnownTypeNamesRule.swift index c8b276d8..82be8a84 100644 --- a/Sources/GraphQL/Validation/Rules/KnownTypeNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/KnownTypeNamesRule.swift @@ -1,12 +1,9 @@ - -/** - * Known type names - * - * A GraphQL document is only valid if referenced types (specifically - * variable definitions and fragment conditions) are defined by the type schema. - * - * See https://spec.graphql.org/draft/#sec-Fragment-Spread-Type-Existence - */ +/// Known type names +/// +/// A GraphQL document is only valid if referenced types (specifically +/// variable definitions and fragment conditions) are defined by the type schema. +/// +/// See https://spec.graphql.org/draft/#sec-Fragment-Spread-Type-Existence func KnownTypeNamesRule(context: SDLorNormalValidationContext) -> Visitor { let definitions = context.ast.definitions let existingTypesMap = context.getSchema()?.typeMap ?? [:] @@ -16,10 +13,9 @@ func KnownTypeNamesRule(context: SDLorNormalValidationContext) -> Visitor { typeNames.insert(typeName) } for definition in definitions { - if - isTypeSystemDefinitionNode(definition), + if isTypeSystemDefinitionNode(definition), let nameResult = definition.get(key: "name"), - case let .node(nameNode) = nameResult, + case .node(let nameNode) = nameResult, let name = nameNode as? Name { typeNames.insert(name.value) @@ -35,7 +31,7 @@ func KnownTypeNamesRule(context: SDLorNormalValidationContext) -> Visitor { if !typeNames.contains(typeName) { let definitionNode = ancestors.count > 2 ? ancestors[2] : parent var isSDL = false - if let definitionNode = definitionNode, case let .node(node) = definitionNode { + if let definitionNode = definitionNode, case .node(let node) = definitionNode { isSDL = isSDLNode(node) } if isSDL, standardTypeNames.contains(typeName) { @@ -48,8 +44,8 @@ func KnownTypeNamesRule(context: SDLorNormalValidationContext) -> Visitor { ) context.report( error: GraphQLError( - message: "Unknown type \"\(typeName)\"." + - didYouMean(suggestions: suggestedTypes), + message: "Unknown type \"\(typeName)\"." + + didYouMean(suggestions: suggestedTypes), nodes: [node] ) ) diff --git a/Sources/GraphQL/Validation/Rules/LoneAnonymousOperationRule.swift b/Sources/GraphQL/Validation/Rules/LoneAnonymousOperationRule.swift index a2588a87..8817eaf1 100644 --- a/Sources/GraphQL/Validation/Rules/LoneAnonymousOperationRule.swift +++ b/Sources/GraphQL/Validation/Rules/LoneAnonymousOperationRule.swift @@ -1,12 +1,9 @@ - -/** - * Lone anonymous operation - * - * A GraphQL document is only valid if when it contains an anonymous operation - * (the query short-hand) that it contains only that one operation definition. - * - * See https://spec.graphql.org/draft/#sec-Lone-Anonymous-Operation - */ +/// Lone anonymous operation +/// +/// A GraphQL document is only valid if when it contains an anonymous operation +/// (the query short-hand) that it contains only that one operation definition. +/// +/// See https://spec.graphql.org/draft/#sec-Lone-Anonymous-Operation func LoneAnonymousOperationRule(context: ValidationContext) -> Visitor { var operationCount = 0 return Visitor( diff --git a/Sources/GraphQL/Validation/Rules/LoneSchemaDefinitionRule.swift b/Sources/GraphQL/Validation/Rules/LoneSchemaDefinitionRule.swift index f922ea0d..18156a4d 100644 --- a/Sources/GraphQL/Validation/Rules/LoneSchemaDefinitionRule.swift +++ b/Sources/GraphQL/Validation/Rules/LoneSchemaDefinitionRule.swift @@ -1,16 +1,11 @@ - -/** - * Lone Schema definition - * - * A GraphQL document is only valid if it contains only one schema definition. - */ +/// Lone Schema definition +/// +/// A GraphQL document is only valid if it contains only one schema definition. func LoneSchemaDefinitionRule(context: SDLValidationContext) -> Visitor { let oldSchema = context.getSchema() let alreadyDefined = - oldSchema?.astNode != nil || - oldSchema?.queryType != nil || - oldSchema?.mutationType != nil || - oldSchema?.subscriptionType != nil + oldSchema?.astNode != nil || oldSchema?.queryType != nil || oldSchema?.mutationType != nil + || oldSchema?.subscriptionType != nil var schemaDefinitionsCount = 0 return Visitor( diff --git a/Sources/GraphQL/Validation/Rules/NoFragmentCyclesRule.swift b/Sources/GraphQL/Validation/Rules/NoFragmentCyclesRule.swift index 8d883051..04c2c4d4 100644 --- a/Sources/GraphQL/Validation/Rules/NoFragmentCyclesRule.swift +++ b/Sources/GraphQL/Validation/Rules/NoFragmentCyclesRule.swift @@ -1,12 +1,9 @@ - -/** - * No fragment cycles - * - * The graph of fragment spreads must not form any cycles including spreading itself. - * Otherwise an operation could infinitely spread or infinitely execute on cycles in the underlying data. - * - * See https://spec.graphql.org/draft/#sec-Fragment-spreads-must-not-form-cycles - */ +/// No fragment cycles +/// +/// The graph of fragment spreads must not form any cycles including spreading itself. +/// Otherwise an operation could infinitely spread or infinitely execute on cycles in the underlying data. +/// +/// See https://spec.graphql.org/draft/#sec-Fragment-spreads-must-not-form-cycles func NoFragmentCyclesRule(context: ValidationContext) -> Visitor { // Tracks already visited fragments to maintain O(N) and to ensure that cycles // are not redundantly reported. @@ -42,14 +39,14 @@ func NoFragmentCyclesRule(context: ValidationContext) -> Visitor { spreadPath.append(spreadNode) if let cycleIndex = cycleIndex { - let cyclePath = Array(spreadPath[cycleIndex ..< spreadPath.count]) - let viaPath = cyclePath[0 ..< max(cyclePath.count - 1, 0)] + let cyclePath = Array(spreadPath[cycleIndex.. Visitor { return Visitor( enter: { node, _, _, _, _ in diff --git a/Sources/GraphQL/Validation/Rules/NoUnusedFragmentsRule.swift b/Sources/GraphQL/Validation/Rules/NoUnusedFragmentsRule.swift index 7680396f..31bbec09 100644 --- a/Sources/GraphQL/Validation/Rules/NoUnusedFragmentsRule.swift +++ b/Sources/GraphQL/Validation/Rules/NoUnusedFragmentsRule.swift @@ -1,12 +1,9 @@ - -/** - * No unused fragments - * - * A GraphQL document is only valid if all fragment definitions are spread - * within operations, or spread within other fragments spread within operations. - * - * See https://spec.graphql.org/draft/#sec-Fragments-Must-Be-Used - */ +/// No unused fragments +/// +/// A GraphQL document is only valid if all fragment definitions are spread +/// within operations, or spread within other fragments spread within operations. +/// +/// See https://spec.graphql.org/draft/#sec-Fragments-Must-Be-Used func NoUnusedFragmentsRule(context: ValidationContext) -> Visitor { var fragmentNameUsed = Set() var fragmentDefs = [FragmentDefinition]() diff --git a/Sources/GraphQL/Validation/Rules/NoUnusedVariablesRule.swift b/Sources/GraphQL/Validation/Rules/NoUnusedVariablesRule.swift index 44cf2992..9541a16e 100644 --- a/Sources/GraphQL/Validation/Rules/NoUnusedVariablesRule.swift +++ b/Sources/GraphQL/Validation/Rules/NoUnusedVariablesRule.swift @@ -1,9 +1,7 @@ -/** - * No unused variables - * - * A GraphQL operation is only valid if all variables defined by an operation - * are used, either directly or within a spread fragment. - */ +/// No unused variables +/// +/// A GraphQL operation is only valid if all variables defined by an operation +/// are used, either directly or within a spread fragment. func NoUnusedVariablesRule(context: ValidationContext) -> Visitor { return Visitor( enter: { _, _, _, _, _ in @@ -15,9 +13,11 @@ func NoUnusedVariablesRule(context: ValidationContext) -> Visitor { } let usages = context.getRecursiveVariableUsages(operation: operation) - let variableNameUsed = Set(usages.map { usage in - usage.node.name.value - }) + let variableNameUsed = Set( + usages.map { usage in + usage.node.name.value + } + ) for variableDef in operation.variableDefinitions { let variableName = variableDef.variable.name.value diff --git a/Sources/GraphQL/Validation/Rules/PossibleFragmentSpreadsRule.swift b/Sources/GraphQL/Validation/Rules/PossibleFragmentSpreadsRule.swift index 4d3de756..b4d99a96 100644 --- a/Sources/GraphQL/Validation/Rules/PossibleFragmentSpreadsRule.swift +++ b/Sources/GraphQL/Validation/Rules/PossibleFragmentSpreadsRule.swift @@ -1,10 +1,8 @@ -/** - * Possible fragment spread - * - * A fragment spread is only valid if the type condition could ever possibly - * be true: if there is a non-empty intersection of the possible parent types, - * and possible types which pass the type condition. - */ +/// Possible fragment spread +/// +/// A fragment spread is only valid if the type condition could ever possibly +/// be true: if there is a non-empty intersection of the possible parent types, +/// and possible types which pass the type condition. func PossibleFragmentSpreadsRule(context: ValidationContext) -> Visitor { return Visitor( enter: { node, _, _, _, _ in @@ -30,7 +28,8 @@ func PossibleFragmentSpreadsRule(context: ValidationContext) -> Visitor { context.report( error: GraphQLError( - message: "Fragment cannot be spread here as objects of type \"\(parentType)\" can never be of type \"\(fragType)\".", + message: + "Fragment cannot be spread here as objects of type \"\(parentType)\" can never be of type \"\(fragType)\".", nodes: [node] ) ) @@ -58,7 +57,8 @@ func PossibleFragmentSpreadsRule(context: ValidationContext) -> Visitor { context.report( error: GraphQLError( - message: "Fragment \"\(fragName)\" cannot be spread here as objects of type \"\(parentType)\" can never be of type \"\(fragType)\".", + message: + "Fragment \"\(fragName)\" cannot be spread here as objects of type \"\(parentType)\" can never be of type \"\(fragType)\".", nodes: [node] ) ) diff --git a/Sources/GraphQL/Validation/Rules/PossibleTypeExtensionsRule.swift b/Sources/GraphQL/Validation/Rules/PossibleTypeExtensionsRule.swift index 055e4373..0f828d95 100644 --- a/Sources/GraphQL/Validation/Rules/PossibleTypeExtensionsRule.swift +++ b/Sources/GraphQL/Validation/Rules/PossibleTypeExtensionsRule.swift @@ -1,9 +1,6 @@ - -/** - * Possible type extension - * - * A type extension is only valid if the type is defined and has the same kind. - */ +/// Possible type extension +/// +/// A type extension is only valid if the type is defined and has the same kind. func PossibleTypeExtensionsRule( context: SDLValidationContext ) -> Visitor { @@ -82,11 +79,13 @@ func PossibleTypeExtensionsRule( context.report( error: GraphQLError( - message: "Cannot extend type \"\(typeName)\" because it is not defined." + - didYouMean(suggestions: suggestionList( - input: typeName, - options: allTypeNames - )), + message: "Cannot extend type \"\(typeName)\" because it is not defined." + + didYouMean( + suggestions: suggestionList( + input: typeName, + options: allTypeNames + ) + ), nodes: [node.name] ) ) diff --git a/Sources/GraphQL/Validation/Rules/ProvidedRequiredArgumentsOnDirectivesRule.swift b/Sources/GraphQL/Validation/Rules/ProvidedRequiredArgumentsOnDirectivesRule.swift index b9319a91..bda4f541 100644 --- a/Sources/GraphQL/Validation/Rules/ProvidedRequiredArgumentsOnDirectivesRule.swift +++ b/Sources/GraphQL/Validation/Rules/ProvidedRequiredArgumentsOnDirectivesRule.swift @@ -1,4 +1,3 @@ - func ProvidedRequiredArgumentsOnDirectivesRule( context: SDLorNormalValidationContext ) -> Visitor { @@ -40,7 +39,8 @@ func ProvidedRequiredArgumentsOnDirectivesRule( if !argNodeMap.contains(argName) { context.report( error: GraphQLError( - message: "Argument \"@\(directiveName)(\(argName):)\" of type \"\(argType)\" is required, but it was not provided.", + message: + "Argument \"@\(directiveName)(\(argName):)\" of type \"\(argType)\" is required, but it was not provided.", nodes: [directiveNode] ) ) diff --git a/Sources/GraphQL/Validation/Rules/ProvidedRequiredArgumentsRule.swift b/Sources/GraphQL/Validation/Rules/ProvidedRequiredArgumentsRule.swift index 296b867e..d4fe4098 100644 --- a/Sources/GraphQL/Validation/Rules/ProvidedRequiredArgumentsRule.swift +++ b/Sources/GraphQL/Validation/Rules/ProvidedRequiredArgumentsRule.swift @@ -1,11 +1,9 @@ import Foundation -/** - * Provided required arguments - * - * A field or directive is only valid if all required (non-null without a - * default value) field arguments have been provided. - */ +/// Provided required arguments +/// +/// A field or directive is only valid if all required (non-null without a +/// default value) field arguments have been provided. func ProvidedRequiredArgumentsRule(context: ValidationContext) -> Visitor { var requiredArgsMap = [String: [String: String]]() @@ -48,10 +46,13 @@ func ProvidedRequiredArgumentsRule(context: ValidationContext) -> Visitor { for argDef in fieldDef.args { if !providedArguments.contains(argDef.name), isRequiredArgument(argDef) { - context.report(error: GraphQLError( - message: "Field \"\(fieldDef.name)\" argument \"\(argDef.name)\" of type \"\(argDef.type)\" is required, but it was not provided.", - nodes: [fieldNode] - )) + context.report( + error: GraphQLError( + message: + "Field \"\(fieldDef.name)\" argument \"\(argDef.name)\" of type \"\(argDef.type)\" is required, but it was not provided.", + nodes: [fieldNode] + ) + ) } } return .continue @@ -64,10 +65,13 @@ func ProvidedRequiredArgumentsRule(context: ValidationContext) -> Visitor { let argNodeMap = Set(argNodes.map { $0.name.value }) for (argName, argType) in requiredArgs { if !argNodeMap.contains(argName) { - context.report(error: GraphQLError( - message: "Directive \"@\(directiveName)\" argument \"\(argName)\" of type \"\(argType)\" is required, but it was not provided.", - nodes: [directiveNode] - )) + context.report( + error: GraphQLError( + message: + "Directive \"@\(directiveName)\" argument \"\(argName)\" of type \"\(argType)\" is required, but it was not provided.", + nodes: [directiveNode] + ) + ) } } } diff --git a/Sources/GraphQL/Validation/Rules/ScalarLeafsRule.swift b/Sources/GraphQL/Validation/Rules/ScalarLeafsRule.swift index b381c4ef..ace8c5d1 100644 --- a/Sources/GraphQL/Validation/Rules/ScalarLeafsRule.swift +++ b/Sources/GraphQL/Validation/Rules/ScalarLeafsRule.swift @@ -1,19 +1,17 @@ func noSubselectionAllowedMessage(fieldName: String, type: GraphQLType) -> String { - return "Field \"\(fieldName)\" must not have a selection since " + - "type \"\(type)\" has no subfields." + return "Field \"\(fieldName)\" must not have a selection since " + + "type \"\(type)\" has no subfields." } func requiredSubselectionMessage(fieldName: String, type: GraphQLType) -> String { - return "Field \"\(fieldName)\" of type \"\(type)\" must have a " + - "selection of subfields." + didYouMean(suggestions: ["\(fieldName) { ... }"]) + return "Field \"\(fieldName)\" of type \"\(type)\" must have a " + "selection of subfields." + + didYouMean(suggestions: ["\(fieldName) { ... }"]) } -/** - * Scalar leafs - * - * A GraphQL document is valid only if all leaf fields (fields without - * sub selections) are of scalar or enum types. - */ +/// Scalar leafs +/// +/// A GraphQL document is valid only if all leaf fields (fields without +/// sub selections) are of scalar or enum types. func ScalarLeafsRule(context: ValidationContext) -> Visitor { return Visitor( enter: { node, _, _, _, _ in diff --git a/Sources/GraphQL/Validation/Rules/UniqueArgumentDefinitionNamesRule.swift b/Sources/GraphQL/Validation/Rules/UniqueArgumentDefinitionNamesRule.swift index 1f97dfaa..c9071ed0 100644 --- a/Sources/GraphQL/Validation/Rules/UniqueArgumentDefinitionNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/UniqueArgumentDefinitionNamesRule.swift @@ -1,10 +1,7 @@ - -/** - * Unique argument definition names - * - * A GraphQL Object or Interface type is only valid if all its fields have uniquely named arguments. - * A GraphQL Directive is only valid if all its arguments are uniquely named. - */ +/// Unique argument definition names +/// +/// A GraphQL Object or Interface type is only valid if all its fields have uniquely named arguments. +/// A GraphQL Directive is only valid if all its arguments are uniquely named. func UniqueArgumentDefinitionNamesRule( context: SDLValidationContext ) -> Visitor { @@ -73,7 +70,8 @@ func UniqueArgumentDefinitionNamesRule( if argNodes.count > 1 { context.report( error: GraphQLError( - message: "Argument \"\(parentName)(\(argName):)\" can only be defined once.", + message: + "Argument \"\(parentName)(\(argName):)\" can only be defined once.", nodes: argNodes.map { node in node.name } ) ) diff --git a/Sources/GraphQL/Validation/Rules/UniqueArgumentNamesRule.swift b/Sources/GraphQL/Validation/Rules/UniqueArgumentNamesRule.swift index 3417560c..e83e1f0f 100644 --- a/Sources/GraphQL/Validation/Rules/UniqueArgumentNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/UniqueArgumentNamesRule.swift @@ -1,12 +1,9 @@ - -/** - * Unique argument names - * - * A GraphQL field or directive is only valid if all supplied arguments are - * uniquely named. - * - * See https://spec.graphql.org/draft/#sec-Argument-Names - */ +/// Unique argument names +/// +/// A GraphQL field or directive is only valid if all supplied arguments are +/// uniquely named. +/// +/// See https://spec.graphql.org/draft/#sec-Argument-Names func UniqueArgumentNamesRule(context: ASTValidationContext) -> Visitor { return Visitor( enter: { node, _, _, _, _ in diff --git a/Sources/GraphQL/Validation/Rules/UniqueDirectiveNamesRule.swift b/Sources/GraphQL/Validation/Rules/UniqueDirectiveNamesRule.swift index 5b44ee0b..f0b0d911 100644 --- a/Sources/GraphQL/Validation/Rules/UniqueDirectiveNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/UniqueDirectiveNamesRule.swift @@ -1,9 +1,6 @@ - -/** - * Unique directive names - * - * A GraphQL document is only valid if all defined directives have unique names. - */ +/// Unique directive names +/// +/// A GraphQL document is only valid if all defined directives have unique names. func UniqueDirectiveNamesRule( context: SDLValidationContext ) -> Visitor { @@ -19,7 +16,8 @@ func UniqueDirectiveNamesRule( if schema?.getDirective(name: directiveName) != nil { context.report( error: GraphQLError( - message: "Directive \"@\(directiveName)\" already exists in the schema. It cannot be redefined.", + message: + "Directive \"@\(directiveName)\" already exists in the schema. It cannot be redefined.", nodes: [node.name] ) ) diff --git a/Sources/GraphQL/Validation/Rules/UniqueDirectivesPerLocationRule.swift b/Sources/GraphQL/Validation/Rules/UniqueDirectivesPerLocationRule.swift index 8e2296f3..c20b133a 100644 --- a/Sources/GraphQL/Validation/Rules/UniqueDirectivesPerLocationRule.swift +++ b/Sources/GraphQL/Validation/Rules/UniqueDirectivesPerLocationRule.swift @@ -1,12 +1,9 @@ - -/** - * Unique directive names per location - * - * A GraphQL document is only valid if all non-repeatable directives at - * a given location are uniquely named. - * - * See https://spec.graphql.org/draft/#sec-Directives-Are-Unique-Per-Location - */ +/// Unique directive names per location +/// +/// A GraphQL document is only valid if all non-repeatable directives at +/// a given location are uniquely named. +/// +/// See https://spec.graphql.org/draft/#sec-Directives-Are-Unique-Per-Location func UniqueDirectivesPerLocationRule(context: SDLorNormalValidationContext) -> Visitor { var uniqueDirectiveMap = [String: Bool]() @@ -28,13 +25,12 @@ func UniqueDirectivesPerLocationRule(context: SDLorNormalValidationContext) -> V return Visitor( enter: { node, _, _, _, _ in -// if let operation = node as? OperationDefinition { + // if let operation = node as? OperationDefinition { // Many different AST nodes may contain directives. Rather than listing // them all, just listen for entering any node, and check to see if it // defines any directives. - if - let directiveNodeResult = node.get(key: "directives"), - case let .array(directiveNodes) = directiveNodeResult, + if let directiveNodeResult = node.get(key: "directives"), + case .array(let directiveNodes) = directiveNodeResult, let directives = directiveNodes as? [Directive] { var seenDirectives = [String: Directive]() @@ -42,8 +38,8 @@ func UniqueDirectivesPerLocationRule(context: SDLorNormalValidationContext) -> V case .schemaDefinition, .schemaExtensionDefinition: seenDirectives = schemaDirectives case .enumTypeDefinition, .unionTypeDefinition, .objectTypeDefinition, - .scalarTypeDefinition, .interfaceTypeDefinition, .operationTypeDefinition, - .inputObjectTypeDefinition: + .scalarTypeDefinition, .interfaceTypeDefinition, .operationTypeDefinition, + .inputObjectTypeDefinition: let node = node as! TypeDefinition let typeName = node.name.value seenDirectives = typeDirectivesMap[typeName] ?? [:] @@ -65,7 +61,8 @@ func UniqueDirectivesPerLocationRule(context: SDLorNormalValidationContext) -> V if let seenDirective = seenDirectives[directiveName] { context.report( error: GraphQLError( - message: "The directive \"@\(directiveName)\" can only be used once at this location.", + message: + "The directive \"@\(directiveName)\" can only be used once at this location.", nodes: [seenDirective, directive] ) ) diff --git a/Sources/GraphQL/Validation/Rules/UniqueEnumValueNamesRule.swift b/Sources/GraphQL/Validation/Rules/UniqueEnumValueNamesRule.swift index 2bf50b85..f0322d56 100644 --- a/Sources/GraphQL/Validation/Rules/UniqueEnumValueNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/UniqueEnumValueNamesRule.swift @@ -1,9 +1,6 @@ - -/** - * Unique enum value names - * - * A GraphQL enum type is only valid if all its values are uniquely named. - */ +/// Unique enum value names +/// +/// A GraphQL enum type is only valid if all its values are uniquely named. func UniqueEnumValueNamesRule( context: SDLValidationContext ) -> Visitor { @@ -36,13 +33,13 @@ func UniqueEnumValueNamesRule( let valueName = valueDef.name.value let existingType = existingTypeMap[typeName] - if - let existingType = existingType as? GraphQLEnumType, + if let existingType = existingType as? GraphQLEnumType, existingType.nameLookup[valueName] != nil { context.report( error: GraphQLError( - message: "Enum value \"\(typeName).\(valueName)\" already exists in the schema. It cannot also be defined in this type extension.", + message: + "Enum value \"\(typeName).\(valueName)\" already exists in the schema. It cannot also be defined in this type extension.", nodes: [valueDef.name] ) ) @@ -52,7 +49,8 @@ func UniqueEnumValueNamesRule( if let knownValueName = valueNames[valueName] { context.report( error: GraphQLError( - message: "Enum value \"\(typeName).\(valueName)\" can only be defined once.", + message: + "Enum value \"\(typeName).\(valueName)\" can only be defined once.", nodes: [knownValueName, valueDef.name] ) ) diff --git a/Sources/GraphQL/Validation/Rules/UniqueFieldDefinitionNamesRule.swift b/Sources/GraphQL/Validation/Rules/UniqueFieldDefinitionNamesRule.swift index bd39fe04..a3aa1d8f 100644 --- a/Sources/GraphQL/Validation/Rules/UniqueFieldDefinitionNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/UniqueFieldDefinitionNamesRule.swift @@ -1,9 +1,6 @@ - -/** - * Unique field definition names - * - * A GraphQL complex type is only valid if all its fields are uniquely named. - */ +/// Unique field definition names +/// +/// A GraphQL complex type is only valid if all its fields are uniquely named. func UniqueFieldDefinitionNamesRule( context: SDLValidationContext ) -> Visitor { @@ -53,13 +50,13 @@ func UniqueFieldDefinitionNamesRule( let fieldNodes = fields for fieldDef in fieldNodes { let fieldName = fieldDef.name.value - if - let existingType = existingTypeMap[typeName], + if let existingType = existingTypeMap[typeName], hasField(type: existingType, fieldName: fieldName) { context.report( error: GraphQLError( - message: "Field \"\(typeName).\(fieldName)\" already exists in the schema. It cannot also be defined in this type extension.", + message: + "Field \"\(typeName).\(fieldName)\" already exists in the schema. It cannot also be defined in this type extension.", nodes: [fieldDef.name] ) ) @@ -88,13 +85,13 @@ func UniqueFieldDefinitionNamesRule( let fieldNodes = fields for fieldDef in fieldNodes { let fieldName = fieldDef.name.value - if - let existingType = existingTypeMap[typeName], + if let existingType = existingTypeMap[typeName], hasField(type: existingType, fieldName: fieldName) { context.report( error: GraphQLError( - message: "Field \"\(typeName).\(fieldName)\" already exists in the schema. It cannot also be defined in this type extension.", + message: + "Field \"\(typeName).\(fieldName)\" already exists in the schema. It cannot also be defined in this type extension.", nodes: [fieldDef.name] ) ) diff --git a/Sources/GraphQL/Validation/Rules/UniqueFragmentNamesRule.swift b/Sources/GraphQL/Validation/Rules/UniqueFragmentNamesRule.swift index ef6810ec..b98d7fca 100644 --- a/Sources/GraphQL/Validation/Rules/UniqueFragmentNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/UniqueFragmentNamesRule.swift @@ -1,11 +1,8 @@ - -/** - * Unique fragment names - * - * A GraphQL document is only valid if all defined fragments have unique names. - * - * See https://spec.graphql.org/draft/#sec-Fragment-Name-Uniqueness - */ +/// Unique fragment names +/// +/// A GraphQL document is only valid if all defined fragments have unique names. +/// +/// See https://spec.graphql.org/draft/#sec-Fragment-Name-Uniqueness func UniqueFragmentNamesRule(context: ValidationContext) -> Visitor { var knownFragmentNames = [String: Name]() return Visitor( @@ -17,7 +14,8 @@ func UniqueFragmentNamesRule(context: ValidationContext) -> Visitor { if let knownFragmentName = knownFragmentNames[fragmentName.value] { context.report( error: GraphQLError( - message: "There can be only one fragment named \"\(fragmentName.value)\".", + message: + "There can be only one fragment named \"\(fragmentName.value)\".", nodes: [knownFragmentName, fragmentName] ) ) diff --git a/Sources/GraphQL/Validation/Rules/UniqueInputFieldNamesRule.swift b/Sources/GraphQL/Validation/Rules/UniqueInputFieldNamesRule.swift index 076a8915..b0d2a367 100644 --- a/Sources/GraphQL/Validation/Rules/UniqueInputFieldNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/UniqueInputFieldNamesRule.swift @@ -1,12 +1,9 @@ - -/** - * Unique input field names - * - * A GraphQL input object value is only valid if all supplied fields are - * uniquely named. - * - * See https://spec.graphql.org/draft/#sec-Input-Object-Field-Uniqueness - */ +/// Unique input field names +/// +/// A GraphQL input object value is only valid if all supplied fields are +/// uniquely named. +/// +/// See https://spec.graphql.org/draft/#sec-Input-Object-Field-Uniqueness func UniqueInputFieldNamesRule(context: ASTValidationContext) -> Visitor { var knownNameStack = [[String: Name]]() var knownNames = [String: Name]() diff --git a/Sources/GraphQL/Validation/Rules/UniqueOperationNamesRule.swift b/Sources/GraphQL/Validation/Rules/UniqueOperationNamesRule.swift index 2ff7f786..63dc7936 100644 --- a/Sources/GraphQL/Validation/Rules/UniqueOperationNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/UniqueOperationNamesRule.swift @@ -1,11 +1,8 @@ - -/** - * Unique operation names - * - * A GraphQL document is only valid if all defined operations have unique names. - * - * See https://spec.graphql.org/draft/#sec-Operation-Name-Uniqueness - */ +/// Unique operation names +/// +/// A GraphQL document is only valid if all defined operations have unique names. +/// +/// See https://spec.graphql.org/draft/#sec-Operation-Name-Uniqueness func UniqueOperationNamesRule(context: ValidationContext) -> Visitor { var knownOperationNames = [String: Name]() return Visitor( @@ -17,7 +14,8 @@ func UniqueOperationNamesRule(context: ValidationContext) -> Visitor { if let knownOperationName = knownOperationNames[operationName.value] { context.report( error: GraphQLError( - message: "There can be only one operation named \"\(operationName.value)\".", + message: + "There can be only one operation named \"\(operationName.value)\".", nodes: [knownOperationName, operationName] ) ) diff --git a/Sources/GraphQL/Validation/Rules/UniqueOperationTypesRule.swift b/Sources/GraphQL/Validation/Rules/UniqueOperationTypesRule.swift index c438cae5..1c0e13a6 100644 --- a/Sources/GraphQL/Validation/Rules/UniqueOperationTypesRule.swift +++ b/Sources/GraphQL/Validation/Rules/UniqueOperationTypesRule.swift @@ -1,9 +1,6 @@ - -/** - * Unique operation types - * - * A GraphQL document is only valid if it has only one type per operation. - */ +/// Unique operation types +/// +/// A GraphQL document is only valid if it has only one type per operation. func UniqueOperationTypesRule( context: SDLValidationContext ) -> Visitor { @@ -49,7 +46,8 @@ func UniqueOperationTypesRule( if existingOperationTypes[operation] != nil { context.report( error: GraphQLError( - message: "Type for \(operation) already defined in the schema. It cannot be redefined.", + message: + "Type for \(operation) already defined in the schema. It cannot be redefined.", nodes: [operationType] ) ) diff --git a/Sources/GraphQL/Validation/Rules/UniqueTypeNamesRule.swift b/Sources/GraphQL/Validation/Rules/UniqueTypeNamesRule.swift index 427deeee..78a02691 100644 --- a/Sources/GraphQL/Validation/Rules/UniqueTypeNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/UniqueTypeNamesRule.swift @@ -1,9 +1,6 @@ - -/** - * Unique type names - * - * A GraphQL document is only valid if all defined types have unique names. - */ +/// Unique type names +/// +/// A GraphQL document is only valid if all defined types have unique names. func UniqueTypeNamesRule(context: SDLValidationContext) -> Visitor { var knownTypeNames = [String: Name]() let schema = context.getSchema() @@ -47,7 +44,8 @@ func UniqueTypeNamesRule(context: SDLValidationContext) -> Visitor { if schema?.getType(name: typeName) != nil { context.report( error: GraphQLError( - message: "Type \"\(typeName)\" already exists in the schema. It cannot also be defined in this type definition.", + message: + "Type \"\(typeName)\" already exists in the schema. It cannot also be defined in this type definition.", nodes: [node.name] ) ) diff --git a/Sources/GraphQL/Validation/Rules/UniqueVariableNamesRule.swift b/Sources/GraphQL/Validation/Rules/UniqueVariableNamesRule.swift index 5c2d5782..3bfc2716 100644 --- a/Sources/GraphQL/Validation/Rules/UniqueVariableNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/UniqueVariableNamesRule.swift @@ -1,9 +1,6 @@ - -/** - * Unique variable names - * - * A GraphQL operation is only valid if all its variables are uniquely named. - */ +/// Unique variable names +/// +/// A GraphQL operation is only valid if all its variables are uniquely named. func UniqueVariableNamesRule(context: ValidationContext) -> Visitor { return Visitor( enter: { node, _, _, _, _ in @@ -20,7 +17,8 @@ func UniqueVariableNamesRule(context: ValidationContext) -> Visitor { if variableNodes.count > 1 { context.report( error: GraphQLError( - message: "There can be only one variable named \"$\(variableName)\".", + message: + "There can be only one variable named \"$\(variableName)\".", nodes: variableNodes.map { $0.variable.name } ) ) diff --git a/Sources/GraphQL/Validation/Rules/ValuesOfCorrectTypeRule.swift b/Sources/GraphQL/Validation/Rules/ValuesOfCorrectTypeRule.swift index 494169d9..f86316c8 100644 --- a/Sources/GraphQL/Validation/Rules/ValuesOfCorrectTypeRule.swift +++ b/Sources/GraphQL/Validation/Rules/ValuesOfCorrectTypeRule.swift @@ -1,12 +1,9 @@ - -/** - * Value literals of correct type - * - * A GraphQL document is only valid if all value literals are of the type - * expected at their position. - * - * See https://spec.graphql.org/draft/#sec-Values-of-Correct-Type - */ +/// Value literals of correct type +/// +/// A GraphQL document is only valid if all value literals are of the type +/// expected at their position. +/// +/// See https://spec.graphql.org/draft/#sec-Values-of-Correct-Type func ValuesOfCorrectTypeRule(context: ValidationContext) -> Visitor { var variableDefinitions = [String: VariableDefinition]() @@ -27,7 +24,7 @@ func ValuesOfCorrectTypeRule(context: ValidationContext) -> Visitor { } guard type is GraphQLList else { isValidValueNode(context, list) - return .break // Don't traverse further. + return .break // Don't traverse further. } return .continue case .objectValue: @@ -35,7 +32,7 @@ func ValuesOfCorrectTypeRule(context: ValidationContext) -> Visitor { let type = getNamedType(type: context.inputType) guard let type = type as? GraphQLInputObjectType else { isValidValueNode(context, object) - return .break // Don't traverse further. + return .break // Don't traverse further. } // Ensure every required field exists. var fieldNodeMap = [String: ObjectField]() @@ -48,7 +45,8 @@ func ValuesOfCorrectTypeRule(context: ValidationContext) -> Visitor { let typeStr = fieldDef.type context.report( error: GraphQLError( - message: "Field \"\(type.name).\(fieldDef.name)\" of required type \"\(typeStr)\" was not provided.", + message: + "Field \"\(type.name).\(fieldDef.name)\" of required type \"\(typeStr)\" was not provided.", nodes: [object] ) ) @@ -68,8 +66,7 @@ func ValuesOfCorrectTypeRule(context: ValidationContext) -> Visitor { case .objectField: let field = node as! ObjectField let parentType = getNamedType(type: context.parentInputType) - if - context.inputType == nil, + if context.inputType == nil, let parentType = parentType as? GraphQLInputObjectType { let parentFields = (try? parentType.getFields()) ?? [:] @@ -80,8 +77,8 @@ func ValuesOfCorrectTypeRule(context: ValidationContext) -> Visitor { context.report( error: GraphQLError( message: - "Field \"\(field.name.value)\" is not defined by type \"\(parentType.name)\"." + - didYouMean(suggestions: suggestions), + "Field \"\(field.name.value)\" is not defined by type \"\(parentType.name)\"." + + didYouMean(suggestions: suggestions), nodes: [field] ) ) @@ -94,7 +91,7 @@ func ValuesOfCorrectTypeRule(context: ValidationContext) -> Visitor { context.report( error: GraphQLError( message: - "Expected value of type \"\(type)\", found \(print(ast: node)).", + "Expected value of type \"\(type)\", found \(print(ast: node)).", nodes: [null] ) ) @@ -111,10 +108,8 @@ func ValuesOfCorrectTypeRule(context: ValidationContext) -> Visitor { ) } -/** - * Any value literal may be a valid representation of a Scalar, depending on - * that scalar type. - */ +/// Any value literal may be a valid representation of a Scalar, depending on +/// that scalar type. func isValidValueNode(_ context: ValidationContext, _ node: Value) { // Report any error at the full type expected by the location. guard let locationType = context.inputType else { @@ -140,7 +135,8 @@ func isValidValueNode(_ context: ValidationContext, _ node: Value) { if try type.parseLiteral(valueAST: node) == .undefined { context.report( error: GraphQLError( - message: "Expected value of type \"\(locationType)\", found \(print(ast: node)).", + message: + "Expected value of type \"\(locationType)\", found \(print(ast: node)).", nodes: [node] ) ) @@ -150,7 +146,8 @@ func isValidValueNode(_ context: ValidationContext, _ node: Value) { if try type.parseLiteral(valueAST: node) == .undefined { context.report( error: GraphQLError( - message: "Expected value of type \"\(locationType)\", found \(print(ast: node)).", + message: + "Expected value of type \"\(locationType)\", found \(print(ast: node)).", nodes: [node] ) ) @@ -162,7 +159,8 @@ func isValidValueNode(_ context: ValidationContext, _ node: Value) { } else { context.report( error: GraphQLError( - message: "Expected value of type \"\(locationType)\", found \(print(ast: node)).", + message: + "Expected value of type \"\(locationType)\", found \(print(ast: node)).", nodes: [node] ) ) @@ -204,16 +202,16 @@ func validateOneOfInputObject( } if let value = value, value.kind == .variable { - let variable = value as! Variable // Force unwrap is safe because of variable definition + let variable = value as! Variable // Force unwrap is safe because of variable definition let variableName = variable.name.value - if - let definition = variableDefinitions[variableName], + if let definition = variableDefinitions[variableName], definition.type.kind != .nonNullType { context.report( error: GraphQLError( - message: "Variable \"\(variableName)\" must be non-nullable to be used for OneOf Input Object \"\(type.name)\".", + message: + "Variable \"\(variableName)\" must be non-nullable to be used for OneOf Input Object \"\(type.name)\".", nodes: [node] ) ) diff --git a/Sources/GraphQL/Validation/Rules/VariablesAreInputTypesRule.swift b/Sources/GraphQL/Validation/Rules/VariablesAreInputTypesRule.swift index 60f5ef7c..1f4a3366 100644 --- a/Sources/GraphQL/Validation/Rules/VariablesAreInputTypesRule.swift +++ b/Sources/GraphQL/Validation/Rules/VariablesAreInputTypesRule.swift @@ -1,12 +1,9 @@ - -/** - * Variables are input types - * - * A GraphQL operation is only valid if all the variables it defines are of - * input types (scalar, enum, or input object). - * - * See https://spec.graphql.org/draft/#sec-Variables-Are-Input-Types - */ +/// Variables are input types +/// +/// A GraphQL operation is only valid if all the variables it defines are of +/// input types (scalar, enum, or input object). +/// +/// See https://spec.graphql.org/draft/#sec-Variables-Are-Input-Types func VariablesAreInputTypesRule(context: ValidationContext) -> Visitor { return Visitor( enter: { node, _, _, _, _ in @@ -23,7 +20,8 @@ func VariablesAreInputTypesRule(context: ValidationContext) -> Visitor { let typeName = print(ast: variableType) context.report( error: GraphQLError( - message: "Variable \"$\(variableName)\" cannot be non-input type \"\(typeName)\".", + message: + "Variable \"$\(variableName)\" cannot be non-input type \"\(typeName)\".", nodes: [variableType] ) ) diff --git a/Sources/GraphQL/Validation/Rules/VariablesInAllowedPositionRule.swift b/Sources/GraphQL/Validation/Rules/VariablesInAllowedPositionRule.swift index c393430e..5efa1370 100644 --- a/Sources/GraphQL/Validation/Rules/VariablesInAllowedPositionRule.swift +++ b/Sources/GraphQL/Validation/Rules/VariablesInAllowedPositionRule.swift @@ -1,11 +1,8 @@ - -/** - * Variables in allowed position - * - * Variable usages must be compatible with the arguments they are passed to. - * - * See https://spec.graphql.org/draft/#sec-All-Variable-Usages-are-Allowed - */ +/// Variables in allowed position +/// +/// Variable usages must be compatible with the arguments they are passed to. +/// +/// See https://spec.graphql.org/draft/#sec-All-Variable-Usages-are-Allowed func VariablesInAllowedPositionRule(context: ValidationContext) -> Visitor { var varDefMap: [String: VariableDefinition] = [:] return Visitor( @@ -29,8 +26,7 @@ func VariablesInAllowedPositionRule(context: ValidationContext) -> Visitor { let varName = usage.node.name.value let schema = context.schema - if - let varDef = varDefMap[varName], + if let varDef = varDefMap[varName], let type = usage.type, let varType = typeFromAST(schema: schema, inputTypeAST: varDef.type) { @@ -39,17 +35,19 @@ func VariablesInAllowedPositionRule(context: ValidationContext) -> Visitor { // the variable type is non-null when the expected type is nullable. // If both are list types, the variable item type can be more strict // than the expected item type (contravariant). - let isAllowed = (try? allowedVariableUsage( - schema: schema, - varType: varType, - varDefaultValue: varDef.defaultValue, - locationType: type, - locationDefaultValue: usage.defaultValue - )) ?? false + let isAllowed = + (try? allowedVariableUsage( + schema: schema, + varType: varType, + varDefaultValue: varDef.defaultValue, + locationType: type, + locationDefaultValue: usage.defaultValue + )) ?? false if !isAllowed { context.report( error: GraphQLError( - message: "Variable \"$\(varName)\" of type \"\(varType)\" used in position expecting type \"\(type)\".", + message: + "Variable \"$\(varName)\" of type \"\(varType)\" used in position expecting type \"\(type)\".", nodes: [varDef, usage.node] ) ) @@ -64,11 +62,9 @@ func VariablesInAllowedPositionRule(context: ValidationContext) -> Visitor { ) } -/** - * Returns true if the variable is allowed in the location it was found, - * which includes considering if default values exist for either the variable - * or the location at which it is located. - */ +/// Returns true if the variable is allowed in the location it was found, +/// which includes considering if default values exist for either the variable +/// or the location at which it is located. func allowedVariableUsage( schema: GraphQLSchema, varType: GraphQLType, @@ -77,8 +73,10 @@ func allowedVariableUsage( locationDefaultValue: Map? ) throws -> Bool { if let locationType = locationType as? GraphQLNonNull, !(varType is GraphQLNonNull) { - let hasNonNullVariableDefaultValue = varDefaultValue != nil && varDefaultValue? - .kind != .nullValue + let hasNonNullVariableDefaultValue = + varDefaultValue != nil + && varDefaultValue? + .kind != .nullValue let hasLocationDefaultValue = locationDefaultValue != .undefined if !hasNonNullVariableDefaultValue && !hasLocationDefaultValue { return false diff --git a/Sources/GraphQL/Validation/SpecifiedRules.swift b/Sources/GraphQL/Validation/SpecifiedRules.swift index 473748e1..6a7b9d02 100644 --- a/Sources/GraphQL/Validation/SpecifiedRules.swift +++ b/Sources/GraphQL/Validation/SpecifiedRules.swift @@ -1,11 +1,9 @@ -/** - * This set includes all validation rules defined by the GraphQL spec. - */ +/// This set includes all validation rules defined by the GraphQL spec. public let specifiedRules: [@Sendable (ValidationContext) -> Visitor] = [ ExecutableDefinitionsRule, UniqueOperationNamesRule, LoneAnonymousOperationRule, -// SingleFieldSubscriptionsRule, + // SingleFieldSubscriptionsRule, KnownTypeNamesRule, FragmentsOnCompositeTypesRule, VariablesAreInputTypesRule, @@ -21,21 +19,19 @@ public let specifiedRules: [@Sendable (ValidationContext) -> Visitor] = [ NoUnusedVariablesRule, KnownDirectivesRule, UniqueDirectivesPerLocationRule, -// DeferStreamDirectiveOnRootFieldRule, -// DeferStreamDirectiveOnValidOperationsRule, -// DeferStreamDirectiveLabelRule, + // DeferStreamDirectiveOnRootFieldRule, + // DeferStreamDirectiveOnValidOperationsRule, + // DeferStreamDirectiveLabelRule, KnownArgumentNamesRule, UniqueArgumentNamesRule, ValuesOfCorrectTypeRule, ProvidedRequiredArgumentsRule, VariablesInAllowedPositionRule, -// OverlappingFieldsCanBeMergedRule, + // OverlappingFieldsCanBeMergedRule, UniqueInputFieldNamesRule, ] -/** - * @internal - */ +/// @internal public let specifiedSDLRules: [SDLValidationRule] = [ LoneSchemaDefinitionRule, UniqueOperationTypesRule, diff --git a/Sources/GraphQL/Validation/Validate.swift b/Sources/GraphQL/Validation/Validate.swift index 3d6d74fc..2073f9cd 100644 --- a/Sources/GraphQL/Validation/Validate.swift +++ b/Sources/GraphQL/Validation/Validate.swift @@ -1,16 +1,14 @@ -/** - * Implements the "Validation" section of the spec. - * - * Validation runs synchronously, returning an array of encountered errors, or - * an empty array if no errors were encountered and the document is valid. - * - * A list of specific validation rules may be provided. If not provided, the - * default list of rules defined by the GraphQL specification will be used. - * - * Each validation rules is a function which returns a visitor - * (see the language/visitor API). Visitor methods are expected to return - * GraphQLErrors, or Arrays of GraphQLErrors when invalid. - */ +/// Implements the "Validation" section of the spec. +/// +/// Validation runs synchronously, returning an array of encountered errors, or +/// an empty array if no errors were encountered and the document is valid. +/// +/// A list of specific validation rules may be provided. If not provided, the +/// default list of rules defined by the GraphQL specification will be used. +/// +/// Each validation rules is a function which returns a visitor +/// (see the language/visitor API). Visitor methods are expected to return +/// GraphQLErrors, or Arrays of GraphQLErrors when invalid. public func validate( schema: GraphQLSchema, ast: Document, @@ -21,9 +19,7 @@ public func validate( return visit(usingRules: rules, schema: schema, typeInfo: typeInfo, documentAST: ast) } -/** - * @internal - */ +/// @internal func validateSDL( documentAST: Document, schemaToExtend: GraphQLSchema? = nil, @@ -44,12 +40,10 @@ func validateSDL( return errors } -/** - * This uses a specialized visitor which runs multiple visitors in parallel, - * while maintaining the visitor skip and break API. - * - * @internal - */ +/// This uses a specialized visitor which runs multiple visitors in parallel, +/// while maintaining the visitor skip and break API. +/// +/// @internal func visit( usingRules rules: [@Sendable (ValidationContext) -> Visitor], schema: GraphQLSchema, @@ -66,12 +60,10 @@ func visit( return context.errors } -/** - * Utility function which asserts a SDL document is valid by throwing an error - * if it is invalid. - * - * @internal - */ +/// Utility function which asserts a SDL document is valid by throwing an error +/// if it is invalid. +/// +/// @internal func assertValidSDL(documentAST: Document) throws { let errors = validateSDL(documentAST: documentAST) if !errors.isEmpty { @@ -82,12 +74,10 @@ func assertValidSDL(documentAST: Document) throws { } } -/** - * Utility function which asserts a SDL document is valid by throwing an error - * if it is invalid. - * - * @internal - */ +/// Utility function which asserts a SDL document is valid by throwing an error +/// if it is invalid. +/// +/// @internal func assertValidSDLExtension( documentAST: Document, schema: GraphQLSchema diff --git a/Sources/GraphQL/Validation/ValidationContext.swift b/Sources/GraphQL/Validation/ValidationContext.swift index a206f7bc..94f95fa1 100644 --- a/Sources/GraphQL/Validation/ValidationContext.swift +++ b/Sources/GraphQL/Validation/ValidationContext.swift @@ -1,14 +1,12 @@ - - public enum HasSelectionSet { case operation(OperationDefinition) case fragment(FragmentDefinition) public var node: Node { switch self { - case let .operation(operation): + case .operation(let operation): return operation - case let .fragment(fragment): + case .fragment(let fragment): return fragment } } @@ -17,18 +15,18 @@ public enum HasSelectionSet { extension HasSelectionSet: Hashable { public func hash(into hasher: inout Hasher) { switch self { - case let .operation(operation): + case .operation(let operation): return hasher.combine(operation.hashValue) - case let .fragment(fragment): + case .fragment(let fragment): return hasher.combine(fragment.hashValue) } } public static func == (lhs: HasSelectionSet, rhs: HasSelectionSet) -> Bool { switch (lhs, rhs) { - case let (.operation(l), .operation(r)): + case (.operation(let l), .operation(let r)): return l == r - case let (.fragment(l), .fragment(r)): + case (.fragment(let l), .fragment(let r)): return l == r default: return false @@ -38,11 +36,9 @@ extension HasSelectionSet: Hashable { public typealias VariableUsage = (node: Variable, type: GraphQLInputType?, defaultValue: Map?) -/** - * An instance of this class is passed as the "this" context to all validators, - * allowing access to commonly useful contextual information from within a - * validation rule. - */ +/// An instance of this class is passed as the "this" context to all validators, +/// allowing access to commonly useful contextual information from within a +/// validation rule. public class ASTValidationContext { let ast: Document var onError: (GraphQLError) -> Void @@ -88,9 +84,9 @@ public class ASTValidationContext { public func getFragmentSpreads(node: SelectionSet) -> [FragmentSpread] { // Uncommenting this creates unpredictably wrong fragment path matching. // Failures can be seen in NoFragmentCyclesRuleTests.testNoSpreadingItselfDeeplyTwoPaths -// if let spreads = fragmentSpreads[node] { -// return spreads -// } + // if let spreads = fragmentSpreads[node] { + // return spreads + // } var spreads = [FragmentSpread]() var setsToVisit: [SelectionSet] = [node] @@ -100,20 +96,20 @@ public class ASTValidationContext { spreads.append(spread) } else if let fragment = selection as? InlineFragment { setsToVisit.append(fragment.selectionSet) - } else if - let field = selection as? Field, + } else if let field = selection as? Field, let selectionSet = field.selectionSet { setsToVisit.append(selectionSet) } } } -// fragmentSpreads[node] = spreads + // fragmentSpreads[node] = spreads return spreads } public func getRecursivelyReferencedFragments(operation: OperationDefinition) - -> [FragmentDefinition] { + -> [FragmentDefinition] + { if let fragments = recursivelyReferencedFragments[operation] { return fragments } @@ -162,11 +158,9 @@ public class SDLValidationContext: ASTValidationContext { public typealias SDLValidationRule = @Sendable (SDLValidationContext) -> Visitor -/** - * An instance of this class is passed as the "this" context to all validators, - * allowing access to commonly useful contextual information from within a - * validation rule. - */ +/// An instance of this class is passed as the "this" context to all validators, +/// allowing access to commonly useful contextual information from within a +/// validation rule. public final class ValidationContext: ASTValidationContext { public let schema: GraphQLSchema let typeInfo: TypeInfo diff --git a/Tests/GraphQLTests/ExecutionTests/OneOfTests.swift b/Tests/GraphQLTests/ExecutionTests/OneOfTests.swift index d15e883f..d293c5be 100644 --- a/Tests/GraphQLTests/ExecutionTests/OneOfTests.swift +++ b/Tests/GraphQLTests/ExecutionTests/OneOfTests.swift @@ -1,109 +1,113 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct OneOfTests { // MARK: OneOf Input Objects @Test func acceptsAGoodDefaultValue() async throws { let query = """ - query ($input: TestInputObject! = {a: "abc"}) { - test(input: $input) { - a - b - } - } - """ + query ($input: TestInputObject! = {a: "abc"}) { + test(input: $input) { + a + b + } + } + """ let result = try await graphql( schema: getSchema(), request: query ) #expect( - result == GraphQLResult(data: [ - "test": [ - "a": "abc", - "b": .null, - ], - ]) + result + == GraphQLResult(data: [ + "test": [ + "a": "abc", + "b": .null, + ] + ]) ) } @Test func rejectsABadDefaultValue() async throws { let query = """ - query ($input: TestInputObject! = {a: "abc", b: 123}) { - test(input: $input) { - a - b - } - } - """ + query ($input: TestInputObject! = {a: "abc", b: 123}) { + test(input: $input) { + a + b + } + } + """ let result = try await graphql( schema: getSchema(), request: query ) #expect(result.errors.count == 1) #expect( - result.errors[0].message == - "OneOf Input Object \"TestInputObject\" must specify exactly one key." + result.errors[0].message + == "OneOf Input Object \"TestInputObject\" must specify exactly one key." ) } @Test func acceptsAGoodVariable() async throws { let query = """ - query ($input: TestInputObject!) { - test(input: $input) { - a - b - } - } - """ + query ($input: TestInputObject!) { + test(input: $input) { + a + b + } + } + """ let result = try await graphql( schema: getSchema(), request: query, variableValues: ["input": ["a": "abc"]] ) #expect( - result == GraphQLResult(data: [ - "test": [ - "a": "abc", - "b": .null, - ], - ]) + result + == GraphQLResult(data: [ + "test": [ + "a": "abc", + "b": .null, + ] + ]) ) } @Test func acceptsAGoodVariableWithAnUndefinedKey() async throws { let query = """ - query ($input: TestInputObject!) { - test(input: $input) { - a - b - } - } - """ + query ($input: TestInputObject!) { + test(input: $input) { + a + b + } + } + """ let result = try await graphql( schema: getSchema(), request: query, variableValues: ["input": ["a": "abc", "b": .undefined]] ) #expect( - result == GraphQLResult(data: [ - "test": [ - "a": "abc", - "b": .null, - ], - ]) + result + == GraphQLResult(data: [ + "test": [ + "a": "abc", + "b": .null, + ] + ]) ) } @Test func rejectsAVariableWithMultipleNonNullKeys() async throws { let query = """ - query ($input: TestInputObject!) { - test(input: $input) { - a - b - } - } - """ + query ($input: TestInputObject!) { + test(input: $input) { + a + b + } + } + """ let result = try await graphql( schema: getSchema(), request: query, @@ -112,21 +116,21 @@ import Testing #expect(result.errors.count == 1) #expect( result.errors[0].message == """ - Variable "$input" got invalid value "{"a":"abc","b":123}". - Exactly one key must be specified for OneOf type "TestInputObject". - """ + Variable "$input" got invalid value "{"a":"abc","b":123}". + Exactly one key must be specified for OneOf type "TestInputObject". + """ ) } @Test func rejectsAVariableWithMultipleNullableKeys() async throws { let query = """ - query ($input: TestInputObject!) { - test(input: $input) { - a - b - } - } - """ + query ($input: TestInputObject!) { + test(input: $input) { + a + b + } + } + """ let result = try await graphql( schema: getSchema(), request: query, @@ -135,9 +139,9 @@ import Testing #expect(result.errors.count == 1) #expect( result.errors[0].message == """ - Variable "$input" got invalid value "{"a":"abc","b":null}". - Exactly one key must be specified for OneOf type "TestInputObject". - """ + Variable "$input" got invalid value "{"a":"abc","b":null}". + Exactly one key must be specified for OneOf type "TestInputObject". + """ ) } } @@ -168,12 +172,12 @@ func getSchema() throws -> GraphQLSchema { "test": GraphQLField( type: testObject, args: [ - "input": GraphQLArgument(type: GraphQLNonNull(testInputObject)), + "input": GraphQLArgument(type: GraphQLNonNull(testInputObject)) ], resolve: { _, args, _, _ in try MapDecoder().decode(TestObject.self, from: args["input"]) } - ), + ) ] ), types: [ diff --git a/Tests/GraphQLTests/FederationTests/FederationTests.swift b/Tests/GraphQLTests/FederationTests/FederationTests.swift index e8063987..6abcc090 100644 --- a/Tests/GraphQLTests/FederationTests/FederationTests.swift +++ b/Tests/GraphQLTests/FederationTests/FederationTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct FederationTests { @Test func federationSampleSchema() throws { // Confirm that the Apollo test schema can be parsed as expected https://github.com/apollographql/apollo-federation-subgraph-compatibility/blob/main/COMPATIBILITY.md @@ -71,53 +72,70 @@ import Testing """ let schemaExtensionDefinition = - SchemaExtensionDefinition(definition: SchemaDefinition(directives: [ - Directive(name: nameNode("link"), arguments: [ - Argument( - name: nameNode("url"), - value: StringValue( - value: "https://specs.apollo.dev/federation/v2.0", - block: false + SchemaExtensionDefinition( + definition: SchemaDefinition( + directives: [ + Directive( + name: nameNode("link"), + arguments: [ + Argument( + name: nameNode("url"), + value: StringValue( + value: "https://specs.apollo.dev/federation/v2.0", + block: false + ) + ), + Argument( + name: nameNode("import"), + value: ListValue(values: [ + StringValue(value: "@extends", block: false), + StringValue(value: "@external", block: false), + StringValue(value: "@key", block: false), + StringValue(value: "@inaccessible", block: false), + StringValue(value: "@override", block: false), + StringValue(value: "@provides", block: false), + StringValue(value: "@requires", block: false), + StringValue(value: "@shareable", block: false), + StringValue(value: "@tag", block: false), + ]) + ), + ] ) - ), - Argument( - name: nameNode("import"), - value: ListValue(values: [ - StringValue(value: "@extends", block: false), - StringValue(value: "@external", block: false), - StringValue(value: "@key", block: false), - StringValue(value: "@inaccessible", block: false), - StringValue(value: "@override", block: false), - StringValue(value: "@provides", block: false), - StringValue(value: "@requires", block: false), - StringValue(value: "@shareable", block: false), - StringValue(value: "@tag", block: false), - ]) - ), - ]), - ], operationTypes: [])) + ], + operationTypes: [] + ) + ) let productObjectTypeDefinition = ObjectTypeDefinition( name: nameNode("Product"), directives: [ - Directive(name: nameNode("key"), arguments: [ - Argument( - name: nameNode("fields"), - value: StringValue(value: "id", block: false) - ), - ]), - Directive(name: nameNode("key"), arguments: [ - Argument( - name: nameNode("fields"), - value: StringValue(value: "sku package", block: false) - ), - ]), - Directive(name: nameNode("key"), arguments: [ - Argument( - name: nameNode("fields"), - value: StringValue(value: "sku variation { id }", block: false) - ), - ]), + Directive( + name: nameNode("key"), + arguments: [ + Argument( + name: nameNode("fields"), + value: StringValue(value: "id", block: false) + ) + ] + ), + Directive( + name: nameNode("key"), + arguments: [ + Argument( + name: nameNode("fields"), + value: StringValue(value: "sku package", block: false) + ) + ] + ), + Directive( + name: nameNode("key"), + arguments: [ + Argument( + name: nameNode("fields"), + value: StringValue(value: "sku variation { id }", block: false) + ) + ] + ), ], fields: [ FieldDefinition(name: nameNode("id"), type: NonNullType(type: typeNode("ID"))), @@ -125,22 +143,36 @@ import Testing FieldDefinition(name: nameNode("package"), type: typeNode("String")), FieldDefinition(name: nameNode("variation"), type: typeNode("ProductVariation")), FieldDefinition(name: nameNode("dimensions"), type: typeNode("ProductDimension")), - FieldDefinition(name: nameNode("createdBy"), type: typeNode("User"), directives: [ - Directive(name: nameNode("provides"), arguments: [ - Argument( - name: nameNode("fields"), - value: StringValue(value: "totalProductsCreated", block: false) - ), - ]), - ]), - FieldDefinition(name: nameNode("notes"), type: typeNode("String"), directives: [ - Directive(name: nameNode("tag"), arguments: [ - Argument( - name: nameNode("name"), - value: StringValue(value: "internal", block: false) - ), - ]), - ]), + FieldDefinition( + name: nameNode("createdBy"), + type: typeNode("User"), + directives: [ + Directive( + name: nameNode("provides"), + arguments: [ + Argument( + name: nameNode("fields"), + value: StringValue(value: "totalProductsCreated", block: false) + ) + ] + ) + ] + ), + FieldDefinition( + name: nameNode("notes"), + type: typeNode("String"), + directives: [ + Directive( + name: nameNode("tag"), + arguments: [ + Argument( + name: nameNode("name"), + value: StringValue(value: "internal", block: false) + ) + ] + ) + ] + ), FieldDefinition( name: nameNode("research"), type: NonNullType( @@ -155,12 +187,15 @@ import Testing let deprecatedProductObjectTypeDefinition = ObjectTypeDefinition( name: nameNode("DeprecatedProduct"), directives: [ - Directive(name: nameNode("key"), arguments: [ - Argument( - name: nameNode("fields"), - value: StringValue(value: "sku package", block: false) - ), - ]), + Directive( + name: nameNode("key"), + arguments: [ + Argument( + name: nameNode("fields"), + value: StringValue(value: "sku package", block: false) + ) + ] + ) ], fields: [ FieldDefinition(name: nameNode("sku"), type: NonNullType(type: typeNode("String"))), @@ -176,19 +211,22 @@ import Testing let productVariationObjectTypeDefinition = ObjectTypeDefinition( name: nameNode("ProductVariation"), fields: [ - FieldDefinition(name: nameNode("id"), type: NonNullType(type: typeNode("ID"))), + FieldDefinition(name: nameNode("id"), type: NonNullType(type: typeNode("ID"))) ] ) let productResearchObjectTypeDefinition = ObjectTypeDefinition( name: nameNode("ProductResearch"), directives: [ - Directive(name: nameNode("key"), arguments: [ - Argument( - name: nameNode("fields"), - value: StringValue(value: "study { caseNumber }", block: false) - ), - ]), + Directive( + name: nameNode("key"), + arguments: [ + Argument( + name: nameNode("fields"), + value: StringValue(value: "study { caseNumber }", block: false) + ) + ] + ) ], fields: [ FieldDefinition( @@ -213,105 +251,141 @@ import Testing let productDimensionObjectTypeDefinition = ObjectTypeDefinition( name: nameNode("ProductDimension"), directives: [ - Directive(name: nameNode("shareable")), + Directive(name: nameNode("shareable")) ], fields: [ FieldDefinition(name: nameNode("size"), type: typeNode("String")), FieldDefinition(name: nameNode("weight"), type: typeNode("Float")), - FieldDefinition(name: nameNode("unit"), type: typeNode("String"), directives: [ - Directive(name: nameNode("inaccessible")), - ]), + FieldDefinition( + name: nameNode("unit"), + type: typeNode("String"), + directives: [ + Directive(name: nameNode("inaccessible")) + ] + ), ] ) let queryExtensionObjectTypeDefinition = - TypeExtensionDefinition(definition: ObjectTypeDefinition( - name: nameNode("Query"), - fields: [ - FieldDefinition(name: nameNode("product"), arguments: [ - InputValueDefinition( - name: nameNode("id"), - type: NonNullType(type: NamedType(name: nameNode("ID"))) + TypeExtensionDefinition( + definition: ObjectTypeDefinition( + name: nameNode("Query"), + fields: [ + FieldDefinition( + name: nameNode("product"), + arguments: [ + InputValueDefinition( + name: nameNode("id"), + type: NonNullType(type: NamedType(name: nameNode("ID"))) + ) + ], + type: typeNode("Product") ), - ], type: typeNode("Product")), - FieldDefinition(name: nameNode("deprecatedProduct"), arguments: [ - InputValueDefinition( - name: nameNode("sku"), - type: NonNullType(type: NamedType(name: nameNode("String"))) - ), - InputValueDefinition( - name: nameNode("package"), - type: NonNullType(type: NamedType(name: nameNode("String"))) + FieldDefinition( + name: nameNode("deprecatedProduct"), + arguments: [ + InputValueDefinition( + name: nameNode("sku"), + type: NonNullType(type: NamedType(name: nameNode("String"))) + ), + InputValueDefinition( + name: nameNode("package"), + type: NonNullType(type: NamedType(name: nameNode("String"))) + ), + ], + type: typeNode("DeprecatedProduct"), + directives: [ + Directive( + name: nameNode("deprecated"), + arguments: [ + Argument( + name: nameNode("reason"), + value: StringValue( + value: "Use product query instead", + block: false + ) + ) + ] + ) + ] ), - ], type: typeNode("DeprecatedProduct"), directives: [ - Directive(name: nameNode("deprecated"), arguments: [ - Argument( - name: nameNode("reason"), - value: StringValue(value: "Use product query instead", block: false) - ), - ]), - ]), - ] - )) + ] + ) + ) let userExtensionObjectTypeDefinition = - TypeExtensionDefinition(definition: ObjectTypeDefinition( - name: nameNode("User"), - directives: [ - Directive(name: nameNode("key"), arguments: [ - Argument( - name: nameNode("fields"), - value: StringValue(value: "email", block: false) - ), - ]), - ], - fields: [ - FieldDefinition( - name: nameNode("averageProductsCreatedPerYear"), - type: typeNode("Int"), - directives: [ - Directive(name: nameNode("requires"), arguments: [ + TypeExtensionDefinition( + definition: ObjectTypeDefinition( + name: nameNode("User"), + directives: [ + Directive( + name: nameNode("key"), + arguments: [ Argument( name: nameNode("fields"), - value: StringValue( - value: "totalProductsCreated yearsOfEmployment", - block: false - ) - ), - ]), - ] - ), - FieldDefinition( - name: nameNode("email"), - type: NonNullType(type: NamedType(name: nameNode("ID"))), - directives: [ - Directive(name: nameNode("external")), - ] - ), - FieldDefinition(name: nameNode("name"), type: typeNode("String"), directives: [ - Directive(name: nameNode("override"), arguments: [ - Argument( - name: nameNode("from"), - value: StringValue(value: "users", block: false) - ), - ]), - ]), - FieldDefinition( - name: nameNode("totalProductsCreated"), - type: typeNode("Int"), - directives: [ - Directive(name: nameNode("external")), - ] - ), - FieldDefinition( - name: nameNode("yearsOfEmployment"), - type: NonNullType(type: typeNode("Int")), - directives: [ - Directive(name: nameNode("external")), - ] - ), - ] - )) + value: StringValue(value: "email", block: false) + ) + ] + ) + ], + fields: [ + FieldDefinition( + name: nameNode("averageProductsCreatedPerYear"), + type: typeNode("Int"), + directives: [ + Directive( + name: nameNode("requires"), + arguments: [ + Argument( + name: nameNode("fields"), + value: StringValue( + value: "totalProductsCreated yearsOfEmployment", + block: false + ) + ) + ] + ) + ] + ), + FieldDefinition( + name: nameNode("email"), + type: NonNullType(type: NamedType(name: nameNode("ID"))), + directives: [ + Directive(name: nameNode("external")) + ] + ), + FieldDefinition( + name: nameNode("name"), + type: typeNode("String"), + directives: [ + Directive( + name: nameNode("override"), + arguments: [ + Argument( + name: nameNode("from"), + value: StringValue(value: "users", block: false) + ) + ] + ) + ] + ), + FieldDefinition( + name: nameNode("totalProductsCreated"), + type: typeNode("Int"), + directives: [ + Directive(name: nameNode("external")) + ] + ), + FieldDefinition( + name: nameNode("yearsOfEmployment"), + type: NonNullType(type: typeNode("Int")), + directives: [ + Directive(name: nameNode("external")) + ] + ), + ] + ) + ) let expected = Document(definitions: [ schemaExtensionDefinition, diff --git a/Tests/GraphQLTests/HelloWorldTests/HelloWorldTests.swift b/Tests/GraphQLTests/HelloWorldTests/HelloWorldTests.swift index 2e9e03da..ebae428f 100644 --- a/Tests/GraphQLTests/HelloWorldTests/HelloWorldTests.swift +++ b/Tests/GraphQLTests/HelloWorldTests/HelloWorldTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct HelloWorldTests { let schema = try! GraphQLSchema( query: GraphQLObjectType( @@ -11,7 +12,7 @@ import Testing resolve: { _, _, _, _ in "world" } - ), + ) ] ) ) @@ -36,7 +37,7 @@ import Testing GraphQLError( message: "Cannot query field \"boyhowdy\" on type \"RootQueryType\".", locations: [SourceLocation(line: 1, column: 3)] - ), + ) ] ) diff --git a/Tests/GraphQLTests/InputTests/InputTests.swift b/Tests/GraphQLTests/InputTests/InputTests.swift index a382763b..6306d784 100644 --- a/Tests/GraphQLTests/InputTests/InputTests.swift +++ b/Tests/GraphQLTests/InputTests/InputTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct InputTests { @Test func argsNonNullNoDefault() async throws { struct Echo: Codable { @@ -17,7 +18,7 @@ import Testing fields: [ "field1": GraphQLField( type: GraphQLNonNull(GraphQLString) - ), + ) ], isTypeOf: { source, _ in source is Echo @@ -33,7 +34,7 @@ import Testing args: [ "field1": GraphQLArgument( type: GraphQLNonNull(GraphQLString) - ), + ) ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -41,7 +42,7 @@ import Testing field1: args.field1 ) } - ), + ) ] ), types: [EchoOutputType] @@ -51,57 +52,59 @@ import Testing var result = try await graphql( schema: schema, request: """ - { - echo( - field1: "value1" - ) { - field1 + { + echo( + field1: "value1" + ) { + field1 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1" + ] + ]) ) result = try await graphql( schema: schema, request: """ - query echo($field1: String!) { - echo( - field1: $field1 - ) { - field1 + query echo($field1: String!) { + echo( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [ - "field1": "value1", + "field1": "value1" ] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1" + ] + ]) ) // Test providing null results in an error result = try await graphql( schema: schema, request: """ - { - echo( - field1: null - ) { - field1 + { + echo( + field1: null + ) { + field1 + } } - } - """ + """ ) #expect( result.errors.count > 0 @@ -109,16 +112,16 @@ import Testing result = try await graphql( schema: schema, request: """ - query echo($field1: String!) { - echo( - field1: $field1 - ) { - field1 + query echo($field1: String!) { + echo( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [ - "field1": .null, + "field1": .null ] ) #expect( @@ -129,12 +132,12 @@ import Testing result = try await graphql( schema: schema, request: """ - { - echo { - field1 + { + echo { + field1 + } } - } - """ + """ ) #expect( result.errors.count > 0 @@ -142,14 +145,14 @@ import Testing result = try await graphql( schema: schema, request: """ - query echo($field1: String!) { - echo( - field1: $field1 - ) { - field1 + query echo($field1: String!) { + echo( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [:] ) #expect( @@ -172,7 +175,7 @@ import Testing fields: [ "field1": GraphQLField( type: GraphQLString - ), + ) ], isTypeOf: { source, _ in source is Echo @@ -188,7 +191,7 @@ import Testing args: [ "field1": GraphQLArgument( type: GraphQLString - ), + ) ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -196,7 +199,7 @@ import Testing field1: args.field1 ) } - ), + ) ] ), types: [EchoOutputType] @@ -206,125 +209,131 @@ import Testing var result = try await graphql( schema: schema, request: """ - { - echo( - field1: "value1" - ) { - field1 + { + echo( + field1: "value1" + ) { + field1 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1" + ] + ]) ) result = try await graphql( schema: schema, request: """ - query echo($field1: String) { - echo( - field1: $field1 - ) { - field1 + query echo($field1: String) { + echo( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [ - "field1": "value1", + "field1": "value1" ] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1" + ] + ]) ) // Test providing null is accepted result = try await graphql( schema: schema, request: """ - { - echo( - field1: null - ) { - field1 + { + echo( + field1: null + ) { + field1 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": .null, - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": .null + ] + ]) ) result = try await graphql( schema: schema, request: """ - query echo($field1: String) { - echo( - field1: $field1 - ) { - field1 + query echo($field1: String) { + echo( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [ - "field1": .null, + "field1": .null ] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": .null, - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": .null + ] + ]) ) // Test not providing parameter is accepted result = try await graphql( schema: schema, request: """ - { - echo { - field1 + { + echo { + field1 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": .null, - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": .null + ] + ]) ) result = try await graphql( schema: schema, request: """ - query echo($field1: String) { - echo( - field1: $field1 - ) { - field1 + query echo($field1: String) { + echo( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [:] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": .null, - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": .null + ] + ]) ) } @@ -343,7 +352,7 @@ import Testing fields: [ "field1": GraphQLField( type: GraphQLNonNull(GraphQLString) - ), + ) ], isTypeOf: { source, _ in source is Echo @@ -360,7 +369,7 @@ import Testing "field1": GraphQLArgument( type: GraphQLNonNull(GraphQLString), defaultValue: .string("defaultValue1") - ), + ) ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -368,7 +377,7 @@ import Testing field1: args.field1 ) } - ), + ) ] ), types: [EchoOutputType] @@ -378,57 +387,59 @@ import Testing var result = try await graphql( schema: schema, request: """ - { - echo( - field1: "value1" - ) { - field1 + { + echo( + field1: "value1" + ) { + field1 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1" + ] + ]) ) result = try await graphql( schema: schema, request: """ - query echo($field1: String!) { - echo( - field1: $field1 - ) { - field1 + query echo($field1: String!) { + echo( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [ - "field1": "value1", + "field1": "value1" ] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1" + ] + ]) ) // Test providing null results in an error result = try await graphql( schema: schema, request: """ - { - echo( - field1: null - ) { - field1 + { + echo( + field1: null + ) { + field1 + } } - } - """ + """ ) #expect( result.errors.count > 0 @@ -436,16 +447,16 @@ import Testing result = try await graphql( schema: schema, request: """ - query echo($field1: String!) { - echo( - field1: $field1 - ) { - field1 + query echo($field1: String!) { + echo( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [ - "field1": .null, + "field1": .null ] ) #expect( @@ -456,53 +467,55 @@ import Testing result = try await graphql( schema: schema, request: """ - { - echo { - field1 + { + echo { + field1 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "defaultValue1", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "defaultValue1" + ] + ]) ) result = try await graphql( schema: schema, request: """ - query echo($field1: String! = "defaultValue1") { - echo ( - field1: $field1 - ) { - field1 + query echo($field1: String! = "defaultValue1") { + echo ( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [:] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "defaultValue1", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "defaultValue1" + ] + ]) ) // Test variable doesn't get argument default result = try await graphql( schema: schema, request: """ - query echo($field1: String!) { - echo ( - field1: $field1 - ) { - field1 + query echo($field1: String!) { + echo ( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [:] ) #expect( @@ -525,7 +538,7 @@ import Testing fields: [ "field1": GraphQLField( type: GraphQLString - ), + ) ], isTypeOf: { source, _ in source is Echo @@ -542,7 +555,7 @@ import Testing "field1": GraphQLArgument( type: GraphQLString, defaultValue: .string("defaultValue1") - ), + ) ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -550,7 +563,7 @@ import Testing field1: args.field1 ) } - ), + ) ] ), types: [EchoOutputType] @@ -560,147 +573,154 @@ import Testing var result = try await graphql( schema: schema, request: """ - { - echo( - field1: "value1" - ) { - field1 + { + echo( + field1: "value1" + ) { + field1 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1" + ] + ]) ) result = try await graphql( schema: schema, request: """ - query echo($field1: String!) { - echo( - field1: $field1 - ) { - field1 + query echo($field1: String!) { + echo( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [ - "field1": "value1", + "field1": "value1" ] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1" + ] + ]) ) // Test providing null results in a null output result = try await graphql( schema: schema, request: """ - { - echo( - field1: null - ) { - field1 + { + echo( + field1: null + ) { + field1 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": .null, - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": .null + ] + ]) ) result = try await graphql( schema: schema, request: """ - query echo($field1: String) { - echo( - field1: $field1 - ) { - field1 + query echo($field1: String) { + echo( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [ - "field1": .null, + "field1": .null ] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": .null, - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": .null + ] + ]) ) // Test not providing parameter results in default result = try await graphql( schema: schema, request: """ - { - echo { - field1 + { + echo { + field1 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "defaultValue1", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "defaultValue1" + ] + ]) ) result = try await graphql( schema: schema, request: """ - query echo($field1: String = "defaultValue1") { - echo ( - field1: $field1 - ) { - field1 + query echo($field1: String = "defaultValue1") { + echo ( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [:] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "defaultValue1", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "defaultValue1" + ] + ]) ) // Test that nullable unprovided variables are coerced to null result = try await graphql( schema: schema, request: """ - query echo($field1: String) { - echo ( - field1: $field1 - ) { - field1 + query echo($field1: String) { + echo ( + field1: $field1 + ) { + field1 + } } - } - """, + """, variableValues: [:] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": .null, - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": .null + ] + ]) ) } @@ -765,7 +785,7 @@ import Testing args: [ "input": GraphQLArgument( type: EchoInputType - ), + ) ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -774,7 +794,7 @@ import Testing field2: args.input.field2 ) } - ), + ) ] ), types: [EchoInputType, EchoOutputType] @@ -784,51 +804,53 @@ import Testing var result = try await graphql( schema: schema, request: """ - { - echo(input:{ - field1: "value1", - field2: "value2", - }) { - field1 - field2 + { + echo(input:{ + field1: "value1", + field2: "value2", + }) { + field1 + field2 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - "field2": "value2", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1", + "field2": "value2", + ] + ]) ) // Test in variables result = try await graphql( schema: schema, request: """ - query echo($input: EchoInput) { - echo(input: $input) { - field1 - field2 + query echo($input: EchoInput) { + echo(input: $input) { + field1 + field2 + } } - } - """, + """, variableValues: [ "input": [ "field1": "value1", "field2": "value2", - ], + ] ] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - "field2": "value2", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1", + "field2": "value2", + ] + ]) ) } @@ -893,7 +915,7 @@ import Testing args: [ "input": GraphQLArgument( type: EchoInputType - ), + ) ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -902,7 +924,7 @@ import Testing field2: args.input.field2 ) } - ), + ) ] ), types: [EchoInputType, EchoOutputType] @@ -912,51 +934,53 @@ import Testing var result = try await graphql( schema: schema, request: """ - { - echo(input:{ - field1: "value1", - field2: null, - }) { - field1 - field2 + { + echo(input:{ + field1: "value1", + field2: null, + }) { + field1 + field2 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - "field2": nil, - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1", + "field2": nil, + ] + ]) ) // Test in variables result = try await graphql( schema: schema, request: """ - query echo($input: EchoInput) { - echo(input: $input) { - field1 - field2 + query echo($input: EchoInput) { + echo(input: $input) { + field1 + field2 + } } - } - """, + """, variableValues: [ "input": [ "field1": "value1", "field2": .null, - ], + ] ] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - "field2": nil, - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1", + "field2": nil, + ] + ]) ) } @@ -1022,7 +1046,7 @@ import Testing args: [ "input": GraphQLArgument( type: EchoInputType - ), + ) ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -1031,7 +1055,7 @@ import Testing field2: args.input.field2 ) } - ), + ) ] ), types: [EchoInputType, EchoOutputType] @@ -1041,49 +1065,51 @@ import Testing var result = try await graphql( schema: schema, request: """ - { - echo(input:{ - field1: "value1" - }) { - field1 - field2 + { + echo(input:{ + field1: "value1" + }) { + field1 + field2 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - "field2": nil, - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1", + "field2": nil, + ] + ]) ) // Test in variables result = try await graphql( schema: schema, request: """ - query echo($input: EchoInput) { - echo(input: $input) { - field1 - field2 + query echo($input: EchoInput) { + echo(input: $input) { + field1 + field2 + } } - } - """, + """, variableValues: [ "input": [ - "field1": "value1", - ], + "field1": "value1" + ] ] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - "field2": nil, - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1", + "field2": nil, + ] + ]) ) } @@ -1102,7 +1128,7 @@ import Testing let container = try decoder.container(keyedBy: CodingKeys.self) #expect(container.contains(.field1)) field1 = try container.decodeIfPresent(String.self, forKey: .field1) - #expect(container.contains(.field2)) // default value should be used + #expect(container.contains(.field2)) // default value should be used field2 = try container.decodeIfPresent(String.self, forKey: .field2) } } @@ -1149,7 +1175,7 @@ import Testing args: [ "input": GraphQLArgument( type: EchoInputType - ), + ) ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -1158,7 +1184,7 @@ import Testing field2: args.input.field2 ) } - ), + ) ] ), types: [EchoInputType, EchoOutputType] @@ -1168,46 +1194,48 @@ import Testing var result = try await graphql( schema: schema, request: """ - { - echo(input:{ - field1: "value1" - }) { - field1 - field2 + { + echo(input:{ + field1: "value1" + }) { + field1 + field2 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - "field2": "value2", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1", + "field2": "value2", + ] + ]) ) // Null literal with default gets null result = try await graphql( schema: schema, request: """ - { - echo(input:{ - field1: "value1" - field2: null - }) { - field1 - field2 + { + echo(input:{ + field1: "value1" + field2: null + }) { + field1 + field2 + } } - } - """ + """ ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - "field2": nil, - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1", + "field2": nil, + ] + ]) ) // Test in variable @@ -1215,52 +1243,54 @@ import Testing result = try await graphql( schema: schema, request: """ - query echo($input: EchoInput) { - echo(input: $input) { - field1 - field2 + query echo($input: EchoInput) { + echo(input: $input) { + field1 + field2 + } } - } - """, + """, variableValues: [ "input": [ - "field1": "value1", - ], + "field1": "value1" + ] ] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - "field2": "value2", - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1", + "field2": "value2", + ] + ]) ) // Null literal with default gets null result = try await graphql( schema: schema, request: """ - query echo($input: EchoInput) { - echo(input: $input) { - field1 - field2 + query echo($input: EchoInput) { + echo(input: $input) { + field1 + field2 + } } - } - """, + """, variableValues: [ "input": [ "field1": "value1", "field2": .null, - ], + ] ] ) #expect( - result == GraphQLResult(data: [ - "echo": [ - "field1": "value1", - "field2": nil, - ], - ]) + result + == GraphQLResult(data: [ + "echo": [ + "field1": "value1", + "field2": nil, + ] + ]) ) } } diff --git a/Tests/GraphQLTests/LanguageTests/BlockStringTests.swift b/Tests/GraphQLTests/LanguageTests/BlockStringTests.swift index bbdee7b4..2f8cbcd6 100644 --- a/Tests/GraphQLTests/LanguageTests/BlockStringTests.swift +++ b/Tests/GraphQLTests/LanguageTests/BlockStringTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct PrintBlockStringTests { @Test func doesNotEscapeCharacters() { let str = "\" \\ / \n \r \t" @@ -16,15 +17,14 @@ import Testing let str = "triple quotation \"\"\"" #expect(printBlockString(str) == "\"\"\"\ntriple quotation \\\"\"\"\n\"\"\"") #expect( - printBlockString(str, minimize: true) == - "\"\"\"triple quotation \\\"\"\"\"\"\"" + printBlockString(str, minimize: true) == "\"\"\"triple quotation \\\"\"\"\"\"\"" ) } @Test func correctlyPrintsSingleLineWithLeadingSpace() { #expect( - printBlockString(" space-led value \"quoted string\"") == - "\"\"\" space-led value \"quoted string\"\n\"\"\"" + printBlockString(" space-led value \"quoted string\"") + == "\"\"\" space-led value \"quoted string\"\n\"\"\"" ) } @@ -38,8 +38,7 @@ import Testing let str = "no indent\n with indent" #expect(printBlockString(str) == "\"\"\"\nno indent\n with indent\n\"\"\"") #expect( - printBlockString(str, minimize: true) == - "\"\"\"\nno indent\n with indent\"\"\"" + printBlockString(str, minimize: true) == "\"\"\"\nno indent\n with indent\"\"\"" ) } @@ -52,22 +51,24 @@ import Testing ].joined(separator: "\n") #expect( - printBlockString(str) == [ - "\"\"\"", - " first ", - " line ", - "indentation", - " string", - "\"\"\"", - ].joined(separator: "\n") + printBlockString(str) + == [ + "\"\"\"", + " first ", + " line ", + "indentation", + " string", + "\"\"\"", + ].joined(separator: "\n") ) #expect( - printBlockString(str, minimize: true) == [ - "\"\"\" first ", - " line ", - "indentation", - " string\"\"\"", - ].joined(separator: "\n") + printBlockString(str, minimize: true) + == [ + "\"\"\" first ", + " line ", + "indentation", + " string\"\"\"", + ].joined(separator: "\n") ) } } diff --git a/Tests/GraphQLTests/LanguageTests/LexerTests.swift b/Tests/GraphQLTests/LanguageTests/LexerTests.swift index 134928bf..c5e8f605 100644 --- a/Tests/GraphQLTests/LanguageTests/LexerTests.swift +++ b/Tests/GraphQLTests/LanguageTests/LexerTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + func lexOne(_ string: String) throws -> Token { let lexer = createLexer(source: Source(body: string)) return try lexer.advance() @@ -9,7 +10,7 @@ func lexOne(_ string: String) throws -> Token { @Suite struct LexerTests { @Test func invalidCharacter() throws { #expect(throws: (any Error).self) { try lexOne("\u{0007}") } -// 'Syntax Error GraphQL (1:1) Invalid character "\\u0007"' + // 'Syntax Error GraphQL (1:1) Invalid character "\\u0007"' } @Test func bOMHeader() throws { @@ -20,7 +21,7 @@ func lexOne(_ string: String) throws -> Token { start: 4, end: 7, line: 1, - column: 5, // TODO: Ignore BOM when counting characters making this 2. + column: 5, // TODO: Ignore BOM when counting characters making this 2. value: "foo" ) @@ -49,13 +50,15 @@ func lexOne(_ string: String) throws -> Token { } @Test func skipsWhitespace() throws { - let token = try lexOne(""" + let token = try lexOne( + """ - foo + foo - """) + """ + ) let expected = Token( kind: .name, @@ -70,10 +73,12 @@ func lexOne(_ string: String) throws -> Token { } @Test func skipsComments() throws { - let token = try lexOne(""" - #comment\r - foo#comment - """) + let token = try lexOne( + """ + #comment\r + foo#comment + """ + ) let expected = Token( kind: .name, @@ -103,19 +108,23 @@ func lexOne(_ string: String) throws -> Token { } @Test func errorsRespectWhitespaces() throws { - #expect(throws: (any Error).self) { try lexOne(""" + #expect(throws: (any Error).self) { + try lexOne( + """ - ? + ? - """) } -// 'Syntax Error GraphQL (3:5) Unexpected character "?".\n' + -// '\n' + -// '2: \n' + -// '3: ?\n' + -// ' ^\n' + -// '4: \n' + """ + ) + } + // 'Syntax Error GraphQL (3:5) Unexpected character "?".\n' + + // '\n' + + // '2: \n' + + // '3: ?\n' + + // ' ^\n' + + // '4: \n' } @Test func strings() throws { @@ -229,10 +238,12 @@ func lexOne(_ string: String) throws -> Token { // "Syntax Error GraphQL (1:19) Invalid character within String: "\\u0000"." #expect(throws: (any Error).self) { - try lexOne(""" - "multi - line" - """) + try lexOne( + """ + "multi + line" + """ + ) } // "Syntax Error GraphQL (1:7) Unterminated string" @@ -476,34 +487,34 @@ func lexOne(_ string: String) throws -> Token { @Test func numberErrors() throws { #expect(throws: (any Error).self) { try lexOne("00") } -// 'Syntax Error GraphQL (1:2) Invalid number, ' + -// 'unexpected digit after 0: "0".' + // 'Syntax Error GraphQL (1:2) Invalid number, ' + + // 'unexpected digit after 0: "0".' #expect(throws: (any Error).self) { try lexOne("+1") } // "Syntax Error GraphQL (1:1) Unexpected character "+"" #expect(throws: (any Error).self) { try lexOne("1.") } -// 'Syntax Error GraphQL (1:3) Invalid number, ' + -// 'expected digit but got: .' + // 'Syntax Error GraphQL (1:3) Invalid number, ' + + // 'expected digit but got: .' #expect(throws: (any Error).self) { try lexOne(".123") } // "Syntax Error GraphQL (1:1) Unexpected character "."" #expect(throws: (any Error).self) { try lexOne("1.A") } -// 'Syntax Error GraphQL (1:3) Invalid number, ' + -// 'expected digit but got: "A".' + // 'Syntax Error GraphQL (1:3) Invalid number, ' + + // 'expected digit but got: "A".' #expect(throws: (any Error).self) { try lexOne("-A") } -// 'Syntax Error GraphQL (1:2) Invalid number, ' + -// 'expected digit but got: "A".' + // 'Syntax Error GraphQL (1:2) Invalid number, ' + + // 'expected digit but got: "A".' #expect(throws: (any Error).self) { try lexOne("1.0e") } -// 'Syntax Error GraphQL (1:5) Invalid number, ' + -// 'expected digit but got: .'); + // 'Syntax Error GraphQL (1:5) Invalid number, ' + + // 'expected digit but got: .'); #expect(throws: (any Error).self) { try lexOne("1.0eA") } -// 'Syntax Error GraphQL (1:5) Invalid number, ' + -// 'expected digit but got: "A".' + // 'Syntax Error GraphQL (1:5) Invalid number, ' + + // 'expected digit but got: "A".' } @Test func symbols() throws { @@ -716,11 +727,11 @@ func lexOne(_ string: String) throws -> Token { @Test func doubleLinkedList() throws { let q = """ - { - #comment - field - } - """ + { + #comment + field + } + """ let lexer = createLexer(source: Source(body: q)) let startToken = lexer.token @@ -729,8 +740,7 @@ func lexOne(_ string: String) throws -> Token { repeat { endToken = try lexer.advance() #expect(endToken.kind != .comment) - } while - endToken.kind != .eof + } while endToken.kind != .eof #expect(startToken.prev == nil) #expect(endToken.next == nil) @@ -784,12 +794,14 @@ func lexOne(_ string: String) throws -> Token { """ let cleanedString = blockStringValue(rawValue: rawString) - #expect(cleanedString == """ - TopLevel { - indented - alsoIndented - } - """) + #expect( + cleanedString == """ + TopLevel { + indented + alsoIndented + } + """ + ) } @Test func blockStringDoubleIndentAndBlankLine() { @@ -813,13 +825,13 @@ func lexOne(_ string: String) throws -> Token { #expect( cleanedString == """ - TopLevel { - indented: { - foo: String + TopLevel { + indented: { + foo: String + } + alsoIndented } - alsoIndented - } - """ + """ ) } @@ -828,76 +840,84 @@ func lexOne(_ string: String) throws -> Token { - TopLevel { - indented - alsoIndented - } + TopLevel { + indented + alsoIndented + } - \t\t + \t\t - """ + """ let cleanedString = blockStringValue(rawValue: rawString) - #expect(cleanedString == """ - TopLevel { - indented - alsoIndented - } - """) + #expect( + cleanedString == """ + TopLevel { + indented + alsoIndented + } + """ + ) } @Test func blockStringIndentBlankLineFirstLineNotIndentWeird() { let rawString = """ - TopLevel { - indented - alsoIndented - } + TopLevel { + indented + alsoIndented + } - \t - """ + \t + """ let cleanedString = blockStringValue(rawValue: rawString) - #expect(cleanedString == """ - TopLevel { - indented - alsoIndented - } - """) + #expect( + cleanedString == """ + TopLevel { + indented + alsoIndented + } + """ + ) } @Test func blockStringIndentMultilineWithSingleSpaceIndent() { let rawString = """ - Multi-line string - With Inner \"foo\" - should be Valid - """ + Multi-line string + With Inner \"foo\" + should be Valid + """ let cleanedString = blockStringValue(rawValue: rawString) - #expect(cleanedString == """ - Multi-line string - With Inner \"foo\" - should be Valid - """) + #expect( + cleanedString == """ + Multi-line string + With Inner \"foo\" + should be Valid + """ + ) } @Test func blockStringIndentMultilineWithSingleSpaceIndentExtraLines() { let rawString = """ - Multi-line string - With Inner \"foo\" - should be Valid - """ + Multi-line string + With Inner \"foo\" + should be Valid + """ let cleanedString = blockStringValue(rawValue: rawString) - #expect(cleanedString == """ - Multi-line string - With Inner \"foo\" - should be Valid - """) + #expect( + cleanedString == """ + Multi-line string + With Inner \"foo\" + should be Valid + """ + ) } // Lexer tests for Blockstring token parsing @@ -928,13 +948,15 @@ func lexOne(_ string: String) throws -> Token { } @Test func blockStringSingleSpaceIndent() throws { - let token = try lexOne(#""" - """ - Multi-line string - With Inner "foo" - should be Valid - """ - """#) + let token = try lexOne( + #""" + """ + Multi-line string + With Inner "foo" + should be Valid + """ + """# + ) let expected = Token( kind: .blockstring, start: 0, @@ -942,10 +964,10 @@ func lexOne(_ string: String) throws -> Token { line: 1, column: 1, value: """ - Multi-line string - With Inner \"foo\" - should be Valid - """ + Multi-line string + With Inner \"foo\" + should be Valid + """ ) #expect( @@ -963,13 +985,15 @@ func lexOne(_ string: String) throws -> Token { } @Test func blockStringUnescapedReturns() throws { - let token = try lexOne(#""" - """ - Multi-line string - with Inner "foo" - should be valid - """ - """#) + let token = try lexOne( + #""" + """ + Multi-line string + with Inner "foo" + should be valid + """ + """# + ) let expected = Token( kind: .blockstring, @@ -978,24 +1002,26 @@ func lexOne(_ string: String) throws -> Token { line: 1, column: 1, value: """ - Multi-line string - with Inner "foo" - should be valid - """ + Multi-line string + with Inner "foo" + should be valid + """ ) #expect(token == expected) } @Test func blockStringUnescapedReturnsIndentTest() throws { - let token = try lexOne(#""" - """ - Multi-line string { - with Inner "foo" - should be valid indented - } - """ - """#) + let token = try lexOne( + #""" + """ + Multi-line string { + with Inner "foo" + should be valid indented + } + """ + """# + ) let expected = Token( kind: .blockstring, @@ -1004,11 +1030,11 @@ func lexOne(_ string: String) throws -> Token { line: 1, column: 1, value: """ - Multi-line string { - with Inner \"foo\" - should be valid indented - } - """ + Multi-line string { + with Inner \"foo\" + should be valid indented + } + """ ) #expect(token == expected) @@ -1034,11 +1060,11 @@ func lexOne(_ string: String) throws -> Token { line: 1, column: 5, value: """ - Multi-line string { - with Inner \"foo\" - should be valid indented - } - """ + Multi-line string { + with Inner \"foo\" + should be valid indented + } + """ ) print(sourceStr) @@ -1061,20 +1087,24 @@ func lexOne(_ string: String) throws -> Token { } @Test func emptyTrimmedCharactersBlockString() throws { - let token = try lexOne(#""" - """ - """ - """#) + let token = try lexOne( + #""" + """ + """ + """# + ) let expected = Token(kind: .blockstring, start: 0, end: 7, line: 1, column: 1, value: "") #expect(token == expected) } @Test func escapedTripleQuoteInBlockString() throws { - let token = try lexOne(#""" - """ - \""" - """ - """#) + let token = try lexOne( + #""" + """ + \""" + """ + """# + ) let expected = Token( kind: .blockstring, start: 0, diff --git a/Tests/GraphQLTests/LanguageTests/ParserTests.swift b/Tests/GraphQLTests/LanguageTests/ParserTests.swift index 1befe83d..ca7688c8 100644 --- a/Tests/GraphQLTests/LanguageTests/ParserTests.swift +++ b/Tests/GraphQLTests/LanguageTests/ParserTests.swift @@ -1,7 +1,8 @@ import Foundation -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct ParserTests { @Test func errorMessages() throws { var source: String @@ -9,12 +10,12 @@ import Testing var error = try expectGraphQLError { try parse(source: "{") } #expect( error.message == """ - Syntax Error GraphQL (1:2) Expected Name, found + Syntax Error GraphQL (1:2) Expected Name, found - 1: { - ^ + 1: { + ^ - """ + """ ) #expect(error.positions == [1]) #expect(error.locations[0].line == 1) @@ -23,71 +24,93 @@ import Testing error = try expectGraphQLError { try parse(source: "{ ...MissingOn }\nfragment MissingOn Type\n") } - #expect(error.message.contains( - "Syntax Error GraphQL (2:20) Expected \"on\", found Name \"Type\"" - )) + #expect( + error.message.contains( + "Syntax Error GraphQL (2:20) Expected \"on\", found Name \"Type\"" + ) + ) error = try expectGraphQLError { try parse(source: "{ field: {} }") } - #expect(error.message.contains( - "Syntax Error GraphQL (1:10) Expected Name, found {" - )) + #expect( + error.message.contains( + "Syntax Error GraphQL (1:10) Expected Name, found {" + ) + ) error = try expectGraphQLError { try parse(source: "notanoperation Foo { field }") } - #expect(error.message.contains( - "Syntax Error GraphQL (1:1) Unexpected Name \"notanoperation\"" - )) + #expect( + error.message.contains( + "Syntax Error GraphQL (1:1) Unexpected Name \"notanoperation\"" + ) + ) error = try expectGraphQLError { try parse(source: "...") } - #expect(error.message.contains( - "Syntax Error GraphQL (1:1) Unexpected ..." - )) + #expect( + error.message.contains( + "Syntax Error GraphQL (1:1) Unexpected ..." + ) + ) error = try expectGraphQLError { - try parse(source: Source( - body: "query", - name: "MyQuery.graphql" - )) + try parse( + source: Source( + body: "query", + name: "MyQuery.graphql" + ) + ) } - #expect(error.message.contains( - "Syntax Error MyQuery.graphql (1:6) Expected {, found " - )) + #expect( + error.message.contains( + "Syntax Error MyQuery.graphql (1:6) Expected {, found " + ) + ) source = "query Foo($x: Complex = { a: { b: [ $var ] } }) { field }" error = try expectGraphQLError { try parse(source: source) } - #expect(error.message.contains( - "Syntax Error GraphQL (1:37) Unexpected $" - )) + #expect( + error.message.contains( + "Syntax Error GraphQL (1:37) Unexpected $" + ) + ) error = try expectGraphQLError { try parse(source: "fragment on on on { on }") } - #expect(error.message.contains( - "Syntax Error GraphQL (1:10) Unexpected Name \"on\"" - )) + #expect( + error.message.contains( + "Syntax Error GraphQL (1:10) Unexpected Name \"on\"" + ) + ) error = try expectGraphQLError { try parse(source: "{ ...on }") } - #expect(error.message.contains( - "Syntax Error GraphQL (1:9) Expected Name, found }" - )) + #expect( + error.message.contains( + "Syntax Error GraphQL (1:9) Expected Name, found }" + ) + ) error = try expectGraphQLError { try parse( source: "type WithImplementsButNoTypes implements {}" ) } - #expect(error.message.contains( - "Syntax Error GraphQL (1:42) Expected Name, found {" - )) + #expect( + error.message.contains( + "Syntax Error GraphQL (1:42) Expected Name, found {" + ) + ) error = try expectGraphQLError { try parse(source: "type WithImplementsWithTrailingAmp implements AInterface & {}") } - #expect(error.message.contains( - "Syntax Error GraphQL (1:60) Expected Name, found {" - )) + #expect( + error.message.contains( + "Syntax Error GraphQL (1:60) Expected Name, found {" + ) + ) } @Test func variableInlineValues() throws { @@ -96,17 +119,17 @@ import Testing @Test func fieldWithArguments() throws { let query = """ - { - stringArgField(stringArg: "Hello World") - intArgField(intArg: 1) - floatArgField(floatArg: 3.14) - falseArgField(boolArg: false) - trueArgField(boolArg: true) - nullArgField(value: null) - enumArgField(enumArg: VALUE) - multipleArgs(arg1: 1, arg2: false, arg3: THIRD) - } - """ + { + stringArgField(stringArg: "Hello World") + intArgField(intArg: 1) + floatArgField(floatArg: 3.14) + falseArgField(boolArg: false) + trueArgField(boolArg: true) + nullArgField(value: null) + enumArgField(enumArg: VALUE) + multipleArgs(arg1: 1, arg2: false, arg3: THIRD) + } + """ let expected = Document( definitions: [ @@ -120,7 +143,7 @@ import Testing Argument( name: Name(value: "stringArg"), value: StringValue(value: "Hello World", block: false) - ), + ) ] ), Field( @@ -129,7 +152,7 @@ import Testing Argument( name: Name(value: "intArg"), value: IntValue(value: "1") - ), + ) ] ), Field( @@ -138,7 +161,7 @@ import Testing Argument( name: Name(value: "floatArg"), value: FloatValue(value: "3.14") - ), + ) ] ), Field( @@ -147,7 +170,7 @@ import Testing Argument( name: Name(value: "boolArg"), value: BooleanValue(value: false) - ), + ) ] ), Field( @@ -156,7 +179,7 @@ import Testing Argument( name: Name(value: "boolArg"), value: BooleanValue(value: true) - ), + ) ] ), Field( @@ -165,7 +188,7 @@ import Testing Argument( name: Name(value: "value"), value: NullValue() - ), + ) ] ), Field( @@ -174,7 +197,7 @@ import Testing Argument( name: Name(value: "enumArg"), value: EnumValue(value: "VALUE") - ), + ) ] ), Field( @@ -196,7 +219,7 @@ import Testing ), ] ) - ), + ) ] ) @@ -204,27 +227,27 @@ import Testing #expect(document == expected) } -// it('parses multi-byte characters', async () => { -// // Note: \u0A0A could be naively interpretted as two line-feed chars. -// expect( -// parse(` -// # This comment has a \u0A0A multi-byte character. -// { field(arg: "Has a \u0A0A multi-byte character.") } -// `) -// ).to.containSubset({ -// definitions: [ { -// selectionSet: { -// selections: [ { -// arguments: [ { -// value: { -// kind: Kind.STRING, -// value: 'Has a \u0A0A multi-byte character.' -// } -// } ] -// } ] -// } -// } ] -// }); + // it('parses multi-byte characters', async () => { + // // Note: \u0A0A could be naively interpretted as two line-feed chars. + // expect( + // parse(` + // # This comment has a \u0A0A multi-byte character. + // { field(arg: "Has a \u0A0A multi-byte character.") } + // `) + // ).to.containSubset({ + // definitions: [ { + // selectionSet: { + // selections: [ { + // arguments: [ { + // value: { + // kind: Kind.STRING, + // value: 'Has a \u0A0A multi-byte character.' + // } + // } ] + // } ] + // } + // } ] + // }); // }); enum ParserTestsError: Error { @@ -262,56 +285,41 @@ import Testing } _ = try parse( - source: "query \(nonKeyword) {" + - "... \(fragmentName)" + - "... on \(nonKeyword) { field }" + - "}" + - "fragment \(fragmentName) on Type {" + - "\(nonKeyword)(\(nonKeyword): $\(nonKeyword)) @\(nonKeyword)(\(nonKeyword): \(nonKeyword))" + - "}" + source: "query \(nonKeyword) {" + "... \(fragmentName)" + + "... on \(nonKeyword) { field }" + + "}" + "fragment \(fragmentName) on Type {" + + "\(nonKeyword)(\(nonKeyword): $\(nonKeyword)) @\(nonKeyword)(\(nonKeyword): \(nonKeyword))" + + "}" ) } } @Test func anonymousMutationOperation() throws { _ = try parse( - source: "mutation {" + - " mutationField" + - "}" + source: "mutation {" + " mutationField" + "}" ) } @Test func anonymousSubscriptionOperation() throws { _ = try parse( - source: "subscription {" + - " subscriptionField" + - "}" + source: "subscription {" + " subscriptionField" + "}" ) } @Test func namedMutationOperation() throws { _ = try parse( - source: "mutation Foo {" + - " mutationField" + - "}" + source: "mutation Foo {" + " mutationField" + "}" ) } @Test func namedSubscriptionOperation() throws { _ = try parse( - source: "subscription Foo {" + - " subscriptionField" + - "}" + source: "subscription Foo {" + " subscriptionField" + "}" ) } @Test func createAST() throws { - let query = "{" + - " node(id: 4) {" + - " id," + - " name" + - " }" + - "}" + let query = "{" + " node(id: 4) {" + " id," + " name" + " }" + "}" let expected = Document( definitions: [ @@ -325,7 +333,7 @@ import Testing Argument( name: Name(value: "id"), value: IntValue(value: "4") - ), + ) ], selectionSet: SelectionSet( selections: [ @@ -333,10 +341,10 @@ import Testing Field(name: Name(value: "name")), ] ) - ), + ) ] ) - ), + ) ] ) @@ -429,11 +437,11 @@ import Testing @Test func parseDirective() throws { let source = #""" - directive @restricted( - """The reason for this restriction""" - reason: String = null - ) on FIELD_DEFINITION - """# + directive @restricted( + """The reason for this restriction""" + reason: String = null + ) on FIELD_DEFINITION + """# let expected = Document(definitions: [ DirectiveDefinition( @@ -448,12 +456,12 @@ import Testing name: Name(value: "reason"), type: NamedType(name: Name(value: "String")), defaultValue: NullValue() - ), + ) ], locations: [ - Name(value: "FIELD_DEFINITION"), + Name(value: "FIELD_DEFINITION") ] - ), + ) ]) let document = try parse(source: source) diff --git a/Tests/GraphQLTests/LanguageTests/PrintStringTests.swift b/Tests/GraphQLTests/LanguageTests/PrintStringTests.swift index cc191352..635e68cb 100644 --- a/Tests/GraphQLTests/LanguageTests/PrintStringTests.swift +++ b/Tests/GraphQLTests/LanguageTests/PrintStringTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct PrintStringTests { @Test func printsASimpleString() { #expect(printString("hello world") == "\"hello world\"") @@ -38,38 +39,36 @@ import Testing @Test func escapesAllControlChars() { #expect( printString( - "\u{0000}\u{0001}\u{0002}\u{0003}\u{0004}\u{0005}\u{0006}\u{0007}" + - "\u{0008}\u{0009}\u{000A}\u{000B}\u{000C}\u{000D}\u{000E}\u{000F}" + - "\u{0010}\u{0011}\u{0012}\u{0013}\u{0014}\u{0015}\u{0016}\u{0017}" + - "\u{0018}\u{0019}\u{001A}\u{001B}\u{001C}\u{001D}\u{001E}\u{001F}" + - "\u{0020}\u{0021}\u{0022}\u{0023}\u{0024}\u{0025}\u{0026}\u{0027}" + - "\u{0028}\u{0029}\u{002A}\u{002B}\u{002C}\u{002D}\u{002E}\u{002F}" + - "\u{0030}\u{0031}\u{0032}\u{0033}\u{0034}\u{0035}\u{0036}\u{0037}" + - "\u{0038}\u{0039}\u{003A}\u{003B}\u{003C}\u{003D}\u{003E}\u{003F}" + - "\u{0040}\u{0041}\u{0042}\u{0043}\u{0044}\u{0045}\u{0046}\u{0047}" + - "\u{0048}\u{0049}\u{004A}\u{004B}\u{004C}\u{004D}\u{004E}\u{004F}" + - "\u{0050}\u{0051}\u{0052}\u{0053}\u{0054}\u{0055}\u{0056}\u{0057}" + - "\u{0058}\u{0059}\u{005A}\u{005B}\u{005C}\u{005D}\u{005E}\u{005F}" + - "\u{0060}\u{0061}\u{0062}\u{0063}\u{0064}\u{0065}\u{0066}\u{0067}" + - "\u{0068}\u{0069}\u{006A}\u{006B}\u{006C}\u{006D}\u{006E}\u{006F}" + - "\u{0070}\u{0071}\u{0072}\u{0073}\u{0074}\u{0075}\u{0076}\u{0077}" + - "\u{0078}\u{0079}\u{007A}\u{007B}\u{007C}\u{007D}\u{007E}\u{007F}" + - "\u{0080}\u{0081}\u{0082}\u{0083}\u{0084}\u{0085}\u{0086}\u{0087}" + - "\u{0088}\u{0089}\u{008A}\u{008B}\u{008C}\u{008D}\u{008E}\u{008F}" + - "\u{0090}\u{0091}\u{0092}\u{0093}\u{0094}\u{0095}\u{0096}\u{0097}" + - "\u{0098}\u{0099}\u{009A}\u{009B}\u{009C}\u{009D}\u{009E}\u{009F}" - ) == - "\"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007" + - "\\b\\t\\n\\u000B\\f\\r\\u000E\\u000F" + - "\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017" + - "\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F" + - " !\\\"#$%&\'()*+,-./0123456789:;<=>?" + - "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_" + - "`abcdefghijklmnopqrstuvwxyz{|}~\\u007F" + - "\\u0080\\u0081\\u0082\\u0083\\u0084\\u0085\\u0086\\u0087" + - "\\u0088\\u0089\\u008A\\u008B\\u008C\\u008D\\u008E\\u008F" + - "\\u0090\\u0091\\u0092\\u0093\\u0094\\u0095\\u0096\\u0097" + - "\\u0098\\u0099\\u009A\\u009B\\u009C\\u009D\\u009E\\u009F\"" + "\u{0000}\u{0001}\u{0002}\u{0003}\u{0004}\u{0005}\u{0006}\u{0007}" + + "\u{0008}\u{0009}\u{000A}\u{000B}\u{000C}\u{000D}\u{000E}\u{000F}" + + "\u{0010}\u{0011}\u{0012}\u{0013}\u{0014}\u{0015}\u{0016}\u{0017}" + + "\u{0018}\u{0019}\u{001A}\u{001B}\u{001C}\u{001D}\u{001E}\u{001F}" + + "\u{0020}\u{0021}\u{0022}\u{0023}\u{0024}\u{0025}\u{0026}\u{0027}" + + "\u{0028}\u{0029}\u{002A}\u{002B}\u{002C}\u{002D}\u{002E}\u{002F}" + + "\u{0030}\u{0031}\u{0032}\u{0033}\u{0034}\u{0035}\u{0036}\u{0037}" + + "\u{0038}\u{0039}\u{003A}\u{003B}\u{003C}\u{003D}\u{003E}\u{003F}" + + "\u{0040}\u{0041}\u{0042}\u{0043}\u{0044}\u{0045}\u{0046}\u{0047}" + + "\u{0048}\u{0049}\u{004A}\u{004B}\u{004C}\u{004D}\u{004E}\u{004F}" + + "\u{0050}\u{0051}\u{0052}\u{0053}\u{0054}\u{0055}\u{0056}\u{0057}" + + "\u{0058}\u{0059}\u{005A}\u{005B}\u{005C}\u{005D}\u{005E}\u{005F}" + + "\u{0060}\u{0061}\u{0062}\u{0063}\u{0064}\u{0065}\u{0066}\u{0067}" + + "\u{0068}\u{0069}\u{006A}\u{006B}\u{006C}\u{006D}\u{006E}\u{006F}" + + "\u{0070}\u{0071}\u{0072}\u{0073}\u{0074}\u{0075}\u{0076}\u{0077}" + + "\u{0078}\u{0079}\u{007A}\u{007B}\u{007C}\u{007D}\u{007E}\u{007F}" + + "\u{0080}\u{0081}\u{0082}\u{0083}\u{0084}\u{0085}\u{0086}\u{0087}" + + "\u{0088}\u{0089}\u{008A}\u{008B}\u{008C}\u{008D}\u{008E}\u{008F}" + + "\u{0090}\u{0091}\u{0092}\u{0093}\u{0094}\u{0095}\u{0096}\u{0097}" + + "\u{0098}\u{0099}\u{009A}\u{009B}\u{009C}\u{009D}\u{009E}\u{009F}" + ) == "\"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007" + + "\\b\\t\\n\\u000B\\f\\r\\u000E\\u000F" + + "\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017" + + "\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F" + + " !\\\"#$%&\'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_" + + "`abcdefghijklmnopqrstuvwxyz{|}~\\u007F" + + "\\u0080\\u0081\\u0082\\u0083\\u0084\\u0085\\u0086\\u0087" + + "\\u0088\\u0089\\u008A\\u008B\\u008C\\u008D\\u008E\\u008F" + + "\\u0090\\u0091\\u0092\\u0093\\u0094\\u0095\\u0096\\u0097" + + "\\u0098\\u0099\\u009A\\u009B\\u009C\\u009D\\u009E\\u009F\"" ) } } diff --git a/Tests/GraphQLTests/LanguageTests/PrinterTests.swift b/Tests/GraphQLTests/LanguageTests/PrinterTests.swift index 1455efde..ee9acf12 100644 --- a/Tests/GraphQLTests/LanguageTests/PrinterTests.swift +++ b/Tests/GraphQLTests/LanguageTests/PrinterTests.swift @@ -1,7 +1,8 @@ import Foundation -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct PrinterTests { @Test func printMinimalAST() { let ast = Name(value: "foo") @@ -58,17 +59,17 @@ import Testing // Variable Directives are currently not support by this library // TODO: Add support for variable directives -// @Test func printsQueryWithVariableDirectives() throws { -// let document = try parse(source: "query ($foo: TestType = { a: 123 } @testDirective(if: -// true) @test) { id }") -// let expected = -// """ -// query ($foo: TestType = { a: 123 } @testDirective(if: true) @test) { -// id -// } -// """ -// #expect(print(ast: document) == expected) -// } + // @Test func printsQueryWithVariableDirectives() throws { + // let document = try parse(source: "query ($foo: TestType = { a: 123 } @testDirective(if: + // true) @test) { id }") + // let expected = + // """ + // query ($foo: TestType = { a: 123 } @testDirective(if: true) @test) { + // id + // } + // """ + // #expect(print(ast: document) == expected) + // } @Test func keepsArgumentsOnOneLineIfLineIsShort() throws { let document = try parse(source: "{trip(wheelchair:false arriveBy:false){dateTime}}") @@ -86,7 +87,8 @@ import Testing @Test func putsArgumentsOnMultipleLinesIfLineIsLong() throws { let document = try parse( - source: "{trip(wheelchair:false arriveBy:false includePlannedCancellations:true transitDistanceReluctance:2000){dateTime}}" + source: + "{trip(wheelchair:false arriveBy:false includePlannedCancellations:true transitDistanceReluctance:2000){dateTime}}" ) let expected = """ @@ -107,7 +109,8 @@ import Testing @Test func putsLargeObjectValuesOnMultipleLinesIfLineIsLong() throws { let document = try parse( - source: "{trip(obj:{wheelchair:false,smallObj:{a: 1},largeObj:{wheelchair:false,smallObj:{a: 1},arriveBy:false,includePlannedCancellations:true,transitDistanceReluctance:2000,anotherLongFieldName:\"Lots and lots and lots and lots of text\"},arriveBy:false,includePlannedCancellations:true,transitDistanceReluctance:2000,anotherLongFieldName:\"Lots and lots and lots and lots of text\"}){dateTime}}" + source: + "{trip(obj:{wheelchair:false,smallObj:{a: 1},largeObj:{wheelchair:false,smallObj:{a: 1},arriveBy:false,includePlannedCancellations:true,transitDistanceReluctance:2000,anotherLongFieldName:\"Lots and lots and lots and lots of text\"},arriveBy:false,includePlannedCancellations:true,transitDistanceReluctance:2000,anotherLongFieldName:\"Lots and lots and lots and lots of text\"}){dateTime}}" ) let expected = """ @@ -140,7 +143,8 @@ import Testing @Test func putsLargeListValuesOnMultipleLinesIfLineIsLong() throws { let document = try parse( - source: "{trip(list:[[\"small array\", \"small\", \"small\"], [\"Lots and lots and lots and lots of text\", \"Lots and lots and lots and lots of text\", \"Lots and lots and lots and lots of text\"]]){dateTime}}" + source: + "{trip(list:[[\"small array\", \"small\", \"small\"], [\"Lots and lots and lots and lots of text\", \"Lots and lots and lots and lots of text\", \"Lots and lots and lots and lots of text\"]]){dateTime}}" ) let expected = """ diff --git a/Tests/GraphQLTests/LanguageTests/SchemaParserTests.swift b/Tests/GraphQLTests/LanguageTests/SchemaParserTests.swift index 6237a78f..a90e4612 100644 --- a/Tests/GraphQLTests/LanguageTests/SchemaParserTests.swift +++ b/Tests/GraphQLTests/LanguageTests/SchemaParserTests.swift @@ -1,7 +1,8 @@ import Foundation -@testable import GraphQL import Testing +@testable import GraphQL + func nameNode(_ name: String) -> Name { return Name(value: name) } @@ -79,9 +80,9 @@ func namedTypeNode(_ name: String) -> NamedType { fieldNode( nameNode("world"), typeNode("String") - ), + ) ] - ), + ) ] ) @@ -90,12 +91,14 @@ func namedTypeNode(_ name: String) -> NamedType { } @Test func parsesTypeWithDescriptionString() throws { - let doc = try parse(source: """ - "Description" - type Hello { - world: String - } - """) + let doc = try parse( + source: """ + "Description" + type Hello { + world: String + } + """ + ) let type = try #require(doc.definitions[0] as? ObjectTypeDefinition) @@ -103,15 +106,17 @@ func namedTypeNode(_ name: String) -> NamedType { } @Test func parsesTypeWithDescriptionMultiLineString() throws { - let doc = try parse(source: #""" - """ - Description - """ - # Even with comments between them - type Hello { - world: String - } - """#) + let doc = try parse( + source: #""" + """ + Description + """ + # Even with comments between them + type Hello { + world: String + } + """# + ) let type = try #require(doc.definitions[0] as? ObjectTypeDefinition) @@ -119,12 +124,14 @@ func namedTypeNode(_ name: String) -> NamedType { } @Test func parsesSchemaWithDescriptionMultiLineString() throws { - let doc = try parse(source: """ - "Description" - schema { - query: Foo - } - """) + let doc = try parse( + source: """ + "Description" + schema { + query: Foo + } + """ + ) let type = try #require(doc.definitions[0] as? SchemaDefinition) @@ -149,10 +156,10 @@ func namedTypeNode(_ name: String) -> NamedType { fieldNode( nameNode("world"), typeNode("String") - ), + ) ] ) - ), + ) ] ) @@ -162,64 +169,69 @@ func namedTypeNode(_ name: String) -> NamedType { @Test func objectExtensionWithoutFields() throws { #expect( - try parse(source: "extend type Hello implements Greeting") == Document( - definitions: [ - TypeExtensionDefinition( - definition: ObjectTypeDefinition( - name: nameNode("Hello"), - interfaces: [typeNode("Greeting")], - directives: [], - fields: [] + try parse(source: "extend type Hello implements Greeting") + == Document( + definitions: [ + TypeExtensionDefinition( + definition: ObjectTypeDefinition( + name: nameNode("Hello"), + interfaces: [typeNode("Greeting")], + directives: [], + fields: [] + ) ) - ), - ] - ) + ] + ) ) } @Test func interfaceExtensionWithoutFields() throws { #expect( - try parse(source: "extend interface Hello implements Greeting") == Document( - definitions: [ - InterfaceExtensionDefinition( - definition: InterfaceTypeDefinition( - name: nameNode("Hello"), - interfaces: [typeNode("Greeting")], - directives: [], - fields: [] + try parse(source: "extend interface Hello implements Greeting") + == Document( + definitions: [ + InterfaceExtensionDefinition( + definition: InterfaceTypeDefinition( + name: nameNode("Hello"), + interfaces: [typeNode("Greeting")], + directives: [], + fields: [] + ) ) - ), - ] - ) + ] + ) ) } @Test func objectExtensionWithoutFieldsFollowedByExtension() throws { #expect( - try parse(source: """ - extend type Hello implements Greeting - - extend type Hello implements SecondGreeting - """) == Document( - definitions: [ - TypeExtensionDefinition( - definition: ObjectTypeDefinition( - name: nameNode("Hello"), - interfaces: [typeNode("Greeting")], - directives: [], - fields: [] - ) - ), - TypeExtensionDefinition( - definition: ObjectTypeDefinition( - name: nameNode("Hello"), - interfaces: [typeNode("SecondGreeting")], - directives: [], - fields: [] - ) - ), - ] + try parse( + source: """ + extend type Hello implements Greeting + + extend type Hello implements SecondGreeting + """ ) + == Document( + definitions: [ + TypeExtensionDefinition( + definition: ObjectTypeDefinition( + name: nameNode("Hello"), + interfaces: [typeNode("Greeting")], + directives: [], + fields: [] + ) + ), + TypeExtensionDefinition( + definition: ObjectTypeDefinition( + name: nameNode("Hello"), + interfaces: [typeNode("SecondGreeting")], + directives: [], + fields: [] + ) + ), + ] + ) ) } @@ -234,109 +246,124 @@ func namedTypeNode(_ name: String) -> NamedType { @Test func interfaceExtensionWithoutFieldsFollowedByExtension() throws { #expect( - try parse(source: """ - extend interface Hello implements Greeting - - extend interface Hello implements SecondGreeting - """) == Document( - definitions: [ - InterfaceExtensionDefinition( - definition: InterfaceTypeDefinition( - name: nameNode("Hello"), - interfaces: [typeNode("Greeting")], - directives: [], - fields: [] - ) - ), - InterfaceExtensionDefinition( - definition: InterfaceTypeDefinition( - name: nameNode("Hello"), - interfaces: [typeNode("SecondGreeting")], - directives: [], - fields: [] - ) - ), - ] + try parse( + source: """ + extend interface Hello implements Greeting + + extend interface Hello implements SecondGreeting + """ ) + == Document( + definitions: [ + InterfaceExtensionDefinition( + definition: InterfaceTypeDefinition( + name: nameNode("Hello"), + interfaces: [typeNode("Greeting")], + directives: [], + fields: [] + ) + ), + InterfaceExtensionDefinition( + definition: InterfaceTypeDefinition( + name: nameNode("Hello"), + interfaces: [typeNode("SecondGreeting")], + directives: [], + fields: [] + ) + ), + ] + ) ) } @Test func objectExtensionDoNotIncludeDescriptions() throws { #expect(throws: (any Error).self) { - try parse(source: """ - "Description" - extend type Hello { - world: String - } - """) + try parse( + source: """ + "Description" + extend type Hello { + world: String + } + """ + ) } #expect(throws: (any Error).self) { - try parse(source: """ - extend "Description" type Hello { - world: String - } - """) + try parse( + source: """ + extend "Description" type Hello { + world: String + } + """ + ) } } @Test func interfaceExtensionDoNotIncludeDescriptions() throws { #expect(throws: (any Error).self) { - try parse(source: """ - "Description" - extend interface Hello { - world: String - } - """) + try parse( + source: """ + "Description" + extend interface Hello { + world: String + } + """ + ) } #expect(throws: (any Error).self) { - try parse(source: """ - extend "Description" interface Hello { - world: String - } - """) + try parse( + source: """ + extend "Description" interface Hello { + world: String + } + """ + ) } } @Test func schemaExtension() throws { #expect( - try parse(source: """ - extend schema { - mutation: Mutation - } - """) == Document( - definitions: [ - SchemaExtensionDefinition( - definition: SchemaDefinition( - directives: [], - operationTypes: [ - OperationTypeDefinition( - operation: .mutation, - type: .init(name: .init(value: "Mutation")) - ), - ] - ) - ), - ] + try parse( + source: """ + extend schema { + mutation: Mutation + } + """ ) + == Document( + definitions: [ + SchemaExtensionDefinition( + definition: SchemaDefinition( + directives: [], + operationTypes: [ + OperationTypeDefinition( + operation: .mutation, + type: .init(name: .init(value: "Mutation")) + ) + ] + ) + ) + ] + ) ) } @Test func schemaExtensionWithOnlyDirectives() throws { #expect( - try parse(source: "extend schema @directive") == Document( - definitions: [ - SchemaExtensionDefinition( - definition: SchemaDefinition( - directives: [ - Directive(name: .init(value: "directive")), - ], - operationTypes: [] + try parse(source: "extend schema @directive") + == Document( + definitions: [ + SchemaExtensionDefinition( + definition: SchemaDefinition( + directives: [ + Directive(name: .init(value: "directive")) + ], + operationTypes: [] + ) ) - ), - ] - ) + ] + ) ) } @@ -365,9 +392,9 @@ func namedTypeNode(_ name: String) -> NamedType { NonNullType( type: typeNode("String") ) - ), + ) ] - ), + ) ] ) @@ -379,20 +406,21 @@ func namedTypeNode(_ name: String) -> NamedType { #expect( try parse( source: "interface Hello implements World { field: String }" - ) == Document( - definitions: [ - InterfaceTypeDefinition( - name: nameNode("Hello"), - interfaces: [typeNode("World")], - fields: [ - FieldDefinition( - name: .init(value: "field"), - type: NamedType(name: .init(value: "String")) - ), - ] - ), - ] ) + == Document( + definitions: [ + InterfaceTypeDefinition( + name: nameNode("Hello"), + interfaces: [typeNode("World")], + fields: [ + FieldDefinition( + name: .init(value: "field"), + type: NamedType(name: .init(value: "String")) + ) + ] + ) + ] + ) ) } @@ -404,7 +432,7 @@ func namedTypeNode(_ name: String) -> NamedType { ObjectTypeDefinition( name: nameNode("Hello"), interfaces: [typeNode("World")] - ), + ) ] ) @@ -423,7 +451,7 @@ func namedTypeNode(_ name: String) -> NamedType { typeNode("Wo"), typeNode("rld"), ] - ), + ) ] ) @@ -435,23 +463,24 @@ func namedTypeNode(_ name: String) -> NamedType { #expect( try parse( source: "interface Hello implements Wo & rld { field: String }" - ) == Document( - definitions: [ - InterfaceTypeDefinition( - name: nameNode("Hello"), - interfaces: [ - typeNode("Wo"), - typeNode("rld"), - ], - fields: [ - FieldDefinition( - name: .init(value: "field"), - type: NamedType(name: .init(value: "String")) - ), - ] - ), - ] ) + == Document( + definitions: [ + InterfaceTypeDefinition( + name: nameNode("Hello"), + interfaces: [ + typeNode("Wo"), + typeNode("rld"), + ], + fields: [ + FieldDefinition( + name: .init(value: "field"), + type: NamedType(name: .init(value: "String")) + ) + ] + ) + ] + ) ) } @@ -466,7 +495,7 @@ func namedTypeNode(_ name: String) -> NamedType { typeNode("Wo"), typeNode("rld"), ] - ), + ) ] ) @@ -478,23 +507,24 @@ func namedTypeNode(_ name: String) -> NamedType { #expect( try parse( source: "interface Hello implements & Wo & rld { field: String }" - ) == Document( - definitions: [ - InterfaceTypeDefinition( - name: nameNode("Hello"), - interfaces: [ - typeNode("Wo"), - typeNode("rld"), - ], - fields: [ - FieldDefinition( - name: .init(value: "field"), - type: NamedType(name: .init(value: "String")) - ), - ] - ), - ] ) + == Document( + definitions: [ + InterfaceTypeDefinition( + name: nameNode("Hello"), + interfaces: [ + typeNode("Wo"), + typeNode("rld"), + ], + fields: [ + FieldDefinition( + name: .init(value: "field"), + type: NamedType(name: .init(value: "String")) + ) + ] + ) + ] + ) ) } @@ -506,9 +536,9 @@ func namedTypeNode(_ name: String) -> NamedType { EnumTypeDefinition( name: nameNode("Hello"), values: [ - enumValueNode("WORLD"), + enumValueNode("WORLD") ] - ), + ) ] ) @@ -527,7 +557,7 @@ func namedTypeNode(_ name: String) -> NamedType { enumValueNode("WO"), enumValueNode("RLD"), ] - ), + ) ] ) @@ -546,9 +576,9 @@ func namedTypeNode(_ name: String) -> NamedType { fieldNode( nameNode("world"), typeNode("String") - ), + ) ] - ), + ) ] ) @@ -571,11 +601,11 @@ func namedTypeNode(_ name: String) -> NamedType { inputValueNode( nameNode("flag"), typeNode("Boolean") - ), + ) ] - ), + ) ] - ), + ) ] ) @@ -599,11 +629,11 @@ func namedTypeNode(_ name: String) -> NamedType { nameNode("flag"), typeNode("Boolean"), BooleanValue(value: true) - ), + ) ] - ), + ) ] - ), + ) ] ) @@ -626,11 +656,11 @@ func namedTypeNode(_ name: String) -> NamedType { inputValueNode( nameNode("things"), ListType(type: typeNode("String")) - ), + ) ] - ), + ) ] - ), + ) ] ) @@ -659,9 +689,9 @@ func namedTypeNode(_ name: String) -> NamedType { typeNode("Int") ), ] - ), + ) ] - ), + ) ] ) @@ -677,9 +707,9 @@ func namedTypeNode(_ name: String) -> NamedType { UnionTypeDefinition( name: nameNode("Hello"), types: [ - typeNode("World"), + typeNode("World") ] - ), + ) ] ) @@ -698,7 +728,7 @@ func namedTypeNode(_ name: String) -> NamedType { typeNode("Wo"), typeNode("Rld"), ] - ), + ) ] ) @@ -713,7 +743,7 @@ func namedTypeNode(_ name: String) -> NamedType { definitions: [ ScalarTypeDefinition( name: nameNode("Hello") - ), + ) ] ) @@ -732,9 +762,9 @@ func namedTypeNode(_ name: String) -> NamedType { inputValueNode( nameNode("world"), typeNode("String") - ), + ) ] - ), + ) ] ) @@ -755,7 +785,7 @@ func namedTypeNode(_ name: String) -> NamedType { OperationTypeDefinition( operation: .query, type: namedTypeNode("Hello") - ), + ) ] ) let result = try parse(source: source) @@ -774,7 +804,7 @@ func namedTypeNode(_ name: String) -> NamedType { fieldNode( nameNode("world"), typeNode("String") - ), + ) ] ) @@ -791,14 +821,14 @@ func namedTypeNode(_ name: String) -> NamedType { @Test func typeWitMultilinehDescription() throws { let source = #""" - """ - The Hello type. - Multi-line description - """ - type Hello { - world: String - } - """# + """ + The Hello type. + Multi-line description + """ + type Hello { + world: String + } + """# let expected = Document( definitions: [ @@ -812,9 +842,9 @@ func namedTypeNode(_ name: String) -> NamedType { fieldNode( nameNode("world"), typeNode("String") - ), + ) ] - ), + ) ] ) @@ -839,12 +869,12 @@ func namedTypeNode(_ name: String) -> NamedType { nameNode("a"), typeNode("String"), StringValue(value: "hello", block: false) - ), + ) ], locations: [ - nameNode("FIELD"), + nameNode("FIELD") ] - ), + ) ] ) @@ -854,11 +884,11 @@ func namedTypeNode(_ name: String) -> NamedType { @Test func directiveMultilineDesciption() throws { let source = #""" - """ - directive description - """ - directive @Test(a: String = "hello") on FIELD - """# + """ + directive description + """ + directive @Test(a: String = "hello") on FIELD + """# let expected = Document( definitions: [ DirectiveDefinition( @@ -873,12 +903,12 @@ func namedTypeNode(_ name: String) -> NamedType { nameNode("a"), typeNode("String"), StringValue(value: "hello", block: false) - ), + ) ], locations: [ - nameNode("FIELD"), + nameNode("FIELD") ] - ), + ) ] ) @@ -896,7 +926,7 @@ func namedTypeNode(_ name: String) -> NamedType { OperationTypeDefinition( operation: .query, type: namedTypeNode("Hello") - ), + ) ] ) let result = try parse(source: source) @@ -911,7 +941,7 @@ func namedTypeNode(_ name: String) -> NamedType { ScalarTypeDefinition( description: StringValue(value: "Hello Scaler Test", block: false), name: nameNode("Hello") - ), + ) ] ) @@ -931,9 +961,9 @@ func namedTypeNode(_ name: String) -> NamedType { fieldNode( nameNode("world"), typeNode("String") - ), + ) ] - ), + ) ] ) @@ -950,9 +980,9 @@ func namedTypeNode(_ name: String) -> NamedType { description: StringValue(value: "Hello World Union!", block: false), name: nameNode("Hello"), types: [ - typeNode("World"), + typeNode("World") ] - ), + ) ] ) @@ -969,9 +999,9 @@ func namedTypeNode(_ name: String) -> NamedType { description: StringValue(value: "Hello World Enum...", block: false), name: nameNode("Hello"), values: [ - enumValueNode("WORLD"), + enumValueNode("WORLD") ] - ), + ) ] ) @@ -991,9 +1021,9 @@ func namedTypeNode(_ name: String) -> NamedType { inputValueNode( nameNode("world"), typeNode("String") - ), + ) ] - ), + ) ] ) @@ -1005,13 +1035,13 @@ func namedTypeNode(_ name: String) -> NamedType { @Test func singleValueEnumWithDescription() throws { let source = """ - enum Hello { - "world description" - WORLD - "Hello there" - HELLO - } - """ + enum Hello { + "world description" + WORLD + "Hello there" + HELLO + } + """ let expected = Document( definitions: [ @@ -1027,7 +1057,7 @@ func namedTypeNode(_ name: String) -> NamedType { "HELLO" ), ] - ), + ) ] ) @@ -1047,9 +1077,9 @@ func namedTypeNode(_ name: String) -> NamedType { StringValue(value: "The world field.", block: false), nameNode("world"), typeNode("String") - ), + ) ] - ), + ) ] ) @@ -1059,14 +1089,14 @@ func namedTypeNode(_ name: String) -> NamedType { @Test func typeFieldWithMultilineDescription() throws { let source = #""" - type Hello { - """ - The world - field. - """ - world: String - } - """# + type Hello { + """ + The world + field. + """ + world: String + } + """# let expected = Document( definitions: [ @@ -1077,9 +1107,9 @@ func namedTypeNode(_ name: String) -> NamedType { StringValue(value: "The world\nfield.", block: true), nameNode("world"), typeNode("String") - ), + ) ] - ), + ) ] ) @@ -1099,9 +1129,9 @@ func namedTypeNode(_ name: String) -> NamedType { StringValue(value: "World field", block: false), nameNode("world"), typeNode("String") - ), + ) ] - ), + ) ] ) @@ -1114,7 +1144,7 @@ func namedTypeNode(_ name: String) -> NamedType { let expected = Document( definitions: [ - ObjectTypeDefinition(name: nameNode("UndefinedType")), + ObjectTypeDefinition(name: nameNode("UndefinedType")) ] ) @@ -1130,7 +1160,7 @@ func namedTypeNode(_ name: String) -> NamedType { InterfaceTypeDefinition( name: nameNode("UndefinedInterface"), fields: [] - ), + ) ] ) @@ -1147,11 +1177,11 @@ func namedTypeNode(_ name: String) -> NamedType { definition: InterfaceTypeDefinition( name: nameNode("Bar"), directives: [ - Directive(name: nameNode("onInterface")), + Directive(name: nameNode("onInterface")) ], fields: [] ) - ), + ) ] ) @@ -1167,13 +1197,13 @@ func namedTypeNode(_ name: String) -> NamedType { UnionTypeDefinition( name: nameNode("AnnotatedUnionTwo"), directives: [ - Directive(name: nameNode("onUnion")), + Directive(name: nameNode("onUnion")) ], types: [ NamedType(name: nameNode("A")), NamedType(name: nameNode("B")), ] - ), + ) ] ) @@ -1190,10 +1220,10 @@ func namedTypeNode(_ name: String) -> NamedType { definition: ScalarTypeDefinition( name: nameNode("CustomScalar"), directives: [ - Directive(name: nameNode("onScalar")), + Directive(name: nameNode("onScalar")) ] ) - ), + ) ] ) @@ -1209,7 +1239,7 @@ func namedTypeNode(_ name: String) -> NamedType { UnionTypeDefinition( name: nameNode("UndefinedUnion"), types: [] - ), + ) ] ) @@ -1230,7 +1260,7 @@ func namedTypeNode(_ name: String) -> NamedType { namedTypeNode("Video"), ] ) - ), + ) ] ) @@ -1246,7 +1276,7 @@ func namedTypeNode(_ name: String) -> NamedType { EnumTypeDefinition( name: nameNode("UndefinedEnum"), values: [] - ), + ) ] ) @@ -1263,11 +1293,11 @@ func namedTypeNode(_ name: String) -> NamedType { definition: EnumTypeDefinition( name: nameNode("Site"), directives: [ - Directive(name: nameNode("onEnum")), + Directive(name: nameNode("onEnum")) ], values: [] ) - ), + ) ] ) @@ -1283,7 +1313,7 @@ func namedTypeNode(_ name: String) -> NamedType { InputObjectTypeDefinition( name: nameNode("UndefinedInput"), fields: [] - ), + ) ] ) @@ -1300,11 +1330,11 @@ func namedTypeNode(_ name: String) -> NamedType { definition: InputObjectTypeDefinition( name: nameNode("InputType"), directives: [ - Directive(name: Name(value: "include")), + Directive(name: Name(value: "include")) ], fields: [] ) - ), + ) ] ) @@ -1314,11 +1344,11 @@ func namedTypeNode(_ name: String) -> NamedType { @Test func directivePipe() throws { let source = """ - directive @include2 on - | FIELD - | FRAGMENT_SPREAD - | INLINE_FRAGMENT - """ + directive @include2 on + | FIELD + | FRAGMENT_SPREAD + | INLINE_FRAGMENT + """ let expected = Document( definitions: [ @@ -1329,7 +1359,7 @@ func namedTypeNode(_ name: String) -> NamedType { nameNode("FRAGMENT_SPREAD"), nameNode("INLINE_FRAGMENT"), ] - ), + ) ] ) @@ -1339,10 +1369,10 @@ func namedTypeNode(_ name: String) -> NamedType { @Test func directiveRepeatable() throws { let source = """ - directive @myRepeatableDir repeatable on - | OBJECT - | INTERFACE - """ + directive @myRepeatableDir repeatable on + | OBJECT + | INTERFACE + """ let expected = Document( definitions: [ @@ -1353,7 +1383,7 @@ func namedTypeNode(_ name: String) -> NamedType { nameNode("INTERFACE"), ], repeatable: true - ), + ) ] ) @@ -1427,11 +1457,11 @@ func namedTypeNode(_ name: String) -> NamedType { ]) ), ] - ), + ) ], operationTypes: [] ) - ), + ) ] ) diff --git a/Tests/GraphQLTests/LanguageTests/SchemaPrinterTests.swift b/Tests/GraphQLTests/LanguageTests/SchemaPrinterTests.swift index c172aadc..7ef7e92a 100644 --- a/Tests/GraphQLTests/LanguageTests/SchemaPrinterTests.swift +++ b/Tests/GraphQLTests/LanguageTests/SchemaPrinterTests.swift @@ -1,7 +1,8 @@ import Foundation -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct SchemaPrinterTests { @Test func printsMinimalAST() { let ast = ScalarTypeDefinition( @@ -28,148 +29,150 @@ import Testing let printedAST = try parse(source: printed, noLocation: true) #expect(printed == print(ast: printedAST)) - #expect(printed == #""" - """This is a description of the schema as a whole.""" - schema { - query: QueryType - mutation: MutationType - } + #expect( + printed == #""" + """This is a description of the schema as a whole.""" + schema { + query: QueryType + mutation: MutationType + } + + """ + This is a description + of the `Foo` type. + """ + type Foo implements Bar & Baz & Two { + "Description of the `one` field." + one: Type + """This is a description of the `two` field.""" + two( + """This is a description of the `argument` argument.""" + argument: InputType! + ): Type + """This is a description of the `three` field.""" + three(argument: InputType, other: String): Int + four(argument: String = "string"): String + five(argument: [String] = ["string", "string"]): String + six(argument: InputType = { key: "value" }): Type + seven(argument: Int = null): Type + eight(argument: OneOfInputType): Type + } - """ - This is a description - of the `Foo` type. - """ - type Foo implements Bar & Baz & Two { - "Description of the `one` field." - one: Type - """This is a description of the `two` field.""" - two( - """This is a description of the `argument` argument.""" - argument: InputType! - ): Type - """This is a description of the `three` field.""" - three(argument: InputType, other: String): Int - four(argument: String = "string"): String - five(argument: [String] = ["string", "string"]): String - six(argument: InputType = { key: "value" }): Type - seven(argument: Int = null): Type - eight(argument: OneOfInputType): Type - } + type AnnotatedObject @onObject(arg: "value") { + annotatedField(arg: Type = "default" @onArgumentDefinition): Type @onField + } - type AnnotatedObject @onObject(arg: "value") { - annotatedField(arg: Type = "default" @onArgumentDefinition): Type @onField - } + type UndefinedType - type UndefinedType + extend type Foo { + seven(argument: [String]): Type + } - extend type Foo { - seven(argument: [String]): Type - } + extend type Foo @onType - extend type Foo @onType + interface Bar { + one: Type + four(argument: String = "string"): String + } - interface Bar { - one: Type - four(argument: String = "string"): String - } + interface AnnotatedInterface @onInterface { + annotatedField(arg: Type @onArgumentDefinition): Type @onField + } - interface AnnotatedInterface @onInterface { - annotatedField(arg: Type @onArgumentDefinition): Type @onField - } + interface UndefinedInterface - interface UndefinedInterface + extend interface Bar implements Two { + two(argument: InputType!): Type + } - extend interface Bar implements Two { - two(argument: InputType!): Type - } + extend interface Bar @onInterface - extend interface Bar @onInterface + interface Baz implements Bar & Two { + one: Type + two(argument: InputType!): Type + four(argument: String = "string"): String + } - interface Baz implements Bar & Two { - one: Type - two(argument: InputType!): Type - four(argument: String = "string"): String - } + union Feed = Story | Article | Advert - union Feed = Story | Article | Advert + union AnnotatedUnion @onUnion = A | B - union AnnotatedUnion @onUnion = A | B + union AnnotatedUnionTwo @onUnion = A | B - union AnnotatedUnionTwo @onUnion = A | B + union UndefinedUnion - union UndefinedUnion + extend union Feed = Photo | Video - extend union Feed = Photo | Video + extend union Feed @onUnion - extend union Feed @onUnion + scalar CustomScalar - scalar CustomScalar + scalar AnnotatedScalar @onScalar - scalar AnnotatedScalar @onScalar + extend scalar CustomScalar @onScalar - extend scalar CustomScalar @onScalar + enum Site { + """This is a description of the `DESKTOP` value""" + DESKTOP + """This is a description of the `MOBILE` value""" + MOBILE + "This is a description of the `WEB` value" + WEB + } - enum Site { - """This is a description of the `DESKTOP` value""" - DESKTOP - """This is a description of the `MOBILE` value""" - MOBILE - "This is a description of the `WEB` value" - WEB - } + enum AnnotatedEnum @onEnum { + ANNOTATED_VALUE @onEnumValue + OTHER_VALUE + } - enum AnnotatedEnum @onEnum { - ANNOTATED_VALUE @onEnumValue - OTHER_VALUE - } + enum UndefinedEnum - enum UndefinedEnum + extend enum Site { + VR + } - extend enum Site { - VR - } + extend enum Site @onEnum - extend enum Site @onEnum - - input InputType { - key: String! - answer: Int = 42 - } + input InputType { + key: String! + answer: Int = 42 + } - input OneOfInputType @oneOf { - string: String - int: Int - } + input OneOfInputType @oneOf { + string: String + int: Int + } - input AnnotatedInput @onInputObject { - annotatedField: Type @onInputFieldDefinition - } + input AnnotatedInput @onInputObject { + annotatedField: Type @onInputFieldDefinition + } - input UndefinedInput + input UndefinedInput - extend input InputType { - other: Float = 1.23e4 @onInputFieldDefinition - } + extend input InputType { + other: Float = 1.23e4 @onInputFieldDefinition + } - extend input InputType @onInputObject + extend input InputType @onInputObject - """This is a description of the `@skip` directive""" - directive @skip( - """This is a description of the `if` argument""" - if: Boolean! @onArgumentDefinition - ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + """This is a description of the `@skip` directive""" + directive @skip( + """This is a description of the `if` argument""" + if: Boolean! @onArgumentDefinition + ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - directive @include2(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + directive @include2(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - directive @myRepeatableDir(name: String!) repeatable on OBJECT | INTERFACE + directive @myRepeatableDir(name: String!) repeatable on OBJECT | INTERFACE - extend schema @onSchema + extend schema @onSchema - extend schema @onSchema { - subscription: SubscriptionType - } - """#) + extend schema @onSchema { + subscription: SubscriptionType + } + """# + ) } } diff --git a/Tests/GraphQLTests/LanguageTests/VisitorTests.swift b/Tests/GraphQLTests/LanguageTests/VisitorTests.swift index ece94b89..f359b770 100644 --- a/Tests/GraphQLTests/LanguageTests/VisitorTests.swift +++ b/Tests/GraphQLTests/LanguageTests/VisitorTests.swift @@ -1,7 +1,8 @@ import Foundation -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct VisitorTests { @Test func handlesEmptyVisitor() throws { let ast = try parse(source: "{ a }", noLocation: true) @@ -12,18 +13,21 @@ import Testing var visited = [VisitedPath]() let ast = try parse(source: "{ a }", noLocation: true) - visit(root: ast, visitor: .init( - enter: { node, key, parent, path, ancestors in - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - visited.append(.init(.enter, path)) - return .continue - }, - leave: { node, key, parent, path, ancestors in - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - visited.append(.init(.leave, path)) - return .continue - } - )) + visit( + root: ast, + visitor: .init( + enter: { node, key, parent, path, ancestors in + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + visited.append(.init(.enter, path)) + return .continue + }, + leave: { node, key, parent, path, ancestors in + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + visited.append(.init(.leave, path)) + return .continue + } + ) + ) #expect( visited == [ @@ -45,33 +49,42 @@ import Testing var visited = [NodeResult]() let ast = try parse(source: "{ a }", noLocation: true) - visit(root: ast, visitor: .init( - enter: { node, _, parent, _, ancestors in - if let parent = parent, parent.isArray { - visited.append(parent) - } - visited.append(.node(node)) - - let expectedAncestors = visited[0 ... max(visited.count - 2, 0)] - #expect(zip(ancestors, expectedAncestors).allSatisfy { lhs, rhs in - nodeResultsEqual(lhs, rhs) - }, "actual: \(ancestors), expected: \(expectedAncestors)") - return .continue - }, - leave: { _, _, parent, _, ancestors in - let expectedAncestors = visited[0 ... max(visited.count - 2, 0)] - #expect(zip(ancestors, expectedAncestors).allSatisfy { lhs, rhs in - nodeResultsEqual(lhs, rhs) - }, "actual: \(ancestors), expected: \(expectedAncestors)") - - if let parent = parent, parent.isArray { + visit( + root: ast, + visitor: .init( + enter: { node, _, parent, _, ancestors in + if let parent = parent, parent.isArray { + visited.append(parent) + } + visited.append(.node(node)) + + let expectedAncestors = visited[0...max(visited.count - 2, 0)] + #expect( + zip(ancestors, expectedAncestors).allSatisfy { lhs, rhs in + nodeResultsEqual(lhs, rhs) + }, + "actual: \(ancestors), expected: \(expectedAncestors)" + ) + return .continue + }, + leave: { _, _, parent, _, ancestors in + let expectedAncestors = visited[0...max(visited.count - 2, 0)] + #expect( + zip(ancestors, expectedAncestors).allSatisfy { lhs, rhs in + nodeResultsEqual(lhs, rhs) + }, + "actual: \(ancestors), expected: \(expectedAncestors)" + ) + + if let parent = parent, parent.isArray { + visited.removeLast() + } visited.removeLast() - } - visited.removeLast() - return .continue - } - )) + return .continue + } + ) + ) } @Test func allowsEditingANodeBothOnEnterAndOnLeave() throws { @@ -79,35 +92,42 @@ import Testing var selectionSet: SelectionSet? - let editedASTNode = visit(root: ast, visitor: .init( - enter: { node, key, parent, path, ancestors in - if let node = node as? OperationDefinition { - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - selectionSet = node.selectionSet - let newName = node.name - .map { Name(loc: $0.loc, value: $0.value + ".enter") } ?? - Name(value: "enter") - let newNode = node - .set(value: .node(newName), key: "name") - .set(value: .node(SelectionSet(selections: [])), key: "selectionSet") - return .node(newNode) - } - return .continue - }, - leave: { node, key, parent, path, ancestors in - if let node = node as? OperationDefinition { - checkVisitorFnArgs(ast, node, key, parent, path, ancestors, isEdited: true) - let newName = node.name - .map { Name(loc: $0.loc, value: $0.value + ".leave") } ?? - Name(value: "leave") - let newNode = node - .set(value: .node(newName), key: "name") - .set(value: .node(selectionSet!), key: "selectionSet") - return .node(newNode) + let editedASTNode = visit( + root: ast, + visitor: .init( + enter: { node, key, parent, path, ancestors in + if let node = node as? OperationDefinition { + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + selectionSet = node.selectionSet + let newName = + node.name + .map { Name(loc: $0.loc, value: $0.value + ".enter") } + ?? Name(value: "enter") + let newNode = + node + .set(value: .node(newName), key: "name") + .set(value: .node(SelectionSet(selections: [])), key: "selectionSet") + return .node(newNode) + } + return .continue + }, + leave: { node, key, parent, path, ancestors in + if let node = node as? OperationDefinition { + checkVisitorFnArgs(ast, node, key, parent, path, ancestors, isEdited: true) + let newName = + node.name + .map { Name(loc: $0.loc, value: $0.value + ".leave") } + ?? Name(value: "leave") + let newNode = + node + .set(value: .node(newName), key: "name") + .set(value: .node(selectionSet!), key: "selectionSet") + return .node(newNode) + } + return .continue } - return .continue - } - )) + ) + ) let editedAST = try #require(editedASTNode as? Document) let operations = try #require(editedAST.definitions as? [OperationDefinition]) @@ -120,44 +140,47 @@ import Testing @Test func allowsEditingTheRootNodeOnEnterAndOnLeave() throws { let ast = try parse(source: "{ a, b, c { a, b, c } }", noLocation: true) - let editedASTNode = visit(root: ast, visitor: .init( - enter: { node, key, parent, path, ancestors in - if let node = node as? Document { - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - var newDefinitions = node.definitions - newDefinitions.append( - DirectiveDefinition( - name: .init(value: "enter"), - locations: [.init(value: "root")] + let editedASTNode = visit( + root: ast, + visitor: .init( + enter: { node, key, parent, path, ancestors in + if let node = node as? Document { + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + var newDefinitions = node.definitions + newDefinitions.append( + DirectiveDefinition( + name: .init(value: "enter"), + locations: [.init(value: "root")] + ) ) - ) - let newNode = node.set( - value: .array(newDefinitions), - key: "definitions" - ) - return .node(newNode) - } - return .continue - }, - leave: { node, key, parent, path, ancestors in - if let node = node as? Document { - checkVisitorFnArgs(ast, node, key, parent, path, ancestors, isEdited: true) - var newDefinitions = node.definitions - newDefinitions.append( - DirectiveDefinition( - name: .init(value: "leave"), - locations: [.init(value: "root")] + let newNode = node.set( + value: .array(newDefinitions), + key: "definitions" ) - ) - let newNode = node.set( - value: .array(newDefinitions), - key: "definitions" - ) - return .node(newNode) + return .node(newNode) + } + return .continue + }, + leave: { node, key, parent, path, ancestors in + if let node = node as? Document { + checkVisitorFnArgs(ast, node, key, parent, path, ancestors, isEdited: true) + var newDefinitions = node.definitions + newDefinitions.append( + DirectiveDefinition( + name: .init(value: "leave"), + locations: [.init(value: "root")] + ) + ) + let newNode = node.set( + value: .array(newDefinitions), + key: "definitions" + ) + return .node(newNode) + } + return .continue } - return .continue - } - )) + ) + ) let editedAST = try #require(editedASTNode as? Document) #expect(editedAST.definitions.count == 3) @@ -176,76 +199,84 @@ import Testing @Test func allowsForEditingOnEnter() throws { let ast = try parse(source: "{ a, b, c { a, b, c } }", noLocation: true) - let editedASTNode = visit(root: ast, visitor: .init( - enter: { node, key, parent, path, ancestors in - if let node = node as? Field { - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - if node.name.value == "b" { - return .node(nil) + let editedASTNode = visit( + root: ast, + visitor: .init( + enter: { node, key, parent, path, ancestors in + if let node = node as? Field { + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + if node.name.value == "b" { + return .node(nil) + } } + return .continue } - return .continue - } - )) + ) + ) let editedAST = try #require(editedASTNode as? Document) let operation = try #require(editedAST.definitions[0] as? OperationDefinition) #expect( - operation.selectionSet.selections.count == 2 // "b" is ignored + operation.selectionSet.selections.count == 2 // "b" is ignored ) let cField = try #require(operation.selectionSet.selections[1] as? Field) #expect( - cField.selectionSet?.selections.count == 2 // "b" is ignored + cField.selectionSet?.selections.count == 2 // "b" is ignored ) } @Test func allowsForEditingOnLeave() throws { let ast = try parse(source: "{ a, b, c { a, b, c } }", noLocation: true) - let editedASTNode = visit(root: ast, visitor: .init( - leave: { node, key, parent, path, ancestors in - if let node = node as? Field { - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - if node.name.value == "b" { - return .node(nil) + let editedASTNode = visit( + root: ast, + visitor: .init( + leave: { node, key, parent, path, ancestors in + if let node = node as? Field { + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + if node.name.value == "b" { + return .node(nil) + } } + return .continue } - return .continue - } - )) + ) + ) let editedAST = try #require(editedASTNode as? Document) let operation = try #require(editedAST.definitions[0] as? OperationDefinition) #expect( - operation.selectionSet.selections.count == 2 // "b" is removed + operation.selectionSet.selections.count == 2 // "b" is removed ) let cField = try #require(operation.selectionSet.selections[1] as? Field) #expect( - cField.selectionSet?.selections.count == 2 // "b" is removed + cField.selectionSet?.selections.count == 2 // "b" is removed ) } @Test func ignoresSkipReturnedOnLeave() throws { let ast = try parse(source: "{ a, b, c { a, b, c } }", noLocation: true) - let editedASTNode = visit(root: ast, visitor: .init( - leave: { _, _, _, _, _ in - .skip // graphql-js 'false' is Swift '.skip' - } - )) + let editedASTNode = visit( + root: ast, + visitor: .init( + leave: { _, _, _, _, _ in + .skip // graphql-js 'false' is Swift '.skip' + } + ) + ) let editedAST = try #require(editedASTNode as? Document) let operation = try #require(editedAST.definitions[0] as? OperationDefinition) #expect( - operation.selectionSet.selections.count == - 3 // "b" remains + operation.selectionSet.selections.count == 3 // "b" remains ) let cField = try #require(operation.selectionSet.selections[2] as? Field) #expect( - cField.selectionSet?.selections.count == 3 // "b" remains + cField.selectionSet?.selections.count == 3 // "b" remains ) } @@ -257,30 +288,36 @@ import Testing var didVisitAddedField = false let ast = try parse(source: "{ a { x } }", noLocation: true) - visit(root: ast, visitor: .init( - enter: { node, key, parent, path, ancestors in - checkVisitorFnArgs(ast, node, key, parent, path, ancestors, isEdited: true) - if let node = node as? Field, node.name.value == "a" { - if let selectionSet = node.selectionSet { - var newSelections = selectionSet.selections - newSelections.append(addedField) - - var newSelectionSet = selectionSet - newSelectionSet = newSelectionSet.set( - value: .array(newSelections), - key: "selections" - ) - - let newNode = node.set(value: .node(newSelectionSet), key: "selectionSet") - return .node(newNode) + visit( + root: ast, + visitor: .init( + enter: { node, key, parent, path, ancestors in + checkVisitorFnArgs(ast, node, key, parent, path, ancestors, isEdited: true) + if let node = node as? Field, node.name.value == "a" { + if let selectionSet = node.selectionSet { + var newSelections = selectionSet.selections + newSelections.append(addedField) + + var newSelectionSet = selectionSet + newSelectionSet = newSelectionSet.set( + value: .array(newSelections), + key: "selections" + ) + + let newNode = node.set( + value: .node(newSelectionSet), + key: "selectionSet" + ) + return .node(newNode) + } } + if let node = node as? Field, node.name.value == "__typename" { + didVisitAddedField = true + } + return .continue } - if let node = node as? Field, node.name.value == "__typename" { - didVisitAddedField = true - } - return .continue - } - )) + ) + ) #expect(didVisitAddedField) } @@ -301,21 +338,24 @@ import Testing var visited = [VisitedElement]() let ast = try parse(source: "{ a, b { x }, c }", noLocation: true) - visit(root: ast, visitor: .init( - enter: { node, key, parent, path, ancestors in - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - visited.append(.init(.enter, node.kind, getValue(node: node))) - if let node = node as? Field, node.name.value == "b" { - return .skip + visit( + root: ast, + visitor: .init( + enter: { node, key, parent, path, ancestors in + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + visited.append(.init(.enter, node.kind, getValue(node: node))) + if let node = node as? Field, node.name.value == "b" { + return .skip + } + return .continue + }, + leave: { node, key, parent, path, ancestors in + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + visited.append(.init(.leave, node.kind, getValue(node: node))) + return .continue } - return .continue - }, - leave: { node, key, parent, path, ancestors in - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - visited.append(.init(.leave, node.kind, getValue(node: node))) - return .continue - } - )) + ) + ) #expect( visited == [ @@ -354,21 +394,24 @@ import Testing var visited = [VisitedElement]() let ast = try parse(source: "{ a, b { x }, c }", noLocation: true) - visit(root: ast, visitor: .init( - enter: { node, key, parent, path, ancestors in - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - visited.append(.init(.enter, node.kind, getValue(node: node))) - if let node = node as? Name, node.value == "x" { - return .break + visit( + root: ast, + visitor: .init( + enter: { node, key, parent, path, ancestors in + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + visited.append(.init(.enter, node.kind, getValue(node: node))) + if let node = node as? Name, node.value == "x" { + return .break + } + return .continue + }, + leave: { node, key, parent, path, ancestors in + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + visited.append(.init(.leave, node.kind, getValue(node: node))) + return .continue } - return .continue - }, - leave: { node, key, parent, path, ancestors in - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - visited.append(.init(.leave, node.kind, getValue(node: node))) - return .continue - } - )) + ) + ) #expect( visited == [ @@ -405,21 +448,24 @@ import Testing var visited = [VisitedElement]() let ast = try parse(source: "{ a, b { x }, c }", noLocation: true) - visit(root: ast, visitor: .init( - enter: { node, key, parent, path, ancestors in - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - visited.append(.init(.enter, node.kind, getValue(node: node))) - return .continue - }, - leave: { node, key, parent, path, ancestors in - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - visited.append(.init(.leave, node.kind, getValue(node: node))) - if let node = node as? Name, node.value == "x" { - return .break + visit( + root: ast, + visitor: .init( + enter: { node, key, parent, path, ancestors in + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + visited.append(.init(.enter, node.kind, getValue(node: node))) + return .continue + }, + leave: { node, key, parent, path, ancestors in + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + visited.append(.init(.leave, node.kind, getValue(node: node))) + if let node = node as? Name, node.value == "x" { + return .break + } + return .continue } - return .continue - } - )) + ) + ) #expect( visited == [ @@ -457,26 +503,29 @@ import Testing var visited = [VisitedElement]() let ast = try parse(source: "{ a, b { x }, c }", noLocation: true) - visit(root: ast, visitor: .init( - enter: { node, key, parent, path, ancestors in - if let node = node as? Name { - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - visited.append(.init(.enter, node.kind, getValue(node: node))) - } - if let node = node as? SelectionSet { - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - visited.append(.init(.enter, node.kind, getValue(node: node))) - } - return .continue - }, - leave: { node, key, parent, path, ancestors in - if let node = node as? SelectionSet { - checkVisitorFnArgs(ast, node, key, parent, path, ancestors) - visited.append(.init(.leave, node.kind, getValue(node: node))) + visit( + root: ast, + visitor: .init( + enter: { node, key, parent, path, ancestors in + if let node = node as? Name { + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + visited.append(.init(.enter, node.kind, getValue(node: node))) + } + if let node = node as? SelectionSet { + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + visited.append(.init(.enter, node.kind, getValue(node: node))) + } + return .continue + }, + leave: { node, key, parent, path, ancestors in + if let node = node as? SelectionSet { + checkVisitorFnArgs(ast, node, key, parent, path, ancestors) + visited.append(.init(.leave, node.kind, getValue(node: node))) + } + return .continue } - return .continue - } - )) + ) + ) #expect( visited == [ @@ -504,25 +553,28 @@ import Testing } let ast = try parse(source: kitchenSink) - visit(root: ast, visitor: .init( - enter: { node, key, parent, _, _ in - var parentKind: Kind? - if case let .node(parent) = parent { - parentKind = parent.kind - } - visited.append(.init(.enter, node.kind, key, parentKind)) - return .continue - }, - leave: { node, key, parent, _, _ in - var parentKind: Kind? - if case let .node(parent) = parent { - parentKind = parent.kind - } - visited.append(.init(.leave, node.kind, key, parentKind)) + visit( + root: ast, + visitor: .init( + enter: { node, key, parent, _, _ in + var parentKind: Kind? + if case .node(let parent) = parent { + parentKind = parent.kind + } + visited.append(.init(.enter, node.kind, key, parentKind)) + return .continue + }, + leave: { node, key, parent, _, _ in + var parentKind: Kind? + if case .node(let parent) = parent { + parentKind = parent.kind + } + visited.append(.init(.leave, node.kind, key, parentKind)) - return .continue - } - )) + return .continue + } + ) + ) #expect( visited == [ @@ -846,8 +898,8 @@ struct VisitedPath { extension VisitedPath: Equatable { static func == (lhs: VisitedPath, rhs: VisitedPath) -> Bool { - return lhs.direction == rhs.direction && - zip(lhs.path, rhs.path).allSatisfy { lhs, rhs in + return lhs.direction == rhs.direction + && zip(lhs.path, rhs.path).allSatisfy { lhs, rhs in lhs.description == rhs.description } } @@ -874,10 +926,8 @@ struct VisitedKindAndParent { extension VisitedKindAndParent: Equatable { static func == (lhs: VisitedKindAndParent, rhs: VisitedKindAndParent) -> Bool { - return lhs.direction == rhs.direction && - lhs.kind == rhs.kind && - lhs.key?.description == rhs.key?.description && - lhs.parentKind == rhs.parentKind + return lhs.direction == rhs.direction && lhs.kind == rhs.kind + && lhs.key?.description == rhs.key?.description && lhs.parentKind == rhs.parentKind } } @@ -937,16 +987,16 @@ func checkVisitorFnArgs( func nodeResultsEqual(_ n1: NodeResult, _ n2: NodeResult) -> Bool { switch n1 { - case let .node(n1): + case .node(let n1): switch n2 { - case let .node(n2): + case .node(let n2): return n1.kind == n2.kind && n1.loc == n2.loc default: return false } - case let .array(n1): + case .array(let n1): switch n2 { - case let .array(n2): + case .array(let n2): return zip(n1, n2).allSatisfy { n1, n2 in nodesEqual(n1, n2) } diff --git a/Tests/GraphQLTests/MapTests/MapTests.swift b/Tests/GraphQLTests/MapTests/MapTests.swift index 6333cfa2..171c3062 100644 --- a/Tests/GraphQLTests/MapTests/MapTests.swift +++ b/Tests/GraphQLTests/MapTests/MapTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct MapTests { @Test func throwableConversion() throws { #expect(try Map.number(5).intValue() == 5) @@ -66,7 +67,7 @@ import Testing "first": .number(1), "second": .null, "third": .undefined, - // fourth not included + // fourth not included ] ) @@ -124,7 +125,7 @@ import Testing "first": .number(1), "second": .null, "third": .undefined, - // fourth not included + // fourth not included ] ) @@ -145,8 +146,8 @@ import Testing let json = String(data: data, encoding: .utf8) #expect( json == """ - {"first":1,"second":null} - """ + {"first":1,"second":null} + """ ) } @@ -169,8 +170,8 @@ import Testing ), encoding: .utf8 ) == """ - {"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8} - """ + {"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8} + """ ) // Test embedded @@ -187,13 +188,13 @@ import Testing "6": .number(6), "7": .number(7), "8": .number(8), - ]), + ]) ]) ), encoding: .utf8 ) == """ - [{"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8}] - """ + [{"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8}] + """ ) } } diff --git a/Tests/GraphQLTests/PersistedQueriesTests/PersistedQueriesTests.swift b/Tests/GraphQLTests/PersistedQueriesTests/PersistedQueriesTests.swift index b8c29ba2..0a4352a4 100644 --- a/Tests/GraphQLTests/PersistedQueriesTests/PersistedQueriesTests.swift +++ b/Tests/GraphQLTests/PersistedQueriesTests/PersistedQueriesTests.swift @@ -2,140 +2,140 @@ import GraphQL import Testing @Suite struct PersistedQueriesTests { -// let schema = try! GraphQLSchema( -// query: GraphQLObjectType( -// name: "RootQueryType", -// fields: [ -// "hello": GraphQLField( -// type: GraphQLString, -// resolve: { _, _, _, _ in "world" } -// ) -// ] -// ) -// ) -// -// @Test func lookupWithUnknownId() throws { -// let result = try lookup("unknown_id") -// switch result { -// case .unknownId(let id): -// #expect(id == "unknown_id") -// return -// default: -// Issue.record("Expected unknownId result, got \(result)") -// } -// } -// -// @Test func lookupWithParseError() throws { -// let result = try lookup("parse_error") -// switch result { -// case .parseError(let error): -// #expect(String(error.message.prefix(57)) == "Syntax Error parse_error (1:4) -// Expected Name, found ") -// #expect(error.locations.first?.line == 1) -// #expect(error.locations.first?.column == 4) -// return -// default: -// Issue.record("Expected parseError result, got \(result)") -// } -// } -// -// @Test func lookupWithValidationErrors() throws { -// let result = try lookup("validation_errors") -// switch result { -// case .validateErrors(let schema, let errors): -// #expect(schema === self.schema) -// #expect(errors.count == 1) -// #expect(errors.first?.message == "Cannot query field \"boyhowdy\" on type -// \"RootQueryType\".") -// #expect(errors.first?.locations.first?.line == 1) -// #expect(errors.first?.locations.first?.column == 3) -// return -// default: -// Issue.record("Expected validateErrors result, got \(result)") -// } -// } -// -// @Test func lookupWithResult() throws { -// let result = try lookup("result") -// switch result { -// case .result(let schema, _): -// #expect(schema === self.schema) -// return -// default: -// Issue.record("Expected result result, got \(result)") -// } -// } -// -// @Test func graphQLWithUnknownId() throws { -// do { -// _ = try graphql(queryRetrieval: self, queryId: "unknown_id") -// } catch let error as GraphQLError { -// #expect(error.message == "Unknown query id") -// } -// } -// -// @Test func graphQLWithWithParseError() throws { -// do { -// _ = try graphql(queryRetrieval: self, queryId: "parse_error") -// } catch let error as GraphQLError { -// #expect(String(error.message.prefix(57)) == "Syntax Error parse_error (1:4) -// Expected Name, found ") -// #expect(error.locations.first?.line == 1) -// #expect(error.locations.first?.column == 4) -// } -// } -// -// @Test func graphQLWithWithValidationErrors() throws { -// let expected: Map = [ -// "errors": [ -// [ -// "message": "Cannot query field \"boyhowdy\" on type \"RootQueryType\".", -// "locations": [["line": 1, "column": 3]] -// ] -// ] -// ] -// let result = try graphql(queryRetrieval: self, queryId: "validation_errors") -// #expect(result == expected) -// } -// -// @Test func graphQLWithWithResult() throws { -// let expected: Map = [ -// "data": [ -// "hello": "world" -// ] -// ] -// let result = try graphql(queryRetrieval: self, queryId: "result") -// #expect(result == expected) -// } -// + // let schema = try! GraphQLSchema( + // query: GraphQLObjectType( + // name: "RootQueryType", + // fields: [ + // "hello": GraphQLField( + // type: GraphQLString, + // resolve: { _, _, _, _ in "world" } + // ) + // ] + // ) + // ) + // + // @Test func lookupWithUnknownId() throws { + // let result = try lookup("unknown_id") + // switch result { + // case .unknownId(let id): + // #expect(id == "unknown_id") + // return + // default: + // Issue.record("Expected unknownId result, got \(result)") + // } + // } + // + // @Test func lookupWithParseError() throws { + // let result = try lookup("parse_error") + // switch result { + // case .parseError(let error): + // #expect(String(error.message.prefix(57)) == "Syntax Error parse_error (1:4) + // Expected Name, found ") + // #expect(error.locations.first?.line == 1) + // #expect(error.locations.first?.column == 4) + // return + // default: + // Issue.record("Expected parseError result, got \(result)") + // } + // } + // + // @Test func lookupWithValidationErrors() throws { + // let result = try lookup("validation_errors") + // switch result { + // case .validateErrors(let schema, let errors): + // #expect(schema === self.schema) + // #expect(errors.count == 1) + // #expect(errors.first?.message == "Cannot query field \"boyhowdy\" on type + // \"RootQueryType\".") + // #expect(errors.first?.locations.first?.line == 1) + // #expect(errors.first?.locations.first?.column == 3) + // return + // default: + // Issue.record("Expected validateErrors result, got \(result)") + // } + // } + // + // @Test func lookupWithResult() throws { + // let result = try lookup("result") + // switch result { + // case .result(let schema, _): + // #expect(schema === self.schema) + // return + // default: + // Issue.record("Expected result result, got \(result)") + // } + // } + // + // @Test func graphQLWithUnknownId() throws { + // do { + // _ = try graphql(queryRetrieval: self, queryId: "unknown_id") + // } catch let error as GraphQLError { + // #expect(error.message == "Unknown query id") + // } + // } + // + // @Test func graphQLWithWithParseError() throws { + // do { + // _ = try graphql(queryRetrieval: self, queryId: "parse_error") + // } catch let error as GraphQLError { + // #expect(String(error.message.prefix(57)) == "Syntax Error parse_error (1:4) + // Expected Name, found ") + // #expect(error.locations.first?.line == 1) + // #expect(error.locations.first?.column == 4) + // } + // } + // + // @Test func graphQLWithWithValidationErrors() throws { + // let expected: Map = [ + // "errors": [ + // [ + // "message": "Cannot query field \"boyhowdy\" on type \"RootQueryType\".", + // "locations": [["line": 1, "column": 3]] + // ] + // ] + // ] + // let result = try graphql(queryRetrieval: self, queryId: "validation_errors") + // #expect(result == expected) + // } + // + // @Test func graphQLWithWithResult() throws { + // let expected: Map = [ + // "data": [ + // "hello": "world" + // ] + // ] + // let result = try graphql(queryRetrieval: self, queryId: "result") + // #expect(result == expected) + // } + // // } -// + // // extension PersistedQueriesTests: PersistedQueryRetrieval { -// typealias Id = String -// -// func lookup(_ id: Id) throws -> PersistedQueryRetrievalResult { -// let source: Source -// switch id { -// case "parse_error": -// source = Source(body: "{ x", name: id) -// case "validation_errors": -// source = Source(body: "{ boyhowdy }", name: id) -// case "result": -// source = Source(body: "{ hello }", name: id) -// default: -// return .unknownId(id) -// } -// do { -// let document = try parse(source: source) -// let validateErrors = validate(schema: schema, ast: document) -// if validateErrors.isEmpty { -// return .result(schema, document) -// } -// return .validateErrors(schema, validateErrors) -// } catch let error as GraphQLError { -// return .parseError(error) -// } catch { -// throw error -// } -// } + // typealias Id = String + // + // func lookup(_ id: Id) throws -> PersistedQueryRetrievalResult { + // let source: Source + // switch id { + // case "parse_error": + // source = Source(body: "{ x", name: id) + // case "validation_errors": + // source = Source(body: "{ boyhowdy }", name: id) + // case "result": + // source = Source(body: "{ hello }", name: id) + // default: + // return .unknownId(id) + // } + // do { + // let document = try parse(source: source) + // let validateErrors = validate(schema: schema, ast: document) + // if validateErrors.isEmpty { + // return .result(schema, document) + // } + // return .validateErrors(schema, validateErrors) + // } catch let error as GraphQLError { + // return .parseError(error) + // } catch { + // throw error + // } + // } } diff --git a/Tests/GraphQLTests/StarWarsTests/StarWarsData.swift b/Tests/GraphQLTests/StarWarsTests/StarWarsData.swift index 29b8bef7..d7b1a15c 100644 --- a/Tests/GraphQLTests/StarWarsTests/StarWarsData.swift +++ b/Tests/GraphQLTests/StarWarsTests/StarWarsData.swift @@ -126,16 +126,12 @@ let droidData: [String: Droid] = [ "2001": r2d2, ] -/** - * Helper function to get a character by ID. - */ +/// Helper function to get a character by ID. @Sendable func getCharacter(id: String) -> Character? { return humanData[id] ?? droidData[id] } -/** - * Allows us to query for a character"s friends. - */ +/// Allows us to query for a character"s friends. @Sendable func getFriends(character: Character) -> [Character] { return character.friends.reduce(into: []) { friends, friendID in if let friend = getCharacter(id: friendID) { @@ -144,9 +140,7 @@ let droidData: [String: Droid] = [ } } -/** - * Allows us to fetch the undisputed hero of the Star Wars trilogy, R2-D2. - */ +/// Allows us to fetch the undisputed hero of the Star Wars trilogy, R2-D2. @Sendable func getHero(episode: Episode?) -> Character { if episode == .empire { // Luke is the hero of Episode V. @@ -156,16 +150,12 @@ let droidData: [String: Droid] = [ return r2d2 } -/** - * Allows us to query for the human with the given id. - */ +/// Allows us to query for the human with the given id. @Sendable func getHuman(id: String) -> Human? { return humanData[id] } -/** - * Allows us to query for the droid with the given id. - */ +/// Allows us to query for the droid with the given id. @Sendable func getDroid(id: String) -> Droid? { return droidData[id] } diff --git a/Tests/GraphQLTests/StarWarsTests/StarWarsIntrospectionTests.swift b/Tests/GraphQLTests/StarWarsTests/StarWarsIntrospectionTests.swift index c30437b6..692214c6 100644 --- a/Tests/GraphQLTests/StarWarsTests/StarWarsIntrospectionTests.swift +++ b/Tests/GraphQLTests/StarWarsTests/StarWarsIntrospectionTests.swift @@ -1,68 +1,66 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct StarWarsIntrospectionTests { @Test func introspectionTypeQuery() async throws { do { - let query = "query IntrospectionTypeQuery {" + - " __schema {" + - " types {" + - " name" + - " }" + - " }" + - "}" + let query = + "query IntrospectionTypeQuery {" + " __schema {" + " types {" + + " name" + + " }" + " }" + "}" let expected = GraphQLResult( data: [ "__schema": [ "types": [ [ - "name": "Boolean", + "name": "Boolean" ], [ - "name": "Character", + "name": "Character" ], [ - "name": "Droid", + "name": "Droid" ], [ - "name": "Episode", + "name": "Episode" ], [ - "name": "Human", + "name": "Human" ], [ - "name": "Query", + "name": "Query" ], [ - "name": "String", + "name": "String" ], [ - "name": "__Directive", + "name": "__Directive" ], [ - "name": "__DirectiveLocation", + "name": "__DirectiveLocation" ], [ - "name": "__EnumValue", + "name": "__EnumValue" ], [ - "name": "__Field", + "name": "__Field" ], [ - "name": "__InputValue", + "name": "__InputValue" ], [ - "name": "__Schema", + "name": "__Schema" ], [ - "name": "__Type", + "name": "__Type" ], [ - "name": "__TypeKind", + "name": "__TypeKind" ], - ], - ], + ] + ] ] ) @@ -77,21 +75,17 @@ import Testing } @Test func introspectionQueryTypeQuery() async throws { - let query = "query IntrospectionQueryTypeQuery {" + - " __schema {" + - " queryType {" + - " name" + - " }" + - " }" + - "}" + let query = + "query IntrospectionQueryTypeQuery {" + " __schema {" + " queryType {" + + " name" + " }" + " }" + "}" let expected = GraphQLResult( data: [ "__schema": [ "queryType": [ - "name": "Query", - ], - ], + "name": "Query" + ] + ] ] ) @@ -103,17 +97,15 @@ import Testing } @Test func introspectionDroidTypeQuery() async throws { - let query = "query IntrospectionDroidTypeQuery {" + - " __type(name: \"Droid\") {" + - " name" + - " }" + - "}" + let query = + "query IntrospectionDroidTypeQuery {" + " __type(name: \"Droid\") {" + " name" + + " }" + "}" let expected = GraphQLResult( data: [ "__type": [ - "name": "Droid", - ], + "name": "Droid" + ] ] ) @@ -125,19 +117,16 @@ import Testing } @Test func introspectionDroidKindQuery() async throws { - let query = "query IntrospectionDroidKindQuery {" + - " __type(name: \"Droid\") {" + - " name" + - " kind" + - " }" + - "}" + let query = + "query IntrospectionDroidKindQuery {" + " __type(name: \"Droid\") {" + " name" + + " kind" + " }" + "}" let expected = GraphQLResult( data: [ "__type": [ "name": "Droid", "kind": "OBJECT", - ], + ] ] ) @@ -149,19 +138,16 @@ import Testing } @Test func introspectionCharacterKindQuery() async throws { - let query = "query IntrospectionCharacterKindQuery {" + - " __type(name: \"Character\") {" + - " name" + - " kind" + - " }" + - "}" + let query = + "query IntrospectionCharacterKindQuery {" + " __type(name: \"Character\") {" + + " name" + " kind" + " }" + "}" let expected = GraphQLResult( data: [ "__type": [ "name": "Character", "kind": "INTERFACE", - ], + ] ] ) @@ -173,18 +159,12 @@ import Testing } @Test func introspectionDroidFieldsQuery() async throws { - let query = "query IntrospectionDroidFieldsQuery {" + - " __type(name: \"Droid\") {" + - " name" + - " fields {" + - " name" + - " type {" + - " name" + - " kind" + - " }" + - " }" + - " }" + - "}" + let query = + "query IntrospectionDroidFieldsQuery {" + " __type(name: \"Droid\") {" + + " name" + + " fields {" + " name" + " type {" + + " name" + + " kind" + " }" + " }" + " }" + "}" let expected = GraphQLResult( data: [ @@ -234,7 +214,7 @@ import Testing ], ], ], - ], + ] ] ) @@ -246,22 +226,12 @@ import Testing } @Test func introspectionDroidNestedFieldsQuery() async throws { - let query = "query IntrospectionDroidNestedFieldsQuery {" + - " __type(name: \"Droid\") {" + - " name" + - " fields {" + - " name" + - " type {" + - " name" + - " kind" + - " ofType {" + - " name" + - " kind" + - " }" + - " }" + - " }" + - " }" + - "}" + let query = + "query IntrospectionDroidNestedFieldsQuery {" + " __type(name: \"Droid\") {" + + " name" + " fields {" + " name" + " type {" + + " name" + " kind" + " ofType {" + + " name" + " kind" + " }" + + " }" + " }" + " }" + "}" let expected = GraphQLResult( data: [ @@ -326,7 +296,7 @@ import Testing ], ], ], - ], + ] ] ) @@ -338,28 +308,16 @@ import Testing } @Test func introspectionFieldArgsQuery() async throws { - let query = "query IntrospectionFieldArgsQuery {" + - " __schema {" + - " queryType {" + - " fields {" + - " name" + - " args {" + - " name" + - " description" + - " type {" + - " name" + - " kind" + - " ofType {" + - " name" + - " kind" + - " }" + - " }" + - " defaultValue" + - " }" + - " }" + - " }" + - " }" + - "}" + let query = + "query IntrospectionFieldArgsQuery {" + " __schema {" + " queryType {" + + " fields {" + " name" + " args {" + + " name" + " description" + + " type {" + " name" + + " kind" + " ofType {" + + " name" + " kind" + + " }" + " }" + + " defaultValue" + + " }" + " }" + " }" + " }" + "}" let expected = GraphQLResult( data: [ @@ -381,7 +339,7 @@ import Testing ], ], "defaultValue": nil, - ], + ] ], ], [ @@ -389,14 +347,15 @@ import Testing "args": [ [ "name": "episode", - "description": "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.", + "description": + "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.", "type": [ "name": "Episode", "kind": "ENUM", "ofType": nil, ], "defaultValue": nil, - ], + ] ], ], [ @@ -414,12 +373,12 @@ import Testing ], ], "defaultValue": nil, - ], + ] ], ], - ], - ], - ], + ] + ] + ] ] ) @@ -431,19 +390,16 @@ import Testing } @Test func introspectionDroidDescriptionQuery() async throws { - let query = "query IntrospectionDroidDescriptionQuery {" + - " __type(name: \"Droid\") {" + - " name" + - " description" + - " }" + - "}" + let query = + "query IntrospectionDroidDescriptionQuery {" + " __type(name: \"Droid\") {" + + " name" + " description" + " }" + "}" let expected = GraphQLResult( data: [ "__type": [ "name": "Droid", "description": "A mechanical creature in the Star Wars universe.", - ], + ] ] ) diff --git a/Tests/GraphQLTests/StarWarsTests/StarWarsQueryTests.swift b/Tests/GraphQLTests/StarWarsTests/StarWarsQueryTests.swift index 0be7c282..829c3728 100644 --- a/Tests/GraphQLTests/StarWarsTests/StarWarsQueryTests.swift +++ b/Tests/GraphQLTests/StarWarsTests/StarWarsQueryTests.swift @@ -1,21 +1,22 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct StarWarsQueryTests { @Test func heroNameQuery() async throws { let query = """ - query HeroNameQuery { - hero { - name + query HeroNameQuery { + hero { + name + } } - } - """ + """ let expected = GraphQLResult( data: [ "hero": [ - "name": "R2-D2", - ], + "name": "R2-D2" + ] ] ) @@ -29,16 +30,16 @@ import Testing @Test func heroNameAndFriendsQuery() async throws { let query = """ - query HeroNameAndFriendsQuery { - hero { - id - name - friends { + query HeroNameAndFriendsQuery { + hero { + id name + friends { + name + } } } - } - """ + """ let expected = GraphQLResult( data: [ @@ -50,7 +51,7 @@ import Testing ["name": "Han Solo"], ["name": "Leia Organa"], ], - ], + ] ] ) @@ -64,19 +65,19 @@ import Testing @Test func nestedQuery() async throws { let query = """ - query NestedQuery { - hero { - name - friends { + query NestedQuery { + hero { name - appearsIn friends { name + appearsIn + friends { + name + } } } } - } - """ + """ let expected = GraphQLResult( data: [ @@ -113,7 +114,7 @@ import Testing ], ], ], - ], + ] ] ) @@ -137,8 +138,8 @@ import Testing let expected = GraphQLResult( data: [ "human": [ - "name": "Luke Skywalker", - ], + "name": "Luke Skywalker" + ] ] ) @@ -169,8 +170,8 @@ import Testing expected = GraphQLResult( data: [ "hero": [ - "name": "R2-D2", - ], + "name": "R2-D2" + ] ] ) @@ -183,14 +184,14 @@ import Testing // or we can pass "EMPIRE" and expect Luke params = [ - "episode": "EMPIRE", + "episode": "EMPIRE" ] expected = GraphQLResult( data: [ "hero": [ - "name": "Luke Skywalker", - ], + "name": "Luke Skywalker" + ] ] ) @@ -217,14 +218,14 @@ import Testing var result: GraphQLResult params = [ - "someId": "1000", + "someId": "1000" ] expected = GraphQLResult( data: [ "human": [ - "name": "Luke Skywalker", - ], + "name": "Luke Skywalker" + ] ] ) @@ -236,14 +237,14 @@ import Testing #expect(result == expected) params = [ - "someId": "1002", + "someId": "1002" ] expected = GraphQLResult( data: [ "human": [ - "name": "Han Solo", - ], + "name": "Han Solo" + ] ] ) @@ -255,12 +256,12 @@ import Testing #expect(result == expected) params = [ - "someId": "not a valid id", + "someId": "not a valid id" ] expected = GraphQLResult( data: [ - "human": nil, + "human": nil ] ) @@ -285,8 +286,8 @@ import Testing let expected = GraphQLResult( data: [ "luke": [ - "name": "Luke Skywalker", - ], + "name": "Luke Skywalker" + ] ] ) @@ -313,10 +314,10 @@ import Testing let expected = GraphQLResult( data: [ "luke": [ - "name": "Luke Skywalker", + "name": "Luke Skywalker" ], "leia": [ - "name": "Leia Organa", + "name": "Leia Organa" ], ] ) @@ -416,7 +417,7 @@ import Testing "hero": [ "__typename": "Droid", "name": "R2-D2", - ], + ] ] ) @@ -444,7 +445,7 @@ import Testing "hero": [ "__typename": "Human", "name": "Luke Skywalker", - ], + ] ] ) @@ -471,14 +472,14 @@ import Testing "hero": [ "name": "R2-D2", "secretBackstory": nil, - ], + ] ], errors: [ GraphQLError( message: "secretBackstory is secret.", locations: [SourceLocation(line: 4, column: 9)], path: ["hero", "secretBackstory"] - ), + ) ] ) @@ -521,7 +522,7 @@ import Testing "secretBackstory": nil, ], ], - ], + ] ], errors: [ GraphQLError( @@ -565,14 +566,14 @@ import Testing "mainHero": [ "name": "R2-D2", "story": nil, - ], + ] ], errors: [ GraphQLError( message: "secretBackstory is secret.", locations: [SourceLocation(line: 4, column: 9)], path: ["mainHero", "story"] - ), + ) ] ) @@ -588,30 +589,32 @@ import Testing name: "A", fields: [:] ) - A.fields = { [ - "nullableA": GraphQLField( - type: A, - resolve: { _, _, _, _ -> [String: String]? in - [:] as [String: String] - } - ), - "nonNullA": GraphQLField( - type: GraphQLNonNull(A), - resolve: { _, _, _, _ -> [String: String]? in - [:] as [String: String] - } - ), - "throws": GraphQLField( - type: GraphQLNonNull(GraphQLString), - resolve: { _, _, _, _ -> [String: String]? in - struct 🏃: Error, CustomStringConvertible { - let description: String + A.fields = { + [ + "nullableA": GraphQLField( + type: A, + resolve: { _, _, _, _ -> [String: String]? in + [:] as [String: String] + } + ), + "nonNullA": GraphQLField( + type: GraphQLNonNull(A), + resolve: { _, _, _, _ -> [String: String]? in + [:] as [String: String] } + ), + "throws": GraphQLField( + type: GraphQLNonNull(GraphQLString), + resolve: { _, _, _, _ -> [String: String]? in + struct 🏃: Error, CustomStringConvertible { + let description: String + } - throw 🏃(description: "catch me if you can.") - } - ), - ] } + throw 🏃(description: "catch me if you can.") + } + ), + ] + } let queryType = try GraphQLObjectType( name: "query", @@ -621,7 +624,7 @@ import Testing resolve: { _, _, _, _ -> [String: String]? in [:] as [String: String] } - ), + ) ] ) @@ -647,15 +650,15 @@ import Testing let expected = GraphQLResult( data: [ "nullableA": [ - "nullableA": nil, - ], + "nullableA": nil + ] ], errors: [ GraphQLError( message: "catch me if you can.", locations: [SourceLocation(line: 6, column: 21)], path: ["nullableA", "nullableA", "nonNullA", "nonNullA", "throws"] - ), + ) ] ) @@ -668,41 +671,47 @@ import Testing var result = try await graphql( schema: starWarsSchema, request: """ - query HeroNameQuery { - hero { - id - name + query HeroNameQuery { + hero { + id + name + } } - } - """ + """ + ) + #expect( + result + == GraphQLResult( + data: [ + "hero": [ + "id": "2001", + "name": "R2-D2", + ] + ] + ) ) - #expect(result == GraphQLResult( - data: [ - "hero": [ - "id": "2001", - "name": "R2-D2", - ], - ] - )) result = try await graphql( schema: starWarsSchema, request: """ - query HeroNameQuery { - hero { - id - name + query HeroNameQuery { + hero { + id + name + } } - } - """ + """ + ) + #expect( + result + != GraphQLResult( + data: [ + "hero": [ + "name": "R2-D2", + "id": "2001", + ] + ] + ) ) - #expect(result != GraphQLResult( - data: [ - "hero": [ - "name": "R2-D2", - "id": "2001", - ], - ] - )) } } diff --git a/Tests/GraphQLTests/StarWarsTests/StarWarsSchema.swift b/Tests/GraphQLTests/StarWarsTests/StarWarsSchema.swift index 781f4c7a..9397b53a 100644 --- a/Tests/GraphQLTests/StarWarsTests/StarWarsSchema.swift +++ b/Tests/GraphQLTests/StarWarsTests/StarWarsSchema.swift @@ -49,12 +49,10 @@ import GraphQL * We begin by setting up our schema. */ -/** - * The original trilogy consists of three movies. - * - * This implements the following type system shorthand: - * enum Episode { NEWHOPE, EMPIRE, JEDI } - */ +/// The original trilogy consists of three movies. +/// +/// This implements the following type system shorthand: +/// enum Episode { NEWHOPE, EMPIRE, JEDI } let EpisodeEnum = try! GraphQLEnumType( name: "Episode", description: "One of the films in the Star Wars Trilogy", @@ -74,43 +72,43 @@ let EpisodeEnum = try! GraphQLEnumType( ] ) -/** - * Characters in the Star Wars trilogy are either humans or droids. - * - * This implements the following type system shorthand: - * interface Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * secretBackstory: String - * } - */ +/// Characters in the Star Wars trilogy are either humans or droids. +/// +/// This implements the following type system shorthand: +/// interface Character { +/// id: String! +/// name: String +/// friends: [Character] +/// appearsIn: [Episode] +/// secretBackstory: String +/// } let CharacterInterface = try! GraphQLInterfaceType( name: "Character", description: "A character in the Star Wars Trilogy", - fields: { [ - "id": GraphQLField( - type: GraphQLNonNull(GraphQLString), - description: "The id of the character." - ), - "name": GraphQLField( - type: GraphQLString, - description: "The name of the character." - ), - "friends": GraphQLField( - type: GraphQLList(CharacterInterface), - description: "The friends of the character, or an empty list if they have none." - ), - "appearsIn": GraphQLField( - type: GraphQLList(EpisodeEnum), - description: "Which movies they appear in." - ), - "secretBackstory": GraphQLField( - type: GraphQLString, - description: "All secrets about their past." - ), - ] }, + fields: { + [ + "id": GraphQLField( + type: GraphQLNonNull(GraphQLString), + description: "The id of the character." + ), + "name": GraphQLField( + type: GraphQLString, + description: "The name of the character." + ), + "friends": GraphQLField( + type: GraphQLList(CharacterInterface), + description: "The friends of the character, or an empty list if they have none." + ), + "appearsIn": GraphQLField( + type: GraphQLList(EpisodeEnum), + description: "Which movies they appear in." + ), + "secretBackstory": GraphQLField( + type: GraphQLString, + description: "All secrets about their past." + ), + ] + }, resolveType: { character, _ in switch character { case is Human: @@ -121,18 +119,16 @@ let CharacterInterface = try! GraphQLInterfaceType( } ) -/** - * We define our human type, which implements the character interface. - * - * This implements the following type system shorthand: - * type Human : Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * secretBackstory: String - * } - */ +/// We define our human type, which implements the character interface. +/// +/// This implements the following type system shorthand: +/// type Human : Character { +/// id: String! +/// name: String +/// friends: [Character] +/// appearsIn: [Episode] +/// secretBackstory: String +/// } let HumanType = try! GraphQLObjectType( name: "Human", description: "A humanoid creature in the Star Wars universe.", @@ -147,8 +143,7 @@ let HumanType = try! GraphQLObjectType( ), "friends": GraphQLField( type: GraphQLList(CharacterInterface), - description: "The friends of the human, or an empty list if they " + - "have none.", + description: "The friends of the human, or an empty list if they " + "have none.", resolve: { human, _, _, _ in getFriends(character: human as! Human) } @@ -179,19 +174,17 @@ let HumanType = try! GraphQLObjectType( } ) -/** - * The other type of character in Star Wars is a droid. - * - * This implements the following type system shorthand: - * type Droid : Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * secretBackstory: String - * primaryFunction: String - * } - */ +/// The other type of character in Star Wars is a droid. +/// +/// This implements the following type system shorthand: +/// type Droid : Character { +/// id: String! +/// name: String +/// friends: [Character] +/// appearsIn: [Episode] +/// secretBackstory: String +/// primaryFunction: String +/// } let DroidType = try! GraphQLObjectType( name: "Droid", description: "A mechanical creature in the Star Wars universe.", @@ -237,20 +230,17 @@ let DroidType = try! GraphQLObjectType( } ) -/** - * This is the type that will be the root of our query, and the - * entry point into our schema. It gives us the ability to fetch - * objects by their IDs, as well as to fetch the undisputed hero - * of the Star Wars trilogy, R2-D2, directly. - * - * This implements the following type system shorthand: - * type Query { - * hero(episode: Episode): Character - * human(id: String!): Human - * droid(id: String!): Droid - * } - * - */ +/// This is the type that will be the root of our query, and the +/// entry point into our schema. It gives us the ability to fetch +/// objects by their IDs, as well as to fetch the undisputed hero +/// of the Star Wars trilogy, R2-D2, directly. +/// +/// This implements the following type system shorthand: +/// type Query { +/// hero(episode: Episode): Character +/// human(id: String!): Human +/// droid(id: String!): Droid +/// } let QueryType = try! GraphQLObjectType( name: "Query", fields: [ @@ -260,9 +250,9 @@ let QueryType = try! GraphQLObjectType( "episode": GraphQLArgument( type: EpisodeEnum, description: - "If omitted, returns the hero of the whole saga. If " + - "provided, returns the hero of that particular episode." - ), + "If omitted, returns the hero of the whole saga. If " + + "provided, returns the hero of that particular episode." + ) ], resolve: { _, arguments, _, _ in let episode = Episode(arguments["episode"].string) @@ -275,7 +265,7 @@ let QueryType = try! GraphQLObjectType( "id": GraphQLArgument( type: GraphQLNonNull(GraphQLString), description: "id of the human" - ), + ) ], resolve: { _, arguments, _, _ in getHuman(id: arguments["id"].string!) @@ -287,7 +277,7 @@ let QueryType = try! GraphQLObjectType( "id": GraphQLArgument( type: GraphQLNonNull(GraphQLString), description: "id of the droid" - ), + ) ], resolve: { _, arguments, _, _ in getDroid(id: arguments["id"].string!) @@ -296,10 +286,8 @@ let QueryType = try! GraphQLObjectType( ] ) -/** - * Finally, we construct our schema (whose starting query type is the query - * type we defined above) and export it. - */ +/// Finally, we construct our schema (whose starting query type is the query +/// type we defined above) and export it. let starWarsSchema = try! GraphQLSchema( query: QueryType, types: [HumanType, DroidType] diff --git a/Tests/GraphQLTests/StarWarsTests/StarWarsValidationTests.swift b/Tests/GraphQLTests/StarWarsTests/StarWarsValidationTests.swift index f5ff108f..cd6b25d3 100644 --- a/Tests/GraphQLTests/StarWarsTests/StarWarsValidationTests.swift +++ b/Tests/GraphQLTests/StarWarsTests/StarWarsValidationTests.swift @@ -1,9 +1,8 @@ -@testable import GraphQL import Testing -/** - * Helper function to test a query and the expected response. - */ +@testable import GraphQL + +/// Helper function to test a query and the expected response. func validationErrors(query: String) throws -> [GraphQLError] { let source = Source(body: query, name: "StarWars.graphql") let ast = try parse(source: source) @@ -12,93 +11,61 @@ func validationErrors(query: String) throws -> [GraphQLError] { @Suite struct StarWarsValidationTests { @Test func nestedQueryWithFragment() throws { - let query = "query NestedQueryWithFragment {" + - " hero {" + - " ...NameAndAppearances" + - " friends {" + - " ...NameAndAppearances" + - " friends {" + - " ...NameAndAppearances" + - " }" + - " }" + - " }" + - "}" + - "fragment NameAndAppearances on Character {" + - " name" + - " appearsIn" + - "}" + let query = + "query NestedQueryWithFragment {" + " hero {" + " ...NameAndAppearances" + + " friends {" + " ...NameAndAppearances" + " friends {" + + " ...NameAndAppearances" + " }" + " }" + " }" + + "}" + + "fragment NameAndAppearances on Character {" + " name" + " appearsIn" + "}" #expect(try validationErrors(query: query).isEmpty) } @Test func heroSpaceshipQuery() throws { - let query = "query HeroSpaceshipQuery {" + - " hero {" + - " favoriteSpaceship" + - " }" + - "}" + - "fragment NameAndAppearances on Character {" + - " name" + - " appearsIn" + - "}" + let query = + "query HeroSpaceshipQuery {" + " hero {" + " favoriteSpaceship" + " }" + + "}" + + "fragment NameAndAppearances on Character {" + " name" + " appearsIn" + "}" #expect(try !validationErrors(query: query).isEmpty) } @Test func heroNoFieldsQuery() throws { - let query = "query HeroNoFieldsQuery {" + - " hero" + - "}" + let query = "query HeroNoFieldsQuery {" + " hero" + "}" #expect(try !validationErrors(query: query).isEmpty) } @Test func heroFieldsOnScalarQuery() throws { - let query = "query HeroFieldsOnScalarQuery {" + - " hero {" + - " name {" + - " firstCharacterOfName" + - " }" + - " }" + - "}" + let query = + "query HeroFieldsOnScalarQuery {" + " hero {" + " name {" + + " firstCharacterOfName" + " }" + " }" + "}" #expect(try !validationErrors(query: query).isEmpty) } @Test func droidFieldOnCharacter() throws { - let query = "query DroidFieldOnCharacter {" + - " hero {" + - " name" + - " primaryFunction" + - " }" + - "}" + let query = + "query DroidFieldOnCharacter {" + " hero {" + " name" + + " primaryFunction" + + " }" + "}" #expect(try !validationErrors(query: query).isEmpty) } @Test func droidFieldInFragment() throws { - let query = "query DroidFieldInFragment {" + - " hero {" + - " name" + - " ...DroidFields" + - " }" + - "}" + - "fragment DroidFields on Droid {" + - " primaryFunction" + - "}" + let query = + "query DroidFieldInFragment {" + " hero {" + " name" + + " ...DroidFields" + + " }" + "}" + "fragment DroidFields on Droid {" + " primaryFunction" + "}" #expect(try validationErrors(query: query).isEmpty) } @Test func droidFieldInInlineFragment() throws { - let query = "query DroidFieldInInlineFragment {" + - " hero {" + - " name" + - " ... on Droid {" + - " primaryFunction" + - " }" + - " }" + - "}" + let query = + "query DroidFieldInInlineFragment {" + " hero {" + " name" + + " ... on Droid {" + " primaryFunction" + " }" + " }" + "}" #expect(try validationErrors(query: query).isEmpty) } diff --git a/Tests/GraphQLTests/SubscriptionTests/SubscriptionSchema.swift b/Tests/GraphQLTests/SubscriptionTests/SubscriptionSchema.swift index 77620ed0..af95fb5b 100644 --- a/Tests/GraphQLTests/SubscriptionTests/SubscriptionSchema.swift +++ b/Tests/GraphQLTests/SubscriptionTests/SubscriptionSchema.swift @@ -82,7 +82,7 @@ let EmailQueryType = try! GraphQLObjectType( fields: [ "inbox": GraphQLField( type: InboxType - ), + ) ] ) @@ -99,7 +99,7 @@ actor EmailDb { subject: "Hello", message: "Hello World", unread: false - ), + ) ] publisher = SimplePubSub() } @@ -164,11 +164,11 @@ func emailSchemaWithResolvers( args: [ "priority": GraphQLArgument( type: GraphQLInt - ), + ) ], resolve: resolve, subscribe: subscribe - ), + ) ] ) ) diff --git a/Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift b/Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift index 4b7aca90..1f9f95b3 100644 --- a/Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift +++ b/Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift @@ -3,7 +3,7 @@ import Testing /// This follows the graphql-js testing, with deviations where noted. @Suite struct SubscriptionTests { - let timeoutDuration = 0.5 // in seconds + let timeoutDuration = 0.5 // in seconds // MARK: Test primary graphqlSubscribe function @@ -12,19 +12,19 @@ import Testing let db = EmailDb() let schema = try await db.defaultSchema() let query = """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } } - } - } - """ + """ let subscriptionResult = try await GraphQL.graphqlSubscribe( schema: schema, @@ -33,27 +33,32 @@ import Testing let stream = try subscriptionResult.get() var iterator = stream.makeAsyncIterator() - await db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) + await db.trigger( + email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + ) + ) await db.stop() let result = try await iterator.next() #expect( - result == GraphQLResult( - data: ["importantEmail": [ - "email": [ - "from": "yuzhi@graphql.org", - "subject": "Alright", - ], - "inbox": [ - "unread": 1, - "total": 2, - ], - ]] - ) + result + == GraphQLResult( + data: [ + "importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Alright", + ], + "inbox": [ + "unread": 1, + "total": 2, + ], + ] + ] + ) ) } @@ -72,7 +77,7 @@ import Testing args: [ "priority": GraphQLArgument( type: GraphQLInt - ), + ) ], resolve: { emailAny, _, _, _ throws in guard let email = emailAny as? Email else { @@ -94,7 +99,7 @@ import Testing args: [ "priority": GraphQLArgument( type: GraphQLInt - ), + ) ], resolve: { emailAny, _, _, _ throws in guard let email = emailAny as? Email else { @@ -114,43 +119,51 @@ import Testing ] ) ) - let stream = try await createSubscription(schema: schema, query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total - } - } - } - """) + let stream = try await createSubscription( + schema: schema, + query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } + } + """ + ) var iterator = stream.makeAsyncIterator() - await db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) + await db.trigger( + email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + ) + ) let result = try await iterator.next() #expect( - result == GraphQLResult( - data: ["importantEmail": [ - "email": [ - "from": "yuzhi@graphql.org", - "subject": "Alright", - ], - "inbox": [ - "unread": 1, - "total": 2, - ], - ]] - ) + result + == GraphQLResult( + data: [ + "importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Alright", + ], + "inbox": [ + "unread": 1, + "total": 2, + ], + ] + ] + ) ) } @@ -202,28 +215,33 @@ import Testing ] ) ) - let subscriptionResult = try await createSubscription(schema: schema, query: """ - subscription { - importantEmail { - email { - from - } - } - notImportantEmail { - email { - from + let subscriptionResult = try await createSubscription( + schema: schema, + query: """ + subscription { + importantEmail { + email { + from + } + } + notImportantEmail { + email { + from + } + } } - } - } - """) + """ + ) var iterator = subscriptionResult.makeAsyncIterator() - await db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) + await db.trigger( + email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + ) + ) _ = try await iterator.next() @@ -244,11 +262,13 @@ import Testing @Test func errorUnknownSubscriptionField() async throws { let db = EmailDb() do { - _ = try await db.subscription(query: """ - subscription { - unknownField - } - """) + _ = try await db.subscription( + query: """ + subscription { + unknownField + } + """ + ) Issue.record("Error should have been thrown") } catch { guard let graphQLErrors = error as? GraphQLErrors else { @@ -260,7 +280,7 @@ import Testing GraphQLError( message: "Cannot query field \"unknownField\" on type \"Subscription\".", locations: [SourceLocation(line: 2, column: 5)] - ), + ) ] ) } @@ -286,15 +306,18 @@ import Testing } ) do { - _ = try await createSubscription(schema: schema, query: """ - subscription { - importantEmail { - email { - from + _ = try await createSubscription( + schema: schema, + query: """ + subscription { + importantEmail { + email { + from + } + } } - } - } - """) + """ + ) Issue.record("Error should have been thrown") } catch { guard let graphQLErrors = error as? GraphQLErrors else { @@ -304,8 +327,9 @@ import Testing #expect( graphQLErrors.errors == [ GraphQLError( - message: "Subscription field resolver must return an AsyncSequence. Received: 'test'" - ), + message: + "Subscription field resolver must return an AsyncSequence. Received: 'test'" + ) ] ) } @@ -315,15 +339,18 @@ import Testing @Test func errorForSubscriptionResolverErrors() async throws { func verifyError(schema: GraphQLSchema) async throws { do { - _ = try await createSubscription(schema: schema, query: """ - subscription { - importantEmail { - email { - from + _ = try await createSubscription( + schema: schema, + query: """ + subscription { + importantEmail { + email { + from + } + } } - } - } - """) + """ + ) Issue.record("Error should have been thrown") } catch { guard let graphQLErrors = error as? GraphQLErrors else { @@ -335,25 +362,31 @@ import Testing } // Throwing an error - try await verifyError(schema: emailSchemaWithResolvers( - subscribe: { _, _, _, _ throws in - throw GraphQLError(message: "test error") - } - )) + try await verifyError( + schema: emailSchemaWithResolvers( + subscribe: { _, _, _, _ throws in + throw GraphQLError(message: "test error") + } + ) + ) // Resolving to an error - try await verifyError(schema: emailSchemaWithResolvers( - subscribe: { _, _, _, _ throws in - GraphQLError(message: "test error") - } - )) + try await verifyError( + schema: emailSchemaWithResolvers( + subscribe: { _, _, _, _ throws in + GraphQLError(message: "test error") + } + ) + ) // Rejecting with an error - try await verifyError(schema: emailSchemaWithResolvers( - subscribe: { _, _, _, _ throws in - GraphQLError(message: "test error") - } - )) + try await verifyError( + schema: emailSchemaWithResolvers( + subscribe: { _, _, _, _ throws in + GraphQLError(message: "test error") + } + ) + ) } // 'resolves to an error for source event stream resolver errors' @@ -363,25 +396,25 @@ import Testing @Test func errorVariablesWrongType() async throws { let db = EmailDb() let query = """ - subscription ($priority: Int) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total + subscription ($priority: Int) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } } - } - } - """ + """ do { _ = try await db.subscription( query: query, variableValues: [ - "priority": "meow", + "priority": "meow" ] ) Issue.record("Should have thrown error") @@ -391,8 +424,8 @@ import Testing return } #expect( - graphQLError.message == - "Variable \"$priority\" got invalid value \"\"meow\"\".\nExpected type \"Int\", found \"meow\"." + graphQLError.message + == "Variable \"$priority\" got invalid value \"\"meow\"\".\nExpected type \"Int\", found \"meow\"." ) } } @@ -402,104 +435,119 @@ import Testing /// 'produces a payload for a single subscriber' @Test func singleSubscriber() async throws { let db = EmailDb() - let stream = try await db.subscription(query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total - } - } - } - """) + let stream = try await db.subscription( + query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } + } + """ + ) var iterator = stream.makeAsyncIterator() - await db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) + await db.trigger( + email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + ) + ) await db.stop() let result = try await iterator.next() #expect( - result == GraphQLResult( - data: ["importantEmail": [ - "email": [ - "from": "yuzhi@graphql.org", - "subject": "Alright", - ], - "inbox": [ - "unread": 1, - "total": 2, - ], - ]] - ) + result + == GraphQLResult( + data: [ + "importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Alright", + ], + "inbox": [ + "unread": 1, + "total": 2, + ], + ] + ] + ) ) } /// 'produces a payload for multiple subscribe in same subscription' @Test func multipleSubscribers() async throws { let db = EmailDb() - let stream1 = try await db.subscription(query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total - } - } - } - """) - - let stream2 = try await db.subscription(query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total - } - } - } - """) + let stream1 = try await db.subscription( + query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } + } + """ + ) + + let stream2 = try await db.subscription( + query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } + } + """ + ) var iterator1 = stream1.makeAsyncIterator() var iterator2 = stream2.makeAsyncIterator() - await db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) + await db.trigger( + email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + ) + ) let result1 = try await iterator1.next() let result2 = try await iterator2.next() let expected = GraphQLResult( - data: ["importantEmail": [ - "email": [ - "from": "yuzhi@graphql.org", - "subject": "Alright", - ], - "inbox": [ - "unread": 1, - "total": 2, - ], - ]] + data: [ + "importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Alright", + ], + "inbox": [ + "unread": 1, + "total": 2, + ], + ] + ] ) #expect(result1 == expected) @@ -509,66 +557,78 @@ import Testing /// 'produces a payload per subscription event' @Test func payloadPerEvent() async throws { let db = EmailDb() - let stream = try await db.subscription(query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total - } - } - } - """) + let stream = try await db.subscription( + query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } + } + """ + ) var iterator = stream.makeAsyncIterator() // A new email arrives! - await db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) + await db.trigger( + email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + ) + ) let result1 = try await iterator.next() #expect( - result1 == GraphQLResult( - data: ["importantEmail": [ - "email": [ - "from": "yuzhi@graphql.org", - "subject": "Alright", - ], - "inbox": [ - "unread": 1, - "total": 2, - ], - ]] - ) + result1 + == GraphQLResult( + data: [ + "importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Alright", + ], + "inbox": [ + "unread": 1, + "total": 2, + ], + ] + ] + ) ) // Another new email arrives - await db.trigger(email: Email( - from: "hyo@graphql.org", - subject: "Tools", - message: "I <3 making things", - unread: true - )) + await db.trigger( + email: Email( + from: "hyo@graphql.org", + subject: "Tools", + message: "I <3 making things", + unread: true + ) + ) let result2 = try await iterator.next() #expect( - result2 == GraphQLResult( - data: ["importantEmail": [ - "email": [ - "from": "hyo@graphql.org", - "subject": "Tools", - ], - "inbox": [ - "unread": 2, - "total": 3, - ], - ]] - ) + result2 + == GraphQLResult( + data: [ + "importantEmail": [ + "email": [ + "from": "hyo@graphql.org", + "subject": "Tools", + ], + "inbox": [ + "unread": 2, + "total": 3, + ], + ] + ] + ) ) } @@ -576,78 +636,90 @@ import Testing /// This is not in the graphql-js tests. @Test func arguments() async throws { let db = EmailDb() - let stream = try await db.subscription(query: """ - subscription ($priority: Int = 5) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total - } - } - } - """) + let stream = try await db.subscription( + query: """ + subscription ($priority: Int = 5) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } + } + """ + ) var iterator = stream.makeAsyncIterator() var results = [GraphQLResult?]() var expected = [GraphQLResult]() - await db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true, - priority: 7 - )) + await db.trigger( + email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true, + priority: 7 + ) + ) expected.append( GraphQLResult( - data: ["importantEmail": [ - "email": [ - "from": "yuzhi@graphql.org", - "subject": "Alright", - ], - "inbox": [ - "unread": 1, - "total": 2, - ], - ]] + data: [ + "importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Alright", + ], + "inbox": [ + "unread": 1, + "total": 2, + ], + ] + ] ) ) try await results.append(iterator.next()) #expect(results == expected) // Low priority email shouldn't trigger an event - await db.trigger(email: Email( - from: "hyo@graphql.org", - subject: "Not Important", - message: "Ignore this email", - unread: true, - priority: 2 - )) + await db.trigger( + email: Email( + from: "hyo@graphql.org", + subject: "Not Important", + message: "Ignore this email", + unread: true, + priority: 2 + ) + ) #expect(results == expected) // Higher priority one should trigger again - await db.trigger(email: Email( - from: "hyo@graphql.org", - subject: "Tools", - message: "I <3 making things", - unread: true, - priority: 5 - )) + await db.trigger( + email: Email( + from: "hyo@graphql.org", + subject: "Tools", + message: "I <3 making things", + unread: true, + priority: 5 + ) + ) expected.append( GraphQLResult( - data: ["importantEmail": [ - "email": [ - "from": "hyo@graphql.org", - "subject": "Tools", - ], - "inbox": [ - "unread": 3, - "total": 4, - ], - ]] + data: [ + "importantEmail": [ + "email": [ + "from": "hyo@graphql.org", + "subject": "Tools", + ], + "inbox": [ + "unread": 3, + "total": 4, + ], + ] + ] ) ) try await results.append(iterator.next()) @@ -657,42 +729,48 @@ import Testing /// 'should not trigger when subscription is already done' @Test func noTriggerAfterDone() async throws { let db = EmailDb() - let stream = try await db.subscription(query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total - } - } - } - """) + let stream = try await db.subscription( + query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } + } + """ + ) var iterator = stream.makeAsyncIterator() var results = [GraphQLResult?]() var expected = [GraphQLResult]() - await db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) + await db.trigger( + email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + ) + ) expected.append( GraphQLResult( - data: ["importantEmail": [ - "email": [ - "from": "yuzhi@graphql.org", - "subject": "Alright", - ], - "inbox": [ - "unread": 1, - "total": 2, - ], - ]] + data: [ + "importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Alright", + ], + "inbox": [ + "unread": 1, + "total": 2, + ], + ] + ] ) ) try await results.append(iterator.next()) @@ -701,12 +779,14 @@ import Testing await db.stop() // This should not trigger an event. - await db.trigger(email: Email( - from: "hyo@graphql.org", - subject: "Tools", - message: "I <3 making things", - unread: true - )) + await db.trigger( + email: Email( + from: "hyo@graphql.org", + subject: "Tools", + message: "I <3 making things", + unread: true + ) + ) // Ensure that the current result was the one before the db was stopped #expect(results == expected) } @@ -717,53 +797,65 @@ import Testing /// 'event order is correct for multiple publishes' @Test func orderCorrectForMultiplePublishes() async throws { let db = EmailDb() - let stream = try await db.subscription(query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - } - } - """) + let stream = try await db.subscription( + query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + } + } + """ + ) var iterator = stream.makeAsyncIterator() - await db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) - await db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Message 2", - message: "Tests are good 2", - unread: true - )) + await db.trigger( + email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + ) + ) + await db.trigger( + email: Email( + from: "yuzhi@graphql.org", + subject: "Message 2", + message: "Tests are good 2", + unread: true + ) + ) let result1 = try await iterator.next() let result2 = try await iterator.next() #expect( - result1 == GraphQLResult( - data: ["importantEmail": [ - "email": [ - "from": "yuzhi@graphql.org", - "subject": "Alright", - ], - ]] - ) + result1 + == GraphQLResult( + data: [ + "importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Alright", + ] + ] + ] + ) ) #expect( - result2 == GraphQLResult( - data: ["importantEmail": [ - "email": [ - "from": "yuzhi@graphql.org", - "subject": "Message 2", - ], - ]] - ) + result2 + == GraphQLResult( + data: [ + "importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Message 2", + ] + ] + ] + ) ) } @@ -778,7 +870,7 @@ import Testing message: "Source is not Email type: \(type(of: emailAny))" ) } - if email.subject == "Goodbye" { // Force the system to fail here. + if email.subject == "Goodbye" { // Force the system to fail here. throw GraphQLError(message: "Never leave.") } return EmailEvent( @@ -791,49 +883,58 @@ import Testing } ) - let stream = try await createSubscription(schema: schema, query: """ - subscription { - importantEmail { - email { - subject + let stream = try await createSubscription( + schema: schema, + query: """ + subscription { + importantEmail { + email { + subject + } + } } - } - } - """) + """ + ) var iterator = stream.makeAsyncIterator() var results = [GraphQLResult?]() var expected = [GraphQLResult]() - await db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Hello", - message: "Tests are good", - unread: true - )) + await db.trigger( + email: Email( + from: "yuzhi@graphql.org", + subject: "Hello", + message: "Tests are good", + unread: true + ) + ) expected.append( GraphQLResult( - data: ["importantEmail": [ - "email": [ - "subject": "Hello", - ], - ]] + data: [ + "importantEmail": [ + "email": [ + "subject": "Hello" + ] + ] + ] ) ) try await results.append(iterator.next()) #expect(results == expected) // An error in execution is presented as such. - await db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Goodbye", - message: "Tests are good", - unread: true - )) + await db.trigger( + email: Email( + from: "yuzhi@graphql.org", + subject: "Goodbye", + message: "Tests are good", + unread: true + ) + ) expected.append( GraphQLResult( data: ["importantEmail": nil], errors: [ - GraphQLError(message: "Never leave."), + GraphQLError(message: "Never leave.") ] ) ) @@ -842,19 +943,23 @@ import Testing // However that does not close the response event stream. Subsequent events are still // executed. - await db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Bonjour", - message: "Tests are good", - unread: true - )) + await db.trigger( + email: Email( + from: "yuzhi@graphql.org", + subject: "Bonjour", + message: "Tests are good", + unread: true + ) + ) expected.append( GraphQLResult( - data: ["importantEmail": [ - "email": [ - "subject": "Bonjour", - ], - ]] + data: [ + "importantEmail": [ + "email": [ + "subject": "Bonjour" + ] + ] + ] ) ) try await results.append(iterator.next()) diff --git a/Tests/GraphQLTests/SwiftUtilitiesTests/DidYouMeanTests.swift b/Tests/GraphQLTests/SwiftUtilitiesTests/DidYouMeanTests.swift index 4e72a98b..11c4ca8d 100644 --- a/Tests/GraphQLTests/SwiftUtilitiesTests/DidYouMeanTests.swift +++ b/Tests/GraphQLTests/SwiftUtilitiesTests/DidYouMeanTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct DidYouMeanTests { @Test func emptyList() { #expect( diff --git a/Tests/GraphQLTests/TypeTests/GraphQLArgumentDefinitionTests.swift b/Tests/GraphQLTests/TypeTests/GraphQLArgumentDefinitionTests.swift index 6705d591..59df002e 100644 --- a/Tests/GraphQLTests/TypeTests/GraphQLArgumentDefinitionTests.swift +++ b/Tests/GraphQLTests/TypeTests/GraphQLArgumentDefinitionTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct GraphQLArgumentDefinitionTests { @Test func argumentWithNullableTypeIsNotARequiredArgument() { let argument = GraphQLArgumentDefinition( diff --git a/Tests/GraphQLTests/TypeTests/GraphQLSchemaTests.swift b/Tests/GraphQLTests/TypeTests/GraphQLSchemaTests.swift index 2cc724ce..72ccf0cb 100644 --- a/Tests/GraphQLTests/TypeTests/GraphQLSchemaTests.swift +++ b/Tests/GraphQLTests/TypeTests/GraphQLSchemaTests.swift @@ -1,9 +1,12 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct GraphQLSchemaTests { - @Test func assertObjectImplementsInterfacePassesWhenObjectFieldHasRequiredArgumentsFromInterface( - ) throws { + @Test + func assertObjectImplementsInterfacePassesWhenObjectFieldHasRequiredArgumentsFromInterface() + throws + { let interface = try GraphQLInterfaceType( name: "Interface", fields: [ @@ -55,15 +58,18 @@ import Testing _ = try GraphQLSchema(query: object, types: [interface, object]) } - @Test func assertObjectImplementsInterfacePassesWhenObjectFieldHasRequiredArgumentMissingInInterfaceButHasDefaultValue( - ) throws { + @Test + func + assertObjectImplementsInterfacePassesWhenObjectFieldHasRequiredArgumentMissingInInterfaceButHasDefaultValue() + throws + { let interface = try GraphQLInterfaceType( name: "Interface", fields: [ "fieldWithOneArg": GraphQLField( type: GraphQLInt, args: [:] - ), + ) ] ) @@ -76,9 +82,9 @@ import Testing "addedRequiredArgWithDefaultValue": GraphQLArgument( type: GraphQLNonNull(GraphQLInt), defaultValue: .int(5) - ), + ) ] - ), + ) ], interfaces: [interface], isTypeOf: { _, _ -> Bool in @@ -89,15 +95,17 @@ import Testing _ = try GraphQLSchema(query: object, types: [interface, object]) } - @Test func assertObjectImplementsInterfacePassesWhenObjectFieldHasNullableArgumentMissingInInterface( - ) throws { + @Test + func assertObjectImplementsInterfacePassesWhenObjectFieldHasNullableArgumentMissingInInterface() + throws + { let interface = try GraphQLInterfaceType( name: "Interface", fields: [ "fieldWithOneArg": GraphQLField( type: GraphQLInt, args: [:] - ), + ) ] ) @@ -107,7 +115,7 @@ import Testing "fieldWithOneArg": GraphQLField( type: GraphQLInt, args: ["addedNullableArg": GraphQLArgument(type: GraphQLInt)] - ), + ) ], interfaces: [interface], isTypeOf: { _, _ -> Bool in @@ -132,7 +140,7 @@ import Testing return [ "object2": GraphQLField( type: object2 - ), + ) ] } object2.fields = { [weak object1] in @@ -142,7 +150,7 @@ import Testing return [ "object1": GraphQLField( type: object1 - ), + ) ] } let query = try GraphQLObjectType( diff --git a/Tests/GraphQLTests/TypeTests/IntrospectionTests.swift b/Tests/GraphQLTests/TypeTests/IntrospectionTests.swift index 08dc415d..2e81ccd8 100644 --- a/Tests/GraphQLTests/TypeTests/IntrospectionTests.swift +++ b/Tests/GraphQLTests/TypeTests/IntrospectionTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct IntrospectionTests { @Test func defaultValues() async throws { let numEnum = try GraphQLEnumType( @@ -28,7 +29,7 @@ import Testing "bool": .init( type: GraphQLBoolean, defaultValue: true - ), + ) ] ), "enum": .init( @@ -37,7 +38,7 @@ import Testing "enum": .init( type: numEnum, defaultValue: "One" - ), + ) ] ), "float": .init( @@ -46,7 +47,7 @@ import Testing "float": .init( type: GraphQLFloat, defaultValue: 2.2 - ), + ) ] ), "id": .init( @@ -55,7 +56,7 @@ import Testing "id": .init( type: GraphQLID, defaultValue: "5" - ), + ) ] ), "int": .init( @@ -64,7 +65,7 @@ import Testing "int": .init( type: GraphQLInt, defaultValue: 5 - ), + ) ] ), "list": .init( @@ -73,7 +74,7 @@ import Testing "list": .init( type: GraphQLList(GraphQLInt), defaultValue: [1, 2, 3] - ), + ) ] ), "object": .init( @@ -82,7 +83,7 @@ import Testing "input": .init( type: inputObject, defaultValue: ["str": "hello"] - ), + ) ] ), "string": .init( @@ -91,7 +92,7 @@ import Testing "string": .init( type: GraphQLString, defaultValue: "hello" - ), + ) ] ), ] @@ -102,27 +103,27 @@ import Testing let introspection = try await graphql( schema: schema, request: """ - query IntrospectionTypeQuery { - __schema { - types { - fields { - args { - defaultValue - name - type { + query IntrospectionTypeQuery { + __schema { + types { + fields { + args { + defaultValue + name + type { + name + } + } name + type { + name + } } - } - name - type { name } } - name } - } - } - """ + """ ) let queryType = try #require( @@ -139,13 +140,13 @@ import Testing "defaultValue": "true", "name": "bool", "type": [ - "name": "Boolean", + "name": "Boolean" ], - ], + ] ], "name": "bool", "type": [ - "name": "Boolean", + "name": "Boolean" ], ], [ @@ -154,13 +155,13 @@ import Testing "defaultValue": "One", "name": "enum", "type": [ - "name": "Enum", + "name": "Enum" ], - ], + ] ], "name": "enum", "type": [ - "name": "Enum", + "name": "Enum" ], ], [ @@ -169,13 +170,13 @@ import Testing "defaultValue": "2.2", "name": "float", "type": [ - "name": "Float", + "name": "Float" ], - ], + ] ], "name": "float", "type": [ - "name": "Float", + "name": "Float" ], ], [ @@ -184,13 +185,13 @@ import Testing "defaultValue": "5", "name": "id", "type": [ - "name": "ID", + "name": "ID" ], - ], + ] ], "name": "id", "type": [ - "name": "ID", + "name": "ID" ], ], [ @@ -199,13 +200,13 @@ import Testing "defaultValue": "5", "name": "int", "type": [ - "name": "Int", + "name": "Int" ], - ], + ] ], "name": "int", "type": [ - "name": "Int", + "name": "Int" ], ], [ @@ -214,13 +215,13 @@ import Testing "defaultValue": "[1, 2, 3]", "name": "list", "type": [ - "name": .null, + "name": .null ], - ], + ] ], "name": "list", "type": [ - "name": .null, + "name": .null ], ], [ @@ -229,13 +230,13 @@ import Testing "defaultValue": "{ str: \"hello\" }", "name": "input", "type": [ - "name": "InputObject", + "name": "InputObject" ], - ], + ] ], "name": "object", "type": [ - "name": "Object", + "name": "Object" ], ], [ @@ -244,13 +245,13 @@ import Testing "defaultValue": "\"hello\"", "name": "string", "type": [ - "name": "String", + "name": "String" ], - ], + ] ], "name": "string", "type": [ - "name": "String", + "name": "String" ], ], ], diff --git a/Tests/GraphQLTests/TypeTests/ScalarTests.swift b/Tests/GraphQLTests/TypeTests/ScalarTests.swift index 30a95d02..4c19ea13 100644 --- a/Tests/GraphQLTests/TypeTests/ScalarTests.swift +++ b/Tests/GraphQLTests/TypeTests/ScalarTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct ScalarTests { @Test func intParseValue() throws { try #expect(GraphQLInt.parseValue(1) == 1) @@ -20,12 +21,12 @@ import Testing try GraphQLInt.parseValue(-9_876_504_321) } // TODO: Avoid rounding these -// #expect( -// throws: (any Error).self, -// "Int cannot represent non-integer value: 0.1" -// ) { -// try GraphQLInt.parseValue(0.1) -// } + // #expect( + // throws: (any Error).self, + // "Int cannot represent non-integer value: 0.1" + // ) { + // try GraphQLInt.parseValue(0.1) + // } #expect( throws: (any Error).self, "Int cannot represent non-integer value: NaN" @@ -101,24 +102,24 @@ import Testing // The GraphQL specification does not allow serializing non-integer values // as Int to avoid accidental data loss. // TODO: Avoid rounding these -// #expect( -// throws: (any Error).self, -// "Int cannot represent non-integer value: 0.1" -// ) { -// try GraphQLInt.serialize(0.1) -// } -// #expect( -// throws: (any Error).self, -// "Int cannot represent non-integer value: 1.1" -// ) { -// try GraphQLInt.serialize(1.1) -// } -// #expect( -// throws: (any Error).self, -// "Int cannot represent non-integer value: -1.1" -// ) { -// try GraphQLInt.serialize(-1.1) -// } + // #expect( + // throws: (any Error).self, + // "Int cannot represent non-integer value: 0.1" + // ) { + // try GraphQLInt.serialize(0.1) + // } + // #expect( + // throws: (any Error).self, + // "Int cannot represent non-integer value: 1.1" + // ) { + // try GraphQLInt.serialize(1.1) + // } + // #expect( + // throws: (any Error).self, + // "Int cannot represent non-integer value: -1.1" + // ) { + // try GraphQLInt.serialize(-1.1) + // } #expect( throws: (any Error).self, #"Int cannot represent non-integer value: "-1.1""# @@ -555,7 +556,7 @@ import Testing try #expect(GraphQLID.serialize(-1) == "-1") let badObjValue: Map = [ - "_id": false, + "_id": false ] #expect( throws: (any Error).self, diff --git a/Tests/GraphQLTests/TypeTests/ValidateSchemaTests.swift b/Tests/GraphQLTests/TypeTests/ValidateSchemaTests.swift index 4c9ada8c..7a889000 100644 --- a/Tests/GraphQLTests/TypeTests/ValidateSchemaTests.swift +++ b/Tests/GraphQLTests/TypeTests/ValidateSchemaTests.swift @@ -1,21 +1,24 @@ -@testable import GraphQL import Testing -let SomeSchema = try! buildSchema(source: """ -scalar SomeScalar +@testable import GraphQL + +let SomeSchema = try! buildSchema( + source: """ + scalar SomeScalar -interface SomeInterface { f: SomeObject } + interface SomeInterface { f: SomeObject } -type SomeObject implements SomeInterface { f: SomeObject } + type SomeObject implements SomeInterface { f: SomeObject } -union SomeUnion = SomeObject + union SomeUnion = SomeObject -enum SomeEnum { ONLY } + enum SomeEnum { ONLY } -input SomeInputObject { val: String = "hello" } + input SomeInputObject { val: String = "hello" } -directive @SomeDirective on QUERY -""") + directive @SomeDirective on QUERY + """ +) let SomeScalarType = SomeSchema.getType(name: "SomeScalar") as! GraphQLScalarType let SomeInterfaceType = SomeSchema.getType(name: "SomeInterface") as! GraphQLInterfaceType let SomeObjectType = SomeSchema.getType(name: "SomeObject") as! GraphQLObjectType @@ -66,7 +69,7 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { query: GraphQLObjectType( name: "Query", fields: [ - "f": .init(type: type), + "f": .init(type: type) ] ) ) @@ -76,108 +79,128 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { // MARK: Type System: A Schema must have Object root types @Test func acceptsASchemaWhoseQueryTypeIsAnObjectType() throws { - let schema = try buildSchema(source: """ - type Query { - test: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: String + } + """ + ) try #expect(validateSchema(schema: schema) == []) - let schemaWithDef = try buildSchema(source: """ - schema { - query: QueryRoot - } + let schemaWithDef = try buildSchema( + source: """ + schema { + query: QueryRoot + } - type QueryRoot { - test: String - } - """) + type QueryRoot { + test: String + } + """ + ) try #expect(validateSchema(schema: schemaWithDef) == []) } @Test func acceptsASchemaWhoseQueryAndMutationTypesAreObjectTypes() throws { - let schema = try buildSchema(source: """ - type Query { - test: String - } - - type Mutation { - test: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: String + } + + type Mutation { + test: String + } + """ + ) try #expect(validateSchema(schema: schema) == []) - let schemaWithDef = try buildSchema(source: """ - schema { - query: QueryRoot - mutation: MutationRoot - } + let schemaWithDef = try buildSchema( + source: """ + schema { + query: QueryRoot + mutation: MutationRoot + } - type QueryRoot { - test: String - } + type QueryRoot { + test: String + } - type MutationRoot { - test: String - } - """) + type MutationRoot { + test: String + } + """ + ) try #expect(validateSchema(schema: schemaWithDef) == []) } @Test func acceptsASchemaWhoseQueryAndSubscriptionTypesAreObjectTypes() throws { - let schema = try buildSchema(source: """ - type Query { - test: String - } - - type Subscription { - test: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: String + } + + type Subscription { + test: String + } + """ + ) try #expect(validateSchema(schema: schema) == []) - let schemaWithDef = try buildSchema(source: """ - schema { - query: QueryRoot - subscription: SubscriptionRoot - } + let schemaWithDef = try buildSchema( + source: """ + schema { + query: QueryRoot + subscription: SubscriptionRoot + } - type QueryRoot { - test: String - } + type QueryRoot { + test: String + } - type SubscriptionRoot { - test: String - } - """) + type SubscriptionRoot { + test: String + } + """ + ) try #expect(validateSchema(schema: schemaWithDef) == []) } @Test func rejectsASchemaWithoutAQueryType() throws { - let schema = try buildSchema(source: """ - type Mutation { - test: String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError(message: "Query root type must be provided."), - ]) - - let schemaWithDef = try buildSchema(source: """ - schema { - mutation: MutationRoot - } - - type MutationRoot { - test: String - } - """) - try #expect(validateSchema(schema: schemaWithDef) == [ - GraphQLError( - message: "Query root type must be provided.", - locations: [.init(line: 2, column: 7)] - ), - ]) + let schema = try buildSchema( + source: """ + type Mutation { + test: String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError(message: "Query root type must be provided.") + ] + ) + + let schemaWithDef = try buildSchema( + source: """ + schema { + mutation: MutationRoot + } + + type MutationRoot { + test: String + } + """ + ) + try #expect( + validateSchema(schema: schemaWithDef) == [ + GraphQLError( + message: "Query root type must be provided.", + locations: [.init(line: 2, column: 7)] + ) + ] + ) } @Test func rejectsASchemaWhoseQueryRootTypeIsNotAnObjectType() throws { @@ -185,26 +208,30 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { throws: (any Error).self, "Query root type must be Object type, it cannot be Query." ) { - try buildSchema(source: """ - input Query { - test: String - } - """) + try buildSchema( + source: """ + input Query { + test: String + } + """ + ) } #expect( throws: (any Error).self, "Query root type must be Object type, it cannot be SomeInputObject." ) { - try buildSchema(source: """ - schema { - query: SomeInputObject - } - - input SomeInputObject { - test: String - } - """) + try buildSchema( + source: """ + schema { + query: SomeInputObject + } + + input SomeInputObject { + test: String + } + """ + ) } } @@ -213,35 +240,39 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { throws: (any Error).self, "Mutation root type must be Object type if provided, it cannot be Mutation." ) { - try buildSchema(source: """ - type Query { - field: String - } - - input Mutation { - test: String - } - """) + try buildSchema( + source: """ + type Query { + field: String + } + + input Mutation { + test: String + } + """ + ) } #expect( throws: (any Error).self, "Mutation root type must be Object type if provided, it cannot be SomeInputObject." ) { - try buildSchema(source: """ - schema { - query: Query - mutation: SomeInputObject - } - - type Query { - field: String - } - - input SomeInputObject { - test: String - } - """) + try buildSchema( + source: """ + schema { + query: Query + mutation: SomeInputObject + } + + type Query { + field: String + } + + input SomeInputObject { + test: String + } + """ + ) } } @@ -250,50 +281,56 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { throws: (any Error).self, "Subscription root type must be Object type if provided, it cannot be Subscription." ) { - try buildSchema(source: """ - type Query { - field: String - } - - input Subscription { - test: String - } - """) + try buildSchema( + source: """ + type Query { + field: String + } + + input Subscription { + test: String + } + """ + ) } #expect( throws: (any Error).self, "Subscription root type must be Object type if provided, it cannot be SomeInputObject." ) { - try buildSchema(source: """ - schema { - query: Query - subscription: SomeInputObject - } - - type Query { - field: String - } - - input SomeInputObject { - test: String - } - """) + try buildSchema( + source: """ + schema { + query: Query + subscription: SomeInputObject + } + + type Query { + field: String + } + + input SomeInputObject { + test: String + } + """ + ) } } @Test func rejectsASchemaExtendedWithInvalidRootTypes() throws { - let schema = try buildSchema(source: """ - input SomeInputObject { - test: String - } + let schema = try buildSchema( + source: """ + input SomeInputObject { + test: String + } - scalar SomeScalar + scalar SomeScalar - enum SomeEnum { - ENUM_VALUE - } - """) + enum SomeEnum { + ENUM_VALUE + } + """ + ) #expect( throws: (any Error).self, @@ -301,11 +338,13 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { ) { try extendSchema( schema: schema, - documentAST: parse(source: """ - extend schema { - query: SomeInputObject - } - """) + documentAST: parse( + source: """ + extend schema { + query: SomeInputObject + } + """ + ) ) } @@ -315,11 +354,13 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { ) { try extendSchema( schema: schema, - documentAST: parse(source: """ - extend schema { - mutation: SomeScalar - } - """) + documentAST: parse( + source: """ + extend schema { + mutation: SomeScalar + } + """ + ) ) } @@ -329,11 +370,13 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { ) { try extendSchema( schema: schema, - documentAST: parse(source: """ - extend schema { - subscription: SomeEnum - } - """) + documentAST: parse( + source: """ + extend schema { + subscription: SomeEnum + } + """ + ) ) } } @@ -348,120 +391,138 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { query: SomeObjectType, directives: [badDirective] ) - try #expect(validateSchema(schema: schema) == [ - GraphQLError(message: "Directive @BadDirective must include 1 or more locations."), - ]) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError(message: "Directive @BadDirective must include 1 or more locations.") + ] + ) } // MARK: Type System: Root types must all be different if provided @Test func acceptsASchemaWithDifferentRootTypes() throws { - let schema = try buildSchema(source: """ - type SomeObject1 { - field: String - } - - type SomeObject2 { - field: String - } - - type SomeObject3 { - field: String - } - - schema { - query: SomeObject1 - mutation: SomeObject2 - subscription: SomeObject3 - } - """) + let schema = try buildSchema( + source: """ + type SomeObject1 { + field: String + } + + type SomeObject2 { + field: String + } + + type SomeObject3 { + field: String + } + + schema { + query: SomeObject1 + mutation: SomeObject2 + subscription: SomeObject3 + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func rejectsASchemaWhereTheSameTypeIsUsedForMultipleRootTypes() throws { - let schema = try buildSchema(source: """ - type SomeObject { - field: String - } - - type UniqueObject { - field: String - } - - schema { - query: SomeObject - mutation: UniqueObject - subscription: SomeObject - } - """) - - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "All root types must be different, \"SomeObject\" type is used as query and subscription root types.", - locations: [ - .init(line: 11, column: 16), - .init(line: 13, column: 23), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type SomeObject { + field: String + } + + type UniqueObject { + field: String + } + + schema { + query: SomeObject + mutation: UniqueObject + subscription: SomeObject + } + """ + ) + + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "All root types must be different, \"SomeObject\" type is used as query and subscription root types.", + locations: [ + .init(line: 11, column: 16), + .init(line: 13, column: 23), + ] + ) + ] + ) } @Test func rejectsASchemaWhereTheSameTypeIsUsedForAllRootTypes() throws { - let schema = try buildSchema(source: """ - type SomeObject { - field: String - } - - schema { - query: SomeObject - mutation: SomeObject - subscription: SomeObject - } - """) - - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "All root types must be different, \"SomeObject\" type is used as query, mutation, and subscription root types.", - locations: [ - .init(line: 7, column: 16), - .init(line: 8, column: 19), - .init(line: 9, column: 23), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type SomeObject { + field: String + } + + schema { + query: SomeObject + mutation: SomeObject + subscription: SomeObject + } + """ + ) + + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "All root types must be different, \"SomeObject\" type is used as query, mutation, and subscription root types.", + locations: [ + .init(line: 7, column: 16), + .init(line: 8, column: 19), + .init(line: 9, column: 23), + ] + ) + ] + ) } // MARK: Type System: Objects must have fields @Test func acceptsAnObjectTypeWithFieldsObject() throws { - let schema = try buildSchema(source: """ - type Query { - field: SomeObject - } - - type SomeObject { - field: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + field: SomeObject + } + + type SomeObject { + field: String + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func rejectsAnObjectTypeWithMissingFields() throws { - let schema = try buildSchema(source: """ - type Query { - test: IncompleteObject - } - - type IncompleteObject - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: "Type IncompleteObject must define one or more fields.", - locations: [.init(line: 6, column: 7)] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: IncompleteObject + } + + type IncompleteObject + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: "Type IncompleteObject must define one or more fields.", + locations: [.init(line: 6, column: 7)] + ) + ] + ) let manualSchema = try schemaWithFieldType( type: GraphQLObjectType( @@ -469,39 +530,46 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { fields: [:] ) ) - try #expect(validateSchema(schema: manualSchema) == [ - GraphQLError(message: "Type IncompleteObject must define one or more fields."), - ]) + try #expect( + validateSchema(schema: manualSchema) == [ + GraphQLError(message: "Type IncompleteObject must define one or more fields.") + ] + ) let manualSchema2 = try schemaWithFieldType( type: - GraphQLObjectType( - name: "IncompleteObject", - fields: { - [:] - } - ) + GraphQLObjectType( + name: "IncompleteObject", + fields: { + [:] + } + ) + ) + try #expect( + validateSchema(schema: manualSchema2) == [ + GraphQLError(message: "Type IncompleteObject must define one or more fields.") + ] ) - try #expect(validateSchema(schema: manualSchema2) == [ - GraphQLError(message: "Type IncompleteObject must define one or more fields."), - ]) } @Test func rejectsAnObjectTypeWithIncorrectlyNamedFields() throws { let schema = try schemaWithFieldType( type: - GraphQLObjectType( - name: "SomeObject", - fields: { - ["__badName": .init(type: GraphQLString)] - } - ) + GraphQLObjectType( + name: "SomeObject", + fields: { + ["__badName": .init(type: GraphQLString)] + } + ) + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Name \"__badName\" must not begin with \"__\", which is reserved by GraphQL introspection." + ) + ] ) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: "Name \"__badName\" must not begin with \"__\", which is reserved by GraphQL introspection." - ), - ]) } // MARK: Type System: Fields args must be properly named @@ -509,17 +577,17 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { @Test func acceptsFieldArgsWithValidNames() throws { let schema = try schemaWithFieldType( type: - GraphQLObjectType( - name: "SomeObject", - fields: [ - "goodField": .init( - type: GraphQLString, - args: [ - "goodArg": .init(type: GraphQLString), - ] - ), - ] - ) + GraphQLObjectType( + name: "SomeObject", + fields: [ + "goodField": .init( + type: GraphQLString, + args: [ + "goodArg": .init(type: GraphQLString) + ] + ) + ] + ) ) try #expect(validateSchema(schema: schema) == []) } @@ -527,292 +595,333 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { @Test func rejectsFieldArgWithInvalidNames() throws { let schema = try schemaWithFieldType( type: - GraphQLObjectType( - name: "SomeObject", - fields: [ - "badField": .init( - type: GraphQLString, - args: [ - "__badName": .init(type: GraphQLString), - ] - ), - ] - ) + GraphQLObjectType( + name: "SomeObject", + fields: [ + "badField": .init( + type: GraphQLString, + args: [ + "__badName": .init(type: GraphQLString) + ] + ) + ] + ) ) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: "Name \"__badName\" must not begin with \"__\", which is reserved by GraphQL introspection." - ), - ]) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Name \"__badName\" must not begin with \"__\", which is reserved by GraphQL introspection." + ) + ] + ) } // MARK: Type System: Union types must be valid @Test func acceptsAUnionTypeWithMemberTypes() throws { - let schema = try buildSchema(source: """ - type Query { - test: GoodUnion - } - - type TypeA { - field: String - } - - type TypeB { - field: String - } - - union GoodUnion = - | TypeA - | TypeB - """) + let schema = try buildSchema( + source: """ + type Query { + test: GoodUnion + } + + type TypeA { + field: String + } + + type TypeB { + field: String + } + + union GoodUnion = + | TypeA + | TypeB + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func rejectsAUnionTypeWithEmptyTypes() throws { - var schema = try buildSchema(source: """ - type Query { - test: BadUnion - } + var schema = try buildSchema( + source: """ + type Query { + test: BadUnion + } - union BadUnion - """) + union BadUnion + """ + ) schema = try extendSchema( schema: schema, - documentAST: parse(source: """ - directive @test on UNION + documentAST: parse( + source: """ + directive @test on UNION - extend union BadUnion @test - """) + extend union BadUnion @test + """ + ) ) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: "Union type BadUnion must define one or more member types.", - locations: [ - .init(line: 6, column: 7), - .init(line: 4, column: 9), - ] - ), - ]) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: "Union type BadUnion must define one or more member types.", + locations: [ + .init(line: 6, column: 7), + .init(line: 4, column: 9), + ] + ) + ] + ) } @Test func rejectsAUnionTypeWithDuplicatedMemberType() throws { - var schema = try buildSchema(source: """ - type Query { - test: BadUnion - } - - type TypeA { - field: String - } - - type TypeB { - field: String - } - - union BadUnion = - | TypeA - | TypeB - | TypeA - """) - - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: "Union type BadUnion can only include type TypeA once.", - locations: [ - .init(line: 15, column: 11), - .init(line: 17, column: 11), - ] - ), - ]) + var schema = try buildSchema( + source: """ + type Query { + test: BadUnion + } + + type TypeA { + field: String + } + + type TypeB { + field: String + } + + union BadUnion = + | TypeA + | TypeB + | TypeA + """ + ) + + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: "Union type BadUnion can only include type TypeA once.", + locations: [ + .init(line: 15, column: 11), + .init(line: 17, column: 11), + ] + ) + ] + ) schema = try extendSchema( schema: schema, documentAST: parse(source: "extend union BadUnion = TypeB") ) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: "Union type BadUnion can only include type TypeA once.", - locations: [ - .init(line: 15, column: 11), - .init(line: 17, column: 11), - ] - ), - GraphQLError( - message: "Union type BadUnion can only include type TypeB once.", - locations: [ - .init(line: 16, column: 11), - .init(line: 1, column: 25), - ] - ), - ]) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: "Union type BadUnion can only include type TypeA once.", + locations: [ + .init(line: 15, column: 11), + .init(line: 17, column: 11), + ] + ), + GraphQLError( + message: "Union type BadUnion can only include type TypeB once.", + locations: [ + .init(line: 16, column: 11), + .init(line: 1, column: 25), + ] + ), + ] + ) } // MARK: Type System: Input Objects must have fields @Test func acceptsAnInputObjectTypeWithFields() throws { - let schema = try buildSchema(source: """ - type Query { - field(arg: SomeInputObject): String - } - - input SomeInputObject { - field: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + field(arg: SomeInputObject): String + } + + input SomeInputObject { + field: String + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func rejectsAnInputObjectTypeWithMissingFields() throws { - var schema = try buildSchema(source: """ - type Query { - field(arg: SomeInputObject): String - } + var schema = try buildSchema( + source: """ + type Query { + field(arg: SomeInputObject): String + } - input SomeInputObject - """) + input SomeInputObject + """ + ) schema = try extendSchema( schema: schema, - documentAST: parse(source: """ - directive @test on INPUT_OBJECT + documentAST: parse( + source: """ + directive @test on INPUT_OBJECT - extend input SomeInputObject @test - """) + extend input SomeInputObject @test + """ + ) ) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Input Object type SomeInputObject must define one or more fields.", - locations: [ - .init(line: 6, column: 7), - .init(line: 4, column: 9), - ] - ), - ]) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Input Object type SomeInputObject must define one or more fields.", + locations: [ + .init(line: 6, column: 7), + .init(line: 4, column: 9), + ] + ) + ] + ) } @Test func acceptsAnInputObjectWithBreakableCircularReference() throws { - let schema = try buildSchema(source: """ - type Query { - field(arg: SomeInputObject): String - } - - input SomeInputObject { - self: SomeInputObject - arrayOfSelf: [SomeInputObject] - nonNullArrayOfSelf: [SomeInputObject]! - nonNullArrayOfNonNullSelf: [SomeInputObject!]! - intermediateSelf: AnotherInputObject - } - - input AnotherInputObject { - parent: SomeInputObject - } - """) + let schema = try buildSchema( + source: """ + type Query { + field(arg: SomeInputObject): String + } + + input SomeInputObject { + self: SomeInputObject + arrayOfSelf: [SomeInputObject] + nonNullArrayOfSelf: [SomeInputObject]! + nonNullArrayOfNonNullSelf: [SomeInputObject!]! + intermediateSelf: AnotherInputObject + } + + input AnotherInputObject { + parent: SomeInputObject + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func rejectsAnInputObjectWithNonBreakableCircularReference() throws { - let schema = try buildSchema(source: """ - type Query { - field(arg: SomeInputObject): String - } - - input SomeInputObject { - nonNullSelf: SomeInputObject! - } - """) - - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: #"Cannot reference Input Object "SomeInputObject" within itself through a series of non-null fields: "nonNullSelf"."#, - locations: [.init(line: 7, column: 9)] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + field(arg: SomeInputObject): String + } + + input SomeInputObject { + nonNullSelf: SomeInputObject! + } + """ + ) + + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + #"Cannot reference Input Object "SomeInputObject" within itself through a series of non-null fields: "nonNullSelf"."#, + locations: [.init(line: 7, column: 9)] + ) + ] + ) } @Test func rejectsInputObjectsWithNonbreakableCircularReferenceSpreadAcrossThem() throws { - let schema = try buildSchema(source: """ - type Query { - field(arg: SomeInputObject): String - } - - input SomeInputObject { - startLoop: AnotherInputObject! - } - - input AnotherInputObject { - nextInLoop: YetAnotherInputObject! - } - - input YetAnotherInputObject { - closeLoop: SomeInputObject! - } - """) - - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - #"Cannot reference Input Object "SomeInputObject" within itself through a series of non-null fields: "startLoop.nextInLoop.closeLoop"."#, - locations: [ - .init(line: 7, column: 9), - .init(line: 11, column: 9), - .init(line: 15, column: 9), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + field(arg: SomeInputObject): String + } + + input SomeInputObject { + startLoop: AnotherInputObject! + } + + input AnotherInputObject { + nextInLoop: YetAnotherInputObject! + } + + input YetAnotherInputObject { + closeLoop: SomeInputObject! + } + """ + ) + + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + #"Cannot reference Input Object "SomeInputObject" within itself through a series of non-null fields: "startLoop.nextInLoop.closeLoop"."#, + locations: [ + .init(line: 7, column: 9), + .init(line: 11, column: 9), + .init(line: 15, column: 9), + ] + ) + ] + ) } @Test func rejectsInputObjectsWithMultipleNonbreakableCircularReference() throws { - let schema = try buildSchema(source: """ - type Query { - field(arg: SomeInputObject): String - } - - input SomeInputObject { - startLoop: AnotherInputObject! - } - - input AnotherInputObject { - closeLoop: SomeInputObject! - startSecondLoop: YetAnotherInputObject! - } - - input YetAnotherInputObject { - closeSecondLoop: AnotherInputObject! - nonNullSelf: YetAnotherInputObject! - } - """) - - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - #"Cannot reference Input Object "SomeInputObject" within itself through a series of non-null fields: "startLoop.closeLoop"."#, - locations: [ - .init(line: 7, column: 9), - .init(line: 11, column: 9), - ] - ), - GraphQLError( - message: - #"Cannot reference Input Object "AnotherInputObject" within itself through a series of non-null fields: "startSecondLoop.closeSecondLoop"."#, - locations: [ - .init(line: 12, column: 9), - .init(line: 16, column: 9), - ] - ), - GraphQLError( - message: #"Cannot reference Input Object "YetAnotherInputObject" within itself through a series of non-null fields: "nonNullSelf"."#, - locations: [.init(line: 17, column: 9)] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + field(arg: SomeInputObject): String + } + + input SomeInputObject { + startLoop: AnotherInputObject! + } + + input AnotherInputObject { + closeLoop: SomeInputObject! + startSecondLoop: YetAnotherInputObject! + } + + input YetAnotherInputObject { + closeSecondLoop: AnotherInputObject! + nonNullSelf: YetAnotherInputObject! + } + """ + ) + + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + #"Cannot reference Input Object "SomeInputObject" within itself through a series of non-null fields: "startLoop.closeLoop"."#, + locations: [ + .init(line: 7, column: 9), + .init(line: 11, column: 9), + ] + ), + GraphQLError( + message: + #"Cannot reference Input Object "AnotherInputObject" within itself through a series of non-null fields: "startSecondLoop.closeSecondLoop"."#, + locations: [ + .init(line: 12, column: 9), + .init(line: 16, column: 9), + ] + ), + GraphQLError( + message: + #"Cannot reference Input Object "YetAnotherInputObject" within itself through a series of non-null fields: "nonNullSelf"."#, + locations: [.init(line: 17, column: 9)] + ), + ] + ) } @Test func rejectsAnInputObjectTypeWithIncorrectlyTypedFields() throws { @@ -820,97 +929,112 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { throws: (any Error).self, "The type of SomeInputObject.badObject must be Input Type but got: SomeObject." ) { - try buildSchema(source: """ - type Query { - field(arg: SomeInputObject): String - } - - type SomeObject { - field: String - } - - union SomeUnion = SomeObject - - input SomeInputObject { - badObject: SomeObject - badUnion: SomeUnion - goodInputObject: SomeInputObject - } - """) + try buildSchema( + source: """ + type Query { + field(arg: SomeInputObject): String + } + + type SomeObject { + field: String + } + + union SomeUnion = SomeObject + + input SomeInputObject { + badObject: SomeObject + badUnion: SomeUnion + goodInputObject: SomeInputObject + } + """ + ) } } @Test func rejectsAnInputObjectTypeWithRequiredArgumentThatIsDeprecated() throws { - let schema = try buildSchema(source: """ - type Query { - field(arg: SomeInputObject): String - } - - input SomeInputObject { - badField: String! @deprecated - optionalField: String @deprecated - anotherOptionalField: String! = "" @deprecated - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Required input field SomeInputObject.badField cannot be deprecated.", - locations: [ - .init(line: 7, column: 27), - .init(line: 7, column: 19), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + field(arg: SomeInputObject): String + } + + input SomeInputObject { + badField: String! @deprecated + optionalField: String @deprecated + anotherOptionalField: String! = "" @deprecated + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Required input field SomeInputObject.badField cannot be deprecated.", + locations: [ + .init(line: 7, column: 27), + .init(line: 7, column: 19), + ] + ) + ] + ) } // MARK: Type System: Enum types must be well defined @Test func rejectsAnEnumTypeWithoutValues() throws { - var schema = try buildSchema(source: """ - type Query { - field: SomeEnum - } + var schema = try buildSchema( + source: """ + type Query { + field: SomeEnum + } - enum SomeEnum - """) + enum SomeEnum + """ + ) schema = try extendSchema( schema: schema, - documentAST: parse(source: """ - directive @test on ENUM + documentAST: parse( + source: """ + directive @test on ENUM - extend enum SomeEnum @test - """) + extend enum SomeEnum @test + """ + ) ) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: "Enum type SomeEnum must define one or more values.", - locations: [ - .init(line: 6, column: 7), - .init(line: 4, column: 9), - ] - ), - ]) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: "Enum type SomeEnum must define one or more values.", + locations: [ + .init(line: 6, column: 7), + .init(line: 4, column: 9), + ] + ) + ] + ) } @Test func rejectsAnEnumTypeWithIncorrectlyNamedValues() throws { let schema = try schemaWithFieldType( type: - GraphQLEnumType( - name: "SomeEnum", - values: [ - "__badName": .init(value: .string("__badName")), - ] - ) + GraphQLEnumType( + name: "SomeEnum", + values: [ + "__badName": .init(value: .string("__badName")) + ] + ) ) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: #"Name "__badName" must not begin with "__", which is reserved by GraphQL introspection."# - ), - ]) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + #"Name "__badName" must not begin with "__", which is reserved by GraphQL introspection."# + ) + ] + ) } // MARK: Type System: Object fields must have output types @@ -921,7 +1045,7 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { let BadObjectType = try GraphQLObjectType( name: "BadObject", fields: [ - "badField": fieldConfig, + "badField": fieldConfig ] ) @@ -929,7 +1053,7 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { query: GraphQLObjectType( name: "Query", fields: [ - "f": .init(type: BadObjectType), + "f": .init(type: BadObjectType) ] ), types: [SomeObjectType] @@ -941,15 +1065,17 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { throws: (any Error).self, "The type of Query.field must be Output Type but got: [SomeInputObject]." ) { - try buildSchema(source: """ - type Query { - field: [SomeInputObject] - } - - input SomeInputObject { - field: String - } - """) + try buildSchema( + source: """ + type Query { + field: [SomeInputObject] + } + + input SomeInputObject { + field: String + } + """ + ) } } @@ -960,204 +1086,233 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { throws: (any Error).self, "Type BadObject must only implement Interface types, it cannot implement SomeInputObject." ) { - try buildSchema(source: """ - type Query { - test: BadObject - } - - input SomeInputObject { - field: String - } - - type BadObject implements SomeInputObject { - field: String - } - """) + try buildSchema( + source: """ + type Query { + test: BadObject + } + + input SomeInputObject { + field: String + } + + type BadObject implements SomeInputObject { + field: String + } + """ + ) } } @Test func rejectsAnObjectImplementingTheSameInterfaceTwice() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field: String - } - - type AnotherObject implements AnotherInterface & AnotherInterface { - field: String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: "Type AnotherObject can only implement AnotherInterface once.", - locations: [ - .init(line: 10, column: 37), - .init(line: 10, column: 56), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field: String + } + + type AnotherObject implements AnotherInterface & AnotherInterface { + field: String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: "Type AnotherObject can only implement AnotherInterface once.", + locations: [ + .init(line: 10, column: 37), + .init(line: 10, column: 56), + ] + ) + ] + ) } @Test func rejectsAnObjectImplementingTheSameInterfaceTwiceDueToExtension() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field: String - } - - type AnotherObject implements AnotherInterface { - field: String - } - """) - let extendedSchema = try extendSchema( - schema: schema, - documentAST: parse(source: "extend type AnotherObject implements AnotherInterface") + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field: String + } + + type AnotherObject implements AnotherInterface { + field: String + } + """ + ) + let extendedSchema = try extendSchema( + schema: schema, + documentAST: parse(source: "extend type AnotherObject implements AnotherInterface") + ) + try #expect( + validateSchema(schema: extendedSchema) == [ + GraphQLError( + message: "Type AnotherObject can only implement AnotherInterface once.", + locations: [ + .init(line: 10, column: 37), + .init(line: 1, column: 38), + ] + ) + ] ) - try #expect(validateSchema(schema: extendedSchema) == [ - GraphQLError( - message: "Type AnotherObject can only implement AnotherInterface once.", - locations: [ - .init(line: 10, column: 37), - .init(line: 1, column: 38), - ] - ), - ]) } // MARK: Type System: Interface extensions should be valid @Test func rejectsAnObjectImplementingTheExtendedInterfaceDueToMissingField() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field: String - } - - type AnotherObject implements AnotherInterface { - field: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field: String + } + + type AnotherObject implements AnotherInterface { + field: String + } + """ + ) let extendedSchema = try extendSchema( schema: schema, - documentAST: parse(source: """ - extend interface AnotherInterface { - newField: String - } - - extend type AnotherObject { - differentNewField: String - } - """) - ) - try #expect(validateSchema(schema: extendedSchema) == [ - GraphQLError( - message: - "Interface field AnotherInterface.newField expected but AnotherObject does not provide it.", - locations: [ - .init(line: 3, column: 11), - .init(line: 10, column: 7), - .init(line: 6, column: 9), - ] - ), - ]) + documentAST: parse( + source: """ + extend interface AnotherInterface { + newField: String + } + + extend type AnotherObject { + differentNewField: String + } + """ + ) + ) + try #expect( + validateSchema(schema: extendedSchema) == [ + GraphQLError( + message: + "Interface field AnotherInterface.newField expected but AnotherObject does not provide it.", + locations: [ + .init(line: 3, column: 11), + .init(line: 10, column: 7), + .init(line: 6, column: 9), + ] + ) + ] + ) } @Test func rejectsAnObjectImplementingTheExtendedInterfaceDueToMissingFieldArgs() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field: String - } - - type AnotherObject implements AnotherInterface { - field: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field: String + } + + type AnotherObject implements AnotherInterface { + field: String + } + """ + ) let extendedSchema = try extendSchema( schema: schema, - documentAST: parse(source: """ - extend interface AnotherInterface { - newField(test: Boolean): String - } - - extend type AnotherObject { - newField: String - } - """) - ) - try #expect(validateSchema(schema: extendedSchema) == [ - GraphQLError( - message: - "Interface field argument AnotherInterface.newField(test:) expected but AnotherObject.newField does not provide it.", - locations: [ - .init(line: 3, column: 20), - .init(line: 7, column: 11), - ] - ), - ]) + documentAST: parse( + source: """ + extend interface AnotherInterface { + newField(test: Boolean): String + } + + extend type AnotherObject { + newField: String + } + """ + ) + ) + try #expect( + validateSchema(schema: extendedSchema) == [ + GraphQLError( + message: + "Interface field argument AnotherInterface.newField(test:) expected but AnotherObject.newField does not provide it.", + locations: [ + .init(line: 3, column: 20), + .init(line: 7, column: 11), + ] + ) + ] + ) } - @Test func rejectsObjectsImplementingTheExtendedInterfaceDueToMismatchingInterfaceType() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } + @Test func rejectsObjectsImplementingTheExtendedInterfaceDueToMismatchingInterfaceType() throws + { + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } - interface AnotherInterface { - field: String - } + interface AnotherInterface { + field: String + } - type AnotherObject implements AnotherInterface { - field: String - } - """) + type AnotherObject implements AnotherInterface { + field: String + } + """ + ) let extendedSchema = try extendSchema( schema: schema, - documentAST: parse(source: """ - extend interface AnotherInterface { - newInterfaceField: NewInterface - } - - interface NewInterface { - newField: String - } - - interface MismatchingInterface { - newField: String - } - - extend type AnotherObject { - newInterfaceField: MismatchingInterface - } - - # Required to prevent unused interface errors - type DummyObject implements NewInterface & MismatchingInterface { - newField: String - } - """) - ) - try #expect(validateSchema(schema: extendedSchema) == [ - GraphQLError( - message: - "Interface field AnotherInterface.newInterfaceField expects type NewInterface but AnotherObject.newInterfaceField is type MismatchingInterface.", - locations: [ - .init(line: 3, column: 30), - .init(line: 15, column: 30), - ] - ), - ]) + documentAST: parse( + source: """ + extend interface AnotherInterface { + newInterfaceField: NewInterface + } + + interface NewInterface { + newField: String + } + + interface MismatchingInterface { + newField: String + } + + extend type AnotherObject { + newInterfaceField: MismatchingInterface + } + + # Required to prevent unused interface errors + type DummyObject implements NewInterface & MismatchingInterface { + newField: String + } + """ + ) + ) + try #expect( + validateSchema(schema: extendedSchema) == [ + GraphQLError( + message: + "Interface field AnotherInterface.newInterfaceField expects type NewInterface but AnotherObject.newInterfaceField is type MismatchingInterface.", + locations: [ + .init(line: 3, column: 30), + .init(line: 15, column: 30), + ] + ) + ] + ) } // MARK: Type System: Interface fields must have output types @@ -1180,7 +1335,7 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { query: GraphQLObjectType( name: "Query", fields: [ - "f": .init(type: BadInterfaceType), + "f": .init(type: BadInterfaceType) ] ), types: [BadImplementingType, SomeObjectType] @@ -1199,36 +1354,40 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { throws: (any Error).self, "The type of SomeInterface.field must be Output Type but got: SomeInputObject." ) { - try buildSchema(source: """ - type Query { - test: SomeInterface - } - - interface SomeInterface { - field: SomeInputObject - } - - input SomeInputObject { - foo: String - } - - type SomeObject implements SomeInterface { - field: SomeInputObject - } - """) + try buildSchema( + source: """ + type Query { + test: SomeInterface + } + + interface SomeInterface { + field: SomeInputObject + } + + input SomeInputObject { + foo: String + } + + type SomeObject implements SomeInterface { + field: SomeInputObject + } + """ + ) } } @Test func acceptsAnInterfaceNotImplementedByAtLeastOneObject() throws { - let schema = try buildSchema(source: """ - type Query { - test: SomeInterface - } - - interface SomeInterface { - foo: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: SomeInterface + } + + interface SomeInterface { + foo: String + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @@ -1241,9 +1400,9 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { "badField": .init( type: GraphQLString, args: [ - "badArg": argConfig, + "badArg": argConfig ] - ), + ) ] ) @@ -1251,7 +1410,7 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { query: GraphQLObjectType( name: "Query", fields: [ - "f": .init(type: BadObjectType), + "f": .init(type: BadObjectType) ] ), directives: [ @@ -1259,9 +1418,9 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { name: "BadDirective", locations: [DirectiveLocation.query], args: [ - "badArg": argConfig, + "badArg": argConfig ] - ), + ) ] ) } @@ -1274,38 +1433,42 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { } @Test func rejectsARequiredArgumentThatIsDeprecated() throws { - let schema = try buildSchema(source: """ - directive @BadDirective( - badArg: String! @deprecated - optionalArg: String @deprecated - anotherOptionalArg: String! = "" @deprecated - ) on FIELD - - type Query { - test( - badArg: String! @deprecated - optionalArg: String @deprecated - anotherOptionalArg: String! = "" @deprecated - ): String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Required argument @BadDirective(badArg:) cannot be deprecated.", - locations: [ - .init(line: 3, column: 25), - .init(line: 3, column: 17), - ] - ), - GraphQLError( - message: "Required argument Query.test(badArg:) cannot be deprecated.", - locations: [ - .init(line: 10, column: 27), - .init(line: 10, column: 19), - ] - ), - ]) + let schema = try buildSchema( + source: """ + directive @BadDirective( + badArg: String! @deprecated + optionalArg: String @deprecated + anotherOptionalArg: String! = "" @deprecated + ) on FIELD + + type Query { + test( + badArg: String! @deprecated + optionalArg: String @deprecated + anotherOptionalArg: String! = "" @deprecated + ): String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Required argument @BadDirective(badArg:) cannot be deprecated.", + locations: [ + .init(line: 3, column: 25), + .init(line: 3, column: 17), + ] + ), + GraphQLError( + message: "Required argument Query.test(badArg:) cannot be deprecated.", + locations: [ + .init(line: 10, column: 27), + .init(line: 10, column: 19), + ] + ), + ] + ) } @Test func rejectsANoninputTypeAsAFieldArgWithLocations() throws { @@ -1313,15 +1476,17 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { throws: (any Error).self, "The type of Query.test(arg:) must be Input Type but got: SomeObject." ) { - try buildSchema(source: """ - type Query { - test(arg: SomeObject): String - } - - type SomeObject { - foo: String - } - """) + try buildSchema( + source: """ + type Query { + test(arg: SomeObject): String + } + + type SomeObject { + foo: String + } + """ + ) } } @@ -1333,7 +1498,7 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { let BadInputObjectType = try GraphQLInputObjectType( name: "BadInputObject", fields: [ - "badField": inputFieldConfig, + "badField": inputFieldConfig ] ) @@ -1344,9 +1509,9 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { "f": .init( type: GraphQLString, args: [ - "badArg": .init(type: BadInputObjectType), + "badArg": .init(type: BadInputObjectType) ] - ), + ) ] ) ) @@ -1364,671 +1529,765 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { throws: (any Error).self, "The type of SomeInputObject.foo must be Input Type but got: SomeObject." ) { - try buildSchema(source: """ - type Query { - test(arg: SomeInputObject): String - } - - input SomeInputObject { - foo: SomeObject - } - - type SomeObject { - bar: String - } - """) + try buildSchema( + source: """ + type Query { + test(arg: SomeInputObject): String + } + + input SomeInputObject { + foo: SomeObject + } + + type SomeObject { + bar: String + } + """ + ) } } // MARK: Type System: OneOf Input Object fields must be nullable @Test func rejectsNonnullableFields() throws { - let schema = try buildSchema(source: """ - type Query { - test(arg: SomeInputObject): String - } - - input SomeInputObject @oneOf { - a: String - b: String! - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: "OneOf input field SomeInputObject.b must be nullable.", - locations: [.init(line: 8, column: 12)] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test(arg: SomeInputObject): String + } + + input SomeInputObject @oneOf { + a: String + b: String! + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: "OneOf input field SomeInputObject.b must be nullable.", + locations: [.init(line: 8, column: 12)] + ) + ] + ) } @Test func rejectsFieldsWithDefaultValues() throws { - let schema = try buildSchema(source: """ - type Query { - test(arg: SomeInputObject): String - } - - input SomeInputObject @oneOf { - a: String - b: String = "foo" - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: "OneOf input field SomeInputObject.b cannot have a default value.", - locations: [.init(line: 8, column: 9)] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test(arg: SomeInputObject): String + } + + input SomeInputObject @oneOf { + a: String + b: String = "foo" + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: "OneOf input field SomeInputObject.b cannot have a default value.", + locations: [.init(line: 8, column: 9)] + ) + ] + ) } // MARK: Objects must adhere to Interface they implement @Test func acceptsAnObjectWhichImplementsAnInterface() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field(input: String): String - } - - type AnotherObject implements AnotherInterface { - field(input: String): String - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field(input: String): String + } + + type AnotherObject implements AnotherInterface { + field(input: String): String + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func acceptsAnObjectWhichImplementsAnInterfaceAlongWithMoreFields() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field(input: String): String - } - - type AnotherObject implements AnotherInterface { - field(input: String): String - anotherField: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field(input: String): String + } + + type AnotherObject implements AnotherInterface { + field(input: String): String + anotherField: String + } + """ + ) try #expect(validateSchema(schema: schema) == []) } - @Test func acceptsAnObjectWhichImplementsAnInterfaceFieldAlongWithAdditionalOptionalArguments( - ) throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } + @Test func acceptsAnObjectWhichImplementsAnInterfaceFieldAlongWithAdditionalOptionalArguments() + throws + { + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } - interface AnotherInterface { - field(input: String): String - } + interface AnotherInterface { + field(input: String): String + } - type AnotherObject implements AnotherInterface { - field(input: String, anotherInput: String): String - } - """) + type AnotherObject implements AnotherInterface { + field(input: String, anotherInput: String): String + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func rejectsAnObjectMissingAnInterfaceField() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field(input: String): String - } - - type AnotherObject implements AnotherInterface { - anotherField: String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field AnotherInterface.field expected but AnotherObject does not provide it.", - locations: [ - .init(line: 7, column: 9), - .init(line: 10, column: 7), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field(input: String): String + } + + type AnotherObject implements AnotherInterface { + anotherField: String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field AnotherInterface.field expected but AnotherObject does not provide it.", + locations: [ + .init(line: 7, column: 9), + .init(line: 10, column: 7), + ] + ) + ] + ) } @Test func rejectsAnObjectWithAnIncorrectlyTypedInterfaceField() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field(input: String): String - } - - type AnotherObject implements AnotherInterface { - field(input: String): Int - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field AnotherInterface.field expects type String but AnotherObject.field is type Int.", - locations: [ - .init(line: 7, column: 31), - .init(line: 11, column: 31), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field(input: String): String + } + + type AnotherObject implements AnotherInterface { + field(input: String): Int + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field AnotherInterface.field expects type String but AnotherObject.field is type Int.", + locations: [ + .init(line: 7, column: 31), + .init(line: 11, column: 31), + ] + ) + ] + ) } @Test func rejectsAnObjectWithADifferentlyTypedInterfaceField() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - type A { foo: String } - type B { foo: String } - - interface AnotherInterface { - field: A - } - - type AnotherObject implements AnotherInterface { - field: B - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field AnotherInterface.field expects type A but AnotherObject.field is type B.", - locations: [ - .init(line: 10, column: 16), - .init(line: 14, column: 16), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + type A { foo: String } + type B { foo: String } + + interface AnotherInterface { + field: A + } + + type AnotherObject implements AnotherInterface { + field: B + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field AnotherInterface.field expects type A but AnotherObject.field is type B.", + locations: [ + .init(line: 10, column: 16), + .init(line: 14, column: 16), + ] + ) + ] + ) } @Test func acceptsAnObjectWithASubtypedInterfaceField_Interface() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field: AnotherInterface - } - - type AnotherObject implements AnotherInterface { - field: AnotherObject - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field: AnotherInterface + } + + type AnotherObject implements AnotherInterface { + field: AnotherObject + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func acceptsAnObjectWithASubtypedInterfaceField_Union() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } - type SomeObject { - field: String - } + type SomeObject { + field: String + } - union SomeUnionType = SomeObject + union SomeUnionType = SomeObject - interface AnotherInterface { - field: SomeUnionType - } + interface AnotherInterface { + field: SomeUnionType + } - type AnotherObject implements AnotherInterface { - field: SomeObject - } - """) + type AnotherObject implements AnotherInterface { + field: SomeObject + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func rejectsAnObjectMissingAnInterfaceArgument() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field(input: String): String - } - - type AnotherObject implements AnotherInterface { - field: String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field argument AnotherInterface.field(input:) expected but AnotherObject.field does not provide it.", - locations: [ - .init(line: 7, column: 15), - .init(line: 11, column: 9), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field(input: String): String + } + + type AnotherObject implements AnotherInterface { + field: String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field argument AnotherInterface.field(input:) expected but AnotherObject.field does not provide it.", + locations: [ + .init(line: 7, column: 15), + .init(line: 11, column: 9), + ] + ) + ] + ) } @Test func rejectsAnObjectWithAnIncorrectlyTypedInterfaceArgument() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field(input: String): String - } - - type AnotherObject implements AnotherInterface { - field(input: Int): String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field argument AnotherInterface.field(input:) expects type String but AnotherObject.field(input:) is type Int.", - locations: [ - .init(line: 7, column: 22), - .init(line: 11, column: 22), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field(input: String): String + } + + type AnotherObject implements AnotherInterface { + field(input: Int): String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field argument AnotherInterface.field(input:) expects type String but AnotherObject.field(input:) is type Int.", + locations: [ + .init(line: 7, column: 22), + .init(line: 11, column: 22), + ] + ) + ] + ) } @Test func rejectsAnObjectWithBothAnIncorrectlyTypedFieldAndArgument() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field(input: String): String - } - - type AnotherObject implements AnotherInterface { - field(input: Int): Int - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field AnotherInterface.field expects type String but AnotherObject.field is type Int.", - locations: [ - .init(line: 7, column: 31), - .init(line: 11, column: 28), - ] - ), - GraphQLError( - message: - "Interface field argument AnotherInterface.field(input:) expects type String but AnotherObject.field(input:) is type Int.", - locations: [ - .init(line: 7, column: 22), - .init(line: 11, column: 22), - ] - ), - ]) - } - - @Test func rejectsAnObjectWhichImplementsAnInterfaceFieldAlongWithAdditionalRequiredArguments( - ) throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field(baseArg: String): String - } - - type AnotherObject implements AnotherInterface { - field( - baseArg: String, - requiredArg: String! - optionalArg1: String, - optionalArg2: String = "", - ): String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - #"Argument "AnotherObject.field(requiredArg:)" must not be required type "String!" if not provided by the Interface field "AnotherInterface.field"."#, - locations: [ - .init(line: 13, column: 11), - .init(line: 7, column: 9), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field(input: String): String + } + + type AnotherObject implements AnotherInterface { + field(input: Int): Int + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field AnotherInterface.field expects type String but AnotherObject.field is type Int.", + locations: [ + .init(line: 7, column: 31), + .init(line: 11, column: 28), + ] + ), + GraphQLError( + message: + "Interface field argument AnotherInterface.field(input:) expects type String but AnotherObject.field(input:) is type Int.", + locations: [ + .init(line: 7, column: 22), + .init(line: 11, column: 22), + ] + ), + ] + ) + } + + @Test func rejectsAnObjectWhichImplementsAnInterfaceFieldAlongWithAdditionalRequiredArguments() + throws + { + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field(baseArg: String): String + } + + type AnotherObject implements AnotherInterface { + field( + baseArg: String, + requiredArg: String! + optionalArg1: String, + optionalArg2: String = "", + ): String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + #"Argument "AnotherObject.field(requiredArg:)" must not be required type "String!" if not provided by the Interface field "AnotherInterface.field"."#, + locations: [ + .init(line: 13, column: 11), + .init(line: 7, column: 9), + ] + ) + ] + ) } @Test func acceptsAnObjectWithAnEquivalentlyWrappedInterfaceFieldType() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field: [String]! - } - - type AnotherObject implements AnotherInterface { - field: [String]! - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field: [String]! + } + + type AnotherObject implements AnotherInterface { + field: [String]! + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func rejectsAnObjectWithANonlistInterfaceFieldListType() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field: [String] - } - - type AnotherObject implements AnotherInterface { - field: String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field AnotherInterface.field expects type [String] but AnotherObject.field is type String.", - locations: [ - .init(line: 7, column: 16), - .init(line: 11, column: 16), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field: [String] + } + + type AnotherObject implements AnotherInterface { + field: String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field AnotherInterface.field expects type [String] but AnotherObject.field is type String.", + locations: [ + .init(line: 7, column: 16), + .init(line: 11, column: 16), + ] + ) + ] + ) } @Test func rejectsAnObjectWithAListInterfaceFieldNonlistType() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field: String - } - - type AnotherObject implements AnotherInterface { - field: [String] - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field AnotherInterface.field expects type String but AnotherObject.field is type [String].", - locations: [ - .init(line: 7, column: 16), - .init(line: 11, column: 16), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field: String + } + + type AnotherObject implements AnotherInterface { + field: [String] + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field AnotherInterface.field expects type String but AnotherObject.field is type [String].", + locations: [ + .init(line: 7, column: 16), + .init(line: 11, column: 16), + ] + ) + ] + ) } @Test func acceptsAnObjectWithASubsetNonnullInterfaceFieldType() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field: String - } - - type AnotherObject implements AnotherInterface { - field: String! - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field: String + } + + type AnotherObject implements AnotherInterface { + field: String! + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func rejectsAnObjectWithASupersetNullableInterfaceFieldType() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface AnotherInterface { - field: String! - } - - type AnotherObject implements AnotherInterface { - field: String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field AnotherInterface.field expects type String! but AnotherObject.field is type String.", - locations: [ - .init(line: 7, column: 16), - .init(line: 11, column: 16), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface AnotherInterface { + field: String! + } + + type AnotherObject implements AnotherInterface { + field: String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field AnotherInterface.field expects type String! but AnotherObject.field is type String.", + locations: [ + .init(line: 7, column: 16), + .init(line: 11, column: 16), + ] + ) + ] + ) } @Test func rejectsAnObjectMissingATransitiveInterface_Object() throws { - let schema = try buildSchema(source: """ - type Query { - test: AnotherObject - } - - interface SuperInterface { - field: String! - } - - interface AnotherInterface implements SuperInterface { - field: String! - } - - type AnotherObject implements AnotherInterface { - field: String! - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Type AnotherObject must implement SuperInterface because it is implemented by AnotherInterface.", - locations: [ - .init(line: 10, column: 45), - .init(line: 14, column: 37), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: AnotherObject + } + + interface SuperInterface { + field: String! + } + + interface AnotherInterface implements SuperInterface { + field: String! + } + + type AnotherObject implements AnotherInterface { + field: String! + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Type AnotherObject must implement SuperInterface because it is implemented by AnotherInterface.", + locations: [ + .init(line: 10, column: 45), + .init(line: 14, column: 37), + ] + ) + ] + ) } // MARK: Interfaces must adhere to Interface they implement @Test func acceptsAnInterfaceWhichImplementsAnInterface() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field(input: String): String - } - - interface ChildInterface implements ParentInterface { - field(input: String): String - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field(input: String): String + } + + interface ChildInterface implements ParentInterface { + field(input: String): String + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func acceptsAnInterfaceWhichImplementsAnInterfaceAlongWithMoreFields() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field(input: String): String - } - - interface ChildInterface implements ParentInterface { - field(input: String): String - anotherField: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field(input: String): String + } + + interface ChildInterface implements ParentInterface { + field(input: String): String + anotherField: String + } + """ + ) try #expect(validateSchema(schema: schema) == []) } - @Test func acceptsAnInterfaceWhichImplementsAnInterfaceFieldAlongWithAdditionalOptionalArguments( - ) throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } + @Test + func acceptsAnInterfaceWhichImplementsAnInterfaceFieldAlongWithAdditionalOptionalArguments() + throws + { + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } - interface ParentInterface { - field(input: String): String - } + interface ParentInterface { + field(input: String): String + } - interface ChildInterface implements ParentInterface { - field(input: String, anotherInput: String): String - } - """) + interface ChildInterface implements ParentInterface { + field(input: String, anotherInput: String): String + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func rejectsAnInterfaceMissingAnInterfaceField() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field(input: String): String - } - - interface ChildInterface implements ParentInterface { - anotherField: String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field ParentInterface.field expected but ChildInterface does not provide it.", - locations: [ - .init(line: 7, column: 9), - .init(line: 10, column: 7), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field(input: String): String + } + + interface ChildInterface implements ParentInterface { + anotherField: String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field ParentInterface.field expected but ChildInterface does not provide it.", + locations: [ + .init(line: 7, column: 9), + .init(line: 10, column: 7), + ] + ) + ] + ) } @Test func rejectsAnInterfaceWithAnIncorrectlyTypedInterfaceField() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field(input: String): String - } - - interface ChildInterface implements ParentInterface { - field(input: String): Int - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field ParentInterface.field expects type String but ChildInterface.field is type Int.", - locations: [ - .init(line: 7, column: 31), - .init(line: 11, column: 31), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field(input: String): String + } + + interface ChildInterface implements ParentInterface { + field(input: String): Int + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field ParentInterface.field expects type String but ChildInterface.field is type Int.", + locations: [ + .init(line: 7, column: 31), + .init(line: 11, column: 31), + ] + ) + ] + ) } @Test func rejectsAnInterfaceWithADifferentlyTypedInterfaceField() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - type A { foo: String } - type B { foo: String } - - interface ParentInterface { - field: A - } - - interface ChildInterface implements ParentInterface { - field: B - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field ParentInterface.field expects type A but ChildInterface.field is type B.", - locations: [ - .init(line: 10, column: 16), - .init(line: 14, column: 16), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + type A { foo: String } + type B { foo: String } + + interface ParentInterface { + field: A + } + + interface ChildInterface implements ParentInterface { + field: B + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field ParentInterface.field expects type A but ChildInterface.field is type B.", + locations: [ + .init(line: 10, column: 16), + .init(line: 14, column: 16), + ] + ) + ] + ) } @Test func acceptsAnInterfaceWithASubtypedInterfaceField_Interface() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field: ParentInterface - } - - interface ChildInterface implements ParentInterface { - field: ChildInterface - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field: ParentInterface + } + + interface ChildInterface implements ParentInterface { + field: ChildInterface + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func acceptsAnInterfaceWithASubtypedInterfaceField_Union() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } - type SomeObject { - field: String - } + type SomeObject { + field: String + } - union SomeUnionType = SomeObject + union SomeUnionType = SomeObject - interface ParentInterface { - field: SomeUnionType - } + interface ParentInterface { + field: SomeUnionType + } - interface ChildInterface implements ParentInterface { - field: SomeObject - } - """) + interface ChildInterface implements ParentInterface { + field: SomeObject + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @@ -2037,344 +2296,395 @@ func schemaWithFieldType(type: GraphQLOutputType) throws -> GraphQLSchema { throws: (any Error).self, "Type BadInterface must only implement Interface types, it cannot implement SomeInputObject." ) { - try buildSchema(source: """ - type Query { - field: String - } - - input SomeInputObject { - field: String - } - - interface BadInterface implements SomeInputObject { - field: String - } - """) + try buildSchema( + source: """ + type Query { + field: String + } + + input SomeInputObject { + field: String + } + + interface BadInterface implements SomeInputObject { + field: String + } + """ + ) } } @Test func rejectsAnInterfaceMissingAnInterfaceArgument() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field(input: String): String - } - - interface ChildInterface implements ParentInterface { - field: String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field argument ParentInterface.field(input:) expected but ChildInterface.field does not provide it.", - locations: [ - .init(line: 7, column: 15), - .init(line: 11, column: 9), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field(input: String): String + } + + interface ChildInterface implements ParentInterface { + field: String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field argument ParentInterface.field(input:) expected but ChildInterface.field does not provide it.", + locations: [ + .init(line: 7, column: 15), + .init(line: 11, column: 9), + ] + ) + ] + ) } @Test func rejectsAnInterfaceWithAnIncorrectlyTypedInterfaceArgument() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field(input: String): String - } - - interface ChildInterface implements ParentInterface { - field(input: Int): String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field argument ParentInterface.field(input:) expects type String but ChildInterface.field(input:) is type Int.", - locations: [ - .init(line: 7, column: 22), - .init(line: 11, column: 22), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field(input: String): String + } + + interface ChildInterface implements ParentInterface { + field(input: Int): String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field argument ParentInterface.field(input:) expects type String but ChildInterface.field(input:) is type Int.", + locations: [ + .init(line: 7, column: 22), + .init(line: 11, column: 22), + ] + ) + ] + ) } @Test func rejectsAnInterfaceWithBothAnIncorrectlyTypedFieldAndArgument() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field(input: String): String - } - - interface ChildInterface implements ParentInterface { - field(input: Int): Int - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field ParentInterface.field expects type String but ChildInterface.field is type Int.", - locations: [ - .init(line: 7, column: 31), - .init(line: 11, column: 28), - ] - ), - GraphQLError( - message: - "Interface field argument ParentInterface.field(input:) expects type String but ChildInterface.field(input:) is type Int.", - locations: [ - .init(line: 7, column: 22), - .init(line: 11, column: 22), - ] - ), - ]) - } - - @Test func rejectsAnInterfaceWhichImplementsAnInterfaceFieldAlongWithAdditionalRequiredArguments( - ) throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field(baseArg: String): String - } - - interface ChildInterface implements ParentInterface { - field( - baseArg: String, - requiredArg: String! - optionalArg1: String, - optionalArg2: String = "", - ): String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - #"Argument "ChildInterface.field(requiredArg:)" must not be required type "String!" if not provided by the Interface field "ParentInterface.field"."#, - locations: [ - .init(line: 13, column: 11), - .init(line: 7, column: 9), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field(input: String): String + } + + interface ChildInterface implements ParentInterface { + field(input: Int): Int + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field ParentInterface.field expects type String but ChildInterface.field is type Int.", + locations: [ + .init(line: 7, column: 31), + .init(line: 11, column: 28), + ] + ), + GraphQLError( + message: + "Interface field argument ParentInterface.field(input:) expects type String but ChildInterface.field(input:) is type Int.", + locations: [ + .init(line: 7, column: 22), + .init(line: 11, column: 22), + ] + ), + ] + ) + } + + @Test + func rejectsAnInterfaceWhichImplementsAnInterfaceFieldAlongWithAdditionalRequiredArguments() + throws + { + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field(baseArg: String): String + } + + interface ChildInterface implements ParentInterface { + field( + baseArg: String, + requiredArg: String! + optionalArg1: String, + optionalArg2: String = "", + ): String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + #"Argument "ChildInterface.field(requiredArg:)" must not be required type "String!" if not provided by the Interface field "ParentInterface.field"."#, + locations: [ + .init(line: 13, column: 11), + .init(line: 7, column: 9), + ] + ) + ] + ) } @Test func acceptsAnInterfaceWithAnEquivalentlyWrappedInterfaceFieldType() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field: [String]! - } - - interface ChildInterface implements ParentInterface { - field: [String]! - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field: [String]! + } + + interface ChildInterface implements ParentInterface { + field: [String]! + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func rejectsAnInterfaceWithANonlistInterfaceFieldListType() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field: [String] - } - - interface ChildInterface implements ParentInterface { - field: String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field ParentInterface.field expects type [String] but ChildInterface.field is type String.", - locations: [ - .init(line: 7, column: 16), - .init(line: 11, column: 16), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field: [String] + } + + interface ChildInterface implements ParentInterface { + field: String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field ParentInterface.field expects type [String] but ChildInterface.field is type String.", + locations: [ + .init(line: 7, column: 16), + .init(line: 11, column: 16), + ] + ) + ] + ) } @Test func rejectsAnInterfaceWithAListInterfaceFieldNonlistType() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field: String - } - - interface ChildInterface implements ParentInterface { - field: [String] - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field ParentInterface.field expects type String but ChildInterface.field is type [String].", - locations: [ - .init(line: 7, column: 16), - .init(line: 11, column: 16), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field: String + } + + interface ChildInterface implements ParentInterface { + field: [String] + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field ParentInterface.field expects type String but ChildInterface.field is type [String].", + locations: [ + .init(line: 7, column: 16), + .init(line: 11, column: 16), + ] + ) + ] + ) } @Test func acceptsAnInterfaceWithASubsetNonnullInterfaceFieldType() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field: String - } - - interface ChildInterface implements ParentInterface { - field: String! - } - """) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field: String + } + + interface ChildInterface implements ParentInterface { + field: String! + } + """ + ) try #expect(validateSchema(schema: schema) == []) } @Test func rejectsAnInterfaceWithASupersetNullableInterfaceFieldType() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface ParentInterface { - field: String! - } - - interface ChildInterface implements ParentInterface { - field: String - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Interface field ParentInterface.field expects type String! but ChildInterface.field is type String.", - locations: [ - .init(line: 7, column: 16), - .init(line: 11, column: 16), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface ParentInterface { + field: String! + } + + interface ChildInterface implements ParentInterface { + field: String + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Interface field ParentInterface.field expects type String! but ChildInterface.field is type String.", + locations: [ + .init(line: 7, column: 16), + .init(line: 11, column: 16), + ] + ) + ] + ) } @Test func rejectsAnObjectMissingATransitiveInterface_Interface() throws { - let schema = try buildSchema(source: """ - type Query { - test: ChildInterface - } - - interface SuperInterface { - field: String! - } - - interface ParentInterface implements SuperInterface { - field: String! - } - - interface ChildInterface implements ParentInterface { - field: String! - } - """) - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Type ChildInterface must implement SuperInterface because it is implemented by ParentInterface.", - locations: [ - .init(line: 10, column: 44), - .init(line: 14, column: 43), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: ChildInterface + } + + interface SuperInterface { + field: String! + } + + interface ParentInterface implements SuperInterface { + field: String! + } + + interface ChildInterface implements ParentInterface { + field: String! + } + """ + ) + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Type ChildInterface must implement SuperInterface because it is implemented by ParentInterface.", + locations: [ + .init(line: 10, column: 44), + .init(line: 14, column: 43), + ] + ) + ] + ) } @Test func rejectsASelfReferenceInterface() throws { - let schema = try buildSchema(source: """ - type Query { - test: FooInterface - } - - interface FooInterface implements FooInterface { - field: String - } - """) - - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: "Type FooInterface cannot implement itself because it would create a circular reference.", - locations: [.init(line: 6, column: 41)] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: FooInterface + } + + interface FooInterface implements FooInterface { + field: String + } + """ + ) + + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Type FooInterface cannot implement itself because it would create a circular reference.", + locations: [.init(line: 6, column: 41)] + ) + ] + ) } @Test func rejectsACircularInterfaceImplementation() throws { - let schema = try buildSchema(source: """ - type Query { - test: FooInterface - } - - interface FooInterface implements BarInterface { - field: String - } - - interface BarInterface implements FooInterface { - field: String - } - """) - - try #expect(validateSchema(schema: schema) == [ - GraphQLError( - message: - "Type FooInterface cannot implement BarInterface because it would create a circular reference.", - locations: [ - .init(line: 10, column: 41), - .init(line: 6, column: 41), - ] - ), - GraphQLError( - message: - "Type BarInterface cannot implement FooInterface because it would create a circular reference.", - locations: [ - .init(line: 6, column: 41), - .init(line: 10, column: 41), - ] - ), - ]) + let schema = try buildSchema( + source: """ + type Query { + test: FooInterface + } + + interface FooInterface implements BarInterface { + field: String + } + + interface BarInterface implements FooInterface { + field: String + } + """ + ) + + try #expect( + validateSchema(schema: schema) == [ + GraphQLError( + message: + "Type FooInterface cannot implement BarInterface because it would create a circular reference.", + locations: [ + .init(line: 10, column: 41), + .init(line: 6, column: 41), + ] + ), + GraphQLError( + message: + "Type BarInterface cannot implement FooInterface because it would create a circular reference.", + locations: [ + .init(line: 6, column: 41), + .init(line: 10, column: 41), + ] + ), + ] + ) } // MARK: assertValidSchema @Test func doesNotThrowOnValidSchemas() throws { - let schema = try buildSchema(source: """ - type Query { - foo: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + foo: String + } + """ + ) #expect(throws: Never.self) { try assertValidSchema(schema: schema) } } diff --git a/Tests/GraphQLTests/UtilitiesTests/BuildASTSchemaTests.swift b/Tests/GraphQLTests/UtilitiesTests/BuildASTSchemaTests.swift index c8375c34..7759a6c0 100644 --- a/Tests/GraphQLTests/UtilitiesTests/BuildASTSchemaTests.swift +++ b/Tests/GraphQLTests/UtilitiesTests/BuildASTSchemaTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct BuildASTSchemaTests { /** * This function does a full cycle of going from a string with the contents of @@ -15,10 +16,10 @@ import Testing let schema = try buildASTSchema( documentAST: parse( source: """ - type Query { - str: String - } - """ + type Query { + str: String + } + """ ) ) @@ -29,52 +30,53 @@ import Testing ) #expect( - result == GraphQLResult(data: [ - "str": "123", - ]) + result + == GraphQLResult(data: [ + "str": "123" + ]) ) } // Closures are invalid Map keys in Swift. -// @Test func canBuildASchemaDirectlyFromTheSource() throws { -// let schema = try buildASTSchema( -// documentAST: try parse( -// source: """ -// type Query { -// add(x: Int, y: Int): Int -// } -// """ -// ) -// ) -// -// let result = try await graphql( -// schema: schema, -// request: "{ add(x: 34, y: 55) }", -// rootValue: [ -// "add": { (x: Int, y: Int) in -// return x + y -// } -// ] -// ) -// -// #expect( -// result == -// GraphQLResult(data: [ -// "add": 89 -// ]) -// ) -// } + // @Test func canBuildASchemaDirectlyFromTheSource() throws { + // let schema = try buildASTSchema( + // documentAST: try parse( + // source: """ + // type Query { + // add(x: Int, y: Int): Int + // } + // """ + // ) + // ) + // + // let result = try await graphql( + // schema: schema, + // request: "{ add(x: 34, y: 55) }", + // rootValue: [ + // "add": { (x: Int, y: Int) in + // return x + y + // } + // ] + // ) + // + // #expect( + // result == + // GraphQLResult(data: [ + // "add": 89 + // ]) + // ) + // } @Test func ignoresNonTypeSystemDefinitions() throws { let sdl = """ - type Query { - str: String - } + type Query { + str: String + } - fragment SomeFragment on Query { - str - } - """ + fragment SomeFragment on Query { + str + } + """ #expect(throws: Never.self) { try buildSchema(source: sdl) } } @@ -85,29 +87,28 @@ import Testing #expect(sdlSchema.directives.map { $0.name } == schema.directives.map { $0.name }) #expect( - sdlSchema.typeMap.mapValues { $0.name } == - schema.typeMap.mapValues { $0.name } + sdlSchema.typeMap.mapValues { $0.name } == schema.typeMap.mapValues { $0.name } ) } @Test func emptyType() throws { let sdl = """ - type EmptyType - """ + type EmptyType + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func simpleType() throws { let sdl = """ - type Query { - str: String - int: Int - float: Float - id: ID - bool: Boolean - } - """ + type Query { + str: String + int: Int + float: Float + id: ID + bool: Boolean + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) @@ -151,60 +152,60 @@ import Testing @Test func withDirectives() throws { let sdl = """ - directive @foo(arg: Int) on FIELD + directive @foo(arg: Int) on FIELD - directive @repeatableFoo(arg: Int) repeatable on FIELD - """ + directive @repeatableFoo(arg: Int) repeatable on FIELD + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func supportsDescriptions() throws { let sdl = #""" - """Do you agree that this is the most creative schema ever?""" - schema { - query: Query - } + """Do you agree that this is the most creative schema ever?""" + schema { + query: Query + } - """This is a directive""" - directive @foo( - """It has an argument""" - arg: Int - ) on FIELD + """This is a directive""" + directive @foo( + """It has an argument""" + arg: Int + ) on FIELD - """Who knows what inside this scalar?""" - scalar MysteryScalar + """Who knows what inside this scalar?""" + scalar MysteryScalar - """This is a input object type""" - input FooInput { - """It has a field""" - field: Int - } + """This is a input object type""" + input FooInput { + """It has a field""" + field: Int + } - """This is a interface type""" - interface Energy { - """It also has a field""" - str: String - } + """This is a interface type""" + interface Energy { + """It also has a field""" + str: String + } - """There is nothing inside!""" - union BlackHole + """There is nothing inside!""" + union BlackHole - """With an enum""" - enum Color { - RED + """With an enum""" + enum Color { + RED - """Not a creative color""" - GREEN - BLUE - } + """Not a creative color""" + GREEN + BLUE + } - """What a great type""" - type Query { - """And a field to boot""" - str: String - } - """# + """What a great type""" + type Query { + """And a field to boot""" + str: String + } + """# try #expect(cycleSDL(sdl: sdl) == sdl) } @@ -241,13 +242,15 @@ import Testing } @Test func overridingDirectivesExcludesSpecified() throws { - let schema = try buildSchema(source: """ - directive @skip on FIELD - directive @include on FIELD - directive @deprecated on FIELD_DEFINITION - directive @specifiedBy on FIELD_DEFINITION - directive @oneOf on OBJECT - """) + let schema = try buildSchema( + source: """ + directive @skip on FIELD + directive @include on FIELD + directive @deprecated on FIELD_DEFINITION + directive @specifiedBy on FIELD_DEFINITION + directive @oneOf on OBJECT + """ + ) #expect(schema.directives.count == 5) #expect( @@ -278,9 +281,11 @@ import Testing } @Test func addingDirectivesMaintainsIncludeSkipDeprecatedSpecifiedByAndOneOf() throws { - let schema = try buildSchema(source: """ - directive @foo(arg: Int) on FIELD - """) + let schema = try buildSchema( + source: """ + directive @foo(arg: Int) on FIELD + """ + ) #expect(schema.directives.count == 6) #expect(schema.getDirective(name: GraphQLSkipDirective.name) != nil) @@ -292,68 +297,68 @@ import Testing @Test func typeModifiers() throws { let sdl = """ - type Query { - nonNullStr: String! - listOfStrings: [String] - listOfNonNullStrings: [String!] - nonNullListOfStrings: [String]! - nonNullListOfNonNullStrings: [String!]! - } - """ + type Query { + nonNullStr: String! + listOfStrings: [String] + listOfNonNullStrings: [String!] + nonNullListOfStrings: [String]! + nonNullListOfNonNullStrings: [String!]! + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func recursiveType() throws { let sdl = """ - type Query { - str: String - recurse: Query - } - """ + type Query { + str: String + recurse: Query + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func twoTypesCircular() throws { let sdl = """ - type TypeOne { - str: String - typeTwo: TypeTwo - } + type TypeOne { + str: String + typeTwo: TypeTwo + } - type TypeTwo { - str: String - typeOne: TypeOne - } - """ + type TypeTwo { + str: String + typeOne: TypeOne + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func singleArgumentField() throws { let sdl = """ - type Query { - str(int: Int): String - floatToStr(float: Float): String - idToStr(id: ID): String - booleanToStr(bool: Boolean): String - strToStr(bool: String): String - } - """ + type Query { + str(int: Int): String + floatToStr(float: Float): String + idToStr(id: ID): String + booleanToStr(bool: Boolean): String + strToStr(bool: String): String + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func simpleTypeWithMultipleArguments() throws { let sdl = """ - type Query { - str(int: Int, bool: Boolean): String - } - """ + type Query { + str(int: Int, bool: Boolean): String + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func emptyInterface() throws { let sdl = """ - interface EmptyInterface - """ + interface EmptyInterface + """ let definition = try #require( parse(source: sdl) .definitions[0] as? InterfaceTypeDefinition @@ -364,119 +369,119 @@ import Testing @Test func simpleTypeWithInterface() throws { let sdl = """ - type Query implements WorldInterface { - str: String - } + type Query implements WorldInterface { + str: String + } - interface WorldInterface { - str: String - } - """ + interface WorldInterface { + str: String + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func simpleInterfaceHierarchy() throws { let sdl = """ - interface Child implements Parent { - str: String - } + interface Child implements Parent { + str: String + } - type Hello implements Parent & Child { - str: String - } + type Hello implements Parent & Child { + str: String + } - interface Parent { - str: String - } - """ + interface Parent { + str: String + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func emptyEnum() throws { let sdl = """ - enum EmptyEnum - """ + enum EmptyEnum + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func simpleOutputEnum() throws { let sdl = """ - enum Hello { - WORLD - } + enum Hello { + WORLD + } - type Query { - hello: Hello - } - """ + type Query { + hello: Hello + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func simpleInputEnum() throws { let sdl = """ - enum Hello { - WORLD - } + enum Hello { + WORLD + } - type Query { - str(hello: Hello): String - } - """ + type Query { + str(hello: Hello): String + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func multipleValueEnum() throws { let sdl = """ - enum Hello { - WO - RLD - } + enum Hello { + WO + RLD + } - type Query { - hello: Hello - } - """ + type Query { + hello: Hello + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func emptyUnion() throws { let sdl = """ - union EmptyUnion - """ + union EmptyUnion + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func simpleUnion() throws { let sdl = """ - union Hello = World + union Hello = World - type Query { - hello: Hello - } + type Query { + hello: Hello + } - type World { - str: String - } - """ + type World { + str: String + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func multipleUnion() throws { let sdl = """ - union Hello = WorldOne | WorldTwo + union Hello = WorldOne | WorldTwo - type Query { - hello: Hello - } + type Query { + hello: Hello + } - type WorldOne { - str: String - } + type WorldOne { + str: String + } - type WorldTwo { - str: String - } - """ + type WorldTwo { + str: String + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @@ -485,179 +490,181 @@ import Testing throws: (any Error).self, "Union type Hello can only include Object types, it cannot include Hello" ) { - try buildSchema(source: """ - union Hello = Hello + try buildSchema( + source: """ + union Hello = Hello - type Query { - hello: Hello - } - """) + type Query { + hello: Hello + } + """ + ) } } @Test func customScalar() throws { let sdl = """ - scalar CustomScalar + scalar CustomScalar - type Query { - customScalar: CustomScalar - } - """ + type Query { + customScalar: CustomScalar + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func emptyInputObject() throws { let sdl = """ - input EmptyInputObject - """ + input EmptyInputObject + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func simpleInputObject() throws { let sdl = """ - input Input { - int: Int - } + input Input { + int: Int + } - type Query { - field(in: Input): String - } - """ + type Query { + field(in: Input): String + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func simpleArgumentFieldWithDefault() throws { let sdl = """ - type Query { - str(int: Int = 2): String - } - """ + type Query { + str(int: Int = 2): String + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func customScalarArgumentFieldWithDefault() throws { let sdl = """ - scalar CustomScalar + scalar CustomScalar - type Query { - str(int: CustomScalar = 2): String - } - """ + type Query { + str(int: CustomScalar = 2): String + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func simpleTypeWithMutation() throws { let sdl = """ - schema { - query: HelloScalars - mutation: Mutation - } + schema { + query: HelloScalars + mutation: Mutation + } - type HelloScalars { - str: String - int: Int - bool: Boolean - } + type HelloScalars { + str: String + int: Int + bool: Boolean + } - type Mutation { - addHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars - } - """ + type Mutation { + addHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func simpleTypeWithSubscription() throws { let sdl = """ - schema { - query: HelloScalars - subscription: Subscription - } + schema { + query: HelloScalars + subscription: Subscription + } - type HelloScalars { - str: String - int: Int - bool: Boolean - } + type HelloScalars { + str: String + int: Int + bool: Boolean + } - type Subscription { - subscribeHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars - } - """ + type Subscription { + subscribeHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func unreferencedTypeImplementingReferencedInterface() throws { let sdl = """ - type Concrete implements Interface { - key: String - } + type Concrete implements Interface { + key: String + } - interface Interface { - key: String - } + interface Interface { + key: String + } - type Query { - interface: Interface - } - """ + type Query { + interface: Interface + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func unreferencedInterfaceImplementingReferencedInterface() throws { let sdl = """ - interface Child implements Parent { - key: String - } + interface Child implements Parent { + key: String + } - interface Parent { - key: String - } + interface Parent { + key: String + } - type Query { - interfaceField: Parent - } - """ + type Query { + interfaceField: Parent + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func unreferencedTypeImplementingReferencedUnion() throws { let sdl = """ - type Concrete { - key: String - } + type Concrete { + key: String + } - type Query { - union: Union - } + type Query { + union: Union + } - union Union = Concrete - """ + union Union = Concrete + """ try #expect(cycleSDL(sdl: sdl) == sdl) } @Test func supportsDeprecated() throws { let sdl = """ - enum MyEnum { - VALUE - OLD_VALUE @deprecated - OTHER_VALUE @deprecated(reason: "Terrible reasons") - } + enum MyEnum { + VALUE + OLD_VALUE @deprecated + OTHER_VALUE @deprecated(reason: "Terrible reasons") + } - input MyInput { - oldInput: String @deprecated - otherInput: String @deprecated(reason: "Use newInput") - newInput: String - } + input MyInput { + oldInput: String @deprecated + otherInput: String @deprecated(reason: "Use newInput") + newInput: String + } - type Query { - field1: String @deprecated - field2: Int @deprecated(reason: "Because I said so") - enum: MyEnum - field3(oldArg: String @deprecated, arg: String): String - field4(oldArg: String @deprecated(reason: "Why not?"), arg: String): String - field5(arg: MyInput): String - } - """ + type Query { + field1: String @deprecated + field2: Int @deprecated(reason: "Because I said so") + enum: MyEnum + field3(oldArg: String @deprecated, arg: String): String + field4(oldArg: String @deprecated(reason: "Why not?"), arg: String): String + field5(arg: MyInput): String + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) let schema = try buildSchema(source: sdl) @@ -690,12 +697,12 @@ import Testing @Test func supportsSpecifiedBy() throws { let sdl = """ - scalar Foo @specifiedBy(url: "https://example.com/foo_spec") + scalar Foo @specifiedBy(url: "https://example.com/foo_spec") - type Query { - foo: Foo @deprecated - } - """ + type Query { + foo: Foo @deprecated + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) let schema = try buildSchema(source: sdl) @@ -705,19 +712,21 @@ import Testing } @Test func correctlyExtendScalarType() throws { - let schema = try buildSchema(source: """ - scalar SomeScalar - extend scalar SomeScalar @foo - extend scalar SomeScalar @bar - - directive @foo on SCALAR - directive @bar on SCALAR - """) + let schema = try buildSchema( + source: """ + scalar SomeScalar + extend scalar SomeScalar @foo + extend scalar SomeScalar @bar + + directive @foo on SCALAR + directive @bar on SCALAR + """ + ) let someScalar = try #require(schema.getType(name: "SomeScalar") as? GraphQLScalarType) #expect( printType(type: someScalar) == """ - scalar SomeScalar - """ + scalar SomeScalar + """ ) try #expect(print(ast: #require(someScalar.astNode)) == "scalar SomeScalar") #expect( @@ -729,39 +738,41 @@ import Testing } @Test func correctlyExtendObjectType() throws { - let schema = try buildSchema(source: """ - type SomeObject implements Foo { - first: String - } + let schema = try buildSchema( + source: """ + type SomeObject implements Foo { + first: String + } - extend type SomeObject implements Bar { - second: Int - } + extend type SomeObject implements Bar { + second: Int + } - extend type SomeObject implements Baz { - third: Float - } + extend type SomeObject implements Baz { + third: Float + } - interface Foo - interface Bar - interface Baz - """) + interface Foo + interface Bar + interface Baz + """ + ) let someObject = try #require(schema.getType(name: "SomeObject") as? GraphQLObjectType) #expect( printType(type: someObject) == """ - type SomeObject implements Foo & Bar & Baz { - first: String - second: Int - third: Float - } - """ + type SomeObject implements Foo & Bar & Baz { + first: String + second: Int + third: Float + } + """ ) try #expect( print(ast: #require(someObject.astNode)) == """ - type SomeObject implements Foo { - first: String - } - """ + type SomeObject implements Foo { + first: String + } + """ ) #expect( someObject.extensionASTNodes.map { print(ast: $0) } == [ @@ -780,37 +791,39 @@ import Testing } @Test func correctlyExtendInterfaceType() throws { - let schema = try buildSchema(source: """ - interface SomeInterface { - first: String - } + let schema = try buildSchema( + source: """ + interface SomeInterface { + first: String + } - extend interface SomeInterface { - second: Int - } + extend interface SomeInterface { + second: Int + } - extend interface SomeInterface { - third: Float - } - """) + extend interface SomeInterface { + third: Float + } + """ + ) let someInterface = try #require( schema.getType(name: "SomeInterface") as? GraphQLInterfaceType ) #expect( printType(type: someInterface) == """ - interface SomeInterface { - first: String - second: Int - third: Float - } - """ + interface SomeInterface { + first: String + second: Int + third: Float + } + """ ) try #expect( print(ast: #require(someInterface.astNode)) == """ - interface SomeInterface { - first: String - } - """ + interface SomeInterface { + first: String + } + """ ) #expect( someInterface.extensionASTNodes.map { print(ast: $0) } == [ @@ -829,20 +842,22 @@ import Testing } @Test func correctlyExtendUnionType() throws { - let schema = try buildSchema(source: """ - union SomeUnion = FirstType - extend union SomeUnion = SecondType - extend union SomeUnion = ThirdType - - type FirstType - type SecondType - type ThirdType - """) + let schema = try buildSchema( + source: """ + union SomeUnion = FirstType + extend union SomeUnion = SecondType + extend union SomeUnion = ThirdType + + type FirstType + type SecondType + type ThirdType + """ + ) let someUnion = try #require(schema.getType(name: "SomeUnion") as? GraphQLUnionType) #expect( printType(type: someUnion) == """ - union SomeUnion = FirstType | SecondType | ThirdType - """ + union SomeUnion = FirstType | SecondType | ThirdType + """ ) try #expect( print( @@ -858,35 +873,37 @@ import Testing } @Test func correctlyExtendEnumType() throws { - let schema = try buildSchema(source: """ - enum SomeEnum { - FIRST - } + let schema = try buildSchema( + source: """ + enum SomeEnum { + FIRST + } - extend enum SomeEnum { - SECOND - } + extend enum SomeEnum { + SECOND + } - extend enum SomeEnum { - THIRD - } - """) + extend enum SomeEnum { + THIRD + } + """ + ) let someEnum = try #require(schema.getType(name: "SomeEnum") as? GraphQLEnumType) #expect( printType(type: someEnum) == """ - enum SomeEnum { - FIRST - SECOND - THIRD - } - """ + enum SomeEnum { + FIRST + SECOND + THIRD + } + """ ) try #expect( print(ast: #require(someEnum.astNode)) == """ - enum SomeEnum { - FIRST - } - """ + enum SomeEnum { + FIRST + } + """ ) #expect( someEnum.extensionASTNodes.map { print(ast: $0) } == [ @@ -905,35 +922,37 @@ import Testing } @Test func correctlyExtendInputObjectType() throws { - let schema = try buildSchema(source: """ - input SomeInput { - first: String - } + let schema = try buildSchema( + source: """ + input SomeInput { + first: String + } - extend input SomeInput { - second: Int - } + extend input SomeInput { + second: Int + } - extend input SomeInput { - third: Float - } - """) + extend input SomeInput { + third: Float + } + """ + ) let someInput = try #require(schema.getType(name: "SomeInput") as? GraphQLInputObjectType) #expect( printType(type: someInput) == """ - input SomeInput { - first: String - second: Int - third: Float - } - """ + input SomeInput { + first: String + second: Int + third: Float + } + """ ) try #expect( print(ast: #require(someInput.astNode)) == """ - input SomeInput { - first: String - } - """ + input SomeInput { + first: String + } + """ ) #expect( someInput.extensionASTNodes.map { print(ast: $0) } == [ @@ -953,36 +972,36 @@ import Testing @Test func correctlyAssignASTNodes() throws { let sdl = """ - schema { - query: Query - } + schema { + query: Query + } - type Query { - testField(testArg: TestInput): TestUnion - } + type Query { + testField(testArg: TestInput): TestUnion + } - input TestInput { - testInputField: TestEnum - } + input TestInput { + testInputField: TestEnum + } - enum TestEnum { - TEST_VALUE - } + enum TestEnum { + TEST_VALUE + } - union TestUnion = TestType + union TestUnion = TestType - interface TestInterface { - interfaceField: String - } + interface TestInterface { + interfaceField: String + } - type TestType implements TestInterface { - interfaceField: String - } + type TestType implements TestInterface { + interfaceField: String + } - scalar TestScalar + scalar TestScalar - directive @test(arg: TestScalar) on FIELD - """ + directive @test(arg: TestScalar) on FIELD + """ let ast = try parse(source: sdl, noLocation: true) let schema = try buildASTSchema(documentAST: ast) @@ -998,20 +1017,20 @@ import Testing let testDirective = try #require(schema.getDirective(name: "test")) // No `Equatable` conformance -// #expect( -// [ -// schema.astNode, -// query.astNode, -// testInput.astNode, -// testEnum.astNode, -// testUnion.astNode, -// testInterface.astNode, -// testType.astNode, -// testScalar.astNode, -// testDirective.astNode, -// ] == -// ast.definitions -// ) + // #expect( + // [ + // schema.astNode, + // query.astNode, + // testInput.astNode, + // testEnum.astNode, + // testUnion.astNode, + // testInterface.astNode, + // testType.astNode, + // testScalar.astNode, + // testDirective.astNode, + // ] == + // ast.definitions + // ) let testField = try #require(query.getFields()["testField"]) try #expect( @@ -1054,27 +1073,31 @@ import Testing } @Test func rootOperationTypesWithCustomNames() throws { - let schema = try buildSchema(source: """ - schema { - query: SomeQuery - mutation: SomeMutation - subscription: SomeSubscription - } - type SomeQuery - type SomeMutation - type SomeSubscription - """) + let schema = try buildSchema( + source: """ + schema { + query: SomeQuery + mutation: SomeMutation + subscription: SomeSubscription + } + type SomeQuery + type SomeMutation + type SomeSubscription + """ + ) #expect(schema.queryType?.name == "SomeQuery") #expect(schema.mutationType?.name == "SomeMutation") #expect(schema.subscriptionType?.name == "SomeSubscription") } @Test func defaultRootOperationTypeNames() throws { - let schema = try buildSchema(source: """ - type Query - type Mutation - type Subscription - """) + let schema = try buildSchema( + source: """ + type Query + type Mutation + type Subscription + """ + ) #expect(schema.queryType?.name == "Query") #expect(schema.mutationType?.name == "Mutation") #expect(schema.subscriptionType?.name == "Subscription") @@ -1087,46 +1110,46 @@ import Testing } @Test func doNotOverrideStandardTypes() throws { - let schema = try buildSchema(source: """ - scalar ID + let schema = try buildSchema( + source: """ + scalar ID - scalar __Schema - """) + scalar __Schema + """ + ) #expect( - schema.getType(name: "ID") as? GraphQLScalarType === - GraphQLID + schema.getType(name: "ID") as? GraphQLScalarType === GraphQLID ) #expect( - schema.getType(name: "__Schema") as? GraphQLObjectType === - __Schema + schema.getType(name: "__Schema") as? GraphQLObjectType === __Schema ) } @Test func allowsToReferenceIntrospectionTypes() throws { - let schema = try buildSchema(source: """ - type Query { - introspectionField: __EnumValue - } - """) + let schema = try buildSchema( + source: """ + type Query { + introspectionField: __EnumValue + } + """ + ) let queryType = try #require(schema.getType(name: "Query") as? GraphQLObjectType) try #expect( queryType.getFields().contains { key, field in - key == "introspectionField" && - (field.type as? GraphQLObjectType) === __EnumValue + key == "introspectionField" && (field.type as? GraphQLObjectType) === __EnumValue } ) #expect( - schema.getType(name: "__EnumValue") as? GraphQLObjectType === - __EnumValue + schema.getType(name: "__EnumValue") as? GraphQLObjectType === __EnumValue ) } @Test func rejectsInvalidSDL() throws { let sdl = """ - type Query { - foo: String @unknown - } - """ + type Query { + foo: String @unknown + } + """ #expect( throws: (any Error).self, "Unknown directive: \"@unknown\"." @@ -1137,20 +1160,20 @@ import Testing @Test func allowsToDisableSDLValidation() throws { let sdl = """ - type Query { - foo: String @unknown - } - """ + type Query { + foo: String @unknown + } + """ _ = try buildSchema(source: sdl, assumeValid: true) _ = try buildSchema(source: sdl, assumeValidSDL: true) } @Test func throwsOnUnknownTypes() throws { let sdl = """ - type Query { - unknown: UnknownType - } - """ + type Query { + unknown: UnknownType + } + """ #expect( throws: (any Error).self, "Unknown type: \"@UnknownType\"." @@ -1160,25 +1183,27 @@ import Testing } @Test func correctlyProcessesViralSchema() throws { - let schema = try buildSchema(source: """ - schema { - query: Query - } + let schema = try buildSchema( + source: """ + schema { + query: Query + } - type Query { - viruses: [Virus!] - } + type Query { + viruses: [Virus!] + } - type Virus { - name: String! - knownMutations: [Mutation!]! - } + type Virus { + name: String! + knownMutations: [Mutation!]! + } - type Mutation { - name: String! - geneSequence: String! - } - """) + type Mutation { + name: String! + geneSequence: String! + } + """ + ) #expect(schema.queryType?.name == "Query") #expect(schema.getType(name: "Virus")?.name == "Virus") #expect(schema.getType(name: "Mutation")?.name == "Mutation") @@ -1189,14 +1214,14 @@ import Testing @Test func supportsNullLiterals() throws { let sdl = """ - input MyInput { - nullLiteral: String! - } + input MyInput { + nullLiteral: String! + } - type Query { - field(in: MyInput = null): String - } - """ + type Query { + field(in: MyInput = null): String + } + """ try #expect(cycleSDL(sdl: sdl) == sdl) let schema = try buildSchema(source: sdl) diff --git a/Tests/GraphQLTests/UtilitiesTests/ConcatASTTests.swift b/Tests/GraphQLTests/UtilitiesTests/ConcatASTTests.swift index c390292e..dcbbf51b 100644 --- a/Tests/GraphQLTests/UtilitiesTests/ConcatASTTests.swift +++ b/Tests/GraphQLTests/UtilitiesTests/ConcatASTTests.swift @@ -1,17 +1,22 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct ConcatASTTests { @Test func concatenatesTwoASTsTogether() throws { - let sourceA = Source(body: """ - { a, b, ...Frag } - """) + let sourceA = Source( + body: """ + { a, b, ...Frag } + """ + ) - let sourceB = Source(body: """ - fragment Frag on T { - c - } - """) + let sourceB = Source( + body: """ + fragment Frag on T { + c + } + """ + ) let astA = try parse(source: sourceA) let astB = try parse(source: sourceB) @@ -19,16 +24,16 @@ import Testing #expect( print(ast: astC) == """ - { - a - b - ...Frag - } + { + a + b + ...Frag + } - fragment Frag on T { - c - } - """ + fragment Frag on T { + c + } + """ ) } } diff --git a/Tests/GraphQLTests/UtilitiesTests/ExtendSchemaTests.swift b/Tests/GraphQLTests/UtilitiesTests/ExtendSchemaTests.swift index 53955b67..ffdf6ece 100644 --- a/Tests/GraphQLTests/UtilitiesTests/ExtendSchemaTests.swift +++ b/Tests/GraphQLTests/UtilitiesTests/ExtendSchemaTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + @Suite struct ExtendSchemaTests { func schemaChanges( _ schema: GraphQLSchema, @@ -30,18 +31,19 @@ import Testing documentAST: parse(source: "{ field }") ) #expect( - ObjectIdentifier(extendedSchema) == - ObjectIdentifier(schema) + ObjectIdentifier(extendedSchema) == ObjectIdentifier(schema) ) } @Test func canBeUsedForLimitedExecution() async throws { let schema = try buildSchema(source: "type Query") - let extendAST = try parse(source: """ - extend type Query { - newField: String - } - """) + let extendAST = try parse( + source: """ + extend type Query { + newField: String + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) let result = try await graphql( schema: extendedSchema, @@ -49,69 +51,62 @@ import Testing rootValue: ["newField": 123] ) #expect( - result == - .init(data: ["newField": "123"]) + result == .init(data: ["newField": "123"]) ) } @Test func doNotModifyBuiltInTypesAnDirectives() throws { - let schema = try buildSchema(source: """ - type Query { - str: String - int: Int - float: Float - id: ID - bool: Boolean - } - """) - let extendAST = try parse(source: """ - extend type Query { - foo: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + str: String + int: Int + float: Float + id: ID + bool: Boolean + } + """ + ) + let extendAST = try parse( + source: """ + extend type Query { + foo: String + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) // Built-ins are used #expect( - extendedSchema.getType(name: "Int") as? GraphQLScalarType === - GraphQLInt + extendedSchema.getType(name: "Int") as? GraphQLScalarType === GraphQLInt ) #expect( - extendedSchema.getType(name: "Float") as? GraphQLScalarType === - GraphQLFloat + extendedSchema.getType(name: "Float") as? GraphQLScalarType === GraphQLFloat ) #expect( - extendedSchema.getType(name: "String") as? GraphQLScalarType === - GraphQLString + extendedSchema.getType(name: "String") as? GraphQLScalarType === GraphQLString ) #expect( - extendedSchema.getType(name: "Boolean") as? GraphQLScalarType === - GraphQLBoolean + extendedSchema.getType(name: "Boolean") as? GraphQLScalarType === GraphQLBoolean ) #expect( - extendedSchema.getType(name: "ID") as? GraphQLScalarType === - GraphQLID + extendedSchema.getType(name: "ID") as? GraphQLScalarType === GraphQLID ) #expect( - extendedSchema.getDirective(name: "include") === - GraphQLIncludeDirective + extendedSchema.getDirective(name: "include") === GraphQLIncludeDirective ) #expect( - extendedSchema.getDirective(name: "skip") === - GraphQLSkipDirective + extendedSchema.getDirective(name: "skip") === GraphQLSkipDirective ) #expect( - extendedSchema.getDirective(name: "deprecated") === - GraphQLDeprecatedDirective + extendedSchema.getDirective(name: "deprecated") === GraphQLDeprecatedDirective ) #expect( - extendedSchema.getDirective(name: "specifiedBy") === - GraphQLSpecifiedByDirective + extendedSchema.getDirective(name: "specifiedBy") === GraphQLSpecifiedByDirective ) #expect( - extendedSchema.getDirective(name: "oneOf") === - GraphQLOneOfDirective + extendedSchema.getDirective(name: "oneOf") === GraphQLOneOfDirective ) } @@ -130,32 +125,34 @@ import Testing } @Test func extendsObjectsByAddingNewFields() throws { - let schema = try buildSchema(source: #""" - type Query { - someObject: SomeObject - } - - type SomeObject implements AnotherInterface & SomeInterface { - self: SomeObject - tree: [SomeObject]! - """Old field description.""" - oldField: String - } - - interface SomeInterface { - self: SomeInterface - } - - interface AnotherInterface { - self: SomeObject - } - """#) + let schema = try buildSchema( + source: #""" + type Query { + someObject: SomeObject + } + + type SomeObject implements AnotherInterface & SomeInterface { + self: SomeObject + tree: [SomeObject]! + """Old field description.""" + oldField: String + } + + interface SomeInterface { + self: SomeInterface + } + + interface AnotherInterface { + self: SomeObject + } + """# + ) let extensionSDL = #""" - extend type SomeObject { - """New field description.""" - newField(arg: Boolean): String - } - """# + extend type SomeObject { + """New field description.""" + newField(arg: Boolean): String + } + """# let extendedSchema = try extendSchema( schema: schema, documentAST: parse(source: extensionSDL) @@ -163,8 +160,7 @@ import Testing try #expect(validateSchema(schema: extendedSchema) == []) try #expect( - schemaChanges(schema, extendedSchema) == - #""" + schemaChanges(schema, extendedSchema) == #""" type SomeObject implements AnotherInterface & SomeInterface { self: SomeObject tree: [SomeObject]! @@ -178,22 +174,24 @@ import Testing } @Test func extendsScalarsByAddingNewDirectives() throws { - let schema = try buildSchema(source: """ - type Query { - someScalar(arg: SomeScalar): SomeScalar - } + let schema = try buildSchema( + source: """ + type Query { + someScalar(arg: SomeScalar): SomeScalar + } - directive @foo(arg: SomeScalar) on SCALAR + directive @foo(arg: SomeScalar) on SCALAR - input FooInput { - foo: SomeScalar - } + input FooInput { + foo: SomeScalar + } - scalar SomeScalar - """) + scalar SomeScalar + """ + ) let extensionSDL = """ - extend scalar SomeScalar @foo - """ + extend scalar SomeScalar @foo + """ let extendedSchema = try extendSchema( schema: schema, documentAST: parse(source: extensionSDL) @@ -206,20 +204,22 @@ import Testing } @Test func extendsScalarsByAddingSpecifiedByDirective() throws { - let schema = try buildSchema(source: """ - type Query { - foo: Foo - } + let schema = try buildSchema( + source: """ + type Query { + foo: Foo + } - scalar Foo + scalar Foo - directive @foo on SCALAR - """) + directive @foo on SCALAR + """ + ) let extensionSDL = """ - extend scalar Foo @foo + extend scalar Foo @foo - extend scalar Foo @specifiedBy(url: "https://example.com/foo_spec") - """ + extend scalar Foo @specifiedBy(url: "https://example.com/foo_spec") + """ let extendedSchema = try extendSchema( schema: schema, @@ -234,82 +234,88 @@ import Testing } @Test func correctlyAssignASTNodesToNewAndExtendedTypes() throws { - let schema = try buildSchema(source: """ - type Query - - scalar SomeScalar - enum SomeEnum - union SomeUnion - input SomeInput - type SomeObject - interface SomeInterface - - directive @foo on SCALAR - """) - let firstExtensionAST = try parse(source: """ - extend type Query { - newField(testArg: TestInput): TestEnum - } - - extend scalar SomeScalar @foo - - extend enum SomeEnum { - NEW_VALUE - } - - extend union SomeUnion = SomeObject - - extend input SomeInput { - newField: String - } - - extend interface SomeInterface { - newField: String - } - - enum TestEnum { - TEST_VALUE - } - - input TestInput { - testInputField: TestEnum - } - """) + let schema = try buildSchema( + source: """ + type Query + + scalar SomeScalar + enum SomeEnum + union SomeUnion + input SomeInput + type SomeObject + interface SomeInterface + + directive @foo on SCALAR + """ + ) + let firstExtensionAST = try parse( + source: """ + extend type Query { + newField(testArg: TestInput): TestEnum + } + + extend scalar SomeScalar @foo + + extend enum SomeEnum { + NEW_VALUE + } + + extend union SomeUnion = SomeObject + + extend input SomeInput { + newField: String + } + + extend interface SomeInterface { + newField: String + } + + enum TestEnum { + TEST_VALUE + } + + input TestInput { + testInputField: TestEnum + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: firstExtensionAST) - let secondExtensionAST = try parse(source: """ - extend type Query { - oneMoreNewField: TestUnion - } + let secondExtensionAST = try parse( + source: """ + extend type Query { + oneMoreNewField: TestUnion + } - extend scalar SomeScalar @test + extend scalar SomeScalar @test - extend enum SomeEnum { - ONE_MORE_NEW_VALUE - } + extend enum SomeEnum { + ONE_MORE_NEW_VALUE + } - extend union SomeUnion = TestType + extend union SomeUnion = TestType - extend input SomeInput { - oneMoreNewField: String - } + extend input SomeInput { + oneMoreNewField: String + } - extend interface SomeInterface { - oneMoreNewField: String - } + extend interface SomeInterface { + oneMoreNewField: String + } - union TestUnion = TestType + union TestUnion = TestType - interface TestInterface { - interfaceField: String - } + interface TestInterface { + interfaceField: String + } - type TestType implements TestInterface { - interfaceField: String - } + type TestType implements TestInterface { + interfaceField: String + } - directive @test(arg: Int) repeatable on FIELD | SCALAR - """) + directive @test(arg: Int) repeatable on FIELD | SCALAR + """ + ) let extendedTwiceSchema = try extendSchema( schema: extendedSchema, documentAST: secondExtensionAST @@ -320,8 +326,7 @@ import Testing documentAST: concatAST(documents: [firstExtensionAST, secondExtensionAST]) ) #expect( - printSchema(schema: extendedInOneGoSchema) == - printSchema(schema: extendedTwiceSchema) + printSchema(schema: extendedInOneGoSchema) == printSchema(schema: extendedTwiceSchema) ) let query = try #require(extendedTwiceSchema.getType(name: "Query") as? GraphQLObjectType) @@ -398,48 +403,41 @@ import Testing let newField = try #require(query.getFields()["newField"]) try #expect(astNode(newField.astNode) == "newField(testArg: TestInput): TestEnum") try #expect( - astNode(newField.argConfigMap()["testArg"]?.astNode) == - "testArg: TestInput" + astNode(newField.argConfigMap()["testArg"]?.astNode) == "testArg: TestInput" ) try #expect( - astNode(query.getFields()["oneMoreNewField"]?.astNode) == - "oneMoreNewField: TestUnion" + astNode(query.getFields()["oneMoreNewField"]?.astNode) == "oneMoreNewField: TestUnion" ) try #expect(astNode(someEnum.nameLookup["NEW_VALUE"]?.astNode) == "NEW_VALUE") try #expect( - astNode(someEnum.nameLookup["ONE_MORE_NEW_VALUE"]?.astNode) == - "ONE_MORE_NEW_VALUE" + astNode(someEnum.nameLookup["ONE_MORE_NEW_VALUE"]?.astNode) == "ONE_MORE_NEW_VALUE" ) try #expect(astNode(someInput.getFields()["newField"]?.astNode) == "newField: String") try #expect( - astNode(someInput.getFields()["oneMoreNewField"]?.astNode) == - "oneMoreNewField: String" + astNode(someInput.getFields()["oneMoreNewField"]?.astNode) == "oneMoreNewField: String" ) try #expect( - astNode(someInterface.getFields()["newField"]?.astNode) == - "newField: String" + astNode(someInterface.getFields()["newField"]?.astNode) == "newField: String" ) try #expect( - astNode(someInterface.getFields()["oneMoreNewField"]?.astNode) == - "oneMoreNewField: String" + astNode(someInterface.getFields()["oneMoreNewField"]?.astNode) + == "oneMoreNewField: String" ) try #expect( - astNode(testInput.getFields()["testInputField"]?.astNode) == - "testInputField: TestEnum" + astNode(testInput.getFields()["testInputField"]?.astNode) == "testInputField: TestEnum" ) try #expect(astNode(testEnum.nameLookup["TEST_VALUE"]?.astNode) == "TEST_VALUE") try #expect( - astNode(testInterface.getFields()["interfaceField"]?.astNode) == - "interfaceField: String" + astNode(testInterface.getFields()["interfaceField"]?.astNode) + == "interfaceField: String" ) try #expect( - astNode(testType.getFields()["interfaceField"]?.astNode) == - "interfaceField: String" + astNode(testType.getFields()["interfaceField"]?.astNode) == "interfaceField: String" ) try #expect(astNode(testDirective.argConfigMap()["arg"]?.astNode) == "arg: Int") @@ -447,15 +445,17 @@ import Testing @Test func buildsTypesWithDeprecatedFieldsValues() throws { let schema = try GraphQLSchema() - let extendAST = try parse(source: """ - type SomeObject { - deprecatedField: String @deprecated(reason: "not used anymore") - } + let extendAST = try parse( + source: """ + type SomeObject { + deprecatedField: String @deprecated(reason: "not used anymore") + } - enum SomeEnum { - DEPRECATED_VALUE @deprecated(reason: "do not use") - } - """) + enum SomeEnum { + DEPRECATED_VALUE @deprecated(reason: "do not use") + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) let someType = try #require( @@ -463,24 +463,24 @@ import Testing .getType(name: "SomeObject") as? GraphQLObjectType ) try #expect( - someType.getFields()["deprecatedField"]?.deprecationReason == - "not used anymore" + someType.getFields()["deprecatedField"]?.deprecationReason == "not used anymore" ) let someEnum = try #require(extendedSchema.getType(name: "SomeEnum") as? GraphQLEnumType) #expect( - someEnum.nameLookup["DEPRECATED_VALUE"]?.deprecationReason == - "do not use" + someEnum.nameLookup["DEPRECATED_VALUE"]?.deprecationReason == "do not use" ) } @Test func extendsObjectsWithDeprecatedFields() throws { let schema = try buildSchema(source: "type SomeObject") - let extendAST = try parse(source: """ - extend type SomeObject { - deprecatedField: String @deprecated(reason: "not used anymore") - } - """) + let extendAST = try parse( + source: """ + extend type SomeObject { + deprecatedField: String @deprecated(reason: "not used anymore") + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) let someType = try #require( @@ -488,56 +488,58 @@ import Testing .getType(name: "SomeObject") as? GraphQLObjectType ) try #expect( - someType.getFields()["deprecatedField"]?.deprecationReason == - "not used anymore" + someType.getFields()["deprecatedField"]?.deprecationReason == "not used anymore" ) } @Test func extendsEnumsWithDeprecatedValues() throws { let schema = try buildSchema(source: "enum SomeEnum") - let extendAST = try parse(source: """ - extend enum SomeEnum { - DEPRECATED_VALUE @deprecated(reason: "do not use") - } - """) + let extendAST = try parse( + source: """ + extend enum SomeEnum { + DEPRECATED_VALUE @deprecated(reason: "do not use") + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) let someEnum = try #require(extendedSchema.getType(name: "SomeEnum") as? GraphQLEnumType) #expect( - someEnum.nameLookup["DEPRECATED_VALUE"]?.deprecationReason == - "do not use" + someEnum.nameLookup["DEPRECATED_VALUE"]?.deprecationReason == "do not use" ) } @Test func addsNewUnusedTypes() throws { - let schema = try buildSchema(source: """ - type Query { - dummy: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + dummy: String + } + """ + ) let extensionSDL = """ - type DummyUnionMember { - someField: String - } + type DummyUnionMember { + someField: String + } - enum UnusedEnum { - SOME_VALUE - } + enum UnusedEnum { + SOME_VALUE + } - input UnusedInput { - someField: String - } + input UnusedInput { + someField: String + } - interface UnusedInterface { - someField: String - } + interface UnusedInterface { + someField: String + } - type UnusedObject { - someField: String - } + type UnusedObject { + someField: String + } - union UnusedUnion = DummyUnionMember - """ + union UnusedUnion = DummyUnionMember + """ let extendedSchema = try extendSchema( schema: schema, documentAST: parse(source: extensionSDL) @@ -545,557 +547,601 @@ import Testing try #expect(validateSchema(schema: extendedSchema) == []) try #expect( - schemaChanges(schema, extendedSchema) == - extensionSDL + schemaChanges(schema, extendedSchema) == extensionSDL ) } @Test func extendsObjectsByAddingNewFieldsWithArguments() throws { - let schema = try buildSchema(source: """ - type SomeObject + let schema = try buildSchema( + source: """ + type SomeObject - type Query { - someObject: SomeObject - } - """) - let extendAST = try parse(source: """ - input NewInputObj { - field1: Int - field2: [Float] - field3: String! - } + type Query { + someObject: SomeObject + } + """ + ) + let extendAST = try parse( + source: """ + input NewInputObj { + field1: Int + field2: [Float] + field3: String! + } - extend type SomeObject { - newField(arg1: String, arg2: NewInputObj!): String - } - """) + extend type SomeObject { + newField(arg1: String, arg2: NewInputObj!): String + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) try #expect(validateSchema(schema: extendedSchema) == []) try #expect( schemaChanges(schema, extendedSchema) == """ - type SomeObject { - newField(arg1: String, arg2: NewInputObj!): String - } + type SomeObject { + newField(arg1: String, arg2: NewInputObj!): String + } - input NewInputObj { - field1: Int - field2: [Float] - field3: String! - } - """ + input NewInputObj { + field1: Int + field2: [Float] + field3: String! + } + """ ) } @Test func extendsObjectsByAddingNewFieldsWithExistingTypes() throws { - let schema = try buildSchema(source: """ - type Query { - someObject: SomeObject - } + let schema = try buildSchema( + source: """ + type Query { + someObject: SomeObject + } - type SomeObject - enum SomeEnum { VALUE } - """) - let extendAST = try parse(source: """ - extend type SomeObject { - newField(arg1: SomeEnum!): SomeEnum - } - """) + type SomeObject + enum SomeEnum { VALUE } + """ + ) + let extendAST = try parse( + source: """ + extend type SomeObject { + newField(arg1: SomeEnum!): SomeEnum + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) try #expect(validateSchema(schema: extendedSchema) == []) try #expect( schemaChanges(schema, extendedSchema) == """ - type SomeObject { - newField(arg1: SomeEnum!): SomeEnum - } - """ + type SomeObject { + newField(arg1: SomeEnum!): SomeEnum + } + """ ) } @Test func extendsObjectsByAddingImplementedInterfaces() throws { - let schema = try buildSchema(source: """ - type Query { - someObject: SomeObject - } + let schema = try buildSchema( + source: """ + type Query { + someObject: SomeObject + } - type SomeObject { - foo: String - } + type SomeObject { + foo: String + } - interface SomeInterface { - foo: String - } - """) - let extendAST = try parse(source: """ - extend type SomeObject implements SomeInterface - """) + interface SomeInterface { + foo: String + } + """ + ) + let extendAST = try parse( + source: """ + extend type SomeObject implements SomeInterface + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) try #expect(validateSchema(schema: extendedSchema) == []) try #expect( schemaChanges(schema, extendedSchema) == """ - type SomeObject implements SomeInterface { - foo: String - } - """ + type SomeObject implements SomeInterface { + foo: String + } + """ ) } @Test func extendsObjectsByIncludingNewTypes() throws { - let schema = try buildSchema(source: """ - type Query { - someObject: SomeObject - } + let schema = try buildSchema( + source: """ + type Query { + someObject: SomeObject + } - type SomeObject { - oldField: String - } - """) + type SomeObject { + oldField: String + } + """ + ) let newTypesSDL = """ - enum NewEnum { - VALUE - } + enum NewEnum { + VALUE + } - interface NewInterface { - baz: String - } + interface NewInterface { + baz: String + } - type NewObject implements NewInterface { - baz: String - } + type NewObject implements NewInterface { + baz: String + } - scalar NewScalar - - union NewUnion = NewObject - """ - let extendAST = try parse(source: """ - \(newTypesSDL) - extend type SomeObject { - newObject: NewObject - newInterface: NewInterface - newUnion: NewUnion - newScalar: NewScalar - newEnum: NewEnum - newTree: [SomeObject]! - } - """) + scalar NewScalar + + union NewUnion = NewObject + """ + let extendAST = try parse( + source: """ + \(newTypesSDL) + extend type SomeObject { + newObject: NewObject + newInterface: NewInterface + newUnion: NewUnion + newScalar: NewScalar + newEnum: NewEnum + newTree: [SomeObject]! + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) try #expect(validateSchema(schema: extendedSchema) == []) try #expect( schemaChanges(schema, extendedSchema) == """ - type SomeObject { - oldField: String - newObject: NewObject - newInterface: NewInterface - newUnion: NewUnion - newScalar: NewScalar - newEnum: NewEnum - newTree: [SomeObject]! - } + type SomeObject { + oldField: String + newObject: NewObject + newInterface: NewInterface + newUnion: NewUnion + newScalar: NewScalar + newEnum: NewEnum + newTree: [SomeObject]! + } - \(newTypesSDL) - """ + \(newTypesSDL) + """ ) } @Test func extendsObjectsByAddingImplementedNewInterfaces() throws { - let schema = try buildSchema(source: """ - type Query { - someObject: SomeObject - } + let schema = try buildSchema( + source: """ + type Query { + someObject: SomeObject + } - type SomeObject implements OldInterface { - oldField: String - } + type SomeObject implements OldInterface { + oldField: String + } - interface OldInterface { - oldField: String - } - """) - let extendAST = try parse(source: """ - extend type SomeObject implements NewInterface { - newField: String - } + interface OldInterface { + oldField: String + } + """ + ) + let extendAST = try parse( + source: """ + extend type SomeObject implements NewInterface { + newField: String + } - interface NewInterface { - newField: String - } - """) + interface NewInterface { + newField: String + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) try #expect(validateSchema(schema: extendedSchema) == []) try #expect( schemaChanges(schema, extendedSchema) == """ - type SomeObject implements OldInterface & NewInterface { - oldField: String - newField: String - } + type SomeObject implements OldInterface & NewInterface { + oldField: String + newField: String + } - interface NewInterface { - newField: String - } - """ + interface NewInterface { + newField: String + } + """ ) } @Test func extendsDifferentTypesMultipleTimes() throws { - let schema = try buildSchema(source: """ - type Query { - someScalar: SomeScalar - someObject(someInput: SomeInput): SomeObject - someInterface: SomeInterface - someEnum: SomeEnum - someUnion: SomeUnion - } + let schema = try buildSchema( + source: """ + type Query { + someScalar: SomeScalar + someObject(someInput: SomeInput): SomeObject + someInterface: SomeInterface + someEnum: SomeEnum + someUnion: SomeUnion + } - scalar SomeScalar + scalar SomeScalar - type SomeObject implements SomeInterface { - oldField: String - } + type SomeObject implements SomeInterface { + oldField: String + } - interface SomeInterface { - oldField: String - } + interface SomeInterface { + oldField: String + } - enum SomeEnum { - OLD_VALUE - } + enum SomeEnum { + OLD_VALUE + } - union SomeUnion = SomeObject + union SomeUnion = SomeObject - input SomeInput { - oldField: String - } - """) + input SomeInput { + oldField: String + } + """ + ) let newTypesSDL = """ - scalar NewScalar + scalar NewScalar - scalar AnotherNewScalar + scalar AnotherNewScalar - type NewObject { - foo: String - } + type NewObject { + foo: String + } - type AnotherNewObject { - foo: String - } + type AnotherNewObject { + foo: String + } - interface NewInterface { - newField: String - } + interface NewInterface { + newField: String + } - interface AnotherNewInterface { - anotherNewField: String - } - """ + interface AnotherNewInterface { + anotherNewField: String + } + """ let schemaWithNewTypes = try extendSchema( schema: schema, documentAST: parse(source: newTypesSDL) ) try #expect( - schemaChanges(schema, schemaWithNewTypes) == - newTypesSDL + schemaChanges(schema, schemaWithNewTypes) == newTypesSDL ) - let extendAST = try parse(source: """ - extend scalar SomeScalar @specifiedBy(url: "http://example.com/foo_spec") + let extendAST = try parse( + source: """ + extend scalar SomeScalar @specifiedBy(url: "http://example.com/foo_spec") - extend type SomeObject implements NewInterface { - newField: String - } + extend type SomeObject implements NewInterface { + newField: String + } - extend type SomeObject implements AnotherNewInterface { - anotherNewField: String - } + extend type SomeObject implements AnotherNewInterface { + anotherNewField: String + } - extend enum SomeEnum { - NEW_VALUE - } + extend enum SomeEnum { + NEW_VALUE + } - extend enum SomeEnum { - ANOTHER_NEW_VALUE - } + extend enum SomeEnum { + ANOTHER_NEW_VALUE + } - extend union SomeUnion = NewObject + extend union SomeUnion = NewObject - extend union SomeUnion = AnotherNewObject + extend union SomeUnion = AnotherNewObject - extend input SomeInput { - newField: String - } + extend input SomeInput { + newField: String + } - extend input SomeInput { - anotherNewField: String - } - """) + extend input SomeInput { + anotherNewField: String + } + """ + ) let extendedSchema = try extendSchema(schema: schemaWithNewTypes, documentAST: extendAST) try #expect(validateSchema(schema: extendedSchema) == []) try #expect( schemaChanges(schema, extendedSchema) == """ - scalar SomeScalar @specifiedBy(url: "http://example.com/foo_spec") + scalar SomeScalar @specifiedBy(url: "http://example.com/foo_spec") - type SomeObject implements SomeInterface & NewInterface & AnotherNewInterface { - oldField: String - newField: String - anotherNewField: String - } + type SomeObject implements SomeInterface & NewInterface & AnotherNewInterface { + oldField: String + newField: String + anotherNewField: String + } - enum SomeEnum { - OLD_VALUE - NEW_VALUE - ANOTHER_NEW_VALUE - } + enum SomeEnum { + OLD_VALUE + NEW_VALUE + ANOTHER_NEW_VALUE + } - union SomeUnion = SomeObject | NewObject | AnotherNewObject + union SomeUnion = SomeObject | NewObject | AnotherNewObject - input SomeInput { - oldField: String - newField: String - anotherNewField: String - } + input SomeInput { + oldField: String + newField: String + anotherNewField: String + } - \(newTypesSDL) - """ + \(newTypesSDL) + """ ) } @Test func extendsInterfacesByAddingNewFields() throws { - let schema = try buildSchema(source: """ - interface SomeInterface { - oldField: String - } + let schema = try buildSchema( + source: """ + interface SomeInterface { + oldField: String + } - interface AnotherInterface implements SomeInterface { - oldField: String - } + interface AnotherInterface implements SomeInterface { + oldField: String + } - type SomeObject implements SomeInterface & AnotherInterface { - oldField: String - } + type SomeObject implements SomeInterface & AnotherInterface { + oldField: String + } - type Query { - someInterface: SomeInterface - } - """) - let extendAST = try parse(source: """ - extend interface SomeInterface { - newField: String - } + type Query { + someInterface: SomeInterface + } + """ + ) + let extendAST = try parse( + source: """ + extend interface SomeInterface { + newField: String + } - extend interface AnotherInterface { - newField: String - } + extend interface AnotherInterface { + newField: String + } - extend type SomeObject { - newField: String - } - """) + extend type SomeObject { + newField: String + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) try #expect(validateSchema(schema: extendedSchema) == []) try #expect( schemaChanges(schema, extendedSchema) == """ - interface SomeInterface { - oldField: String - newField: String - } + interface SomeInterface { + oldField: String + newField: String + } - interface AnotherInterface implements SomeInterface { - oldField: String - newField: String - } + interface AnotherInterface implements SomeInterface { + oldField: String + newField: String + } - type SomeObject implements SomeInterface & AnotherInterface { - oldField: String - newField: String - } - """ + type SomeObject implements SomeInterface & AnotherInterface { + oldField: String + newField: String + } + """ ) } @Test func extendsInterfacesByAddingNewImplementedInterfaces() throws { - let schema = try buildSchema(source: """ - interface SomeInterface { - oldField: String - } + let schema = try buildSchema( + source: """ + interface SomeInterface { + oldField: String + } - interface AnotherInterface implements SomeInterface { - oldField: String - } + interface AnotherInterface implements SomeInterface { + oldField: String + } - type SomeObject implements SomeInterface & AnotherInterface { - oldField: String - } + type SomeObject implements SomeInterface & AnotherInterface { + oldField: String + } - type Query { - someInterface: SomeInterface - } - """) - let extendAST = try parse(source: """ - interface NewInterface { - newField: String - } + type Query { + someInterface: SomeInterface + } + """ + ) + let extendAST = try parse( + source: """ + interface NewInterface { + newField: String + } - extend interface AnotherInterface implements NewInterface { - newField: String - } + extend interface AnotherInterface implements NewInterface { + newField: String + } - extend type SomeObject implements NewInterface { - newField: String - } - """) + extend type SomeObject implements NewInterface { + newField: String + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) try #expect(validateSchema(schema: extendedSchema) == []) try #expect( schemaChanges(schema, extendedSchema) == """ - interface AnotherInterface implements SomeInterface & NewInterface { - oldField: String - newField: String - } + interface AnotherInterface implements SomeInterface & NewInterface { + oldField: String + newField: String + } - type SomeObject implements SomeInterface & AnotherInterface & NewInterface { - oldField: String - newField: String - } + type SomeObject implements SomeInterface & AnotherInterface & NewInterface { + oldField: String + newField: String + } - interface NewInterface { - newField: String - } - """ + interface NewInterface { + newField: String + } + """ ) } @Test func allowsExtensionOfInterfaceWithMissingObjectFields() throws { - let schema = try buildSchema(source: """ - type Query { - someInterface: SomeInterface - } + let schema = try buildSchema( + source: """ + type Query { + someInterface: SomeInterface + } - type SomeObject implements SomeInterface { - oldField: SomeInterface - } + type SomeObject implements SomeInterface { + oldField: SomeInterface + } - interface SomeInterface { - oldField: SomeInterface - } - """) - let extendAST = try parse(source: """ - extend interface SomeInterface { - newField: String - } - """) + interface SomeInterface { + oldField: SomeInterface + } + """ + ) + let extendAST = try parse( + source: """ + extend interface SomeInterface { + newField: String + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) try #expect(validateSchema(schema: extendedSchema).count > 0) try #expect( schemaChanges(schema, extendedSchema) == """ - interface SomeInterface { - oldField: SomeInterface - newField: String - } - """ + interface SomeInterface { + oldField: SomeInterface + newField: String + } + """ ) } @Test func extendsInterfacesMultipleTimes() throws { - let schema = try buildSchema(source: """ - type Query { - someInterface: SomeInterface - } + let schema = try buildSchema( + source: """ + type Query { + someInterface: SomeInterface + } - interface SomeInterface { - some: SomeInterface - } - """) - let extendAST = try parse(source: """ - extend interface SomeInterface { - newFieldA: Int - } + interface SomeInterface { + some: SomeInterface + } + """ + ) + let extendAST = try parse( + source: """ + extend interface SomeInterface { + newFieldA: Int + } - extend interface SomeInterface { - newFieldB(test: Boolean): String - } - """) + extend interface SomeInterface { + newFieldB(test: Boolean): String + } + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) try #expect(validateSchema(schema: extendedSchema) == []) try #expect( schemaChanges(schema, extendedSchema) == """ - interface SomeInterface { - some: SomeInterface - newFieldA: Int - newFieldB(test: Boolean): String - } - """ + interface SomeInterface { + some: SomeInterface + newFieldA: Int + newFieldB(test: Boolean): String + } + """ ) } @Test func mayExtendMutationsAndSubscriptions() throws { - let mutationSchema = try buildSchema(source: """ - type Query { - queryField: String - } + let mutationSchema = try buildSchema( + source: """ + type Query { + queryField: String + } - type Mutation { - mutationField: String - } + type Mutation { + mutationField: String + } - type Subscription { - subscriptionField: String - } - """) - let ast = try parse(source: """ - extend type Query { - newQueryField: Int - } + type Subscription { + subscriptionField: String + } + """ + ) + let ast = try parse( + source: """ + extend type Query { + newQueryField: Int + } - extend type Mutation { - newMutationField: Int - } + extend type Mutation { + newMutationField: Int + } - extend type Subscription { - newSubscriptionField: Int - } - """) + extend type Subscription { + newSubscriptionField: Int + } + """ + ) let originalPrint = printSchema(schema: mutationSchema) let extendedSchema = try extendSchema(schema: mutationSchema, documentAST: ast) #expect(printSchema(schema: mutationSchema) == originalPrint) #expect( printSchema(schema: extendedSchema) == """ - type Query { - queryField: String - newQueryField: Int - } + type Query { + queryField: String + newQueryField: Int + } - type Mutation { - mutationField: String - newMutationField: Int - } + type Mutation { + mutationField: String + newMutationField: Int + } - type Subscription { - subscriptionField: String - newSubscriptionField: Int - } - """ + type Subscription { + subscriptionField: String + newSubscriptionField: Int + } + """ ) } @Test func mayExtendDirectivesWithNewDirective() throws { - let schema = try buildSchema(source: """ - type Query { - foo: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + foo: String + } + """ + ) let extensionSDL = #""" - """New directive.""" - directive @new(enable: Boolean!, tag: String) repeatable on QUERY | FIELD - """# + """New directive.""" + directive @new(enable: Boolean!, tag: String) repeatable on QUERY | FIELD + """# let extendedSchema = try extendSchema( schema: schema, documentAST: parse(source: extensionSDL) @@ -1103,8 +1149,7 @@ import Testing try #expect(validateSchema(schema: extendedSchema) == []) try #expect( - schemaChanges(schema, extendedSchema) == - extensionSDL + schemaChanges(schema, extendedSchema) == extensionSDL ) } @@ -1130,11 +1175,13 @@ import Testing @Test func throwsOnUnknownTypes() throws { let schema = try GraphQLSchema() - let extendAST = try parse(source: """ - type Query { - unknown: UnknownType - } - """) + let extendAST = try parse( + source: """ + type Query { + unknown: UnknownType + } + """ + ) #expect( throws: (any Error).self, @@ -1146,9 +1193,11 @@ import Testing @Test func doesNotAllowReplacingADefaultDirective() throws { let schema = try GraphQLSchema() - let extendAST = try parse(source: """ - directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD - """) + let extendAST = try parse( + source: """ + directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD + """ + ) #expect( throws: (any Error).self, @@ -1159,16 +1208,20 @@ import Testing } @Test func doesNotAllowReplacingAnExistingEnumValue() throws { - let schema = try buildSchema(source: """ - enum SomeEnum { - ONE - } - """) - let extendAST = try parse(source: """ - extend enum SomeEnum { - ONE - } - """) + let schema = try buildSchema( + source: """ + enum SomeEnum { + ONE + } + """ + ) + let extendAST = try parse( + source: """ + extend enum SomeEnum { + ONE + } + """ + ) #expect( throws: (any Error).self, @@ -1192,17 +1245,19 @@ import Testing } @Test func addsSchemaDefinitionMissingInTheOriginalSchema() throws { - let schema = try buildSchema(source: """ - directive @foo on SCHEMA - type Foo - """) + let schema = try buildSchema( + source: """ + directive @foo on SCHEMA + type Foo + """ + ) #expect(schema.queryType == nil) let extensionSDL = """ - schema @foo { - query: Foo - } - """ + schema @foo { + query: Foo + } + """ let extendedSchema = try extendSchema( schema: schema, documentAST: parse(source: extensionSDL) @@ -1214,15 +1269,17 @@ import Testing } @Test func addsNewRootTypesViaSchemaExtension() throws { - let schema = try buildSchema(source: """ - type Query - type MutationRoot - """) + let schema = try buildSchema( + source: """ + type Query + type MutationRoot + """ + ) let extensionSDL = """ - extend schema { - mutation: MutationRoot - } - """ + extend schema { + mutation: MutationRoot + } + """ let extendedSchema = try extendSchema( schema: schema, documentAST: parse(source: extensionSDL) @@ -1234,14 +1291,16 @@ import Testing } @Test func addsDirectiveViaSchemaExtension() throws { - let schema = try buildSchema(source: """ - type Query + let schema = try buildSchema( + source: """ + type Query - directive @foo on SCHEMA - """) + directive @foo on SCHEMA + """ + ) let extensionSDL = """ - extend schema @foo - """ + extend schema @foo + """ let extendedSchema = try extendSchema( schema: schema, documentAST: parse(source: extensionSDL) @@ -1252,15 +1311,17 @@ import Testing @Test func addsMultipleNewRootTypesViaSchemaExtension() throws { let schema = try buildSchema(source: "type Query") - let extendAST = try parse(source: """ - extend schema { - mutation: Mutation - subscription: Subscription - } + let extendAST = try parse( + source: """ + extend schema { + mutation: Mutation + subscription: Subscription + } - type Mutation - type Subscription - """) + type Mutation + type Subscription + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) let mutationType = extendedSchema.mutationType @@ -1272,17 +1333,19 @@ import Testing @Test func appliesMultipleSchemaExtensions() throws { let schema = try buildSchema(source: "type Query") - let extendAST = try parse(source: """ - extend schema { - mutation: Mutation - } - type Mutation + let extendAST = try parse( + source: """ + extend schema { + mutation: Mutation + } + type Mutation - extend schema { - subscription: Subscription - } - type Subscription - """) + extend schema { + subscription: Subscription + } + type Subscription + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) let mutationType = extendedSchema.mutationType @@ -1293,22 +1356,26 @@ import Testing } @Test func schemaExtensionASTAreAvailableFromSchemaObject() throws { - let schema = try buildSchema(source: """ - type Query - - directive @foo on SCHEMA - """) - let extendAST = try parse(source: """ - extend schema { - mutation: Mutation - } - type Mutation + let schema = try buildSchema( + source: """ + type Query - extend schema { - subscription: Subscription - } - type Subscription - """) + directive @foo on SCHEMA + """ + ) + let extendAST = try parse( + source: """ + extend schema { + mutation: Mutation + } + type Mutation + + extend schema { + subscription: Subscription + } + type Subscription + """ + ) let extendedSchema = try extendSchema(schema: schema, documentAST: extendAST) let secondExtendAST = try parse(source: "extend schema @foo") @@ -1319,16 +1386,16 @@ import Testing #expect( extensionASTNodes(extendedTwiceSchema.extensionASTNodes) == """ - extend schema { - mutation: Mutation - } + extend schema { + mutation: Mutation + } - extend schema { - subscription: Subscription - } + extend schema { + subscription: Subscription + } - extend schema @foo - """ + extend schema @foo + """ ) } } diff --git a/Tests/GraphQLTests/UtilitiesTests/PrintSchemaTests.swift b/Tests/GraphQLTests/UtilitiesTests/PrintSchemaTests.swift index 867090b7..c25011a9 100644 --- a/Tests/GraphQLTests/UtilitiesTests/PrintSchemaTests.swift +++ b/Tests/GraphQLTests/UtilitiesTests/PrintSchemaTests.swift @@ -1,7 +1,8 @@ -@testable import GraphQL import OrderedCollections import Testing +@testable import GraphQL + func expectPrintedSchema(schema: GraphQLSchema) throws -> String { let schemaText = printSchema(schema: schema) // keep printSchema and buildSchema in sync @@ -22,21 +23,25 @@ func buildSingleFieldSchema( @Suite struct TypeSystemPrinterTests { @Test func printsStringField() throws { let schema = try buildSingleFieldSchema(fieldConfig: GraphQLField(type: GraphQLString)) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField: String - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField: String + } + """ + ) } @Test func printsStringListField() throws { let schema = try buildSingleFieldSchema(fieldConfig: GraphQLField(type: GraphQLList(GraphQLString))) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField: [String] - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField: [String] + } + """ + ) } @Test func printsStringNonNullField() throws { @@ -44,11 +49,13 @@ func buildSingleFieldSchema( try buildSingleFieldSchema( fieldConfig: GraphQLField(type: GraphQLNonNull(GraphQLString)) ) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField: String! - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField: String! + } + """ + ) } @Test func printsStringNonNullListField() throws { @@ -56,11 +63,13 @@ func buildSingleFieldSchema( try buildSingleFieldSchema( fieldConfig: GraphQLField(type: GraphQLNonNull(GraphQLList(GraphQLString))) ) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField: [String]! - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField: [String]! + } + """ + ) } @Test func printsStringListNonNullsField() throws { @@ -68,11 +77,13 @@ func buildSingleFieldSchema( try buildSingleFieldSchema( fieldConfig: GraphQLField(type: GraphQLList(GraphQLNonNull(GraphQLString))) ) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField: [String!] - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField: [String!] + } + """ + ) } @Test func printsStringNonNullListNonNullsField() throws { @@ -82,11 +93,13 @@ func buildSingleFieldSchema( type: GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString))) ) ) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField: [String!]! - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField: [String!]! + } + """ + ) } @Test func printsObjectField() throws { @@ -95,134 +108,172 @@ func buildSingleFieldSchema( fields: ["str": GraphQLField(type: GraphQLString)] ) let schema = try GraphQLSchema(types: [FooType]) - try #expect(expectPrintedSchema(schema: schema) == """ - type Foo { - str: String - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Foo { + str: String + } + """ + ) } @Test func printsStringFieldWithIntArg() throws { - let schema = try buildSingleFieldSchema(fieldConfig: GraphQLField( - type: GraphQLString, - args: ["argOne": GraphQLArgument(type: GraphQLInt)] - )) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField(argOne: Int): String - } - """) + let schema = try buildSingleFieldSchema( + fieldConfig: GraphQLField( + type: GraphQLString, + args: ["argOne": GraphQLArgument(type: GraphQLInt)] + ) + ) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField(argOne: Int): String + } + """ + ) } @Test func printsStringFieldWithIntArgWithDefault() throws { - let schema = try buildSingleFieldSchema(fieldConfig: GraphQLField( - type: GraphQLString, - args: ["argOne": GraphQLArgument(type: GraphQLInt, defaultValue: 2)] - )) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField(argOne: Int = 2): String - } - """) + let schema = try buildSingleFieldSchema( + fieldConfig: GraphQLField( + type: GraphQLString, + args: ["argOne": GraphQLArgument(type: GraphQLInt, defaultValue: 2)] + ) + ) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField(argOne: Int = 2): String + } + """ + ) } @Test func printsStringFieldWithStringArgWithDefault() throws { - let schema = try buildSingleFieldSchema(fieldConfig: GraphQLField( - type: GraphQLString, - args: ["argOne": GraphQLArgument(type: GraphQLString, defaultValue: "test default")] - )) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField(argOne: String = "test default"): String - } - """) + let schema = try buildSingleFieldSchema( + fieldConfig: GraphQLField( + type: GraphQLString, + args: ["argOne": GraphQLArgument(type: GraphQLString, defaultValue: "test default")] + ) + ) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField(argOne: String = "test default"): String + } + """ + ) } @Test func printsStringFieldWithIntArgWithDefaultNull() throws { - let schema = try buildSingleFieldSchema(fieldConfig: GraphQLField( - type: GraphQLString, - args: ["argOne": GraphQLArgument(type: GraphQLInt, defaultValue: .null)] - )) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField(argOne: Int = null): String - } - """) + let schema = try buildSingleFieldSchema( + fieldConfig: GraphQLField( + type: GraphQLString, + args: ["argOne": GraphQLArgument(type: GraphQLInt, defaultValue: .null)] + ) + ) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField(argOne: Int = null): String + } + """ + ) } @Test func printsStringFieldWithNonNullIntArg() throws { - let schema = try buildSingleFieldSchema(fieldConfig: GraphQLField( - type: GraphQLString, - args: ["argOne": GraphQLArgument(type: GraphQLNonNull(GraphQLInt))] - )) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField(argOne: Int!): String - } - """) + let schema = try buildSingleFieldSchema( + fieldConfig: GraphQLField( + type: GraphQLString, + args: ["argOne": GraphQLArgument(type: GraphQLNonNull(GraphQLInt))] + ) + ) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField(argOne: Int!): String + } + """ + ) } @Test func printsStringFieldWithMultipleArgs() throws { - let schema = try buildSingleFieldSchema(fieldConfig: GraphQLField( - type: GraphQLString, - args: [ - "argOne": GraphQLArgument(type: GraphQLInt), - "argTwo": GraphQLArgument(type: GraphQLString), - ] - )) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField(argOne: Int, argTwo: String): String - } - """) + let schema = try buildSingleFieldSchema( + fieldConfig: GraphQLField( + type: GraphQLString, + args: [ + "argOne": GraphQLArgument(type: GraphQLInt), + "argTwo": GraphQLArgument(type: GraphQLString), + ] + ) + ) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField(argOne: Int, argTwo: String): String + } + """ + ) } @Test func printsStringFieldWithMultipleArgsFirstIsDefault() throws { - let schema = try buildSingleFieldSchema(fieldConfig: GraphQLField( - type: GraphQLString, - args: [ - "argOne": GraphQLArgument(type: GraphQLInt, defaultValue: 1), - "argTwo": GraphQLArgument(type: GraphQLString), - "argThree": GraphQLArgument(type: GraphQLBoolean), - ] - )) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField(argOne: Int = 1, argTwo: String, argThree: Boolean): String - } - """) + let schema = try buildSingleFieldSchema( + fieldConfig: GraphQLField( + type: GraphQLString, + args: [ + "argOne": GraphQLArgument(type: GraphQLInt, defaultValue: 1), + "argTwo": GraphQLArgument(type: GraphQLString), + "argThree": GraphQLArgument(type: GraphQLBoolean), + ] + ) + ) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField(argOne: Int = 1, argTwo: String, argThree: Boolean): String + } + """ + ) } @Test func printsStringFieldWithMultipleArgsSecondIsDefault() throws { - let schema = try buildSingleFieldSchema(fieldConfig: GraphQLField( - type: GraphQLString, - args: [ - "argOne": GraphQLArgument(type: GraphQLInt), - "argTwo": GraphQLArgument(type: GraphQLString, defaultValue: "foo"), - "argThree": GraphQLArgument(type: GraphQLBoolean), - ] - )) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField(argOne: Int, argTwo: String = "foo", argThree: Boolean): String - } - """) + let schema = try buildSingleFieldSchema( + fieldConfig: GraphQLField( + type: GraphQLString, + args: [ + "argOne": GraphQLArgument(type: GraphQLInt), + "argTwo": GraphQLArgument(type: GraphQLString, defaultValue: "foo"), + "argThree": GraphQLArgument(type: GraphQLBoolean), + ] + ) + ) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField(argOne: Int, argTwo: String = "foo", argThree: Boolean): String + } + """ + ) } @Test func printsStringFieldWithMultipleArgsLastIsDefault() throws { - let schema = try buildSingleFieldSchema(fieldConfig: GraphQLField( - type: GraphQLString, - args: [ - "argOne": GraphQLArgument(type: GraphQLInt), - "argTwo": GraphQLArgument(type: GraphQLString), - "argThree": GraphQLArgument(type: GraphQLBoolean, defaultValue: .bool(false)), - ] - )) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - singleField(argOne: Int, argTwo: String, argThree: Boolean = false): String - } - """) + let schema = try buildSingleFieldSchema( + fieldConfig: GraphQLField( + type: GraphQLString, + args: [ + "argOne": GraphQLArgument(type: GraphQLInt), + "argTwo": GraphQLArgument(type: GraphQLString), + "argThree": GraphQLArgument(type: GraphQLBoolean, defaultValue: .bool(false)), + ] + ) + ) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + singleField(argOne: Int, argTwo: String, argThree: Boolean = false): String + } + """ + ) } @Test func printsSchemaWithDescription() throws { @@ -230,14 +281,16 @@ func buildSingleFieldSchema( description: "Schema description.", query: GraphQLObjectType(name: "Query", fields: [:]) ) - try #expect(expectPrintedSchema(schema: schema) == #""" - """Schema description.""" - schema { - query: Query - } - - type Query - """#) + try #expect( + expectPrintedSchema(schema: schema) == #""" + """Schema description.""" + schema { + query: Query + } + + type Query + """# + ) } @Test func omitsSchemaOfCommonNames() throws { @@ -246,52 +299,60 @@ func buildSingleFieldSchema( mutation: GraphQLObjectType(name: "Mutation", fields: [:]), subscription: GraphQLObjectType(name: "Subscription", fields: [:]) ) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query - type Mutation + type Mutation - type Subscription - """) + type Subscription + """ + ) } @Test func printsCustomQueryRootTypes() throws { let schema = try GraphQLSchema( query: GraphQLObjectType(name: "CustomType", fields: [:]) ) - try #expect(expectPrintedSchema(schema: schema) == """ - schema { - query: CustomType - } - - type CustomType - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + schema { + query: CustomType + } + + type CustomType + """ + ) } @Test func printsCustomMutationRootTypes() throws { let schema = try GraphQLSchema( mutation: GraphQLObjectType(name: "CustomType", fields: [:]) ) - try #expect(expectPrintedSchema(schema: schema) == """ - schema { - mutation: CustomType - } - - type CustomType - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + schema { + mutation: CustomType + } + + type CustomType + """ + ) } @Test func printsCustomSubscriptionRootTypes() throws { let schema = try GraphQLSchema( subscription: GraphQLObjectType(name: "CustomType", fields: [:]) ) - try #expect(expectPrintedSchema(schema: schema) == """ - schema { - subscription: CustomType - } - - type CustomType - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + schema { + subscription: CustomType + } + + type CustomType + """ + ) } @Test func printInterface() throws { @@ -307,15 +368,17 @@ func buildSingleFieldSchema( ) let schema = try GraphQLSchema(types: [BarType]) - try #expect(expectPrintedSchema(schema: schema) == """ - type Bar implements Foo { - str: String - } - - interface Foo { - str: String - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Bar implements Foo { + str: String + } + + interface Foo { + str: String + } + """ + ) } @Test func printMultipleInterface() throws { @@ -339,20 +402,22 @@ func buildSingleFieldSchema( ) let schema = try GraphQLSchema(types: [BarType]) - try #expect(expectPrintedSchema(schema: schema) == """ - type Bar implements Foo & Baz { - str: String - int: Int - } - - interface Foo { - str: String - } - - interface Baz { - int: Int - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Bar implements Foo & Baz { + str: String + int: Int + } + + interface Foo { + str: String + } + + interface Baz { + int: Int + } + """ + ) } @Test func printHierarchicalInterface() throws { @@ -382,30 +447,32 @@ func buildSingleFieldSchema( let Query = try GraphQLObjectType( name: "Query", fields: [ - "bar": GraphQLField(type: BarType), + "bar": GraphQLField(type: BarType) ] ) let schema = try GraphQLSchema(query: Query, types: [BarType]) - try #expect(expectPrintedSchema(schema: schema) == """ - type Bar implements Foo & Baz { - str: String - int: Int - } - - interface Foo { - str: String - } - - interface Baz implements Foo { - int: Int - str: String - } - - type Query { - bar: Bar - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Bar implements Foo & Baz { + str: String + int: Int + } + + interface Foo { + str: String + } + + interface Baz implements Foo { + int: Int + str: String + } + + type Query { + bar: Bar + } + """ + ) } @Test func printUnions() throws { @@ -430,19 +497,21 @@ func buildSingleFieldSchema( ) let schema = try GraphQLSchema(types: [SingleUnion, MultipleUnion]) - try #expect(expectPrintedSchema(schema: schema) == """ - union SingleUnion = Foo + try #expect( + expectPrintedSchema(schema: schema) == """ + union SingleUnion = Foo - type Foo { - bool: Boolean - } + type Foo { + bool: Boolean + } - union MultipleUnion = Foo | Bar + union MultipleUnion = Foo | Bar - type Bar { - str: String - } - """) + type Bar { + str: String + } + """ + ) } @Test func printInputType() throws { @@ -452,11 +521,13 @@ func buildSingleFieldSchema( ) let schema = try GraphQLSchema(types: [InputType]) - try #expect(expectPrintedSchema(schema: schema) == """ - input InputType { - int: Int - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + input InputType { + int: Int + } + """ + ) } @Test func printInputTypewithOneOfDirective() throws { @@ -467,20 +538,24 @@ func buildSingleFieldSchema( ) let schema = try GraphQLSchema(types: [InputType]) - try #expect(expectPrintedSchema(schema: schema) == """ - input InputType @oneOf { - int: Int - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + input InputType @oneOf { + int: Int + } + """ + ) } @Test func customScalar() throws { let OddType = try GraphQLScalarType(name: "Odd") let schema = try GraphQLSchema(types: [OddType]) - try #expect(expectPrintedSchema(schema: schema) == """ - scalar Odd - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + scalar Odd + """ + ) } @Test func customScalarWithSpecifiedByURL() throws { @@ -490,9 +565,11 @@ func buildSingleFieldSchema( ) let schema = try GraphQLSchema(types: [FooType]) - try #expect(expectPrintedSchema(schema: schema) == """ - scalar Foo @specifiedBy(url: "https://example.com/foo_spec") - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + scalar Foo @specifiedBy(url: "https://example.com/foo_spec") + """ + ) } @Test func `enum`() throws { @@ -506,13 +583,15 @@ func buildSingleFieldSchema( ) let schema = try GraphQLSchema(types: [RGBType]) - try #expect(expectPrintedSchema(schema: schema) == """ - enum RGB { - RED - GREEN - BLUE - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + enum RGB { + RED + GREEN + BLUE + } + """ + ) } @Test func printsEmptyTypes() throws { @@ -525,17 +604,19 @@ func buildSingleFieldSchema( GraphQLUnionType(name: "SomeUnion", types: []), ] ) - try #expect(expectPrintedSchema(schema: schema) == """ - enum SomeEnum + try #expect( + expectPrintedSchema(schema: schema) == """ + enum SomeEnum - input SomeInputObject + input SomeInputObject - interface SomeInterface + interface SomeInterface - type SomeObject + type SomeObject - union SomeUnion - """) + union SomeUnion + """ + ) } @Test func printsCustomDirectives() throws { @@ -555,12 +636,14 @@ func buildSingleFieldSchema( ) let schema = try GraphQLSchema(directives: [SimpleDirective, ComplexDirective]) - try #expect(expectPrintedSchema(schema: schema) == #""" - directive @simpleDirective on FIELD + try #expect( + expectPrintedSchema(schema: schema) == #""" + directive @simpleDirective on FIELD - """Complex Directive""" - directive @complexDirective(stringArg: String, intArg: Int = -1) repeatable on FIELD | QUERY - """#) + """Complex Directive""" + directive @complexDirective(stringArg: String, intArg: Int = -1) repeatable on FIELD | QUERY + """# + ) } @Test func printsAnEmptyDescriptions() throws { @@ -619,78 +702,80 @@ func buildSingleFieldSchema( types: [scalarType, interfaceType, unionType, enumType], directives: [someDirective] ) - try #expect(expectPrintedSchema(schema: schema) == #""" - """""" - schema { - query: Query - } - - """""" - directive @someDirective( - """""" - someArg: String - - """""" - anotherArg: String - ) on QUERY - - """""" - scalar SomeScalar - - """""" - interface SomeInterface { - """""" - someField( - """""" - someArg: String - - """""" - anotherArg: String - ): String - - """""" - anotherField( - """""" - someArg: String - - """""" - anotherArg: String - ): String - } - - """""" - union SomeUnion = Query - - """""" - type Query { - """""" - someField( - """""" - someArg: String - - """""" - anotherArg: String - ): String - - """""" - anotherField( - """""" - someArg: String - - """""" - anotherArg: String - ): String - } - - """""" - enum SomeEnum { - """""" - SOME_VALUE - - """""" - ANOTHER_VALUE - } - """#) + try #expect( + expectPrintedSchema(schema: schema) == #""" + """""" + schema { + query: Query + } + + """""" + directive @someDirective( + """""" + someArg: String + + """""" + anotherArg: String + ) on QUERY + + """""" + scalar SomeScalar + + """""" + interface SomeInterface { + """""" + someField( + """""" + someArg: String + + """""" + anotherArg: String + ): String + + """""" + anotherField( + """""" + someArg: String + + """""" + anotherArg: String + ): String + } + + """""" + union SomeUnion = Query + + """""" + type Query { + """""" + someField( + """""" + someArg: String + + """""" + anotherArg: String + ): String + + """""" + anotherField( + """""" + someArg: String + + """""" + anotherArg: String + ): String + } + + """""" + enum SomeEnum { + """""" + SOME_VALUE + + """""" + ANOTHER_VALUE + } + """# + ) } @Test func printsADescriptionWithOnlyWhitespace() throws { @@ -700,12 +785,14 @@ func buildSingleFieldSchema( description: " " ) ) - try #expect(expectPrintedSchema(schema: schema) == """ - type Query { - " " - singleField: String - } - """) + try #expect( + expectPrintedSchema(schema: schema) == """ + type Query { + " " + singleField: String + } + """ + ) } @Test func oneLinePrintsAShortDescription() throws { @@ -715,246 +802,250 @@ func buildSingleFieldSchema( description: "This field is awesome" ) ) - try #expect(expectPrintedSchema(schema: schema) == #""" - type Query { - """This field is awesome""" - singleField: String - } - """#) + try #expect( + expectPrintedSchema(schema: schema) == #""" + type Query { + """This field is awesome""" + singleField: String + } + """# + ) } @Test func printIntrospectionSchema() throws { let schema = try GraphQLSchema() - #expect(GraphQL.printIntrospectionSchema(schema: schema) == #""" - """ - Directs the executor to include this field or fragment only when the \`if\` argument is true. - """ - directive @include( - """Included when true.""" - if: Boolean! - ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - - """ - Directs the executor to skip this field or fragment when the \`if\` argument is true. - """ - directive @skip( - """Skipped when true.""" - if: Boolean! - ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - - """Marks an element of a GraphQL schema as no longer supported.""" - directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/). - """ - reason: String = "No longer supported" - ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE - - """Exposes a URL that specifies the behavior of this scalar.""" - directive @specifiedBy( - """The URL that specifies the behavior of this scalar.""" - url: String! - ) on SCALAR - - """ - Indicates exactly one field must be supplied and this field must not be \`null\`. - """ - directive @oneOf on INPUT_OBJECT - - """ - A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations. - """ - type __Schema { - description: String - - """A list of all types supported by this server.""" - types: [__Type!]! - - """The type that query operations will be rooted at.""" - queryType: __Type! - - """ - If this server supports mutation, the type that mutation operations will be rooted at. - """ - mutationType: __Type - - """ - If this server support subscription, the type that subscription operations will be rooted at. - """ - subscriptionType: __Type - - """A list of all directives supported by this server.""" - directives: [__Directive!]! - } - - """ - The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the \`__TypeKind\` enum. - - Depending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional \`specifiedByURL\`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types. - """ - type __Type { - kind: __TypeKind! - name: String - description: String - specifiedByURL: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields(includeDeprecated: Boolean = false): [__InputValue!] - ofType: __Type - isOneOf: Boolean - } - - """An enum describing what kind of type a given \`__Type\` is.""" - enum __TypeKind { - """Indicates this type is a scalar.""" - SCALAR - - """ - Indicates this type is an object. \`fields\` and \`interfaces\` are valid fields. - """ - OBJECT - - """ - Indicates this type is an interface. \`fields\`, \`interfaces\`, and \`possibleTypes\` are valid fields. - """ - INTERFACE - - """Indicates this type is a union. \`possibleTypes\` is a valid field.""" - UNION - - """Indicates this type is an enum. \`enumValues\` is a valid field.""" - ENUM - - """ - Indicates this type is an input object. \`inputFields\` is a valid field. - """ - INPUT_OBJECT - - """Indicates this type is a list. \`ofType\` is a valid field.""" - LIST - - """Indicates this type is a non-null. \`ofType\` is a valid field.""" - NON_NULL - } - - """ - Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type. - """ - type __Field { - name: String! - description: String - args(includeDeprecated: Boolean = false): [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String - } - - """ - Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value. - """ - type __InputValue { - name: String! - description: String - type: __Type! - - """ - A GraphQL-formatted string representing the default value for this input value. - """ - defaultValue: String - isDeprecated: Boolean! - deprecationReason: String - } - - """ - One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string. - """ - type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String - } - - """ - A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. - - In some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor. - """ - type __Directive { - name: String! - description: String - isRepeatable: Boolean! - locations: [__DirectiveLocation!]! - args(includeDeprecated: Boolean = false): [__InputValue!]! - } - - """ - A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies. - """ - enum __DirectiveLocation { - """Location adjacent to a query operation.""" - QUERY - - """Location adjacent to a mutation operation.""" - MUTATION - - """Location adjacent to a subscription operation.""" - SUBSCRIPTION - - """Location adjacent to a field.""" - FIELD - - """Location adjacent to a fragment definition.""" - FRAGMENT_DEFINITION - - """Location adjacent to a fragment spread.""" - FRAGMENT_SPREAD - - """Location adjacent to an inline fragment.""" - INLINE_FRAGMENT - - """Location adjacent to an operation variable definition.""" - VARIABLE_DEFINITION - - """Location adjacent to a fragment variable definition.""" - FRAGMENT_VARIABLE_DEFINITION - - """Location adjacent to a schema definition.""" - SCHEMA - - """Location adjacent to a scalar definition.""" - SCALAR - - """Location adjacent to an object type definition.""" - OBJECT - - """Location adjacent to a field definition.""" - FIELD_DEFINITION - - """Location adjacent to an argument definition.""" - ARGUMENT_DEFINITION - - """Location adjacent to an interface definition.""" - INTERFACE - - """Location adjacent to a union definition.""" - UNION - - """Location adjacent to an enum definition.""" - ENUM - - """Location adjacent to an enum value definition.""" - ENUM_VALUE - - """Location adjacent to an input object type definition.""" - INPUT_OBJECT - - """Location adjacent to an input object field definition.""" - INPUT_FIELD_DEFINITION - } - """#) + #expect( + GraphQL.printIntrospectionSchema(schema: schema) == #""" + """ + Directs the executor to include this field or fragment only when the \`if\` argument is true. + """ + directive @include( + """Included when true.""" + if: Boolean! + ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + + """ + Directs the executor to skip this field or fragment when the \`if\` argument is true. + """ + directive @skip( + """Skipped when true.""" + if: Boolean! + ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + + """Marks an element of a GraphQL schema as no longer supported.""" + directive @deprecated( + """ + Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/). + """ + reason: String = "No longer supported" + ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE + + """Exposes a URL that specifies the behavior of this scalar.""" + directive @specifiedBy( + """The URL that specifies the behavior of this scalar.""" + url: String! + ) on SCALAR + + """ + Indicates exactly one field must be supplied and this field must not be \`null\`. + """ + directive @oneOf on INPUT_OBJECT + + """ + A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations. + """ + type __Schema { + description: String + + """A list of all types supported by this server.""" + types: [__Type!]! + + """The type that query operations will be rooted at.""" + queryType: __Type! + + """ + If this server supports mutation, the type that mutation operations will be rooted at. + """ + mutationType: __Type + + """ + If this server support subscription, the type that subscription operations will be rooted at. + """ + subscriptionType: __Type + + """A list of all directives supported by this server.""" + directives: [__Directive!]! + } + + """ + The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the \`__TypeKind\` enum. + + Depending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional \`specifiedByURL\`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types. + """ + type __Type { + kind: __TypeKind! + name: String + description: String + specifiedByURL: String + fields(includeDeprecated: Boolean = false): [__Field!] + interfaces: [__Type!] + possibleTypes: [__Type!] + enumValues(includeDeprecated: Boolean = false): [__EnumValue!] + inputFields(includeDeprecated: Boolean = false): [__InputValue!] + ofType: __Type + isOneOf: Boolean + } + + """An enum describing what kind of type a given \`__Type\` is.""" + enum __TypeKind { + """Indicates this type is a scalar.""" + SCALAR + + """ + Indicates this type is an object. \`fields\` and \`interfaces\` are valid fields. + """ + OBJECT + + """ + Indicates this type is an interface. \`fields\`, \`interfaces\`, and \`possibleTypes\` are valid fields. + """ + INTERFACE + + """Indicates this type is a union. \`possibleTypes\` is a valid field.""" + UNION + + """Indicates this type is an enum. \`enumValues\` is a valid field.""" + ENUM + + """ + Indicates this type is an input object. \`inputFields\` is a valid field. + """ + INPUT_OBJECT + + """Indicates this type is a list. \`ofType\` is a valid field.""" + LIST + + """Indicates this type is a non-null. \`ofType\` is a valid field.""" + NON_NULL + } + + """ + Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type. + """ + type __Field { + name: String! + description: String + args(includeDeprecated: Boolean = false): [__InputValue!]! + type: __Type! + isDeprecated: Boolean! + deprecationReason: String + } + + """ + Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value. + """ + type __InputValue { + name: String! + description: String + type: __Type! + + """ + A GraphQL-formatted string representing the default value for this input value. + """ + defaultValue: String + isDeprecated: Boolean! + deprecationReason: String + } + + """ + One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string. + """ + type __EnumValue { + name: String! + description: String + isDeprecated: Boolean! + deprecationReason: String + } + + """ + A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. + + In some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor. + """ + type __Directive { + name: String! + description: String + isRepeatable: Boolean! + locations: [__DirectiveLocation!]! + args(includeDeprecated: Boolean = false): [__InputValue!]! + } + + """ + A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies. + """ + enum __DirectiveLocation { + """Location adjacent to a query operation.""" + QUERY + + """Location adjacent to a mutation operation.""" + MUTATION + + """Location adjacent to a subscription operation.""" + SUBSCRIPTION + + """Location adjacent to a field.""" + FIELD + + """Location adjacent to a fragment definition.""" + FRAGMENT_DEFINITION + + """Location adjacent to a fragment spread.""" + FRAGMENT_SPREAD + + """Location adjacent to an inline fragment.""" + INLINE_FRAGMENT + + """Location adjacent to an operation variable definition.""" + VARIABLE_DEFINITION + + """Location adjacent to a fragment variable definition.""" + FRAGMENT_VARIABLE_DEFINITION + + """Location adjacent to a schema definition.""" + SCHEMA + + """Location adjacent to a scalar definition.""" + SCALAR + + """Location adjacent to an object type definition.""" + OBJECT + + """Location adjacent to a field definition.""" + FIELD_DEFINITION + + """Location adjacent to an argument definition.""" + ARGUMENT_DEFINITION + + """Location adjacent to an interface definition.""" + INTERFACE + + """Location adjacent to a union definition.""" + UNION + + """Location adjacent to an enum definition.""" + ENUM + + """Location adjacent to an enum value definition.""" + ENUM_VALUE + + """Location adjacent to an input object type definition.""" + INPUT_OBJECT + + """Location adjacent to an input object field definition.""" + INPUT_FIELD_DEFINITION + } + """# + ) } @Test func printsViralSchemaCorrectly() throws { @@ -979,31 +1070,31 @@ func buildSingleFieldSchema( let Query = try GraphQLObjectType( name: "Query", fields: [ - "viruses": GraphQLField(type: GraphQLList(GraphQLNonNull(Virus))), + "viruses": GraphQLField(type: GraphQLList(GraphQLNonNull(Virus))) ] ) let viralSchema = try GraphQLSchema(query: Query) #expect( printSchema(schema: viralSchema) == """ - schema { - query: Query - } - - type Query { - viruses: [Virus!] - } - - type Virus { - name: String! - knownMutations: [Mutation!]! - } - - type Mutation { - name: String! - geneSequence: String! - } - """ + schema { + query: Query + } + + type Query { + viruses: [Virus!] + } + + type Virus { + name: String! + knownMutations: [Mutation!]! + } + + type Mutation { + name: String! + geneSequence: String! + } + """ ) } } diff --git a/Tests/GraphQLTests/ValidationTests/ExampleSchema.swift b/Tests/GraphQLTests/ValidationTests/ExampleSchema.swift index 16c20b1e..ebca302a 100644 --- a/Tests/GraphQLTests/ValidationTests/ExampleSchema.swift +++ b/Tests/GraphQLTests/ValidationTests/ExampleSchema.swift @@ -13,7 +13,7 @@ let ValidationExampleBeing = try! GraphQLInterfaceType( print(type(of: inputValue)) return nil } - ), + ) ], resolveType: { _, _ in "Unknown" @@ -51,7 +51,7 @@ let ValidationExamplePet = try! GraphQLInterfaceType( print(type(of: inputValue)) return nil } - ), + ) ], resolveType: { _, _ in "Unknown" @@ -140,7 +140,7 @@ let ValidationExampleDog = try! GraphQLObjectType( "doesKnowCommand": GraphQLField( type: GraphQLBoolean, args: [ - "dogCommand": GraphQLArgument(type: ValidationExampleDogCommand), + "dogCommand": GraphQLArgument(type: ValidationExampleDogCommand) ], resolve: { inputValue, _, _, _ -> String? in print(type(of: inputValue)) @@ -153,7 +153,7 @@ let ValidationExampleDog = try! GraphQLObjectType( "atOtherHomes": GraphQLArgument( type: GraphQLBoolean, defaultValue: true - ), + ) ], resolve: { inputValue, _, _, _ -> String? in print(type(of: inputValue)) @@ -252,7 +252,11 @@ let ValidationExampleCat = try! GraphQLObjectType( print(type(of: inputValue)) return nil }, - "furColor": GraphQLField(type: ValidationExampleFurColor) { inputValue, _, _, _ -> String? in + "furColor": GraphQLField(type: ValidationExampleFurColor) { + inputValue, + _, + _, + _ -> String? in print(type(of: inputValue)) return nil }, @@ -275,7 +279,7 @@ let ValidationExampleCatOrDog = try! GraphQLUnionType( let ValidationExampleIntelligent = try! GraphQLInterfaceType( name: "Intelligent", fields: [ - "iq": GraphQLField(type: GraphQLInt), + "iq": GraphQLField(type: GraphQLInt) ], resolveType: { _, _ in "Unknown" @@ -293,7 +297,7 @@ let ValidationExampleSentient = try! GraphQLInterfaceType( ) { inputValue, _, _, _ -> String? in print(type(of: inputValue)) return nil - }, + } ], resolveType: { _, _ in "Unknown" @@ -360,7 +364,7 @@ let ValidationExampleCatCommand = try! GraphQLEnumType( values: [ "JUMP": GraphQLEnumValue( value: "JUMP" - ), + ) ] ) @@ -507,7 +511,7 @@ let ValidationExampleComplicatedArgs = try! GraphQLObjectType( args: [ "stringListNonNullArg": GraphQLArgument( type: GraphQLList(GraphQLNonNull(GraphQLString)) - ), + ) ], resolve: { inputValue, _, _, _ -> String? in print(type(of: inputValue)) @@ -586,7 +590,11 @@ let ValidationExampleQueryRoot = try! GraphQLObjectType( print(type(of: inputValue)) return nil }, - "catOrDog": GraphQLField(type: ValidationExampleCatOrDog) { inputValue, _, _, _ -> String? in + "catOrDog": GraphQLField(type: ValidationExampleCatOrDog) { + inputValue, + _, + _, + _ -> String? in print(type(of: inputValue)) return nil }, @@ -611,7 +619,7 @@ let ValidationExampleSchema = try! GraphQLSchema( directives: { var directives = specifiedDirectives directives.append(contentsOf: [ - ValidationFieldDirective, + ValidationFieldDirective ]) return directives }() diff --git a/Tests/GraphQLTests/ValidationTests/ExecutableDefinitionsRuleTests.swift b/Tests/GraphQLTests/ValidationTests/ExecutableDefinitionsRuleTests.swift index 2f90f934..8455dffa 100644 --- a/Tests/GraphQLTests/ValidationTests/ExecutableDefinitionsRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/ExecutableDefinitionsRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class ExecutableDefinitionsRuleTests: ValidationTestCase { override init() { super.init() @@ -40,20 +41,20 @@ class ExecutableDefinitionsRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - query Foo { - dog { - name - } - } + query Foo { + dog { + name + } + } - type Cow { - name: String - } + type Cow { + name: String + } - extend type Dog { - color: String - } - """ + extend type Dog { + color: String + } + """ ) try assertValidationError( @@ -72,16 +73,16 @@ class ExecutableDefinitionsRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 3, query: """ - schema { - query: Query - } + schema { + query: Query + } - type Query { - test: String - } + type Query { + test: String + } - extend schema @directive - """ + extend schema @directive + """ ) try assertValidationError( diff --git a/Tests/GraphQLTests/ValidationTests/FieldsOnCorrectTypeTests.swift b/Tests/GraphQLTests/ValidationTests/FieldsOnCorrectTypeTests.swift index cefc5c02..ed7d5044 100644 --- a/Tests/GraphQLTests/ValidationTests/FieldsOnCorrectTypeTests.swift +++ b/Tests/GraphQLTests/ValidationTests/FieldsOnCorrectTypeTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class FieldsOnCorrectTypeTests: ValidationTestCase { override init() { super.init() @@ -59,23 +60,27 @@ class FieldsOnCorrectTypeTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - fragment typeKnownAgain on Pet { - unknown_pet_field { - ... on Cat { - unknown_cat_field + fragment typeKnownAgain on Pet { + unknown_pet_field { + ... on Cat { + unknown_cat_field + } } } - } - """ + """ ) try assertValidationError( - error: errors[0], line: 2, column: 5, + error: errors[0], + line: 2, + column: 5, message: "Cannot query field \"unknown_pet_field\" on type \"Pet\"." ) try assertValidationError( - error: errors[1], line: 4, column: 13, + error: errors[1], + line: 4, + column: 13, message: "Cannot query field \"unknown_cat_field\" on type \"Cat\"." ) } @@ -87,8 +92,11 @@ class FieldsOnCorrectTypeTests: ValidationTestCase { ) try assertValidationError( - error: errors.first, line: 1, column: 35, - message: "Cannot query field \"meowVolume\" on type \"Dog\". Did you mean \"barkVolume\"?" + error: errors.first, + line: 1, + column: 35, + message: + "Cannot query field \"meowVolume\" on type \"Dog\". Did you mean \"barkVolume\"?" ) } @@ -99,7 +107,9 @@ class FieldsOnCorrectTypeTests: ValidationTestCase { ) try assertValidationError( - error: errors.first, line: 1, column: 39, + error: errors.first, + line: 1, + column: 39, message: "Cannot query field \"unknown_field\" on type \"Dog\"." ) } @@ -111,7 +121,9 @@ class FieldsOnCorrectTypeTests: ValidationTestCase { ) try assertValidationError( - error: errors.first, line: 1, column: 47, + error: errors.first, + line: 1, + column: 47, message: "Cannot query field \"unknown_field\" on type \"Pet\"." ) } @@ -123,8 +135,11 @@ class FieldsOnCorrectTypeTests: ValidationTestCase { ) try assertValidationError( - error: errors.first, line: 1, column: 64, - message: "Cannot query field \"meowVolume\" on type \"Dog\". Did you mean \"barkVolume\"?" + error: errors.first, + line: 1, + column: 64, + message: + "Cannot query field \"meowVolume\" on type \"Dog\". Did you mean \"barkVolume\"?" ) } @@ -135,8 +150,11 @@ class FieldsOnCorrectTypeTests: ValidationTestCase { ) try assertValidationError( - error: errors.first, line: 1, column: 48, - message: "Cannot query field \"mooVolume\" on type \"Dog\". Did you mean \"barkVolume\"?" + error: errors.first, + line: 1, + column: 48, + message: + "Cannot query field \"mooVolume\" on type \"Dog\". Did you mean \"barkVolume\"?" ) } @@ -147,8 +165,11 @@ class FieldsOnCorrectTypeTests: ValidationTestCase { ) try assertValidationError( - error: errors.first, line: 1, column: 53, - message: "Cannot query field \"kawVolume\" on type \"Dog\". Did you mean \"barkVolume\"?" + error: errors.first, + line: 1, + column: 53, + message: + "Cannot query field \"kawVolume\" on type \"Dog\". Did you mean \"barkVolume\"?" ) } @@ -159,7 +180,9 @@ class FieldsOnCorrectTypeTests: ValidationTestCase { ) try assertValidationError( - error: errors.first, line: 1, column: 41, + error: errors.first, + line: 1, + column: 41, message: "Cannot query field \"tailLength\" on type \"Pet\"." ) } @@ -171,40 +194,42 @@ class FieldsOnCorrectTypeTests: ValidationTestCase { ) try assertValidationError( - error: errors.first, line: 1, column: 56, + error: errors.first, + line: 1, + column: 56, message: "Cannot query field \"nickname\" on type \"Pet\". Did you mean \"name\"?" ) } -// @Test func invalidWhenDirectFieldSelectionOnUnion() throws { -// let errors = try assertInvalid( -// errorCount: 1, -// query: """ -// fragment directFieldSelectionOnUnion on CatOrDog { -// directField -// } -// """ -// ) -// -// try assertValidationError( -// error: errors.first, line: 1, column: 0, -// message: "" -// ) -// } -// -// @Test func invalidWhenDefinedOnImplementorsQueriedOnUnion() throws { -// let errors = try assertInvalid( -// errorCount: 1, -// query: """ -// fragment definedOnImplementorsQueriedOnUnion on CatOrDog { -// name -// } -// """ -// ) -// -// try assertValidationError( -// error: errors.first, line: 1, column: 0, -// message: "" -// ) -// } + // @Test func invalidWhenDirectFieldSelectionOnUnion() throws { + // let errors = try assertInvalid( + // errorCount: 1, + // query: """ + // fragment directFieldSelectionOnUnion on CatOrDog { + // directField + // } + // """ + // ) + // + // try assertValidationError( + // error: errors.first, line: 1, column: 0, + // message: "" + // ) + // } + // + // @Test func invalidWhenDefinedOnImplementorsQueriedOnUnion() throws { + // let errors = try assertInvalid( + // errorCount: 1, + // query: """ + // fragment definedOnImplementorsQueriedOnUnion on CatOrDog { + // name + // } + // """ + // ) + // + // try assertValidationError( + // error: errors.first, line: 1, column: 0, + // message: "" + // ) + // } } diff --git a/Tests/GraphQLTests/ValidationTests/FragmentsOnCompositeTypesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/FragmentsOnCompositeTypesRuleTests.swift index b556ea34..333ec81b 100644 --- a/Tests/GraphQLTests/ValidationTests/FragmentsOnCompositeTypesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/FragmentsOnCompositeTypesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class FragmentsOnCompositeTypesRuleTests: ValidationTestCase { override init() { super.init() @@ -77,16 +78,17 @@ class FragmentsOnCompositeTypesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - fragment scalarFragment on Boolean { - bad - } - """ + """ + fragment scalarFragment on Boolean { + bad + } + """ ) try assertValidationError( error: errors[0], locations: [(line: 1, column: 28)], - message: "Fragment \"scalarFragment\" cannot condition on non composite type \"Boolean\"." + message: + "Fragment \"scalarFragment\" cannot condition on non composite type \"Boolean\"." ) } @@ -94,16 +96,17 @@ class FragmentsOnCompositeTypesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - fragment scalarFragment on FurColor { - bad - } - """ + """ + fragment scalarFragment on FurColor { + bad + } + """ ) try assertValidationError( error: errors[0], locations: [(line: 1, column: 28)], - message: "Fragment \"scalarFragment\" cannot condition on non composite type \"FurColor\"." + message: + "Fragment \"scalarFragment\" cannot condition on non composite type \"FurColor\"." ) } @@ -111,16 +114,17 @@ class FragmentsOnCompositeTypesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - fragment inputFragment on ComplexInput { - stringField - } - """ + """ + fragment inputFragment on ComplexInput { + stringField + } + """ ) try assertValidationError( error: errors[0], locations: [(line: 1, column: 27)], - message: "Fragment \"inputFragment\" cannot condition on non composite type \"ComplexInput\"." + message: + "Fragment \"inputFragment\" cannot condition on non composite type \"ComplexInput\"." ) } @@ -128,13 +132,13 @@ class FragmentsOnCompositeTypesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - fragment invalidFragment on Pet { - ... on String { - barks - } - } - """ + """ + fragment invalidFragment on Pet { + ... on String { + barks + } + } + """ ) try assertValidationError( error: errors[0], diff --git a/Tests/GraphQLTests/ValidationTests/KnownArgumentNamesOnDirectivesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/KnownArgumentNamesOnDirectivesRuleTests.swift index a4a0f823..3e01be0b 100644 --- a/Tests/GraphQLTests/ValidationTests/KnownArgumentNamesOnDirectivesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/KnownArgumentNamesOnDirectivesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class KnownArgumentNamesOnDirectivesRuleTests: SDLValidationTestCase { override init() { super.init() @@ -33,7 +34,7 @@ class KnownArgumentNamesOnDirectivesRuleTests: SDLValidationTestCase { GraphQLError( message: #"Unknown argument "unknown" on directive "@test"."#, locations: [.init(line: 2, column: 21)] - ), + ) ] ) } @@ -51,7 +52,7 @@ class KnownArgumentNamesOnDirectivesRuleTests: SDLValidationTestCase { GraphQLError( message: #"Unknown argument "agr" on directive "@test". Did you mean "arg"?"#, locations: [.init(line: 2, column: 21)] - ), + ) ] ) } @@ -67,7 +68,7 @@ class KnownArgumentNamesOnDirectivesRuleTests: SDLValidationTestCase { GraphQLError( message: #"Unknown argument "unknown" on directive "@deprecated"."#, locations: [.init(line: 2, column: 27)] - ), + ) ] ) } @@ -84,22 +85,24 @@ class KnownArgumentNamesOnDirectivesRuleTests: SDLValidationTestCase { GraphQLError( message: #"Unknown argument "reason" on directive "@deprecated"."#, locations: [.init(line: 2, column: 27)] - ), + ) ] ) } @Test func unknownArgOnDirectiveDefinedInSchemaExtension() throws { - let schema = try buildSchema(source: """ - type Query { - foo: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + foo: String + } + """ + ) let sdl = """ - directive @test(arg: String) on OBJECT + directive @test(arg: String) on OBJECT - extend type Query @test(unknown: "") - """ + extend type Query @test(unknown: "") + """ try assertValidationErrors( sdl, schema: schema, @@ -107,22 +110,24 @@ class KnownArgumentNamesOnDirectivesRuleTests: SDLValidationTestCase { GraphQLError( message: #"Unknown argument "unknown" on directive "@test"."#, locations: [.init(line: 3, column: 26)] - ), + ) ] ) } @Test func unknownArgOnDirectiveUsedInSchemaExtension() throws { - let schema = try buildSchema(source: """ - directive @test(arg: String) on OBJECT + let schema = try buildSchema( + source: """ + directive @test(arg: String) on OBJECT - type Query { - foo: String - } - """) + type Query { + foo: String + } + """ + ) let sdl = """ - extend type Query @test(unknown: "") - """ + extend type Query @test(unknown: "") + """ try assertValidationErrors( sdl, schema: schema, @@ -130,7 +135,7 @@ class KnownArgumentNamesOnDirectivesRuleTests: SDLValidationTestCase { GraphQLError( message: #"Unknown argument "unknown" on directive "@test"."#, locations: [.init(line: 1, column: 25)] - ), + ) ] ) } diff --git a/Tests/GraphQLTests/ValidationTests/KnownArgumentNamesTests.swift b/Tests/GraphQLTests/ValidationTests/KnownArgumentNamesTests.swift index 3e14f904..9e84a261 100644 --- a/Tests/GraphQLTests/ValidationTests/KnownArgumentNamesTests.swift +++ b/Tests/GraphQLTests/ValidationTests/KnownArgumentNamesTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class KnownArgumentNamesTests: ValidationTestCase { override init() { super.init() @@ -22,12 +23,16 @@ class KnownArgumentNamesTests: ValidationTestCase { @Test func invalidWithSlightlyMisspelledArgument() throws { let errors = try assertInvalid( errorCount: 1, - query: "fragment objectFieldSelection on Dog { __typename isHousetrained(atOtherHomees: true) }" + query: + "fragment objectFieldSelection on Dog { __typename isHousetrained(atOtherHomees: true) }" ) try assertValidationError( - error: errors.first, line: 1, column: 66, - message: #"Field "isHousetrained" on type "Dog" does not have argument "atOtherHomees". Did you mean "atOtherHomes"?"# + error: errors.first, + line: 1, + column: 66, + message: + #"Field "isHousetrained" on type "Dog" does not have argument "atOtherHomees". Did you mean "atOtherHomes"?"# ) } @@ -38,7 +43,9 @@ class KnownArgumentNamesTests: ValidationTestCase { ) try assertValidationError( - error: errors.first, line: 1, column: 56, + error: errors.first, + line: 1, + column: 56, message: #"Field "name" on type "Dog" does not have argument "uppercased"."# ) } diff --git a/Tests/GraphQLTests/ValidationTests/KnownDirectivesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/KnownDirectivesRuleTests.swift index ccb7ba53..2f83e911 100644 --- a/Tests/GraphQLTests/ValidationTests/KnownDirectivesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/KnownDirectivesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class KnownDirectivesRuleTests: ValidationTestCase { override init() { super.init() @@ -45,13 +46,13 @@ class KnownDirectivesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - human @unknown(directive: "value") { - name + """ + { + human @unknown(directive: "value") { + name + } } - } - """, + """, schema: schemaWithDirectives ) @@ -66,17 +67,17 @@ class KnownDirectivesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 3, query: - """ - { - __typename @unknown - human @unknown { - name - pets @unknown { + """ + { + __typename @unknown + human @unknown { name + pets @unknown { + name + } } } - } - """, + """, schema: schemaWithDirectives ) @@ -129,28 +130,28 @@ class KnownDirectivesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 12, query: - """ - query ($var: Boolean @onQuery) @onMutation { - human @onQuery { - ...Frag @onQuery - ... @onQuery { - name @onQuery + """ + query ($var: Boolean @onQuery) @onMutation { + human @onQuery { + ...Frag @onQuery + ... @onQuery { + name @onQuery + } } } - } - mutation @onQuery { - someField @onQuery - } + mutation @onQuery { + someField @onQuery + } - subscription @onQuery { - someField @onQuery - } + subscription @onQuery { + someField @onQuery + } - fragment Frag on Human @onQuery { - name @onQuery - } - """, + fragment Frag on Human @onQuery { + name @onQuery + } + """, schema: schemaWithDirectives ) @@ -223,7 +224,7 @@ class KnownDirectivesRuleTests: ValidationTestCase { "dummy": GraphQLField(type: GraphQLString) { inputValue, _, _, _ -> String? in print(type(of: inputValue)) return nil - }, + } ] ), directives: { @@ -292,42 +293,48 @@ class KnownDirectivesRuleSDLTests: SDLValidationTestCase { } @Test func withDirectiveDefinedInSchemaExtension() throws { - let schema = try buildSchema(source: """ - type Query { - foo: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + foo: String + } + """ + ) let sdl = """ - directive @test on OBJECT + directive @test on OBJECT - extend type Query @test - """ + extend type Query @test + """ try assertValidationErrors(sdl, schema: schema, []) } @Test func withDirectiveUsedInSchemaExtension() throws { - let schema = try buildSchema(source: """ - directive @test on OBJECT + let schema = try buildSchema( + source: """ + directive @test on OBJECT - type Query { - foo: String - } - """) + type Query { + foo: String + } + """ + ) let sdl = """ - extend type Query @test - """ + extend type Query @test + """ try assertValidationErrors(sdl, schema: schema, []) } @Test func withUnknownDirectiveInSchemaExtension() throws { - let schema = try buildSchema(source: """ - type Query { - foo: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + foo: String + } + """ + ) let sdl = """ - extend type Query @unknown - """ + extend type Query @unknown + """ try assertValidationErrors( sdl, schema: schema, @@ -335,7 +342,7 @@ class KnownDirectivesRuleSDLTests: SDLValidationTestCase { GraphQLError( message: #"Unknown directive "@unknown"."#, locations: [.init(line: 1, column: 19)] - ), + ) ] ) } @@ -425,11 +432,13 @@ class KnownDirectivesRuleSDLTests: SDLValidationTestCase { locations: [.init(line: 1, column: 35)] ), GraphQLError( - message: #"Directive "@onInputFieldDefinition" may not be used on ARGUMENT_DEFINITION."#, + message: + #"Directive "@onInputFieldDefinition" may not be used on ARGUMENT_DEFINITION."#, locations: [.init(line: 2, column: 22)] ), GraphQLError( - message: #"Directive "@onInputFieldDefinition" may not be used on FIELD_DEFINITION."#, + message: + #"Directive "@onInputFieldDefinition" may not be used on FIELD_DEFINITION."#, locations: [.init(line: 2, column: 55)] ), GraphQLError( @@ -441,11 +450,13 @@ class KnownDirectivesRuleSDLTests: SDLValidationTestCase { locations: [.init(line: 7, column: 23)] ), GraphQLError( - message: #"Directive "@onInputFieldDefinition" may not be used on ARGUMENT_DEFINITION."#, + message: + #"Directive "@onInputFieldDefinition" may not be used on ARGUMENT_DEFINITION."#, locations: [.init(line: 8, column: 22)] ), GraphQLError( - message: #"Directive "@onInputFieldDefinition" may not be used on FIELD_DEFINITION."#, + message: + #"Directive "@onInputFieldDefinition" may not be used on FIELD_DEFINITION."#, locations: [.init(line: 8, column: 55)] ), GraphQLError( @@ -465,7 +476,8 @@ class KnownDirectivesRuleSDLTests: SDLValidationTestCase { locations: [.init(line: 17, column: 15)] ), GraphQLError( - message: #"Directive "@onArgumentDefinition" may not be used on INPUT_FIELD_DEFINITION."#, + message: + #"Directive "@onArgumentDefinition" may not be used on INPUT_FIELD_DEFINITION."#, locations: [.init(line: 18, column: 16)] ), GraphQLError( @@ -490,8 +502,7 @@ class KnownDirectivesRuleSDLTests: SDLValidationTestCase { try! GraphQLDirective(name: "onFieldDefinition", locations: [.fieldDefinition]), try! GraphQLDirective( name: "onArgumentDefinition", - locations: - [.argumentDefinition] + locations: [.argumentDefinition] ), try! GraphQLDirective(name: "onInterface", locations: [.interface]), try! GraphQLDirective(name: "onUnion", locations: [.union]), @@ -500,8 +511,7 @@ class KnownDirectivesRuleSDLTests: SDLValidationTestCase { try! GraphQLDirective(name: "onInputObject", locations: [.inputObject]), try! GraphQLDirective( name: "onInputFieldDefinition", - locations: - [.inputFieldDefinition] + locations: [.inputFieldDefinition] ), ]) return directives diff --git a/Tests/GraphQLTests/ValidationTests/KnownFragmentNamesTests.swift b/Tests/GraphQLTests/ValidationTests/KnownFragmentNamesTests.swift index 426a2823..920991e1 100644 --- a/Tests/GraphQLTests/ValidationTests/KnownFragmentNamesTests.swift +++ b/Tests/GraphQLTests/ValidationTests/KnownFragmentNamesTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class KnownFragmentNamesTests: ValidationTestCase { override init() { super.init() @@ -39,20 +40,20 @@ class KnownFragmentNamesTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 3, query: - """ - { - human(id: 4) { - ...UnknownFragment1 - ... on Human { - ...UnknownFragment2 + """ + { + human(id: 4) { + ...UnknownFragment1 + ... on Human { + ...UnknownFragment2 + } + } } - } - } - fragment HumanFields on Human { - name - ...UnknownFragment3 - } - """ + fragment HumanFields on Human { + name + ...UnknownFragment3 + } + """ ) try assertValidationError( diff --git a/Tests/GraphQLTests/ValidationTests/KnownTypeNamesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/KnownTypeNamesRuleTests.swift index 857c703f..3ac8311d 100644 --- a/Tests/GraphQLTests/ValidationTests/KnownTypeNamesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/KnownTypeNamesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class KnownTypeNamesRuleTests: ValidationTestCase { override init() { super.init() @@ -31,17 +32,17 @@ class KnownTypeNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 3, query: - """ - query Foo($var: [JumbledUpLetters!]!) { - user(id: 4) { - name - pets { ... on Badger { name }, ...PetFields } - } - } - fragment PetFields on Peat { - name - } - """ + """ + query Foo($var: [JumbledUpLetters!]!) { + user(id: 4) { + name + pets { ... on Badger { name }, ...PetFields } + } + } + fragment PetFields on Peat { + name + } + """ ) try assertValidationError( error: errors[0], diff --git a/Tests/GraphQLTests/ValidationTests/LoneAnonymousOperationRuleTests.swift b/Tests/GraphQLTests/ValidationTests/LoneAnonymousOperationRuleTests.swift index 7a3dba30..0f456ba9 100644 --- a/Tests/GraphQLTests/ValidationTests/LoneAnonymousOperationRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/LoneAnonymousOperationRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class LoneAnonymousOperationRuleTests: ValidationTestCase { override init() { super.init() @@ -58,14 +59,14 @@ class LoneAnonymousOperationRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: - """ - { - fieldA - } - { - fieldB - } - """ + """ + { + fieldA + } + { + fieldB + } + """ ) try assertValidationError( error: errors[0], @@ -83,14 +84,14 @@ class LoneAnonymousOperationRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - fieldA - } - mutation Foo { - fieldB - } - """ + """ + { + fieldA + } + mutation Foo { + fieldB + } + """ ) try assertValidationError( error: errors[0], @@ -103,14 +104,14 @@ class LoneAnonymousOperationRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - fieldA - } - subscription Foo { - fieldB - } - """ + """ + { + fieldA + } + subscription Foo { + fieldB + } + """ ) try assertValidationError( error: errors[0], diff --git a/Tests/GraphQLTests/ValidationTests/LoneSchemaDefinitionRuleTests.swift b/Tests/GraphQLTests/ValidationTests/LoneSchemaDefinitionRuleTests.swift index e223fc50..cba1ad1d 100644 --- a/Tests/GraphQLTests/ValidationTests/LoneSchemaDefinitionRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/LoneSchemaDefinitionRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class LoneSchemaDefinitionRuleTests: SDLValidationTestCase { override init() { super.init() @@ -66,11 +67,13 @@ class LoneSchemaDefinitionRuleTests: SDLValidationTestCase { } @Test func defineSchemaInSchemaExtension() throws { - let schema = try buildSchema(source: """ - type Foo { - foo: String - } - """) + let schema = try buildSchema( + source: """ + type Foo { + foo: String + } + """ + ) try assertValidationErrors( """ @@ -84,15 +87,17 @@ class LoneSchemaDefinitionRuleTests: SDLValidationTestCase { } @Test func redefineSchemaInSchemaExtension() throws { - let schema = try buildSchema(source: """ - schema { - query: Foo - } - - type Foo { - foo: String - } - """) + let schema = try buildSchema( + source: """ + schema { + query: Foo + } + + type Foo { + foo: String + } + """ + ) try assertValidationErrors( """ @@ -105,21 +110,23 @@ class LoneSchemaDefinitionRuleTests: SDLValidationTestCase { GraphQLError( message: "Cannot define a new schema within a schema extension.", locations: [.init(line: 1, column: 1)] - ), + ) ] ) } @Test func redefineImplicitSchemaInSchemaExtension() throws { - let schema = try buildSchema(source: """ - type Query { - fooField: Foo - } - - type Foo { - foo: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + fooField: Foo + } + + type Foo { + foo: String + } + """ + ) try assertValidationErrors( """ @@ -132,21 +139,23 @@ class LoneSchemaDefinitionRuleTests: SDLValidationTestCase { GraphQLError( message: "Cannot define a new schema within a schema extension.", locations: [.init(line: 1, column: 1)] - ), + ) ] ) } @Test func extendSchemaInSchemaExtension() throws { - let schema = try buildSchema(source: """ - type Query { - fooField: Foo - } - - type Foo { - foo: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + fooField: Foo + } + + type Foo { + foo: String + } + """ + ) try assertValidationErrors( """ diff --git a/Tests/GraphQLTests/ValidationTests/NoDeprecatedCustomRuleTests.swift b/Tests/GraphQLTests/ValidationTests/NoDeprecatedCustomRuleTests.swift index 7a315298..16c84abe 100644 --- a/Tests/GraphQLTests/ValidationTests/NoDeprecatedCustomRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/NoDeprecatedCustomRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class NoDeprecatedCustomRuleTests: ValidationTestCase { override init() { super.init() @@ -10,10 +11,16 @@ class NoDeprecatedCustomRuleTests: ValidationTestCase { // MARK: no deprecated fields let deprecatedFieldSchema = try! GraphQLSchema( - query: .init(name: "Query", fields: [ - "normalField": .init(type: GraphQLString), - "deprecatedField": .init(type: GraphQLString, deprecationReason: "Some field reason."), - ]) + query: .init( + name: "Query", + fields: [ + "normalField": .init(type: GraphQLString), + "deprecatedField": .init( + type: GraphQLString, + deprecationReason: "Some field reason." + ), + ] + ) ) @Test func ignoresFieldsThatAreNotDeprecated() throws { @@ -46,14 +53,14 @@ class NoDeprecatedCustomRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - { - deprecatedField - } + { + deprecatedField + } - fragment QueryFragment on Query { - deprecatedField - } - """, + fragment QueryFragment on Query { + deprecatedField + } + """, schema: deprecatedFieldSchema ) try assertValidationError( @@ -71,12 +78,21 @@ class NoDeprecatedCustomRuleTests: ValidationTestCase { // MARK: no deprecated arguments on fields let deprecatedFieldArgumentSchema = try! GraphQLSchema( - query: .init(name: "Query", fields: [ - "someField": .init(type: GraphQLString, args: [ - "normalArg": .init(type: GraphQLString), - "deprecatedArg": .init(type: GraphQLString, deprecationReason: "Some arg reason."), - ]), - ]) + query: .init( + name: "Query", + fields: [ + "someField": .init( + type: GraphQLString, + args: [ + "normalArg": .init(type: GraphQLString), + "deprecatedArg": .init( + type: GraphQLString, + deprecationReason: "Some arg reason." + ), + ] + ) + ] + ) ) @Test func ignoresFieldArgumentsThatAreNotDeprecated() throws { @@ -106,30 +122,34 @@ class NoDeprecatedCustomRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - { - someField(deprecatedArg: "") - } - """, + { + someField(deprecatedArg: "") + } + """, schema: deprecatedFieldArgumentSchema ) try assertValidationError( error: errors[0], locations: [(line: 2, column: 13)], - message: #"Field "Query.someField" argument "deprecatedArg" is deprecated. Some arg reason."# + message: + #"Field "Query.someField" argument "deprecatedArg" is deprecated. Some arg reason."# ) } // MARK: no deprecated arguments on directives let deprecatedDirectiveArgumentSchema = try! GraphQLSchema( - query: .init(name: "Query", fields: [ - "someField": .init(type: GraphQLString), - ]), + query: .init( + name: "Query", + fields: [ + "someField": .init(type: GraphQLString) + ] + ), directives: [ .init( name: "someDirective", locations: [ - .field, + .field ], args: [ "normalArg": .init(type: GraphQLString), @@ -138,7 +158,7 @@ class NoDeprecatedCustomRuleTests: ValidationTestCase { deprecationReason: "Some arg reason." ), ] - ), + ) ] ) @@ -169,48 +189,58 @@ class NoDeprecatedCustomRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - { - someField @someDirective(deprecatedArg: "") - } - """, + { + someField @someDirective(deprecatedArg: "") + } + """, schema: deprecatedDirectiveArgumentSchema ) try assertValidationError( error: errors[0], locations: [(line: 2, column: 28)], - message: #"Directive "@someDirective" argument "deprecatedArg" is deprecated. Some arg reason."# + message: + #"Directive "@someDirective" argument "deprecatedArg" is deprecated. Some arg reason."# ) } // MARK: no deprecated input fields let deprecatedInputFieldSchema: GraphQLSchema = { - let inputType = try! GraphQLInputObjectType(name: "InputType", fields: [ - "normalField": .init(type: GraphQLString), - "deprecatedField": .init( - type: GraphQLString, - deprecationReason: "Some input field reason." - ), - ]) + let inputType = try! GraphQLInputObjectType( + name: "InputType", + fields: [ + "normalField": .init(type: GraphQLString), + "deprecatedField": .init( + type: GraphQLString, + deprecationReason: "Some input field reason." + ), + ] + ) return try! GraphQLSchema( - query: .init(name: "Query", fields: [ - "someField": .init(type: GraphQLString, args: [ - "someArg": .init(type: inputType), - ]), - ]), + query: .init( + name: "Query", + fields: [ + "someField": .init( + type: GraphQLString, + args: [ + "someArg": .init(type: inputType) + ] + ) + ] + ), types: [ - inputType, + inputType ], directives: [ .init( name: "someDirective", locations: [ - .field, + .field ], args: [ - "someArg": .init(type: inputType), + "someArg": .init(type: inputType) ] - ), + ) ] ) }() @@ -253,44 +283,55 @@ class NoDeprecatedCustomRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - { - someField( - someArg: { deprecatedField: "" } - ) @someDirective(someArg: { deprecatedField: "" }) - } - """, + { + someField( + someArg: { deprecatedField: "" } + ) @someDirective(someArg: { deprecatedField: "" }) + } + """, schema: deprecatedInputFieldSchema ) try assertValidationError( error: errors[0], locations: [(line: 3, column: 16)], - message: #"The input field InputType.deprecatedField is deprecated. Some input field reason."# + message: + #"The input field InputType.deprecatedField is deprecated. Some input field reason."# ) try assertValidationError( error: errors[1], locations: [(line: 4, column: 31)], - message: #"The input field InputType.deprecatedField is deprecated. Some input field reason."# + message: + #"The input field InputType.deprecatedField is deprecated. Some input field reason."# ) } // MARK: no deprecated enum values let deprecatedEnumValueSchema: GraphQLSchema = { - let enumType = try! GraphQLEnumType(name: "EnumType", values: [ - "NORMAL_VALUE": .init(value: .string("NORMAL_VALUE")), - "DEPRECATED_VALUE": .init( - value: .string("DEPRECATED_VALUE"), - deprecationReason: "Some enum reason." - ), - ]) + let enumType = try! GraphQLEnumType( + name: "EnumType", + values: [ + "NORMAL_VALUE": .init(value: .string("NORMAL_VALUE")), + "DEPRECATED_VALUE": .init( + value: .string("DEPRECATED_VALUE"), + deprecationReason: "Some enum reason." + ), + ] + ) return try! GraphQLSchema( - query: .init(name: "Query", fields: [ - "someField": .init(type: GraphQLString, args: [ - "enumArg": .init(type: enumType), - ]), - ]), + query: .init( + name: "Query", + fields: [ + "someField": .init( + type: GraphQLString, + args: [ + "enumArg": .init(type: enumType) + ] + ) + ] + ), types: [ - enumType, + enumType ] ) }() @@ -330,12 +371,12 @@ class NoDeprecatedCustomRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - query ( - $variable: EnumType = DEPRECATED_VALUE - ) { - someField(enumArg: DEPRECATED_VALUE) - } - """, + query ( + $variable: EnumType = DEPRECATED_VALUE + ) { + someField(enumArg: DEPRECATED_VALUE) + } + """, schema: deprecatedEnumValueSchema ) try assertValidationError( diff --git a/Tests/GraphQLTests/ValidationTests/NoFragmentCyclesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/NoFragmentCyclesRuleTests.swift index 319d8e33..89ab253d 100644 --- a/Tests/GraphQLTests/ValidationTests/NoFragmentCyclesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/NoFragmentCyclesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class NoFragmentCyclesRuleTests: ValidationTestCase { override init() { super.init() @@ -65,8 +66,8 @@ class NoFragmentCyclesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment fragA on Human { relatives { ...fragA } }, - """ + fragment fragA on Human { relatives { ...fragA } }, + """ ) try assertValidationError( @@ -80,8 +81,8 @@ class NoFragmentCyclesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment fragA on Dog { ...fragA } - """ + fragment fragA on Dog { ...fragA } + """ ) try assertValidationError( @@ -95,12 +96,12 @@ class NoFragmentCyclesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment fragA on Pet { - ... on Dog { - ...fragA - } - } - """ + fragment fragA on Pet { + ... on Dog { + ...fragA + } + } + """ ) try assertValidationError( @@ -114,9 +115,9 @@ class NoFragmentCyclesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment fragA on Dog { ...fragB } - fragment fragB on Dog { ...fragA } - """ + fragment fragA on Dog { ...fragB } + fragment fragB on Dog { ...fragA } + """ ) try assertValidationError( @@ -133,9 +134,9 @@ class NoFragmentCyclesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment fragB on Dog { ...fragA } - fragment fragA on Dog { ...fragB } - """ + fragment fragB on Dog { ...fragA } + fragment fragA on Dog { ...fragB } + """ ) try assertValidationError( @@ -152,17 +153,17 @@ class NoFragmentCyclesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment fragA on Pet { - ... on Dog { - ...fragB - } - } - fragment fragB on Pet { - ... on Dog { - ...fragA - } - } - """ + fragment fragA on Pet { + ... on Dog { + ...fragB + } + } + fragment fragB on Pet { + ... on Dog { + ...fragA + } + } + """ ) try assertValidationError( @@ -179,15 +180,15 @@ class NoFragmentCyclesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - fragment fragA on Dog { ...fragB } - fragment fragB on Dog { ...fragC } - fragment fragC on Dog { ...fragO } - fragment fragX on Dog { ...fragY } - fragment fragY on Dog { ...fragZ } - fragment fragZ on Dog { ...fragO } - fragment fragO on Dog { ...fragP } - fragment fragP on Dog { ...fragA, ...fragX } - """ + fragment fragA on Dog { ...fragB } + fragment fragB on Dog { ...fragC } + fragment fragC on Dog { ...fragO } + fragment fragX on Dog { ...fragY } + fragment fragY on Dog { ...fragZ } + fragment fragZ on Dog { ...fragO } + fragment fragO on Dog { ...fragP } + fragment fragP on Dog { ...fragA, ...fragX } + """ ) try assertValidationError( @@ -199,7 +200,8 @@ class NoFragmentCyclesRuleTests: ValidationTestCase { (line: 7, column: 25), (line: 8, column: 25), ], - message: #"Cannot spread fragment "fragA" within itself via "fragB", "fragC", "fragO", "fragP"."# + message: + #"Cannot spread fragment "fragA" within itself via "fragB", "fragC", "fragO", "fragP"."# ) try assertValidationError( @@ -211,7 +213,8 @@ class NoFragmentCyclesRuleTests: ValidationTestCase { (line: 5, column: 25), (line: 6, column: 25), ], - message: #"Cannot spread fragment "fragO" within itself via "fragP", "fragX", "fragY", "fragZ"."# + message: + #"Cannot spread fragment "fragO" within itself via "fragP", "fragX", "fragY", "fragZ"."# ) } @@ -219,10 +222,10 @@ class NoFragmentCyclesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - fragment fragA on Dog { ...fragB, ...fragC } - fragment fragB on Dog { ...fragA } - fragment fragC on Dog { ...fragA } - """ + fragment fragA on Dog { ...fragB, ...fragC } + fragment fragB on Dog { ...fragA } + fragment fragC on Dog { ...fragA } + """ ) try assertValidationError( @@ -248,10 +251,10 @@ class NoFragmentCyclesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - fragment fragA on Dog { ...fragC } - fragment fragB on Dog { ...fragC } - fragment fragC on Dog { ...fragA, ...fragB } - """ + fragment fragA on Dog { ...fragC } + fragment fragB on Dog { ...fragC } + fragment fragC on Dog { ...fragA, ...fragB } + """ ) try assertValidationError( @@ -277,16 +280,16 @@ class NoFragmentCyclesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 3, query: """ - fragment fragA on Dog { ...fragB } - fragment fragB on Dog { ...fragB, ...fragC } - fragment fragC on Dog { ...fragA, ...fragB } - """ + fragment fragA on Dog { ...fragB } + fragment fragB on Dog { ...fragB, ...fragC } + fragment fragC on Dog { ...fragA, ...fragB } + """ ) try assertValidationError( error: errors[0], locations: [ - (line: 2, column: 25), + (line: 2, column: 25) ], message: #"Cannot spread fragment "fragB" within itself."# ) diff --git a/Tests/GraphQLTests/ValidationTests/NoUndefinedVariablesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/NoUndefinedVariablesRuleTests.swift index d4849e4b..7e82df73 100644 --- a/Tests/GraphQLTests/ValidationTests/NoUndefinedVariablesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/NoUndefinedVariablesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class NoUndefinedVariablesRuleTests: ValidationTestCase { override init() { super.init() @@ -126,10 +127,10 @@ class NoUndefinedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - query Foo($a: String, $b: String, $c: String) { - field(a: $a, b: $b, c: $c, d: $d) - } - """ + query Foo($a: String, $b: String, $c: String) { + field(a: $a, b: $b, c: $c, d: $d) + } + """ ) try assertValidationError( error: errors[0], @@ -145,10 +146,10 @@ class NoUndefinedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - { - field(a: $a) - } - """ + { + field(a: $a) + } + """ ) try assertValidationError( error: errors[0], @@ -164,10 +165,10 @@ class NoUndefinedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - query Foo($b: String) { - field(a: $a, b: $b, c: $c) - } - """ + query Foo($b: String) { + field(a: $a, b: $b, c: $c) + } + """ ) try assertValidationError( error: errors[0], @@ -191,13 +192,13 @@ class NoUndefinedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - { - ...FragA - } - fragment FragA on Type { - field(a: $a) - } - """ + { + ...FragA + } + fragment FragA on Type { + field(a: $a) + } + """ ) try assertValidationError( error: errors[0], @@ -213,23 +214,23 @@ class NoUndefinedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - query Foo($a: String, $b: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field(c: $c) - } - """ + query Foo($a: String, $b: String) { + ...FragA + } + fragment FragA on Type { + field(a: $a) { + ...FragB + } + } + fragment FragB on Type { + field(b: $b) { + ...FragC + } + } + fragment FragC on Type { + field(c: $c) + } + """ ) try assertValidationError( error: errors[0], @@ -245,23 +246,23 @@ class NoUndefinedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - query Foo($b: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field(c: $c) - } - """ + query Foo($b: String) { + ...FragA + } + fragment FragA on Type { + field(a: $a) { + ...FragB + } + } + fragment FragB on Type { + field(b: $b) { + ...FragC + } + } + fragment FragC on Type { + field(c: $c) + } + """ ) try assertValidationError( error: errors[0], @@ -285,16 +286,16 @@ class NoUndefinedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - query Foo($a: String) { - ...FragAB - } - query Bar($a: String) { - ...FragAB - } - fragment FragAB on Type { - field(a: $a, b: $b) - } - """ + query Foo($a: String) { + ...FragAB + } + query Bar($a: String) { + ...FragAB + } + fragment FragAB on Type { + field(a: $a, b: $b) + } + """ ) try assertValidationError( error: errors[0], @@ -318,19 +319,19 @@ class NoUndefinedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - query Foo($b: String) { - ...FragA - } - query Bar($a: String) { - ...FragB - } - fragment FragA on Type { - field(a: $a) - } - fragment FragB on Type { - field(b: $b) - } - """ + query Foo($b: String) { + ...FragA + } + query Bar($a: String) { + ...FragB + } + fragment FragA on Type { + field(a: $a) + } + fragment FragB on Type { + field(b: $b) + } + """ ) try assertValidationError( error: errors[0], @@ -354,21 +355,21 @@ class NoUndefinedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 6, query: """ - query Foo($b: String) { - ...FragAB - } - query Bar($a: String) { - ...FragAB - } - fragment FragAB on Type { - field1(a: $a, b: $b) - ...FragC - field3(a: $a, b: $b) - } - fragment FragC on Type { - field2(c: $c) - } - """ + query Foo($b: String) { + ...FragAB + } + query Bar($a: String) { + ...FragAB + } + fragment FragAB on Type { + field1(a: $a, b: $b) + ...FragC + field3(a: $a, b: $b) + } + fragment FragC on Type { + field2(c: $c) + } + """ ) try assertValidationError( error: errors[0], diff --git a/Tests/GraphQLTests/ValidationTests/NoUnusedFragmentsRuleTests.swift b/Tests/GraphQLTests/ValidationTests/NoUnusedFragmentsRuleTests.swift index dc4dd508..e3d3d69b 100644 --- a/Tests/GraphQLTests/ValidationTests/NoUnusedFragmentsRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/NoUnusedFragmentsRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class NoUnusedFragmentsRuleTests: ValidationTestCase { override init() { super.init() @@ -63,42 +64,46 @@ class NoUnusedFragmentsRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - query Foo { - human(id: 4) { - ...HumanFields1 - } - } - query Bar { - human(id: 4) { - ...HumanFields2 - } - } - fragment HumanFields1 on Human { - name - ...HumanFields3 - } - fragment HumanFields2 on Human { - name - } - fragment HumanFields3 on Human { - name - } - fragment Unused1 on Human { - name - } - fragment Unused2 on Human { - name - } - """ + query Foo { + human(id: 4) { + ...HumanFields1 + } + } + query Bar { + human(id: 4) { + ...HumanFields2 + } + } + fragment HumanFields1 on Human { + name + ...HumanFields3 + } + fragment HumanFields2 on Human { + name + } + fragment HumanFields3 on Human { + name + } + fragment Unused1 on Human { + name + } + fragment Unused2 on Human { + name + } + """ ) try assertValidationError( - error: errors[0], line: 21, column: 1, + error: errors[0], + line: 21, + column: 1, message: "Fragment \"Unused1\" is never used." ) try assertValidationError( - error: errors[1], line: 24, column: 1, + error: errors[1], + line: 24, + column: 1, message: "Fragment \"Unused2\" is never used." ) } @@ -107,44 +112,48 @@ class NoUnusedFragmentsRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - query Foo { - human(id: 4) { - ...HumanFields1 - } - } - query Bar { - human(id: 4) { - ...HumanFields2 - } - } - fragment HumanFields1 on Human { - name - ...HumanFields3 - } - fragment HumanFields2 on Human { - name - } - fragment HumanFields3 on Human { - name - } - fragment Unused1 on Human { - name - ...Unused2 - } - fragment Unused2 on Human { - name - ...Unused1 - } - """ + query Foo { + human(id: 4) { + ...HumanFields1 + } + } + query Bar { + human(id: 4) { + ...HumanFields2 + } + } + fragment HumanFields1 on Human { + name + ...HumanFields3 + } + fragment HumanFields2 on Human { + name + } + fragment HumanFields3 on Human { + name + } + fragment Unused1 on Human { + name + ...Unused2 + } + fragment Unused2 on Human { + name + ...Unused1 + } + """ ) try assertValidationError( - error: errors[0], line: 21, column: 1, + error: errors[0], + line: 21, + column: 1, message: "Fragment \"Unused1\" is never used." ) try assertValidationError( - error: errors[1], line: 25, column: 1, + error: errors[1], + line: 25, + column: 1, message: "Fragment \"Unused2\" is never used." ) } @@ -153,19 +162,21 @@ class NoUnusedFragmentsRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - query Foo { - human(id: 4) { - ...bar - } - } - fragment foo on Human { - name - } - """ + query Foo { + human(id: 4) { + ...bar + } + } + fragment foo on Human { + name + } + """ ) try assertValidationError( - error: errors[0], line: 6, column: 1, + error: errors[0], + line: 6, + column: 1, message: "Fragment \"foo\" is never used." ) } diff --git a/Tests/GraphQLTests/ValidationTests/NoUnusedVariablesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/NoUnusedVariablesRuleTests.swift index 5161799f..d3b56fe3 100644 --- a/Tests/GraphQLTests/ValidationTests/NoUnusedVariablesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/NoUnusedVariablesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class NoUnusedVariablesRuleTests: ValidationTestCase { override init() { super.init() @@ -110,14 +111,16 @@ class NoUnusedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - query ($a: String, $b: String, $c: String) { - field(a: $a, b: $b) - } - """ + query ($a: String, $b: String, $c: String) { + field(a: $a, b: $b) + } + """ ) try assertValidationError( - error: errors.first, line: 1, column: 32, + error: errors.first, + line: 1, + column: 32, message: "Variable \"$c\" is never used." ) } @@ -126,19 +129,23 @@ class NoUnusedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - query Foo($a: String, $b: String, $c: String) { - field(b: $b) - } - """ + query Foo($a: String, $b: String, $c: String) { + field(b: $b) + } + """ ) try assertValidationError( - error: errors[0], line: 1, column: 11, + error: errors[0], + line: 1, + column: 11, message: #"Variable "$a" is never used in operation "Foo"."# ) try assertValidationError( - error: errors[1], line: 1, column: 35, + error: errors[1], + line: 1, + column: 35, message: #"Variable "$c" is never used in operation "Foo"."# ) } @@ -147,27 +154,29 @@ class NoUnusedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - query Foo($a: String, $b: String, $c: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragB + query Foo($a: String, $b: String, $c: String) { + ...FragA } - } - fragment FragB on Type { - field(b: $b) { - ...FragC + fragment FragA on Type { + field(a: $a) { + ...FragB + } } - } - fragment FragC on Type { - field - } - """ + fragment FragB on Type { + field(b: $b) { + ...FragC + } + } + fragment FragC on Type { + field + } + """ ) try assertValidationError( - error: errors.first, line: 1, column: 35, + error: errors.first, + line: 1, + column: 35, message: #"Variable "$c" is never used in operation "Foo"."# ) } @@ -176,32 +185,36 @@ class NoUnusedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - query Foo($a: String, $b: String, $c: String) { - ...FragA - } - fragment FragA on Type { - field { - ...FragB + query Foo($a: String, $b: String, $c: String) { + ...FragA } - } - fragment FragB on Type { - field(b: $b) { - ...FragC + fragment FragA on Type { + field { + ...FragB + } } - } - fragment FragC on Type { - field - } - """ + fragment FragB on Type { + field(b: $b) { + ...FragC + } + } + fragment FragC on Type { + field + } + """ ) try assertValidationError( - error: errors[0], line: 1, column: 11, + error: errors[0], + line: 1, + column: 11, message: #"Variable "$a" is never used in operation "Foo"."# ) try assertValidationError( - error: errors[1], line: 1, column: 35, + error: errors[1], + line: 1, + column: 35, message: #"Variable "$c" is never used in operation "Foo"."# ) } @@ -210,20 +223,22 @@ class NoUnusedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - query Foo($b: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) - } - fragment FragB on Type { - field(b: $b) - } - """ + query Foo($b: String) { + ...FragA + } + fragment FragA on Type { + field(a: $a) + } + fragment FragB on Type { + field(b: $b) + } + """ ) try assertValidationError( - error: errors.first, line: 1, column: 11, + error: errors.first, + line: 1, + column: 11, message: #"Variable "$b" is never used in operation "Foo"."# ) } @@ -232,28 +247,32 @@ class NoUnusedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - query Foo($b: String) { - ...FragA - } - query Bar($a: String) { - ...FragB - } - fragment FragA on Type { - field(a: $a) - } - fragment FragB on Type { - field(b: $b) - } - """ + query Foo($b: String) { + ...FragA + } + query Bar($a: String) { + ...FragB + } + fragment FragA on Type { + field(a: $a) + } + fragment FragB on Type { + field(b: $b) + } + """ ) try assertValidationError( - error: errors[0], line: 1, column: 11, + error: errors[0], + line: 1, + column: 11, message: #"Variable "$b" is never used in operation "Foo"."# ) try assertValidationError( - error: errors[1], line: 4, column: 11, + error: errors[1], + line: 4, + column: 11, message: #"Variable "$a" is never used in operation "Bar"."# ) } @@ -272,14 +291,16 @@ class NoUnusedVariablesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - query Foo($a: String, $b: String) { - field(object: { a: $a }) - } - """ + query Foo($a: String, $b: String) { + field(object: { a: $a }) + } + """ ) try assertValidationError( - error: errors[0], line: 1, column: 23, + error: errors[0], + line: 1, + column: 23, message: #"Variable "$b" is never used in operation "Foo"."# ) } diff --git a/Tests/GraphQLTests/ValidationTests/PossibleFragmentSpreadsRuleRuleTests.swift b/Tests/GraphQLTests/ValidationTests/PossibleFragmentSpreadsRuleRuleTests.swift index 34195ad8..a06ed6bf 100644 --- a/Tests/GraphQLTests/ValidationTests/PossibleFragmentSpreadsRuleRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/PossibleFragmentSpreadsRuleRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { override init() { super.init() @@ -120,30 +121,30 @@ class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { ) } -// @Test func interfaceIntoOverlappingInterface() throws { -// try assertValid( -// """ -// fragment interfaceWithinInterface on Pet { -// ...beingFragment -// } -// fragment beingFragment on Being { -// name -// } -// """ -// ) -// } -// -// @Test func interfaceIntoOverlappingInterfaceInInlineFragment() throws { -// try assertValid( -// """ -// fragment interfaceWithinInterface on Pet { -// ... on Being { -// name -// } -// } -// """ -// ) -// } + // @Test func interfaceIntoOverlappingInterface() throws { + // try assertValid( + // """ + // fragment interfaceWithinInterface on Pet { + // ...beingFragment + // } + // fragment beingFragment on Being { + // name + // } + // """ + // ) + // } + // + // @Test func interfaceIntoOverlappingInterfaceInInlineFragment() throws { + // try assertValid( + // """ + // fragment interfaceWithinInterface on Pet { + // ... on Being { + // name + // } + // } + // """ + // ) + // } @Test func interfaceIntoOverlappingUnion() throws { try assertValid( @@ -185,18 +186,21 @@ class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment invalidObjectWithinObject on Cat { - ...dogFragment - } - fragment dogFragment on Dog { - barkVolume - } - """ + fragment invalidObjectWithinObject on Cat { + ...dogFragment + } + fragment dogFragment on Dog { + barkVolume + } + """ ) try assertValidationError( - error: errors.first, line: 2, column: 5, - message: #"Fragment "dogFragment" cannot be spread here as objects of type "Cat" can never be of type "Dog"."# + error: errors.first, + line: 2, + column: 5, + message: + #"Fragment "dogFragment" cannot be spread here as objects of type "Cat" can never be of type "Dog"."# ) } @@ -204,15 +208,18 @@ class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment invalidObjectWithinObjectAnon on Cat { - ... on Dog { barkVolume } - } - """ + fragment invalidObjectWithinObjectAnon on Cat { + ... on Dog { barkVolume } + } + """ ) try assertValidationError( - error: errors.first, line: 2, column: 3, - message: #"Fragment cannot be spread here as objects of type "Cat" can never be of type "Dog"."# + error: errors.first, + line: 2, + column: 3, + message: + #"Fragment cannot be spread here as objects of type "Cat" can never be of type "Dog"."# ) } @@ -220,20 +227,23 @@ class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment invalidObjectWithinInterface on Pet { - ...humanFragment - } - fragment humanFragment on Human { - pets { - name + fragment invalidObjectWithinInterface on Pet { + ...humanFragment } - } - """ + fragment humanFragment on Human { + pets { + name + } + } + """ ) try assertValidationError( - error: errors.first, line: 2, column: 5, - message: #"Fragment "humanFragment" cannot be spread here as objects of type "Pet" can never be of type "Human"."# + error: errors.first, + line: 2, + column: 5, + message: + #"Fragment "humanFragment" cannot be spread here as objects of type "Pet" can never be of type "Human"."# ) } @@ -241,20 +251,23 @@ class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment invalidObjectWithinUnion on CatOrDog { - ...humanFragment - } - fragment humanFragment on Human { - pets { - name + fragment invalidObjectWithinUnion on CatOrDog { + ...humanFragment } - } - """ + fragment humanFragment on Human { + pets { + name + } + } + """ ) try assertValidationError( - error: errors.first, line: 2, column: 5, - message: #"Fragment "humanFragment" cannot be spread here as objects of type "CatOrDog" can never be of type "Human"."# + error: errors.first, + line: 2, + column: 5, + message: + #"Fragment "humanFragment" cannot be spread here as objects of type "CatOrDog" can never be of type "Human"."# ) } @@ -262,18 +275,21 @@ class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment invalidUnionWithinObject on Human { - ...catOrDogFragment - } - fragment catOrDogFragment on CatOrDog { - __typename - } - """ + fragment invalidUnionWithinObject on Human { + ...catOrDogFragment + } + fragment catOrDogFragment on CatOrDog { + __typename + } + """ ) try assertValidationError( - error: errors.first, line: 2, column: 5, - message: #"Fragment "catOrDogFragment" cannot be spread here as objects of type "Human" can never be of type "CatOrDog"."# + error: errors.first, + line: 2, + column: 5, + message: + #"Fragment "catOrDogFragment" cannot be spread here as objects of type "Human" can never be of type "CatOrDog"."# ) } @@ -281,18 +297,21 @@ class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment invalidUnionWithinInterface on Pet { - ...humanOrAlienFragment - } - fragment humanOrAlienFragment on HumanOrAlien { - __typename - } - """ + fragment invalidUnionWithinInterface on Pet { + ...humanOrAlienFragment + } + fragment humanOrAlienFragment on HumanOrAlien { + __typename + } + """ ) try assertValidationError( - error: errors.first, line: 2, column: 5, - message: #"Fragment "humanOrAlienFragment" cannot be spread here as objects of type "Pet" can never be of type "HumanOrAlien"."# + error: errors.first, + line: 2, + column: 5, + message: + #"Fragment "humanOrAlienFragment" cannot be spread here as objects of type "Pet" can never be of type "HumanOrAlien"."# ) } @@ -300,18 +319,21 @@ class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment invalidUnionWithinUnion on CatOrDog { - ...humanOrAlienFragment - } - fragment humanOrAlienFragment on HumanOrAlien { - __typename - } - """ + fragment invalidUnionWithinUnion on CatOrDog { + ...humanOrAlienFragment + } + fragment humanOrAlienFragment on HumanOrAlien { + __typename + } + """ ) try assertValidationError( - error: errors.first, line: 2, column: 5, - message: #"Fragment "humanOrAlienFragment" cannot be spread here as objects of type "CatOrDog" can never be of type "HumanOrAlien"."# + error: errors.first, + line: 2, + column: 5, + message: + #"Fragment "humanOrAlienFragment" cannot be spread here as objects of type "CatOrDog" can never be of type "HumanOrAlien"."# ) } @@ -319,18 +341,21 @@ class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment invalidInterfaceWithinObject on Cat { - ...intelligentFragment - } - fragment intelligentFragment on Intelligent { - iq - } - """ + fragment invalidInterfaceWithinObject on Cat { + ...intelligentFragment + } + fragment intelligentFragment on Intelligent { + iq + } + """ ) try assertValidationError( - error: errors.first, line: 2, column: 5, - message: #"Fragment "intelligentFragment" cannot be spread here as objects of type "Cat" can never be of type "Intelligent"."# + error: errors.first, + line: 2, + column: 5, + message: + #"Fragment "intelligentFragment" cannot be spread here as objects of type "Cat" can never be of type "Intelligent"."# ) } @@ -338,18 +363,21 @@ class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment invalidInterfaceWithinInterface on Pet { - ...intelligentFragment - } - fragment intelligentFragment on Intelligent { - iq - } - """ + fragment invalidInterfaceWithinInterface on Pet { + ...intelligentFragment + } + fragment intelligentFragment on Intelligent { + iq + } + """ ) try assertValidationError( - error: errors.first, line: 2, column: 5, - message: #"Fragment "intelligentFragment" cannot be spread here as objects of type "Pet" can never be of type "Intelligent"."# + error: errors.first, + line: 2, + column: 5, + message: + #"Fragment "intelligentFragment" cannot be spread here as objects of type "Pet" can never be of type "Intelligent"."# ) } @@ -357,15 +385,18 @@ class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment invalidInterfaceWithinInterfaceAnon on Pet { - ...on Intelligent { iq } - } - """ + fragment invalidInterfaceWithinInterfaceAnon on Pet { + ...on Intelligent { iq } + } + """ ) try assertValidationError( - error: errors.first, line: 2, column: 5, - message: #"Fragment cannot be spread here as objects of type "Pet" can never be of type "Intelligent"."# + error: errors.first, + line: 2, + column: 5, + message: + #"Fragment cannot be spread here as objects of type "Pet" can never be of type "Intelligent"."# ) } @@ -373,18 +404,21 @@ class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - fragment invalidInterfaceWithinUnion on HumanOrAlien { - ...petFragment - } - fragment petFragment on Pet { - name - } - """ + fragment invalidInterfaceWithinUnion on HumanOrAlien { + ...petFragment + } + fragment petFragment on Pet { + name + } + """ ) try assertValidationError( - error: errors.first, line: 2, column: 5, - message: #"Fragment "petFragment" cannot be spread here as objects of type "HumanOrAlien" can never be of type "Pet"."# + error: errors.first, + line: 2, + column: 5, + message: + #"Fragment "petFragment" cannot be spread here as objects of type "HumanOrAlien" can never be of type "Pet"."# ) } } diff --git a/Tests/GraphQLTests/ValidationTests/PossibleTypeExtensionsRuleTests.swift b/Tests/GraphQLTests/ValidationTests/PossibleTypeExtensionsRuleTests.swift index b9e567c6..7d695217 100644 --- a/Tests/GraphQLTests/ValidationTests/PossibleTypeExtensionsRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/PossibleTypeExtensionsRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class PossibleTypeExtensionsRuleTests: SDLValidationTestCase { override init() { super.init() @@ -84,27 +85,33 @@ class PossibleTypeExtensionsRuleTests: SDLValidationTestCase { """, [ GraphQLError( - message: #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, + message: + #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, locations: [.init(line: 3, column: 15)] ), GraphQLError( - message: #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, + message: + #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, locations: [.init(line: 4, column: 13)] ), GraphQLError( - message: #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, + message: + #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, locations: [.init(line: 5, column: 18)] ), GraphQLError( - message: #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, + message: + #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, locations: [.init(line: 6, column: 14)] ), GraphQLError( - message: #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, + message: + #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, locations: [.init(line: 7, column: 13)] ), GraphQLError( - message: #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, + message: + #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, locations: [.init(line: 8, column: 14)] ), ] @@ -219,61 +226,69 @@ class PossibleTypeExtensionsRuleTests: SDLValidationTestCase { } @Test func extendingTypesWithinExistingSchema() throws { - let schema = try buildSchema(source: """ - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - """) + let schema = try buildSchema( + source: """ + scalar FooScalar + type FooObject + interface FooInterface + union FooUnion + enum FooEnum + input FooInputObject + """ + ) let sdl = """ - extend scalar FooScalar @dummy - extend type FooObject @dummy - extend interface FooInterface @dummy - extend union FooUnion @dummy - extend enum FooEnum @dummy - extend input FooInputObject @dummy - """ + extend scalar FooScalar @dummy + extend type FooObject @dummy + extend interface FooInterface @dummy + extend union FooUnion @dummy + extend enum FooEnum @dummy + extend input FooInputObject @dummy + """ try assertValidationErrors(sdl, schema: schema, []) } @Test func extendingUnknownTypesWithinExistingSchema() throws { let schema = try buildSchema(source: "type Known") let sdl = """ - extend scalar Unknown @dummy - extend type Unknown @dummy - extend interface Unknown @dummy - extend union Unknown @dummy - extend enum Unknown @dummy - extend input Unknown @dummy - """ + extend scalar Unknown @dummy + extend type Unknown @dummy + extend interface Unknown @dummy + extend union Unknown @dummy + extend enum Unknown @dummy + extend input Unknown @dummy + """ try assertValidationErrors( sdl, schema: schema, [ GraphQLError( - message: #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, + message: + #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, locations: [.init(line: 1, column: 15)] ), GraphQLError( - message: #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, + message: + #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, locations: [.init(line: 2, column: 13)] ), GraphQLError( - message: #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, + message: + #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, locations: [.init(line: 3, column: 18)] ), GraphQLError( - message: #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, + message: + #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, locations: [.init(line: 4, column: 14)] ), GraphQLError( - message: #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, + message: + #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, locations: [.init(line: 5, column: 13)] ), GraphQLError( - message: #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, + message: + #"Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?"#, locations: [.init(line: 6, column: 14)] ), ] @@ -281,22 +296,24 @@ class PossibleTypeExtensionsRuleTests: SDLValidationTestCase { } @Test func extendingTypesWithDifferentKindsWithinExistingSchema() throws { - let schema = try buildSchema(source: """ - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - """) + let schema = try buildSchema( + source: """ + scalar FooScalar + type FooObject + interface FooInterface + union FooUnion + enum FooEnum + input FooInputObject + """ + ) let sdl = """ - extend type FooScalar @dummy - extend interface FooObject @dummy - extend union FooInterface @dummy - extend enum FooUnion @dummy - extend input FooEnum @dummy - extend scalar FooInputObject @dummy - """ + extend type FooScalar @dummy + extend interface FooObject @dummy + extend union FooInterface @dummy + extend enum FooUnion @dummy + extend input FooEnum @dummy + extend scalar FooInputObject @dummy + """ try assertValidationErrors( sdl, schema: schema, diff --git a/Tests/GraphQLTests/ValidationTests/ProvidedRequiredArgumentsOnDirectivesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/ProvidedRequiredArgumentsOnDirectivesRuleTests.swift index 5cd77ded..a57b7148 100644 --- a/Tests/GraphQLTests/ValidationTests/ProvidedRequiredArgumentsOnDirectivesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/ProvidedRequiredArgumentsOnDirectivesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class ProvidedRequiredArgumentsOnDirectivesRuleTests: SDLValidationTestCase { override init() { super.init() @@ -31,9 +32,10 @@ class ProvidedRequiredArgumentsOnDirectivesRuleTests: SDLValidationTestCase { """, [ GraphQLError( - message: #"Argument "@test(arg:)" of type "String!" is required, but it was not provided."#, + message: + #"Argument "@test(arg:)" of type "String!" is required, but it was not provided."#, locations: [.init(line: 2, column: 15)] - ), + ) ] ) } @@ -47,9 +49,10 @@ class ProvidedRequiredArgumentsOnDirectivesRuleTests: SDLValidationTestCase { """, [ GraphQLError( - message: #"Argument "@include(if:)" of type "Boolean!" is required, but it was not provided."#, + message: + #"Argument "@include(if:)" of type "Boolean!" is required, but it was not provided."#, locations: [.init(line: 2, column: 15)] - ), + ) ] ) } @@ -64,55 +67,62 @@ class ProvidedRequiredArgumentsOnDirectivesRuleTests: SDLValidationTestCase { """, [ GraphQLError( - message: #"Argument "@deprecated(reason:)" of type "String!" is required, but it was not provided."#, + message: + #"Argument "@deprecated(reason:)" of type "String!" is required, but it was not provided."#, locations: [.init(line: 2, column: 15)] - ), + ) ] ) } @Test func missingArgOnDirectiveDefinedInSchemaExtension() throws { - let schema = try buildSchema(source: """ - type Query { - foo: String - } - """) + let schema = try buildSchema( + source: """ + type Query { + foo: String + } + """ + ) let sdl = """ - directive @test(arg: String!) on OBJECT + directive @test(arg: String!) on OBJECT - extend type Query @test - """ + extend type Query @test + """ try assertValidationErrors( sdl, schema: schema, [ GraphQLError( - message: #"Argument "@test(arg:)" of type "String!" is required, but it was not provided."#, + message: + #"Argument "@test(arg:)" of type "String!" is required, but it was not provided."#, locations: [.init(line: 3, column: 20)] - ), + ) ] ) } @Test func missingArgOnDirectiveUsedInSchemaExtension() throws { - let schema = try buildSchema(source: """ - directive @test(arg: String!) on OBJECT + let schema = try buildSchema( + source: """ + directive @test(arg: String!) on OBJECT - type Query { - foo: String - } - """) + type Query { + foo: String + } + """ + ) let sdl = """ - extend type Query @test - """ + extend type Query @test + """ try assertValidationErrors( sdl, schema: schema, [ GraphQLError( - message: #"Argument "@test(arg:)" of type "String!" is required, but it was not provided."#, + message: + #"Argument "@test(arg:)" of type "String!" is required, but it was not provided."#, locations: [.init(line: 1, column: 19)] - ), + ) ] ) } diff --git a/Tests/GraphQLTests/ValidationTests/ProvidedRequiredArgumentsRuleTests.swift b/Tests/GraphQLTests/ValidationTests/ProvidedRequiredArgumentsRuleTests.swift index 4ce687a1..c487ba8a 100644 --- a/Tests/GraphQLTests/ValidationTests/ProvidedRequiredArgumentsRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/ProvidedRequiredArgumentsRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class ProvidedRequiredArgumentsRuleTests: ValidationTestCase { override init() { super.init() @@ -159,20 +160,21 @@ class ProvidedRequiredArgumentsRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - { - complicatedArgs { - multipleReqs(req2: 2) - } - } - """ + { + complicatedArgs { + multipleReqs(req2: 2) + } + } + """ ) try assertValidationError( error: errors[0], locations: [ - (line: 3, column: 5), + (line: 3, column: 5) ], - message: #"Field "multipleReqs" argument "req1" of type "Int!" is required, but it was not provided."# + message: + #"Field "multipleReqs" argument "req1" of type "Int!" is required, but it was not provided."# ) } @@ -180,27 +182,29 @@ class ProvidedRequiredArgumentsRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - { - complicatedArgs { - multipleReqs - } - } - """ + { + complicatedArgs { + multipleReqs + } + } + """ ) try assertValidationError( error: errors[0], locations: [ - (line: 3, column: 5), + (line: 3, column: 5) ], - message: #"Field "multipleReqs" argument "req1" of type "Int!" is required, but it was not provided."# + message: + #"Field "multipleReqs" argument "req1" of type "Int!" is required, but it was not provided."# ) try assertValidationError( error: errors[1], locations: [ - (line: 3, column: 5), + (line: 3, column: 5) ], - message: #"Field "multipleReqs" argument "req2" of type "Int!" is required, but it was not provided."# + message: + #"Field "multipleReqs" argument "req2" of type "Int!" is required, but it was not provided."# ) } @@ -208,20 +212,21 @@ class ProvidedRequiredArgumentsRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: """ - { - complicatedArgs { - multipleReqs(req1: "one") - } - } - """ + { + complicatedArgs { + multipleReqs(req1: "one") + } + } + """ ) try assertValidationError( error: errors[0], locations: [ - (line: 3, column: 5), + (line: 3, column: 5) ], - message: #"Field "multipleReqs" argument "req2" of type "Int!" is required, but it was not provided."# + message: + #"Field "multipleReqs" argument "req2" of type "Int!" is required, but it was not provided."# ) } @@ -256,27 +261,29 @@ class ProvidedRequiredArgumentsRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: """ - { - dog @include { - name @skip - } - } - """ + { + dog @include { + name @skip + } + } + """ ) try assertValidationError( error: errors[0], locations: [ - (line: 2, column: 7), + (line: 2, column: 7) ], - message: #"Directive "@include" argument "if" of type "Boolean!" is required, but it was not provided."# + message: + #"Directive "@include" argument "if" of type "Boolean!" is required, but it was not provided."# ) try assertValidationError( error: errors[1], locations: [ - (line: 3, column: 10), + (line: 3, column: 10) ], - message: #"Directive "@skip" argument "if" of type "Boolean!" is required, but it was not provided."# + message: + #"Directive "@skip" argument "if" of type "Boolean!" is required, but it was not provided."# ) } diff --git a/Tests/GraphQLTests/ValidationTests/UniqueArgumentDefinitionNamesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/UniqueArgumentDefinitionNamesRuleTests.swift index c743c6bd..23daf71f 100644 --- a/Tests/GraphQLTests/ValidationTests/UniqueArgumentDefinitionNamesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/UniqueArgumentDefinitionNamesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class UniqueArgumentDefinitionNamesRuleTests: SDLValidationTestCase { override init() { super.init() @@ -153,7 +154,8 @@ class UniqueArgumentDefinitionNamesRuleTests: SDLValidationTestCase { ] ), GraphQLError( - message: #"Argument "SomeInterface.anotherField(foo:)" can only be defined once."#, + message: + #"Argument "SomeInterface.anotherField(foo:)" can only be defined once."#, locations: [ .init(line: 28, column: 5), .init(line: 29, column: 5), diff --git a/Tests/GraphQLTests/ValidationTests/UniqueArgumentNamesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/UniqueArgumentNamesRuleTests.swift index 1c9f64e1..b2e2a56b 100644 --- a/Tests/GraphQLTests/ValidationTests/UniqueArgumentNamesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/UniqueArgumentNamesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class UniqueArgumentNamesRuleTests: ValidationTestCase { override init() { super.init() @@ -102,11 +103,11 @@ class UniqueArgumentNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - field(arg1: "value", arg1: "value") - } - """ + """ + { + field(arg1: "value", arg1: "value") + } + """ ) try assertValidationError( error: errors[0], @@ -122,11 +123,11 @@ class UniqueArgumentNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - field(arg1: "value", arg1: "value", arg1: "value") - } - """ + """ + { + field(arg1: "value", arg1: "value", arg1: "value") + } + """ ) try assertValidationError( error: errors[0], @@ -143,11 +144,11 @@ class UniqueArgumentNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - field @directive(arg1: "value", arg1: "value") - } - """ + """ + { + field @directive(arg1: "value", arg1: "value") + } + """ ) try assertValidationError( error: errors[0], @@ -163,11 +164,11 @@ class UniqueArgumentNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - field @directive(arg1: "value", arg1: "value", arg1: "value") - } - """ + """ + { + field @directive(arg1: "value", arg1: "value", arg1: "value") + } + """ ) try assertValidationError( error: errors[0], diff --git a/Tests/GraphQLTests/ValidationTests/UniqueDirectiveNamesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/UniqueDirectiveNamesRuleTests.swift index c37debad..b4340d01 100644 --- a/Tests/GraphQLTests/ValidationTests/UniqueDirectiveNamesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/UniqueDirectiveNamesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class UniqueDirectiveNamesRuleTests: SDLValidationTestCase { override init() { super.init() @@ -63,7 +64,7 @@ class UniqueDirectiveNamesRuleTests: SDLValidationTestCase { .init(line: 1, column: 12), .init(line: 3, column: 12), ] - ), + ) ] ) } @@ -80,9 +81,10 @@ class UniqueDirectiveNamesRuleTests: SDLValidationTestCase { schema: schema, [ GraphQLError( - message: #"Directive "@skip" already exists in the schema. It cannot be redefined."#, + message: + #"Directive "@skip" already exists in the schema. It cannot be redefined."#, locations: [.init(line: 1, column: 12)] - ), + ) ] ) } @@ -99,9 +101,10 @@ class UniqueDirectiveNamesRuleTests: SDLValidationTestCase { schema: schema, [ GraphQLError( - message: #"Directive "@foo" already exists in the schema. It cannot be redefined."#, + message: + #"Directive "@foo" already exists in the schema. It cannot be redefined."#, locations: [.init(line: 1, column: 12)] - ), + ) ] ) } diff --git a/Tests/GraphQLTests/ValidationTests/UniqueDirectivesPerLocationRuleTests.swift b/Tests/GraphQLTests/ValidationTests/UniqueDirectivesPerLocationRuleTests.swift index a84493fa..fd5720db 100644 --- a/Tests/GraphQLTests/ValidationTests/UniqueDirectivesPerLocationRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/UniqueDirectivesPerLocationRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class UniqueDirectivesPerLocationRuleTests: ValidationTestCase { override init() { super.init() @@ -93,11 +94,11 @@ class UniqueDirectivesPerLocationRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - fragment Test on Type { - field @directive @directive - } - """, + """ + fragment Test on Type { + field @directive @directive + } + """, schema: schema ) try assertValidationError( @@ -114,11 +115,11 @@ class UniqueDirectivesPerLocationRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: - """ - fragment Test on Type { - field @directive @directive @directive - } - """, + """ + fragment Test on Type { + field @directive @directive @directive + } + """, schema: schema ) try assertValidationError( @@ -143,11 +144,11 @@ class UniqueDirectivesPerLocationRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: - """ - fragment Test on Type { - field @directiveA @directiveB @directiveA @directiveB - } - """, + """ + fragment Test on Type { + field @directiveA @directiveB @directiveA @directiveB + } + """, schema: schema ) try assertValidationError( @@ -183,8 +184,14 @@ class UniqueDirectivesPerLocationRuleTests: ValidationTestCase { directives.append(contentsOf: [ ValidationFieldDirective, try! GraphQLDirective(name: "directive", locations: [.field, .fragmentDefinition]), - try! GraphQLDirective(name: "directiveA", locations: [.field, .fragmentDefinition]), - try! GraphQLDirective(name: "directiveB", locations: [.field, .fragmentDefinition]), + try! GraphQLDirective( + name: "directiveA", + locations: [.field, .fragmentDefinition] + ), + try! GraphQLDirective( + name: "directiveB", + locations: [.field, .fragmentDefinition] + ), try! GraphQLDirective( name: "repeatable", locations: [.field, .fragmentDefinition], diff --git a/Tests/GraphQLTests/ValidationTests/UniqueEnumValueNamesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/UniqueEnumValueNamesRuleTests.swift index 4e736b74..14e9d147 100644 --- a/Tests/GraphQLTests/ValidationTests/UniqueEnumValueNamesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/UniqueEnumValueNamesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class UniqueEnumValueNamesRuleTests: SDLValidationTestCase { override init() { super.init() @@ -55,7 +56,7 @@ class UniqueEnumValueNamesRuleTests: SDLValidationTestCase { .init(line: 2, column: 3), .init(line: 4, column: 3), ] - ), + ) ] ) } @@ -94,7 +95,7 @@ class UniqueEnumValueNamesRuleTests: SDLValidationTestCase { .init(line: 2, column: 3), .init(line: 5, column: 3), ] - ), + ) ] ) } @@ -116,7 +117,7 @@ class UniqueEnumValueNamesRuleTests: SDLValidationTestCase { .init(line: 3, column: 3), .init(line: 5, column: 3), ] - ), + ) ] ) } @@ -139,7 +140,7 @@ class UniqueEnumValueNamesRuleTests: SDLValidationTestCase { .init(line: 3, column: 3), .init(line: 6, column: 3), ] - ), + ) ] ) } @@ -147,41 +148,45 @@ class UniqueEnumValueNamesRuleTests: SDLValidationTestCase { @Test func addingNewValueToTheTypeInsideExistingSchema() throws { let schema = try buildSchema(source: "enum SomeEnum") let sdl = """ - extend enum SomeEnum { - FOO - } - """ + extend enum SomeEnum { + FOO + } + """ try assertValidationErrors(sdl, schema: schema, []) } @Test func addingConflictingValueToExistingSchemaTwice() throws { - let schema = try buildSchema(source: """ - enum SomeEnum { - FOO - } - """) + let schema = try buildSchema( + source: """ + enum SomeEnum { + FOO + } + """ + ) let sdl = """ - extend enum SomeEnum { - FOO - } - extend enum SomeEnum { - FOO - } - """ + extend enum SomeEnum { + FOO + } + extend enum SomeEnum { + FOO + } + """ try assertValidationErrors( sdl, schema: schema, [ GraphQLError( - message: #"Enum value "SomeEnum.FOO" already exists in the schema. It cannot also be defined in this type extension."#, + message: + #"Enum value "SomeEnum.FOO" already exists in the schema. It cannot also be defined in this type extension."#, locations: [ - .init(line: 2, column: 3), + .init(line: 2, column: 3) ] ), GraphQLError( - message: #"Enum value "SomeEnum.FOO" already exists in the schema. It cannot also be defined in this type extension."#, + message: + #"Enum value "SomeEnum.FOO" already exists in the schema. It cannot also be defined in this type extension."#, locations: [ - .init(line: 5, column: 3), + .init(line: 5, column: 3) ] ), ] @@ -191,13 +196,13 @@ class UniqueEnumValueNamesRuleTests: SDLValidationTestCase { @Test func addingEnumValuesToExistingSchemaTwice() throws { let schema = try buildSchema(source: "enum SomeEnum") let sdl = """ - extend enum SomeEnum { - FOO - } - extend enum SomeEnum { - FOO - } - """ + extend enum SomeEnum { + FOO + } + extend enum SomeEnum { + FOO + } + """ try assertValidationErrors( sdl, schema: schema, @@ -208,7 +213,7 @@ class UniqueEnumValueNamesRuleTests: SDLValidationTestCase { .init(line: 2, column: 3), .init(line: 5, column: 3), ] - ), + ) ] ) } diff --git a/Tests/GraphQLTests/ValidationTests/UniqueFieldDefinitionNamesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/UniqueFieldDefinitionNamesRuleTests.swift index ba32f610..41bd810f 100644 --- a/Tests/GraphQLTests/ValidationTests/UniqueFieldDefinitionNamesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/UniqueFieldDefinitionNamesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class UniqueFieldDefinitionNamesRuleTests: SDLValidationTestCase { override init() { super.init() @@ -297,88 +298,98 @@ class UniqueFieldDefinitionNamesRuleTests: SDLValidationTestCase { } @Test func addingNewFieldToTheTypeInsideExistingSchema() throws { - let schema = try buildSchema(source: """ - type SomeObject - interface SomeInterface - input SomeInputObject - """) + let schema = try buildSchema( + source: """ + type SomeObject + interface SomeInterface + input SomeInputObject + """ + ) let sdl = """ - extend type SomeObject { - foo: String - } - - extend interface SomeInterface { - foo: String - } - - extend input SomeInputObject { - foo: String - } - """ + extend type SomeObject { + foo: String + } + + extend interface SomeInterface { + foo: String + } + + extend input SomeInputObject { + foo: String + } + """ try assertValidationErrors(sdl, schema: schema, []) } @Test func addingConflictingFieldsToExistingSchemaTwice() throws { - let schema = try buildSchema(source: """ - type SomeObject { - foo: String - } - - interface SomeInterface { - foo: String - } - - input SomeInputObject { - foo: String - } - """) + let schema = try buildSchema( + source: """ + type SomeObject { + foo: String + } + + interface SomeInterface { + foo: String + } + + input SomeInputObject { + foo: String + } + """ + ) let sdl = """ - extend type SomeObject { - foo: String - } - extend interface SomeInterface { - foo: String - } - extend input SomeInputObject { - foo: String - } - - extend type SomeObject { - foo: String - } - extend interface SomeInterface { - foo: String - } - extend input SomeInputObject { - foo: String - } - """ + extend type SomeObject { + foo: String + } + extend interface SomeInterface { + foo: String + } + extend input SomeInputObject { + foo: String + } + + extend type SomeObject { + foo: String + } + extend interface SomeInterface { + foo: String + } + extend input SomeInputObject { + foo: String + } + """ try assertValidationErrors( sdl, schema: schema, [ GraphQLError( - message: #"Field "SomeObject.foo" already exists in the schema. It cannot also be defined in this type extension."#, + message: + #"Field "SomeObject.foo" already exists in the schema. It cannot also be defined in this type extension."#, locations: [.init(line: 2, column: 3)] ), GraphQLError( - message: #"Field "SomeInterface.foo" already exists in the schema. It cannot also be defined in this type extension."#, + message: + #"Field "SomeInterface.foo" already exists in the schema. It cannot also be defined in this type extension."#, locations: [.init(line: 5, column: 3)] ), GraphQLError( - message: #"Field "SomeInputObject.foo" already exists in the schema. It cannot also be defined in this type extension."#, + message: + #"Field "SomeInputObject.foo" already exists in the schema. It cannot also be defined in this type extension."#, locations: [.init(line: 8, column: 3)] ), GraphQLError( - message: #"Field "SomeObject.foo" already exists in the schema. It cannot also be defined in this type extension."#, + message: + #"Field "SomeObject.foo" already exists in the schema. It cannot also be defined in this type extension."#, locations: [.init(line: 12, column: 3)] ), GraphQLError( - message: #"Field "SomeInterface.foo" already exists in the schema. It cannot also be defined in this type extension."#, + message: + #"Field "SomeInterface.foo" already exists in the schema. It cannot also be defined in this type extension."#, locations: [.init(line: 15, column: 3)] ), GraphQLError( - message: #"Field "SomeInputObject.foo" already exists in the schema. It cannot also be defined in this type extension."#, + message: + #"Field "SomeInputObject.foo" already exists in the schema. It cannot also be defined in this type extension."#, locations: [.init(line: 18, column: 3)] ), ] @@ -386,33 +397,35 @@ class UniqueFieldDefinitionNamesRuleTests: SDLValidationTestCase { } @Test func addingFieldsToExistingSchemaTwice() throws { - let schema = try buildSchema(source: """ - type SomeObject - interface SomeInterface - input SomeInputObject - """) + let schema = try buildSchema( + source: """ + type SomeObject + interface SomeInterface + input SomeInputObject + """ + ) let sdl = """ - extend type SomeObject { - foo: String - } - extend type SomeObject { - foo: String - } - - extend interface SomeInterface { - foo: String - } - extend interface SomeInterface { - foo: String - } - - extend input SomeInputObject { - foo: String - } - extend input SomeInputObject { - foo: String - } - """ + extend type SomeObject { + foo: String + } + extend type SomeObject { + foo: String + } + + extend interface SomeInterface { + foo: String + } + extend interface SomeInterface { + foo: String + } + + extend input SomeInputObject { + foo: String + } + extend input SomeInputObject { + foo: String + } + """ try assertValidationErrors( sdl, schema: schema, diff --git a/Tests/GraphQLTests/ValidationTests/UniqueFragmentNamesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/UniqueFragmentNamesRuleTests.swift index 474be4f9..fe8c0d37 100644 --- a/Tests/GraphQLTests/ValidationTests/UniqueFragmentNamesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/UniqueFragmentNamesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class UniqueFragmentNamesRuleTests: ValidationTestCase { override init() { super.init() @@ -84,17 +85,17 @@ class UniqueFragmentNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - ...fragA - } - fragment fragA on Type { - fieldA - } - fragment fragA on Type { - fieldB - } - """ + """ + { + ...fragA + } + fragment fragA on Type { + fieldA + } + fragment fragA on Type { + fieldB + } + """ ) try assertValidationError( error: errors[0], @@ -110,14 +111,14 @@ class UniqueFragmentNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - fragment fragA on Type { - fieldA - } - fragment fragA on Type { - fieldB - } - """ + """ + fragment fragA on Type { + fieldA + } + fragment fragA on Type { + fieldB + } + """ ) try assertValidationError( error: errors[0], diff --git a/Tests/GraphQLTests/ValidationTests/UniqueInputFieldNamesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/UniqueInputFieldNamesRuleTests.swift index f2e44505..79674d70 100644 --- a/Tests/GraphQLTests/ValidationTests/UniqueInputFieldNamesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/UniqueInputFieldNamesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class UniqueInputFieldNamesRuleTests: ValidationTestCase { override init() { super.init() @@ -59,11 +60,11 @@ class UniqueInputFieldNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - field(arg: { f1: "value", f1: "value" }) - } - """ + """ + { + field(arg: { f1: "value", f1: "value" }) + } + """ ) try assertValidationError( error: errors[0], @@ -79,11 +80,11 @@ class UniqueInputFieldNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: - """ - { - field(arg: { f1: "value", f1: "value", f1: "value" }) - } - """ + """ + { + field(arg: { f1: "value", f1: "value", f1: "value" }) + } + """ ) try assertValidationError( error: errors[0], @@ -107,11 +108,11 @@ class UniqueInputFieldNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - field(arg: { f1: {f2: "value", f2: "value" }}) - } - """ + """ + { + field(arg: { f1: {f2: "value", f2: "value" }}) + } + """ ) try assertValidationError( error: errors[0], diff --git a/Tests/GraphQLTests/ValidationTests/UniqueOperationNamesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/UniqueOperationNamesRuleTests.swift index 869c8aa0..5bd1be3a 100644 --- a/Tests/GraphQLTests/ValidationTests/UniqueOperationNamesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/UniqueOperationNamesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class UniqueOperationNamesRuleTests: ValidationTestCase { override init() { super.init() @@ -86,14 +87,14 @@ class UniqueOperationNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - query Foo { - fieldA - } - query Foo { - fieldB - } - """ + """ + query Foo { + fieldA + } + query Foo { + fieldB + } + """ ) try assertValidationError( error: errors[0], @@ -109,14 +110,14 @@ class UniqueOperationNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - query Foo { - fieldA - } - mutation Foo { - fieldB - } - """ + """ + query Foo { + fieldA + } + mutation Foo { + fieldB + } + """ ) try assertValidationError( error: errors[0], @@ -132,14 +133,14 @@ class UniqueOperationNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - query Foo { - fieldA - } - subscription Foo { - fieldB - } - """ + """ + query Foo { + fieldA + } + subscription Foo { + fieldB + } + """ ) try assertValidationError( error: errors[0], diff --git a/Tests/GraphQLTests/ValidationTests/UniqueOperationTypesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/UniqueOperationTypesRuleTests.swift index 4da5412d..cb895887 100644 --- a/Tests/GraphQLTests/ValidationTests/UniqueOperationTypesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/UniqueOperationTypesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class UniqueOperationTypesRuleTests: SDLValidationTestCase { override init() { super.init() @@ -234,51 +235,56 @@ class UniqueOperationTypesRuleTests: SDLValidationTestCase { @Test func defineAndExtendSchemaInsideExtensionSDL() throws { let schema = try buildSchema(source: "type Foo") let sdl = """ - schema { query: Foo } - extend schema { mutation: Foo } - extend schema { subscription: Foo } - """ + schema { query: Foo } + extend schema { mutation: Foo } + extend schema { subscription: Foo } + """ try assertValidationErrors(sdl, schema: schema, []) } @Test func addingNewOperationTypesToExistingSchema() throws { let schema = try buildSchema(source: "type Query") let sdl = """ - extend schema { mutation: Foo } - extend schema { subscription: Foo } - """ + extend schema { mutation: Foo } + extend schema { subscription: Foo } + """ try assertValidationErrors(sdl, schema: schema, []) } @Test func addingConflictingOperationTypesToExistingSchema() throws { - let schema = try buildSchema(source: """ - type Query - type Mutation - type Subscription + let schema = try buildSchema( + source: """ + type Query + type Mutation + type Subscription - type Foo - """) + type Foo + """ + ) let sdl = """ - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - """ + extend schema { + query: Foo + mutation: Foo + subscription: Foo + } + """ try assertValidationErrors( sdl, schema: schema, [ GraphQLError( - message: "Type for query already defined in the schema. It cannot be redefined.", + message: + "Type for query already defined in the schema. It cannot be redefined.", locations: [.init(line: 2, column: 3)] ), GraphQLError( - message: "Type for mutation already defined in the schema. It cannot be redefined.", + message: + "Type for mutation already defined in the schema. It cannot be redefined.", locations: [.init(line: 3, column: 3)] ), GraphQLError( - message: "Type for subscription already defined in the schema. It cannot be redefined.", + message: + "Type for subscription already defined in the schema. It cannot be redefined.", locations: [.init(line: 4, column: 3)] ), ] @@ -286,50 +292,58 @@ class UniqueOperationTypesRuleTests: SDLValidationTestCase { } @Test func addingConflictingOperationTypesToExistingSchemaTwice() throws { - let schema = try buildSchema(source: """ - type Query - type Mutation - type Subscription - """) + let schema = try buildSchema( + source: """ + type Query + type Mutation + type Subscription + """ + ) let sdl = """ - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } + extend schema { + query: Foo + mutation: Foo + subscription: Foo + } - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - """ + extend schema { + query: Foo + mutation: Foo + subscription: Foo + } + """ try assertValidationErrors( sdl, schema: schema, [ GraphQLError( - message: "Type for query already defined in the schema. It cannot be redefined.", + message: + "Type for query already defined in the schema. It cannot be redefined.", locations: [.init(line: 2, column: 3)] ), GraphQLError( - message: "Type for mutation already defined in the schema. It cannot be redefined.", + message: + "Type for mutation already defined in the schema. It cannot be redefined.", locations: [.init(line: 3, column: 3)] ), GraphQLError( - message: "Type for subscription already defined in the schema. It cannot be redefined.", + message: + "Type for subscription already defined in the schema. It cannot be redefined.", locations: [.init(line: 4, column: 3)] ), GraphQLError( - message: "Type for query already defined in the schema. It cannot be redefined.", + message: + "Type for query already defined in the schema. It cannot be redefined.", locations: [.init(line: 8, column: 3)] ), GraphQLError( - message: "Type for mutation already defined in the schema. It cannot be redefined.", + message: + "Type for mutation already defined in the schema. It cannot be redefined.", locations: [.init(line: 9, column: 3)] ), GraphQLError( - message: "Type for subscription already defined in the schema. It cannot be redefined.", + message: + "Type for subscription already defined in the schema. It cannot be redefined.", locations: [.init(line: 10, column: 3)] ), ] diff --git a/Tests/GraphQLTests/ValidationTests/UniqueTypeNamesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/UniqueTypeNamesRuleTests.swift index 967a3ed0..c2c4c52a 100644 --- a/Tests/GraphQLTests/ValidationTests/UniqueTypeNamesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/UniqueTypeNamesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class UniqueTypeNamesRuleTests: SDLValidationTestCase { override init() { super.init() @@ -121,39 +122,45 @@ class UniqueTypeNamesRuleTests: SDLValidationTestCase { @Test func addingConflictingTypesToExistingSchema() throws { let schema = try buildSchema(source: "type Foo") let sdl = """ - scalar Foo - type Foo - interface Foo - union Foo - enum Foo - input Foo - """ + scalar Foo + type Foo + interface Foo + union Foo + enum Foo + input Foo + """ try assertValidationErrors( sdl, schema: schema, [ GraphQLError( - message: #"Type "Foo" already exists in the schema. It cannot also be defined in this type definition."#, + message: + #"Type "Foo" already exists in the schema. It cannot also be defined in this type definition."#, locations: [.init(line: 1, column: 8)] ), GraphQLError( - message: #"Type "Foo" already exists in the schema. It cannot also be defined in this type definition."#, + message: + #"Type "Foo" already exists in the schema. It cannot also be defined in this type definition."#, locations: [.init(line: 2, column: 6)] ), GraphQLError( - message: #"Type "Foo" already exists in the schema. It cannot also be defined in this type definition."#, + message: + #"Type "Foo" already exists in the schema. It cannot also be defined in this type definition."#, locations: [.init(line: 3, column: 11)] ), GraphQLError( - message: #"Type "Foo" already exists in the schema. It cannot also be defined in this type definition."#, + message: + #"Type "Foo" already exists in the schema. It cannot also be defined in this type definition."#, locations: [.init(line: 4, column: 7)] ), GraphQLError( - message: #"Type "Foo" already exists in the schema. It cannot also be defined in this type definition."#, + message: + #"Type "Foo" already exists in the schema. It cannot also be defined in this type definition."#, locations: [.init(line: 5, column: 6)] ), GraphQLError( - message: #"Type "Foo" already exists in the schema. It cannot also be defined in this type definition."#, + message: + #"Type "Foo" already exists in the schema. It cannot also be defined in this type definition."#, locations: [.init(line: 6, column: 7)] ), ] diff --git a/Tests/GraphQLTests/ValidationTests/UniqueVariableNamesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/UniqueVariableNamesRuleTests.swift index 3a4553bd..a70e70bb 100644 --- a/Tests/GraphQLTests/ValidationTests/UniqueVariableNamesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/UniqueVariableNamesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class UniqueVariableNamesRuleTests: ValidationTestCase { override init() { super.init() @@ -20,11 +21,11 @@ class UniqueVariableNamesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 3, query: - """ - query A($x: Int, $x: Int, $x: String) { __typename } - query B($x: String, $x: Int) { __typename } - query C($x: Int, $x: Int) { __typename } - """ + """ + query A($x: Int, $x: Int, $x: String) { __typename } + query B($x: String, $x: Int) { __typename } + query C($x: Int, $x: Int) { __typename } + """ ) try assertValidationError( error: errors[0], diff --git a/Tests/GraphQLTests/ValidationTests/ValidationTests.swift b/Tests/GraphQLTests/ValidationTests/ValidationTests.swift index df631c71..31b2bb7a 100644 --- a/Tests/GraphQLTests/ValidationTests/ValidationTests.swift +++ b/Tests/GraphQLTests/ValidationTests/ValidationTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class ValidationTestCase { typealias Rule = @Sendable (ValidationContext) -> Visitor @@ -90,13 +91,11 @@ class SDLValidationTestCase { let validationErrors = validateSDL(documentAST: doc, schemaToExtend: schema, rules: [rule]) #expect( - validationErrors.map(\.message) == - errors.map(\.message) + validationErrors.map(\.message) == errors.map(\.message) ) #expect( - validationErrors.map(\.locations) == - errors.map(\.locations) + validationErrors.map(\.locations) == errors.map(\.locations) ) } } diff --git a/Tests/GraphQLTests/ValidationTests/ValuesOfCorrectTypeRuleTests.swift b/Tests/GraphQLTests/ValidationTests/ValuesOfCorrectTypeRuleTests.swift index 059496e2..4367218d 100644 --- a/Tests/GraphQLTests/ValidationTests/ValuesOfCorrectTypeRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/ValuesOfCorrectTypeRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class ValuesOfCorrectTypeRuleTests: ValidationTestCase { override init() { super.init() @@ -181,13 +182,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - stringArgField(stringArg: 1) - } - } - """ + """ + { + complicatedArgs { + stringArgField(stringArg: 1) + } + } + """ ) try assertValidationError( error: errors[0], @@ -200,13 +201,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - stringArgField(stringArg: 1.0) - } - } - """ + """ + { + complicatedArgs { + stringArgField(stringArg: 1.0) + } + } + """ ) try assertValidationError( error: errors[0], @@ -219,13 +220,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - stringArgField(stringArg: true) - } - } - """ + """ + { + complicatedArgs { + stringArgField(stringArg: true) + } + } + """ ) try assertValidationError( error: errors[0], @@ -238,13 +239,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - stringArgField(stringArg: BAR) - } - } - """ + """ + { + complicatedArgs { + stringArgField(stringArg: BAR) + } + } + """ ) try assertValidationError( error: errors[0], @@ -257,13 +258,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - intArgField(intArg: "3") - } - } - """ + """ + { + complicatedArgs { + intArgField(intArg: "3") + } + } + """ ) try assertValidationError( error: errors[0], @@ -273,36 +274,36 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { } // Swift doesn't parse BigInt anyway -// @Test func bigIntIntoInt() throws { -// let errors = try assertInvalid( -// errorCount: 1, -// query: -// """ -// { -// complicatedArgs { -// intArgField(intArg: 829384293849283498239482938) -// } -// } -// """ -// ) -// try assertValidationError( -// error: errors[0], -// locations: [(line: 3, column: 25)], -// message: "Int cannot represent non-32-bit signed integer value: 829384293849283498239482938" -// ) -// } + // @Test func bigIntIntoInt() throws { + // let errors = try assertInvalid( + // errorCount: 1, + // query: + // """ + // { + // complicatedArgs { + // intArgField(intArg: 829384293849283498239482938) + // } + // } + // """ + // ) + // try assertValidationError( + // error: errors[0], + // locations: [(line: 3, column: 25)], + // message: "Int cannot represent non-32-bit signed integer value: 829384293849283498239482938" + // ) + // } @Test func unquotedStringIntoInt() throws { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - intArgField(intArg: FOO) - } - } - """ + """ + { + complicatedArgs { + intArgField(intArg: FOO) + } + } + """ ) try assertValidationError( error: errors[0], @@ -315,13 +316,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - intArgField(intArg: 3.0) - } - } - """ + """ + { + complicatedArgs { + intArgField(intArg: 3.0) + } + } + """ ) try assertValidationError( error: errors[0], @@ -334,13 +335,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - intArgField(intArg: 3.333) - } - } - """ + """ + { + complicatedArgs { + intArgField(intArg: 3.333) + } + } + """ ) try assertValidationError( error: errors[0], @@ -355,13 +356,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - floatArgField(floatArg: "3.333") - } - } - """ + """ + { + complicatedArgs { + floatArgField(floatArg: "3.333") + } + } + """ ) try assertValidationError( error: errors[0], @@ -374,13 +375,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - floatArgField(floatArg: true) - } - } - """ + """ + { + complicatedArgs { + floatArgField(floatArg: true) + } + } + """ ) try assertValidationError( error: errors[0], @@ -393,13 +394,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - floatArgField(floatArg: FOO) - } - } - """ + """ + { + complicatedArgs { + floatArgField(floatArg: FOO) + } + } + """ ) try assertValidationError( error: errors[0], @@ -414,13 +415,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - booleanArgField(booleanArg: 2) - } - } - """ + """ + { + complicatedArgs { + booleanArgField(booleanArg: 2) + } + } + """ ) try assertValidationError( error: errors[0], @@ -433,13 +434,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - booleanArgField(booleanArg: 1.0) - } - } - """ + """ + { + complicatedArgs { + booleanArgField(booleanArg: 1.0) + } + } + """ ) try assertValidationError( error: errors[0], @@ -452,13 +453,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - booleanArgField(booleanArg: "true") - } - } - """ + """ + { + complicatedArgs { + booleanArgField(booleanArg: "true") + } + } + """ ) try assertValidationError( error: errors[0], @@ -471,13 +472,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - booleanArgField(booleanArg: TRUE) - } - } - """ + """ + { + complicatedArgs { + booleanArgField(booleanArg: TRUE) + } + } + """ ) try assertValidationError( error: errors[0], @@ -492,13 +493,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - idArgField(idArg: 1.0) - } - } - """ + """ + { + complicatedArgs { + idArgField(idArg: 1.0) + } + } + """ ) try assertValidationError( error: errors[0], @@ -511,13 +512,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - idArgField(idArg: true) - } - } - """ + """ + { + complicatedArgs { + idArgField(idArg: true) + } + } + """ ) try assertValidationError( error: errors[0], @@ -530,13 +531,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - idArgField(idArg: SOMETHING) - } - } - """ + """ + { + complicatedArgs { + idArgField(idArg: SOMETHING) + } + } + """ ) try assertValidationError( error: errors[0], @@ -551,13 +552,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - dog { - doesKnowCommand(dogCommand: 2) - } - } - """ + """ + { + dog { + doesKnowCommand(dogCommand: 2) + } + } + """ ) try assertValidationError( error: errors[0], @@ -570,13 +571,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - dog { - doesKnowCommand(dogCommand: 1.0) - } - } - """ + """ + { + dog { + doesKnowCommand(dogCommand: 1.0) + } + } + """ ) try assertValidationError( error: errors[0], @@ -589,18 +590,19 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - dog { - doesKnowCommand(dogCommand: "SIT") - } - } - """ + """ + { + dog { + doesKnowCommand(dogCommand: "SIT") + } + } + """ ) try assertValidationError( error: errors[0], locations: [(line: 3, column: 33)], - message: #"Enum "DogCommand" cannot represent non-enum value: "SIT". Did you mean the enum value "SIT"?"# + message: + #"Enum "DogCommand" cannot represent non-enum value: "SIT". Did you mean the enum value "SIT"?"# ) } @@ -608,13 +610,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - dog { - doesKnowCommand(dogCommand: true) - } - } - """ + """ + { + dog { + doesKnowCommand(dogCommand: true) + } + } + """ ) try assertValidationError( error: errors[0], @@ -627,13 +629,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - dog { - doesKnowCommand(dogCommand: JUGGLE) - } - } - """ + """ + { + dog { + doesKnowCommand(dogCommand: JUGGLE) + } + } + """ ) try assertValidationError( error: errors[0], @@ -646,13 +648,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - dog { - doesKnowCommand(dogCommand: sit) - } - } - """ + """ + { + dog { + doesKnowCommand(dogCommand: sit) + } + } + """ ) try assertValidationError( error: errors[0], @@ -717,13 +719,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - stringListArgField(stringListArg: ["one", 2]) - } - } - """ + """ + { + complicatedArgs { + stringListArgField(stringListArg: ["one", 2]) + } + } + """ ) try assertValidationError( error: errors[0], @@ -736,13 +738,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - stringListArgField(stringListArg: 1) - } - } - """ + """ + { + complicatedArgs { + stringListArgField(stringListArg: 1) + } + } + """ ) try assertValidationError( error: errors[0], @@ -879,13 +881,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: - """ - { - complicatedArgs { - multipleReqs(req2: "two", req1: "one") - } - } - """ + """ + { + complicatedArgs { + multipleReqs(req2: "two", req1: "one") + } + } + """ ) try assertValidationError( error: errors[0], @@ -903,13 +905,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - multipleReqs(req1: "one") - } - } - """ + """ + { + complicatedArgs { + multipleReqs(req1: "one") + } + } + """ ) try assertValidationError( error: errors[0], @@ -922,13 +924,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - multipleReqs(req1: null) - } - } - """ + """ + { + complicatedArgs { + multipleReqs(req1: null) + } + } + """ ) try assertValidationError( error: errors[0], @@ -1055,18 +1057,19 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - complexArgField(complexArg: { intField: 4 }) - } - } - """ + """ + { + complicatedArgs { + complexArgField(complexArg: { intField: 4 }) + } + } + """ ) try assertValidationError( error: errors[0], locations: [(line: 3, column: 33)], - message: #"Field "ComplexInput.requiredField" of required type "Boolean!" was not provided."# + message: + #"Field "ComplexInput.requiredField" of required type "Boolean!" was not provided."# ) } @@ -1074,16 +1077,16 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - complexArgField(complexArg: { - stringListField: ["one", 2], - requiredField: true, - }) - } - } - """ + """ + { + complicatedArgs { + complexArgField(complexArg: { + stringListField: ["one", 2], + requiredField: true, + }) + } + } + """ ) try assertValidationError( error: errors[0], @@ -1096,16 +1099,16 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - complexArgField(complexArg: { - requiredField: true, - nonNullField: null, - }) - } - } - """ + """ + { + complicatedArgs { + complexArgField(complexArg: { + requiredField: true, + nonNullField: null, + }) + } + } + """ ) try assertValidationError( error: errors[0], @@ -1118,21 +1121,22 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - complexArgField(complexArg: { - requiredField: true, - invalidField: "value" - }) - } - } - """ + """ + { + complicatedArgs { + complexArgField(complexArg: { + requiredField: true, + invalidField: "value" + }) + } + } + """ ) try assertValidationError( error: errors[0], locations: [(line: 5, column: 7)], - message: #"Field "invalidField" is not defined by type "ComplexInput". Did you mean "intField" or "nonNullField"?"# + message: + #"Field "invalidField" is not defined by type "ComplexInput". Did you mean "intField" or "nonNullField"?"# ) } @@ -1161,9 +1165,9 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { "invalidArg": GraphQLField( type: GraphQLString, args: [ - "arg": GraphQLArgument(type: customScalar), + "arg": GraphQLArgument(type: customScalar) ] - ), + ) ] ) ) @@ -1199,9 +1203,9 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { "invalidArg": GraphQLField( type: GraphQLString, args: [ - "arg": GraphQLArgument(type: customScalar), + "arg": GraphQLArgument(type: customScalar) ] - ), + ) ] ) ) @@ -1231,24 +1235,26 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { "anyArg": GraphQLField( type: GraphQLString, args: [ - "arg": GraphQLArgument(type: customScalar), + "arg": GraphQLArgument(type: customScalar) ] - ), + ) ] ), types: [ - customScalar, + customScalar ] ) - let doc = try parse(source: """ - { - test1: anyArg(arg: 123) - test2: anyArg(arg: "abc") - test3: anyArg(arg: [123, "abc"]) - test4: anyArg(arg: {deep: [123, "abc"]}) - } - """) + let doc = try parse( + source: """ + { + test1: anyArg(arg: 123) + test2: anyArg(arg: "abc") + test3: anyArg(arg: [123, "abc"]) + test4: anyArg(arg: {deep: [123, "abc"]}) + } + """ + ) let errors = validate(schema: schema, ast: doc, rules: [ValuesOfCorrectTypeRule]) #expect(errors == []) } @@ -1259,13 +1265,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - oneOfArgField(oneOfArg: { stringField: 2 }) - } - } - """ + """ + { + complicatedArgs { + oneOfArgField(oneOfArg: { stringField: 2 }) + } + } + """ ) try assertValidationError( @@ -1279,13 +1285,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - oneOfArgField(oneOfArg: { stringField: null }) - } - } - """ + """ + { + complicatedArgs { + oneOfArgField(oneOfArg: { stringField: null }) + } + } + """ ) try assertValidationError( @@ -1299,19 +1305,20 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - query ($string: String) { - complicatedArgs { - oneOfArgField(oneOfArg: { stringField: $string }) - } - } - """ + """ + query ($string: String) { + complicatedArgs { + oneOfArgField(oneOfArg: { stringField: $string }) + } + } + """ ) try assertValidationError( error: errors[0], locations: [(line: 3, column: 29)], - message: #"Variable "string" must be non-nullable to be used for OneOf Input Object "OneOfInput"."# + message: + #"Variable "string" must be non-nullable to be used for OneOf Input Object "OneOfInput"."# ) } @@ -1319,13 +1326,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - { - complicatedArgs { - oneOfArgField(oneOfArg: { stringField: "abc", intField: 123 }) - } - } - """ + """ + { + complicatedArgs { + oneOfArgField(oneOfArg: { stringField: "abc", intField: 123 }) + } + } + """ ) try assertValidationError( @@ -1356,13 +1363,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: - """ - { - dog @include(if: "yes") { - name @skip(if: ENUM) - } - } - """ + """ + { + dog @include(if: "yes") { + name @skip(if: ENUM) + } + } + """ ) try assertValidationError( @@ -1413,15 +1420,15 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 3, query: - """ - query WithDefaultValues( - $a: Int! = null, - $b: String! = null, - $c: ComplexInput = { requiredField: null, intField: null } - ) { - dog { name } - } - """ + """ + query WithDefaultValues( + $a: Int! = null, + $b: String! = null, + $c: ComplexInput = { requiredField: null, intField: null } + ) { + dog { name } + } + """ ) try assertValidationError( @@ -1447,15 +1454,15 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 3, query: - """ - query InvalidDefaultValues( - $a: Int = "one", - $b: String = 4, - $c: ComplexInput = "NotVeryComplex" - ) { - dog { name } - } - """ + """ + query InvalidDefaultValues( + $a: Int = "one", + $b: String = 4, + $c: ComplexInput = "NotVeryComplex" + ) { + dog { name } + } + """ ) try assertValidationError( @@ -1481,13 +1488,13 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 2, query: - """ - query WithDefaultValues( - $a: ComplexInput = { requiredField: 123, intField: "abc" } - ) { - dog { name } - } - """ + """ + query WithDefaultValues( + $a: ComplexInput = { requiredField: 123, intField: "abc" } + ) { + dog { name } + } + """ ) try assertValidationError( @@ -1507,17 +1514,18 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - query MissingRequiredField($a: ComplexInput = {intField: 3}) { - dog { name } - } - """ + """ + query MissingRequiredField($a: ComplexInput = {intField: 3}) { + dog { name } + } + """ ) try assertValidationError( error: errors[0], locations: [(line: 1, column: 47)], - message: #"Field "ComplexInput.requiredField" of required type "Boolean!" was not provided."# + message: + #"Field "ComplexInput.requiredField" of required type "Boolean!" was not provided."# ) } @@ -1525,11 +1533,11 @@ class ValuesOfCorrectTypeRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - query InvalidItem($a: [String] = ["one", 2]) { - dog { name } - } - """ + """ + query InvalidItem($a: [String] = ["one", 2]) { + dog { name } + } + """ ) try assertValidationError( diff --git a/Tests/GraphQLTests/ValidationTests/VariablesAreInputTypesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/VariablesAreInputTypesRuleTests.swift index 16d94c8e..fbbc9e05 100644 --- a/Tests/GraphQLTests/ValidationTests/VariablesAreInputTypesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/VariablesAreInputTypesRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class VariablesAreInputTypesRuleTests: ValidationTestCase { override init() { super.init() @@ -31,11 +32,11 @@ class VariablesAreInputTypesRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 3, query: - """ - query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) { - field(a: $a, b: $b, c: $c) - } - """ + """ + query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) { + field(a: $a, b: $b, c: $c) + } + """ ) try assertValidationError( error: errors[0], diff --git a/Tests/GraphQLTests/ValidationTests/VariablesInAllowedPositionRuleTests.swift b/Tests/GraphQLTests/ValidationTests/VariablesInAllowedPositionRuleTests.swift index 3ff3821b..73b317f4 100644 --- a/Tests/GraphQLTests/ValidationTests/VariablesInAllowedPositionRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/VariablesInAllowedPositionRuleTests.swift @@ -1,6 +1,7 @@ -@testable import GraphQL import Testing +@testable import GraphQL + class VariablesInAllowedPositionRuleTests: ValidationTestCase { override init() { super.init() @@ -173,13 +174,13 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - query Query($intArg: Int) { - complicatedArgs { - nonNullIntArgField(nonNullIntArg: $intArg) - } - } - """ + """ + query Query($intArg: Int) { + complicatedArgs { + nonNullIntArgField(nonNullIntArg: $intArg) + } + } + """ ) try assertValidationError( error: errors[0], @@ -195,17 +196,17 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - fragment nonNullIntArgFieldFrag on ComplicatedArgs { - nonNullIntArgField(nonNullIntArg: $intArg) - } + """ + fragment nonNullIntArgFieldFrag on ComplicatedArgs { + nonNullIntArgField(nonNullIntArg: $intArg) + } - query Query($intArg: Int) { - complicatedArgs { - ...nonNullIntArgFieldFrag - } - } - """ + query Query($intArg: Int) { + complicatedArgs { + ...nonNullIntArgFieldFrag + } + } + """ ) try assertValidationError( error: errors[0], @@ -221,21 +222,21 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - fragment outerFrag on ComplicatedArgs { - ...nonNullIntArgFieldFrag - } + """ + fragment outerFrag on ComplicatedArgs { + ...nonNullIntArgFieldFrag + } - fragment nonNullIntArgFieldFrag on ComplicatedArgs { - nonNullIntArgField(nonNullIntArg: $intArg) - } + fragment nonNullIntArgFieldFrag on ComplicatedArgs { + nonNullIntArgField(nonNullIntArg: $intArg) + } - query Query($intArg: Int) { - complicatedArgs { - ...outerFrag - } - } - """ + query Query($intArg: Int) { + complicatedArgs { + ...outerFrag + } + } + """ ) try assertValidationError( error: errors[0], @@ -251,13 +252,13 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - query Query($stringVar: String) { - complicatedArgs { - booleanArgField(booleanArg: $stringVar) - } - } - """ + """ + query Query($stringVar: String) { + complicatedArgs { + booleanArgField(booleanArg: $stringVar) + } + } + """ ) try assertValidationError( error: errors[0], @@ -265,7 +266,8 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { (line: 1, column: 13), (line: 3, column: 33), ], - message: #"Variable "$stringVar" of type "String" used in position expecting type "Boolean"."# + message: + #"Variable "$stringVar" of type "String" used in position expecting type "Boolean"."# ) } @@ -273,13 +275,13 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - query Query($stringVar: String) { - complicatedArgs { - stringListArgField(stringListArg: $stringVar) - } - } - """ + """ + query Query($stringVar: String) { + complicatedArgs { + stringListArgField(stringListArg: $stringVar) + } + } + """ ) try assertValidationError( error: errors[0], @@ -287,7 +289,8 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { (line: 1, column: 13), (line: 3, column: 39), ], - message: #"Variable "$stringVar" of type "String" used in position expecting type "[String]"."# + message: + #"Variable "$stringVar" of type "String" used in position expecting type "[String]"."# ) } @@ -295,11 +298,11 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - query Query($boolVar: Boolean) { - dog @include(if: $boolVar) - } - """ + """ + query Query($boolVar: Boolean) { + dog @include(if: $boolVar) + } + """ ) try assertValidationError( error: errors[0], @@ -307,7 +310,8 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { (line: 1, column: 13), (line: 2, column: 20), ], - message: #"Variable "$boolVar" of type "Boolean" used in position expecting type "Boolean!"."# + message: + #"Variable "$boolVar" of type "Boolean" used in position expecting type "Boolean!"."# ) } @@ -315,11 +319,11 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - query Query($stringVar: String) { - dog @include(if: $stringVar) - } - """ + """ + query Query($stringVar: String) { + dog @include(if: $stringVar) + } + """ ) try assertValidationError( error: errors[0], @@ -327,7 +331,8 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { (line: 1, column: 13), (line: 2, column: 20), ], - message: #"Variable "$stringVar" of type "String" used in position expecting type "Boolean!"."# + message: + #"Variable "$stringVar" of type "String" used in position expecting type "Boolean!"."# ) } @@ -335,13 +340,13 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - query Query($stringListVar: [String]) { - complicatedArgs { - stringListNonNullArgField(stringListNonNullArg: $stringListVar) - } - } - """ + """ + query Query($stringListVar: [String]) { + complicatedArgs { + stringListNonNullArgField(stringListNonNullArg: $stringListVar) + } + } + """ ) try assertValidationError( error: errors[0], @@ -349,7 +354,8 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { (line: 1, column: 13), (line: 3, column: 53), ], - message: #"Variable "$stringListVar" of type "[String]" used in position expecting type "[String!]"."# + message: + #"Variable "$stringListVar" of type "[String]" used in position expecting type "[String!]"."# ) } @@ -357,13 +363,13 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { let errors = try assertInvalid( errorCount: 1, query: - """ - query Query($intVar: Int = null) { - complicatedArgs { - nonNullIntArgField(nonNullIntArg: $intVar) - } - } - """ + """ + query Query($intVar: Int = null) { + complicatedArgs { + nonNullIntArgField(nonNullIntArg: $intVar) + } + } + """ ) try assertValidationError( error: errors[0], @@ -376,30 +382,36 @@ class VariablesInAllowedPositionRuleTests: ValidationTestCase { } @Test func intOptionalWithNonNullDefaultValue() throws { - try assertValid(""" - query Query($intVar: Int = 1) { - complicatedArgs { - nonNullIntArgField(nonNullIntArg: $intVar) - } - } - """) + try assertValid( + """ + query Query($intVar: Int = 1) { + complicatedArgs { + nonNullIntArgField(nonNullIntArg: $intVar) + } + } + """ + ) } @Test func optionalVariableWithDefaultValueAndNonNullField() throws { - try assertValid(""" - query Query($intVar: Int) { - complicatedArgs { - nonNullFieldWithDefault(nonNullIntArg: $intVar) - } - } - """) + try assertValid( + """ + query Query($intVar: Int) { + complicatedArgs { + nonNullFieldWithDefault(nonNullIntArg: $intVar) + } + } + """ + ) } @Test func booleanWithDefaultValueInDirective() throws { - try assertValid(""" - query Query($boolVar: Boolean = false) { - dog @include(if: $boolVar) - } - """) + try assertValid( + """ + query Query($boolVar: Boolean = false) { + dog @include(if: $boolVar) + } + """ + ) } } From cbf5ffbbc9075ad5525a3ceffa77526b03ae55b9 Mon Sep 17 00:00:00 2001 From: Jay Herron Date: Sun, 5 Apr 2026 00:30:15 -0600 Subject: [PATCH 3/3] docs: Document new formatting --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9a7ba6d4..decda187 100644 --- a/README.md +++ b/README.md @@ -124,11 +124,11 @@ Those contributing to this package are expected to follow the [Swift Code of Con [Swift API Design Guidelines](https://swift.org/documentation/api-design-guidelines/), and the [SSWG Technical Best Practices](https://github.com/swift-server/sswg/blob/main/process/incubation.md#technical-best-practices). -This repo uses [SwiftFormat](https://github.com/nicklockwood/SwiftFormat), and includes lint checks to enforce these formatting standards. -To format your code, install `swiftformat` and run: +This repo uses the standard [swift format](https://github.com/swiftlang/swift-format), and includes lint checks to enforce these formatting standards. +To format your code, run: ```bash -swiftformat . +swift format --parallel --in-place --recursive ./ ``` Most of this repo mirrors the structure of