diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 54ab0852..bb490233 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,6 +10,19 @@ on: workflow_dispatch: jobs: + formatlint: + name: Lint for correct formatting + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: sinoru/actions-setup-swift@v2 + with: + swift-version: '5.6.1' + - name: GitHub Action for SwiftFormat + uses: CassiusPacheco/action-swiftformat@v0.1.0 + with: + swiftformat-version: '0.49.11' + macos: name: Build and test on macos-latest runs-on: macOS-latest diff --git a/.swiftformat b/.swiftformat new file mode 100644 index 00000000..74ed9799 --- /dev/null +++ b/.swiftformat @@ -0,0 +1,7 @@ +--maxwidth 100 +--semicolons never +--xcodeindentation enabled +--wraparguments before-first +--wrapcollections before-first +--wrapconditions before-first +--wrapparameters before-first diff --git a/Package.swift b/Package.swift index c05a35e9..a6c70357 100644 --- a/Package.swift +++ b/Package.swift @@ -12,7 +12,7 @@ let package = Package( ], targets: [ .target( - name: "GraphQL", + name: "GraphQL", dependencies: [ .product(name: "NIO", package: "swift-nio"), .product(name: "OrderedCollections", package: "swift-collections"), diff --git a/README.md b/README.md index 0ce6fee3..96ce7d51 100644 --- a/README.md +++ b/README.md @@ -97,8 +97,6 @@ To execute a subscription use the `graphqlSubscribe` function: ```swift let subscriptionResult = try graphqlSubscribe( schema: schema, - request: "{ hello }", - eventLoopGroup: eventLoopGroup ).wait() // Must downcast from EventStream to concrete type to use in 'for await' loop below let concurrentStream = subscriptionResult.stream! as! ConcurrentEventStream @@ -131,6 +129,13 @@ 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: + +```bash +swiftformat . +``` + Most of this repo mirrors the structure of (the canonical GraphQL implementation written in Javascript/Typescript)[https://github.com/graphql/graphql-js]. If there is any feature missing, looking at the original code and "translating" it to Swift works, most of the time. For example: diff --git a/Sources/GraphQL/Error/GraphQLError.swift b/Sources/GraphQL/Error/GraphQLError.swift index 125326f1..d6bdebf5 100644 --- a/Sources/GraphQL/Error/GraphQLError.swift +++ b/Sources/GraphQL/Error/GraphQLError.swift @@ -4,8 +4,8 @@ * 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 { +public struct GraphQLError: Error, Codable { + enum CodingKeys: String, CodingKey { case message case locations case path @@ -78,22 +78,22 @@ public struct GraphQLError : Error, Codable { self.source = nil } - if positions.isEmpty && !nodes.isEmpty { - self.positions = nodes.filter({ $0.loc != nil }).map({ $0.loc!.start }) + if positions.isEmpty, !nodes.isEmpty { + self.positions = nodes.filter { $0.loc != nil }.map { $0.loc!.start } } else { self.positions = positions } if let source = self.source, !self.positions.isEmpty { - self.locations = self.positions.map({ getLocation(source: source, position: $0) }) + locations = self.positions.map { getLocation(source: source, position: $0) } } else { - self.locations = [] + locations = [] } self.path = path self.originalError = originalError } - + public init( message: String, locations: [SourceLocation], @@ -102,46 +102,46 @@ public struct GraphQLError : Error, Codable { self.message = message self.locations = locations self.path = path - self.nodes = [] - self.source = nil - self.positions = [] - self.originalError = nil + nodes = [] + source = nil + positions = [] + originalError = nil } - + public init(_ error: Error) { self.init( message: error.localizedDescription, originalError: error ) } - + public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) message = try container.decode(String.self, forKey: .message) locations = try container.decode([SourceLocation]?.self, forKey: .locations) ?? [] path = try container.decode(IndexPath.self, forKey: .path) } - + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - + try container.encode(message, forKey: .message) - + if !locations.isEmpty { try container.encode(locations, forKey: .locations) } - + try container.encode(path, forKey: .path) } } -extension GraphQLError : CustomStringConvertible { +extension GraphQLError: CustomStringConvertible { public var description: String { return message } } -extension GraphQLError : Hashable { +extension GraphQLError: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(message) } @@ -153,41 +153,41 @@ extension GraphQLError : Hashable { // MARK: IndexPath -public struct IndexPath : Codable { +public struct IndexPath: Codable { public let elements: [IndexPathValue] - + public init(_ elements: [IndexPathElement] = []) { - self.elements = elements.map({ $0.indexPathValue }) + self.elements = elements.map { $0.indexPathValue } } - + public func appending(_ elements: IndexPathElement) -> IndexPath { return IndexPath(self.elements + [elements]) } - + public init(from decoder: Decoder) throws { var container = try decoder.unkeyedContainer() elements = try container.decode([IndexPathValue].self) } - + public func encode(to encoder: Encoder) throws { var container = encoder.unkeyedContainer() try container.encode(contentsOf: elements) } } -extension IndexPath : ExpressibleByArrayLiteral { +extension IndexPath: ExpressibleByArrayLiteral { public init(arrayLiteral elements: IndexPathElement...) { - self.elements = elements.map({ $0.indexPathValue }) + self.elements = elements.map { $0.indexPathValue } } } -public enum IndexPathValue : Codable { +public enum IndexPathValue: Codable { case index(Int) case key(String) - + public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() - + if let index = try? container.decode(Int.self) { self = .index(index) } else if let key = try? container.decode(String.self) { @@ -196,10 +196,10 @@ public enum IndexPathValue : Codable { throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid type.") } } - + public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() - + switch self { case let .index(index): try container.encode(index) @@ -209,13 +209,13 @@ public enum IndexPathValue : Codable { } } -extension IndexPathValue : IndexPathElement { +extension IndexPathValue: IndexPathElement { public var indexPathValue: IndexPathValue { return self } } -extension IndexPathValue : CustomStringConvertible { +extension IndexPathValue: CustomStringConvertible { public var description: String { switch self { case let .index(index): @@ -239,29 +239,29 @@ extension IndexPathElement { } } -extension IndexPathElement { - public var indexValue: Int? { - if case .index(let index) = indexPathValue { +public extension IndexPathElement { + var indexValue: Int? { + if case let .index(index) = indexPathValue { return index } return nil } - - public var keyValue: String? { - if case .key(let key) = indexPathValue { + + var keyValue: String? { + if case let .key(key) = indexPathValue { return key } return nil } } -extension Int : IndexPathElement { +extension Int: IndexPathElement { public var indexPathValue: IndexPathValue { return .index(self) } } -extension String : IndexPathElement { +extension String: IndexPathElement { public var indexPathValue: IndexPathValue { return .key(self) } diff --git a/Sources/GraphQL/Error/SyntaxError.swift b/Sources/GraphQL/Error/SyntaxError.swift index 26f2eb75..b16b9e34 100644 --- a/Sources/GraphQL/Error/SyntaxError.swift +++ b/Sources/GraphQL/Error/SyntaxError.swift @@ -10,8 +10,8 @@ func syntaxError(source: Source, position: Int, description: String) -> GraphQLE let error = GraphQLError( message: "Syntax Error \(source.name) (\(location.line):\(location.column)) " + - description + "\n\n" + - highlightSourceAtLocation(source: source, location: location), + description + "\n\n" + + highlightSourceAtLocation(source: source, location: location), source: source, positions: [position] ) @@ -49,17 +49,16 @@ func highlightSourceAtLocation(source: Source, location: SourceLocation) -> Stri } func splitLines(string: String) -> [String] { - var lines: [String] = [] var location = 0 - + let nsstring = NSString(string: string) do { let regex = try NSRegularExpression(pattern: "\r\n|[\n\r]", options: []) - for match in regex.matches(in: string, options: [], range: NSRange(0.. [String] { if lines.isEmpty { return [string] } else { - let range = NSRange(location..?> = fields.mapValues { _ -> Future? in return nil } - var err: Error? = nil + var results: OrderedDictionary?> = fields + .mapValues { _ -> Future? in nil } + var err: Error? fields.forEach { field in let fieldASTs = field.value - let fieldKey = field.key + let fieldKey = field.key let fieldPath = path.appending(fieldKey) dispatchQueue.async(group: group) { guard err == nil else { @@ -208,16 +208,15 @@ public struct ConcurrentDispatchFieldExecutionStrategy: QueryFieldExecutionStrat } } } - + group.wait() - + if let error = err { throw error } - - return results.compactMapValues({ $0 }).flatten(on: exeContext.eventLoopGroup) - } + return results.compactMapValues { $0 }.flatten(on: exeContext.eventLoopGroup) + } } /** @@ -276,7 +275,8 @@ func execute( return eventLoopGroup.next().makeSucceededFuture(GraphQLResult(errors: [error])) } catch { - return eventLoopGroup.next().makeSucceededFuture(GraphQLResult(errors: [GraphQLError(error)])) + return eventLoopGroup.next() + .makeSucceededFuture(GraphQLResult(errors: [GraphQLError(error)])) } do { @@ -288,17 +288,17 @@ func execute( rootValue: rootValue ).flatMapThrowing { data -> GraphQLResult in var dataMap: Map = [:] - + for (key, value) in data { dataMap[key] = try map(from: value) } - - var result: GraphQLResult = GraphQLResult(data: dataMap) - + + var result: GraphQLResult = .init(data: dataMap) + if !buildContext.errors.isEmpty { result.errors = buildContext.errors } - + // executeErrors = buildContext.errors return result }.flatMapError { error -> Future in @@ -325,12 +325,13 @@ func execute( // errors: executeErrors, // result: result // ) - return result + result } } catch let error as GraphQLError { return eventLoopGroup.next().makeSucceededFuture(GraphQLResult(errors: [error])) } catch { - return eventLoopGroup.next().makeSucceededFuture(GraphQLResult(errors: [GraphQLError(error)])) + return eventLoopGroup.next() + .makeSucceededFuture(GraphQLResult(errors: [GraphQLError(error)])) } } @@ -354,7 +355,7 @@ func buildExecutionContext( operationName: String? ) throws -> ExecutionContext { let errors: [GraphQLError] = [] - var possibleOperation: OperationDefinition? = nil + var possibleOperation: OperationDefinition? var fragments: [String: FragmentDefinition] = [:] for definition in documentAST.definitions { @@ -394,7 +395,7 @@ func buildExecutionContext( definitionASTs: operation.variableDefinitions, inputs: rawVariableValues ) - + return ExecutionContext( queryStrategy: queryStrategy, mutationStrategy: mutationStrategy, @@ -421,7 +422,7 @@ func executeOperation( ) throws -> Future> { let type = try getOperationRootType(schema: exeContext.schema, operation: operation) var inputFields: OrderedDictionary = [:] - var visitedFragmentNames: [String : Bool] = [:] + var visitedFragmentNames: [String: Bool] = [:] let fields = try collectFields( exeContext: exeContext, @@ -432,7 +433,7 @@ func executeOperation( ) let fieldExecutionStrategy: FieldExecutionStrategy - + switch operation.operation { case .query: fieldExecutionStrategy = exeContext.queryStrategy @@ -458,28 +459,28 @@ func getOperationRootType( schema: GraphQLSchema, operation: OperationDefinition ) throws -> GraphQLObjectType { - switch operation.operation { + switch operation.operation { case .query: - return schema.queryType + return schema.queryType case .mutation: - guard let mutationType = schema.mutationType else { - throw GraphQLError( - message: "Schema is not configured for mutations", - nodes: [operation] - ) - } + guard let mutationType = schema.mutationType else { + throw GraphQLError( + message: "Schema is not configured for mutations", + nodes: [operation] + ) + } - return mutationType + return mutationType case .subscription: - guard let subscriptionType = schema.subscriptionType else { - throw GraphQLError( - message: "Schema is not configured for subscriptions", - nodes: [operation] - ) - } + guard let subscriptionType = schema.subscriptionType else { + throw GraphQLError( + message: "Schema is not configured for subscriptions", + nodes: [operation] + ) + } - return subscriptionType - } + return subscriptionType + } } /** @@ -531,7 +532,7 @@ func collectFields( type: runtimeType ) - guard shouldInclude && fragmentConditionMatches else { + guard shouldInclude, fragmentConditionMatches else { continue } @@ -550,7 +551,7 @@ func collectFields( directives: fragmentSpread.directives ) - guard visitedFragmentNames[fragmentName] == nil && shouldInclude else { + guard visitedFragmentNames[fragmentName] == nil, shouldInclude else { continue } @@ -581,7 +582,7 @@ func collectFields( break } } - + return fields } @@ -613,7 +614,7 @@ func shouldIncludeNode(exeContext: ExecutionContext, directives: [Directive] = [ return false } } - + return true } @@ -629,11 +630,19 @@ func doesFragmentConditionMatch( return true } - guard let conditionalType = typeFromAST(schema: exeContext.schema, inputTypeAST: typeConditionAST) else { + guard + let conditionalType = typeFromAST( + schema: exeContext.schema, + inputTypeAST: typeConditionAST + ) + else { return true } - if let conditionalType = conditionalType as? GraphQLObjectType, conditionalType.name == type.name { + if + let conditionalType = conditionalType as? GraphQLObjectType, + conditionalType.name == type.name + { return true } @@ -643,7 +652,7 @@ func doesFragmentConditionMatch( maybeSubType: type ) } - + return false } @@ -889,7 +898,9 @@ func completeValue( result: .success(result) ).flatMapThrowing { value -> Any? in guard let value = value else { - throw GraphQLError(message: "Cannot return null for non-nullable field \(info.parentType.name).\(info.fieldName).") + throw GraphQLError( + message: "Cannot return null for non-nullable field \(info.parentType.name).\(info.fieldName)." + ) } return value @@ -917,7 +928,8 @@ func completeValue( // If field type is a leaf type, Scalar or Enum, serialize to a valid value, // returning .null if serialization is not possible. if let returnType = returnType as? GraphQLLeafType { - return exeContext.eventLoopGroup.next().makeSucceededFuture(try completeLeafValue(returnType: returnType, result: r)) + return exeContext.eventLoopGroup.next() + .makeSucceededFuture(try completeLeafValue(returnType: returnType, result: r)) } // If field type is an abstract type, Interface or Union, determine the @@ -946,7 +958,9 @@ func completeValue( } // Not reachable. All possible output types have been considered. - throw GraphQLError(message: "Cannot complete value of unexpected type \"\(returnType)\".") + throw GraphQLError( + message: "Cannot complete value of unexpected type \"\(returnType)\"." + ) } } } @@ -967,7 +981,7 @@ func completeListValue( throw GraphQLError( message: "Expected array, but did not find one for field " + - "\(info.parentType.name).\(info.fieldName)." + "\(info.parentType.name).\(info.fieldName)." ) } @@ -978,7 +992,8 @@ func completeListValue( // No need to modify the info object containing the path, // since from here on it is not ever accessed by resolver funcs. let fieldPath = path.appending(index) - let futureItem = item as? Future ?? exeContext.eventLoopGroup.next().makeSucceededFuture(item) + let futureItem = item as? Future ?? exeContext.eventLoopGroup.next() + .makeSucceededFuture(item) let completedItem = try completeValueCatchingError( exeContext: exeContext, @@ -1003,17 +1018,17 @@ func completeLeafValue(returnType: GraphQLLeafType, result: Any?) throws -> Map guard let result = result else { return .null } - + let serializedResult = try returnType.serialize(value: result) if serializedResult == .null { throw GraphQLError( message: "Expected a value of type \"\(returnType)\" but " + - "received: \(result)" + "received: \(result)" ) } - + return serializedResult } @@ -1029,7 +1044,8 @@ func completeAbstractValue( path: IndexPath, result: Any ) throws -> Future { - var resolveRes = try returnType.resolveType?(result, exeContext.eventLoopGroup, info).typeResolveResult + var resolveRes = try returnType.resolveType?(result, exeContext.eventLoopGroup, info) + .typeResolveResult resolveRes = try resolveRes ?? defaultResolveType( value: result, @@ -1049,9 +1065,9 @@ func completeAbstractValue( var runtimeType: GraphQLType? switch resolveResult { - case .name(let name): + case let .name(name): runtimeType = exeContext.schema.getType(name: name) - case .type(let type): + case let .type(type): runtimeType = type } @@ -1059,8 +1075,8 @@ func completeAbstractValue( 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))\".", + "runtime for field \(info.parentType.name).\(info.fieldName) with " + + "value \"\(resolveResult)\", received \"\(String(describing: runtimeType))\".", nodes: fieldASTs ) } @@ -1069,7 +1085,7 @@ func completeAbstractValue( throw GraphQLError( message: "Runtime Object type \"\(objectType.name)\" is not a possible type " + - "for \"\(returnType.name)\".", + "for \"\(returnType.name)\".", nodes: fieldASTs ) } @@ -1147,7 +1163,10 @@ func defaultResolveType( ) throws -> TypeResolveResult? { let possibleTypes = info.schema.getPossibleTypes(abstractType: abstractType) - guard let type = try possibleTypes.find({ try $0.isTypeOf?(value, eventLoopGroup, info) ?? false }) else { + guard + let type = try possibleTypes + .find({ try $0.isTypeOf?(value, eventLoopGroup, info) ?? false }) + else { return nil } @@ -1161,15 +1180,15 @@ func defaultResolveType( */ func defaultResolve( source: Any, - args: Map, - context: Any, + args _: Map, + context _: Any, eventLoopGroup: EventLoopGroup, info: GraphQLResolveInfo ) -> Future { guard let source = unwrap(source) else { return eventLoopGroup.next().makeSucceededFuture(nil) } - + if let subscriptable = source as? KeySubscriptable { let value = subscriptable[info.fieldName] return eventLoopGroup.next().makeSucceededFuture(value) @@ -1196,17 +1215,19 @@ func getFieldDef( parentType: GraphQLObjectType, fieldName: String ) throws -> GraphQLFieldDefinition { - if fieldName == SchemaMetaFieldDef.name && schema.queryType.name == parentType.name { + if fieldName == SchemaMetaFieldDef.name, schema.queryType.name == parentType.name { return SchemaMetaFieldDef - } else if fieldName == TypeMetaFieldDef.name && schema.queryType.name == parentType.name { + } else if fieldName == TypeMetaFieldDef.name, schema.queryType.name == parentType.name { return TypeMetaFieldDef } else if fieldName == TypeNameMetaFieldDef.name { return TypeNameMetaFieldDef } - + // This field should exist because we passed validation before execution guard let fieldDefinition = parentType.fields[fieldName] else { - throw GraphQLError(message: "Expected field definition not found: '\(fieldName)' on '\(parentType.name)'") + throw GraphQLError( + message: "Expected field definition not found: '\(fieldName)' on '\(parentType.name)'" + ) } return fieldDefinition } diff --git a/Sources/GraphQL/Execution/Values.swift b/Sources/GraphQL/Execution/Values.swift index 0336f4e4..11c0a666 100644 --- a/Sources/GraphQL/Execution/Values.swift +++ b/Sources/GraphQL/Execution/Values.swift @@ -6,12 +6,15 @@ import OrderedCollections * 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], inputs: [String: Map]) throws -> [String: Map] { - +func getVariableValues( + schema: GraphQLSchema, + definitionASTs: [VariableDefinition], + inputs: [String: Map] +) throws -> [String: Map] { var vars = [String: Map]() for defAST in definitionASTs { let varName = defAST.variable.name.value - + let input: Map if let nonNilInput = inputs[varName] { input = nonNilInput @@ -28,23 +31,26 @@ func getVariableValues(schema: GraphQLSchema, definitionASTs: [VariableDefinitio return vars } - /** * 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]?, variables: [String: Map] = [:]) throws -> Map { +func getArgumentValues( + argDefs: [GraphQLArgumentDefinition], + argASTs: [Argument]?, + variables: [String: Map] = [:] +) throws -> Map { guard let argASTs = argASTs else { return [:] } - let argASTMap = argASTs.keyMap({ $0.name.value }) - + let argASTMap = argASTs.keyMap { $0.name.value } + var args = OrderedDictionary() for argDef in argDefs { let argName = argDef.name let argValue: Map - + if let argAST = argASTMap[argName] { argValue = try valueFromAST( valueAST: argAST.value, @@ -59,7 +65,7 @@ func getArgumentValues(argDefs: [GraphQLArgumentDefinition], argASTs: [Argument] argValue = .undefined } } - + let errors = try validate(value: argValue, forType: argDef.type) guard errors.isEmpty else { let message = "\n" + errors.joined(separator: "\n") @@ -73,12 +79,15 @@ func getArgumentValues(argDefs: [GraphQLArgumentDefinition], argASTs: [Argument] 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. */ -func getVariableValue(schema: GraphQLSchema, definitionAST: VariableDefinition, input: Map) throws -> Map { +func getVariableValue( + schema: GraphQLSchema, + definitionAST: VariableDefinition, + input: Map +) throws -> Map { let type = typeFromAST(schema: schema, inputTypeAST: definitionAST.type) let variable = definitionAST.variable @@ -86,26 +95,27 @@ func getVariableValue(schema: GraphQLSchema, definitionAST: VariableDefinition, throw GraphQLError( message: "Variable \"$\(variable.name.value)\" expected value of type " + - "\"\(definitionAST.type)\" which cannot be used as an input type.", + "\"\(definitionAST.type)\" which cannot be used as an input type.", nodes: [definitionAST] ) } - + var toCoerce = input if input == .undefined, let defaultValue = definitionAST.defaultValue { toCoerce = try valueFromAST(valueAST: defaultValue, type: inputType) } - + let errors = try validate(value: toCoerce, forType: inputType) guard errors.isEmpty else { let message = !errors.isEmpty ? "\n" + errors.joined(separator: "\n") : "" throw GraphQLError( message: - "Variable \"$\(variable.name.value)\" got invalid value \"\(toCoerce)\".\(message)", // TODO: "\(JSON.stringify(input)).\(message)", + "Variable \"$\(variable.name.value)\" got invalid value \"\(toCoerce)\".\(message)", + // TODO: "\(JSON.stringify(input)).\(message)", nodes: [definitionAST] ) } - + return try coerceValue(value: toCoerce, type: inputType) } @@ -121,8 +131,8 @@ func coerceValue(value: Map, type: GraphQLInputType) throws -> Map { } return try coerceValue(value: value, type: nonNullType) } - - guard value != .undefined && value != .null else { + + guard value != .undefined, value != .null else { return value } @@ -131,24 +141,24 @@ func coerceValue(value: Map, type: GraphQLInputType) throws -> Map { throw GraphQLError(message: "Input list must wrap an input type") } - if case .array(let value) = value { + if case let .array(value) = value { let coercedValues = try value.map { item in try coerceValue(value: item, type: itemType) } return .array(coercedValues) } - + // Convert solitary value into single-value array return .array([try coerceValue(value: value, type: itemType)]) } if let objectType = type as? GraphQLInputObjectType { - guard case .dictionary(let value) = value else { + guard case let .dictionary(value) = value else { throw GraphQLError(message: "Must be dictionary to extract to an input type") } let fields = objectType.fields - + var object = OrderedDictionary() for (fieldName, field) in fields { if let fieldValueMap = value[fieldName], fieldValueMap != .undefined { @@ -167,10 +177,10 @@ func coerceValue(value: Map, type: GraphQLInputType) throws -> Map { } return .dictionary(object) } - + if let leafType = type as? GraphQLLeafType { return try leafType.parseValue(value: value) } - + throw GraphQLError(message: "Provided type is not an input type") } diff --git a/Sources/GraphQL/Extensions/Codable+Extensions.swift b/Sources/GraphQL/Extensions/Codable+Extensions.swift index 77501eda..e4607490 100644 --- a/Sources/GraphQL/Extensions/Codable+Extensions.swift +++ b/Sources/GraphQL/Extensions/Codable+Extensions.swift @@ -1,11 +1,11 @@ -public class AnyEncodable : Encodable { +public class AnyEncodable: Encodable { private let encodable: Encodable - + public init(_ encodable: Encodable) { self.encodable = encodable } - + public func encode(to encoder: Encoder) throws { - return try self.encodable.encode(to: encoder) + return try encodable.encode(to: encoder) } } diff --git a/Sources/GraphQL/GraphQL.swift b/Sources/GraphQL/GraphQL.swift index b4c32870..c6916f5f 100644 --- a/Sources/GraphQL/GraphQL.swift +++ b/Sources/GraphQL/GraphQL.swift @@ -1,40 +1,42 @@ import NIO -public struct GraphQLResult : Equatable, Codable, CustomStringConvertible { +public struct GraphQLResult: Equatable, Codable, CustomStringConvertible { public var data: Map? public var errors: [GraphQLError] - + public init(data: Map? = nil, errors: [GraphQLError] = []) { self.data = data self.errors = errors } - - enum CodingKeys : String, CodingKey { + + enum CodingKeys: String, CodingKey { case data case errors } - + public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - self.data = try container.decodeIfPresent(Map.self, forKey: .data) - self.errors = try container.decodeIfPresent([GraphQLError].self, forKey: .errors) ?? [] + data = try container.decodeIfPresent(Map.self, forKey: .data) + errors = try container.decodeIfPresent([GraphQLError].self, forKey: .errors) ?? [] } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - - if let data = self.data { + + if let data = data { try container.encode(data, forKey: .data) } - - if !self.errors.isEmpty { - try container.encode(self.errors, forKey: .errors) + + if !errors.isEmpty { + try container.encode(errors, forKey: .errors) } } - + public var description: String { - guard let data = try? GraphQLJSONEncoder().encode(self), - let dataString = String(data: data, encoding: .utf8) else { + guard + let data = try? GraphQLJSONEncoder().encode(self), + let dataString = String(data: data, encoding: .utf8) + else { return "Unable to encode GraphQLResult" } return dataString @@ -45,12 +47,13 @@ public struct GraphQLResult : Equatable, Codable, CustomStringConvertible { public struct SubscriptionResult { public let stream: SubscriptionEventStream? public let errors: [GraphQLError] - + public init(stream: SubscriptionEventStream? = nil, errors: [GraphQLError] = []) { self.stream = stream self.errors = errors } } + /// SubscriptionObservable represents an event stream of fully resolved GraphQL subscription results. Subscribers can be added to this stream. public typealias SubscriptionEventStream = EventStream> @@ -90,10 +93,14 @@ public func graphql( variableValues: [String: Map] = [:], operationName: String? = nil ) throws -> Future { - let source = Source(body: request, name: "GraphQL request") let documentAST = try parse(instrumentation: instrumentation, source: source) - let validationErrors = validate(instrumentation: instrumentation, schema: schema, ast: documentAST, rules: validationRules) + let validationErrors = validate( + instrumentation: instrumentation, + schema: schema, + ast: documentAST, + rules: validationRules + ) guard validationErrors.isEmpty else { return eventLoopGroup.next().makeSucceededFuture(GraphQLResult(errors: validationErrors)) @@ -145,13 +152,13 @@ public func graphql( operationName: String? = nil ) throws -> Future { switch try queryRetrieval.lookup(queryId) { - case .unknownId(_): + case .unknownId: throw GraphQLError(message: "Unknown query id") - case .parseError(let parseError): + case let .parseError(parseError): throw parseError - case .validateErrors(_, let validationErrors): + case let .validateErrors(_, validationErrors): return eventLoopGroup.next().makeSucceededFuture(GraphQLResult(errors: validationErrors)) - case .result(let schema, let documentAST): + case let .result(schema, documentAST): return execute( queryStrategy: queryStrategy, mutationStrategy: mutationStrategy, @@ -208,13 +215,18 @@ public func graphqlSubscribe( variableValues: [String: Map] = [:], operationName: String? = nil ) throws -> Future { - let source = Source(body: request, name: "GraphQL Subscription request") let documentAST = try parse(instrumentation: instrumentation, source: source) - let validationErrors = validate(instrumentation: instrumentation, schema: schema, ast: documentAST, rules: validationRules) + let validationErrors = validate( + instrumentation: instrumentation, + schema: schema, + ast: documentAST, + rules: validationRules + ) guard validationErrors.isEmpty else { - return eventLoopGroup.next().makeSucceededFuture(SubscriptionResult(errors: validationErrors)) + return eventLoopGroup.next() + .makeSucceededFuture(SubscriptionResult(errors: validationErrors)) } return subscribe( @@ -236,110 +248,110 @@ public func graphqlSubscribe( #if compiler(>=5.5) && canImport(_Concurrency) -@available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) -/// This is the primary entry point function for fulfilling GraphQL operations -/// by parsing, validating, and executing a GraphQL document along side a -/// GraphQL schema. -/// -/// More sophisticated GraphQL servers, such as those which persist queries, -/// may wish to separate the validation and execution phases to a static time -/// tooling step, and a server runtime step. -/// -/// - parameter queryStrategy: The field execution strategy to use for query requests -/// - parameter mutationStrategy: The field execution strategy to use for mutation requests -/// - parameter subscriptionStrategy: The field execution strategy to use for subscription requests -/// - parameter instrumentation: The instrumentation implementation to call during the parsing, validating, execution, and field resolution stages. -/// - parameter schema: The GraphQL type system to use when validating and executing a query. -/// - parameter request: A GraphQL language formatted string representing the requested operation. -/// - parameter rootValue: The value provided as the first argument to resolver functions on the top level type (e.g. the query object type). -/// - parameter contextValue: A context value provided to all resolver functions functions -/// - parameter variableValues: A mapping of variable name to runtime value to use for all variables defined in the `request`. -/// - parameter operationName: The name of the operation to use if `request` contains multiple possible operations. Can be omitted if `request` contains only one operation. -/// -/// - throws: throws GraphQLError if an error occurs while parsing the `request`. -/// -/// - returns: returns a `Map` dictionary containing the result of the query inside the key `data` and any validation or execution errors inside the key `errors`. The value of `data` might be `null` if, for example, the query is invalid. It's possible to have both `data` and `errors` if an error occurs only in a specific field. If that happens the value of that field will be `null` and there will be an error inside `errors` specifying the reason for the failure and the path of the failed field. -public func graphql( - queryStrategy: QueryFieldExecutionStrategy = SerialFieldExecutionStrategy(), - mutationStrategy: MutationFieldExecutionStrategy = SerialFieldExecutionStrategy(), - subscriptionStrategy: SubscriptionFieldExecutionStrategy = SerialFieldExecutionStrategy(), - instrumentation: Instrumentation = NoOpInstrumentation, - schema: GraphQLSchema, - request: String, - rootValue: Any = (), - context: Any = (), - eventLoopGroup: EventLoopGroup, - variableValues: [String: Map] = [:], - operationName: String? = nil -) async throws -> GraphQLResult { - return try await graphql( - queryStrategy: queryStrategy, - mutationStrategy: mutationStrategy, - subscriptionStrategy: subscriptionStrategy, - instrumentation: instrumentation, - schema: schema, - request: request, - rootValue: rootValue, - context: context, - eventLoopGroup: eventLoopGroup, - variableValues: variableValues, - operationName: operationName - ).get() -} + @available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) + /// This is the primary entry point function for fulfilling GraphQL operations + /// by parsing, validating, and executing a GraphQL document along side a + /// GraphQL schema. + /// + /// More sophisticated GraphQL servers, such as those which persist queries, + /// may wish to separate the validation and execution phases to a static time + /// tooling step, and a server runtime step. + /// + /// - parameter queryStrategy: The field execution strategy to use for query requests + /// - parameter mutationStrategy: The field execution strategy to use for mutation requests + /// - parameter subscriptionStrategy: The field execution strategy to use for subscription requests + /// - parameter instrumentation: The instrumentation implementation to call during the parsing, validating, execution, and field resolution stages. + /// - parameter schema: The GraphQL type system to use when validating and executing a query. + /// - parameter request: A GraphQL language formatted string representing the requested operation. + /// - parameter rootValue: The value provided as the first argument to resolver functions on the top level type (e.g. the query object type). + /// - parameter contextValue: A context value provided to all resolver functions functions + /// - parameter variableValues: A mapping of variable name to runtime value to use for all variables defined in the `request`. + /// - parameter operationName: The name of the operation to use if `request` contains multiple possible operations. Can be omitted if `request` contains only one operation. + /// + /// - throws: throws GraphQLError if an error occurs while parsing the `request`. + /// + /// - returns: returns a `Map` dictionary containing the result of the query inside the key `data` and any validation or execution errors inside the key `errors`. The value of `data` might be `null` if, for example, the query is invalid. It's possible to have both `data` and `errors` if an error occurs only in a specific field. If that happens the value of that field will be `null` and there will be an error inside `errors` specifying the reason for the failure and the path of the failed field. + public func graphql( + queryStrategy: QueryFieldExecutionStrategy = SerialFieldExecutionStrategy(), + mutationStrategy: MutationFieldExecutionStrategy = SerialFieldExecutionStrategy(), + subscriptionStrategy: SubscriptionFieldExecutionStrategy = SerialFieldExecutionStrategy(), + instrumentation: Instrumentation = NoOpInstrumentation, + schema: GraphQLSchema, + request: String, + rootValue: Any = (), + context: Any = (), + eventLoopGroup: EventLoopGroup, + variableValues: [String: Map] = [:], + operationName: String? = nil + ) async throws -> GraphQLResult { + return try await graphql( + queryStrategy: queryStrategy, + mutationStrategy: mutationStrategy, + subscriptionStrategy: subscriptionStrategy, + instrumentation: instrumentation, + schema: schema, + request: request, + rootValue: rootValue, + context: context, + eventLoopGroup: eventLoopGroup, + variableValues: variableValues, + operationName: operationName + ).get() + } -@available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) -/// This is the primary entry point function for fulfilling GraphQL subscription -/// operations by parsing, validating, and executing a GraphQL subscription -/// document along side a GraphQL schema. -/// -/// More sophisticated GraphQL servers, such as those which persist queries, -/// may wish to separate the validation and execution phases to a static time -/// tooling step, and a server runtime step. -/// -/// - parameter queryStrategy: The field execution strategy to use for query requests -/// - parameter mutationStrategy: The field execution strategy to use for mutation requests -/// - parameter subscriptionStrategy: The field execution strategy to use for subscription requests -/// - parameter instrumentation: The instrumentation implementation to call during the parsing, validating, execution, and field resolution stages. -/// - parameter schema: The GraphQL type system to use when validating and executing a query. -/// - parameter request: A GraphQL language formatted string representing the requested operation. -/// - parameter rootValue: The value provided as the first argument to resolver functions on the top level type (e.g. the query object type). -/// - parameter contextValue: A context value provided to all resolver functions -/// - parameter variableValues: A mapping of variable name to runtime value to use for all variables defined in the `request`. -/// - parameter operationName: The name of the operation to use if `request` contains multiple possible operations. Can be omitted if `request` contains only one operation. -/// -/// - throws: throws GraphQLError if an error occurs while parsing the `request`. -/// -/// - returns: returns a SubscriptionResult containing the subscription observable inside the key `observable` and any validation or execution errors inside the key `errors`. The -/// value of `observable` might be `null` if, for example, the query is invalid. It's not possible to have both `observable` and `errors`. The observable payloads are -/// GraphQLResults which contain the result of the query inside the key `data` and any validation or execution errors inside the key `errors`. The value of `data` might be `null`. -/// It's possible to have both `data` and `errors` if an error occurs only in a specific field. If that happens the value of that field will be `null` and there -/// will be an error inside `errors` specifying the reason for the failure and the path of the failed field. -public func graphqlSubscribe( - queryStrategy: QueryFieldExecutionStrategy = SerialFieldExecutionStrategy(), - mutationStrategy: MutationFieldExecutionStrategy = SerialFieldExecutionStrategy(), - subscriptionStrategy: SubscriptionFieldExecutionStrategy = SerialFieldExecutionStrategy(), - instrumentation: Instrumentation = NoOpInstrumentation, - schema: GraphQLSchema, - request: String, - rootValue: Any = (), - context: Any = (), - eventLoopGroup: EventLoopGroup, - variableValues: [String: Map] = [:], - operationName: String? = nil -) async throws -> SubscriptionResult { - return try await graphqlSubscribe( - queryStrategy: queryStrategy, - mutationStrategy: mutationStrategy, - subscriptionStrategy: subscriptionStrategy, - instrumentation: instrumentation, - schema: schema, - request: request, - rootValue: rootValue, - context: context, - eventLoopGroup: eventLoopGroup, - variableValues: variableValues, - operationName: operationName - ).get() -} + @available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) + /// This is the primary entry point function for fulfilling GraphQL subscription + /// operations by parsing, validating, and executing a GraphQL subscription + /// document along side a GraphQL schema. + /// + /// More sophisticated GraphQL servers, such as those which persist queries, + /// may wish to separate the validation and execution phases to a static time + /// tooling step, and a server runtime step. + /// + /// - parameter queryStrategy: The field execution strategy to use for query requests + /// - parameter mutationStrategy: The field execution strategy to use for mutation requests + /// - parameter subscriptionStrategy: The field execution strategy to use for subscription requests + /// - parameter instrumentation: The instrumentation implementation to call during the parsing, validating, execution, and field resolution stages. + /// - parameter schema: The GraphQL type system to use when validating and executing a query. + /// - parameter request: A GraphQL language formatted string representing the requested operation. + /// - parameter rootValue: The value provided as the first argument to resolver functions on the top level type (e.g. the query object type). + /// - parameter contextValue: A context value provided to all resolver functions + /// - parameter variableValues: A mapping of variable name to runtime value to use for all variables defined in the `request`. + /// - parameter operationName: The name of the operation to use if `request` contains multiple possible operations. Can be omitted if `request` contains only one operation. + /// + /// - throws: throws GraphQLError if an error occurs while parsing the `request`. + /// + /// - returns: returns a SubscriptionResult containing the subscription observable inside the key `observable` and any validation or execution errors inside the key `errors`. The + /// value of `observable` might be `null` if, for example, the query is invalid. It's not possible to have both `observable` and `errors`. The observable payloads are + /// GraphQLResults which contain the result of the query inside the key `data` and any validation or execution errors inside the key `errors`. The value of `data` might be `null`. + /// It's possible to have both `data` and `errors` if an error occurs only in a specific field. If that happens the value of that field will be `null` and there + /// will be an error inside `errors` specifying the reason for the failure and the path of the failed field. + public func graphqlSubscribe( + queryStrategy: QueryFieldExecutionStrategy = SerialFieldExecutionStrategy(), + mutationStrategy: MutationFieldExecutionStrategy = SerialFieldExecutionStrategy(), + subscriptionStrategy: SubscriptionFieldExecutionStrategy = SerialFieldExecutionStrategy(), + instrumentation: Instrumentation = NoOpInstrumentation, + schema: GraphQLSchema, + request: String, + rootValue: Any = (), + context: Any = (), + eventLoopGroup: EventLoopGroup, + variableValues: [String: Map] = [:], + operationName: String? = nil + ) async throws -> SubscriptionResult { + return try await graphqlSubscribe( + queryStrategy: queryStrategy, + mutationStrategy: mutationStrategy, + subscriptionStrategy: subscriptionStrategy, + instrumentation: instrumentation, + schema: schema, + request: request, + rootValue: rootValue, + context: context, + eventLoopGroup: eventLoopGroup, + variableValues: variableValues, + operationName: operationName + ).get() + } #endif diff --git a/Sources/GraphQL/GraphQLRequest.swift b/Sources/GraphQL/GraphQLRequest.swift index 0e4eced3..9cb973f1 100644 --- a/Sources/GraphQL/GraphQLRequest.swift +++ b/Sources/GraphQL/GraphQLRequest.swift @@ -5,21 +5,21 @@ public struct GraphQLRequest: Equatable, Codable { public var query: String public var operationName: String? public var variables: [String: Map] - + public init(query: String, operationName: String? = nil, variables: [String: Map] = [:]) { self.query = query self.operationName = operationName self.variables = variables } - + // To handle decoding with a default of variables = [] public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - self.query = try container.decode(String.self, forKey: .query) - self.operationName = try container.decodeIfPresent(String.self, forKey: .operationName) - self.variables = try container.decodeIfPresent([String: Map].self, forKey: .variables) ?? [:] + query = try container.decode(String.self, forKey: .query) + operationName = try container.decodeIfPresent(String.self, forKey: .operationName) + variables = try container.decodeIfPresent([String: Map].self, forKey: .variables) ?? [:] } - + /// Boolean indicating if the GraphQL request is a subscription operation. /// This operation performs an entire AST parse on the GraphQL request, so consider /// performance when calling multiple times. @@ -28,7 +28,7 @@ public struct GraphQLRequest: Equatable, Codable { public func isSubscription() throws -> Bool { let documentAST = try GraphQL.parse( instrumentation: NoOpInstrumentation, - source: Source(body: self.query, name: "GraphQL request") + source: Source(body: query, name: "GraphQL request") ) let firstOperation = documentAST.definitions.compactMap { $0 as? OperationDefinition }.first guard let operationType = firstOperation?.operation else { @@ -37,4 +37,3 @@ public struct GraphQLRequest: Equatable, Codable { return operationType == .subscription } } - diff --git a/Sources/GraphQL/Instrumentation/DispatchQueueInstrumentationWrapper.swift b/Sources/GraphQL/Instrumentation/DispatchQueueInstrumentationWrapper.swift index 26ca4837..4773427b 100644 --- a/Sources/GraphQL/Instrumentation/DispatchQueueInstrumentationWrapper.swift +++ b/Sources/GraphQL/Instrumentation/DispatchQueueInstrumentationWrapper.swift @@ -7,18 +7,27 @@ import NIO /// 1. Allows a non thread safe Instrumentation implementation to be used along side a multithreaded execution strategy /// 2. Allows slow or heavy instrumentation processing to happen outside of the current query execution public class DispatchQueueInstrumentationWrapper: Instrumentation { - - let instrumentation:Instrumentation + let instrumentation: Instrumentation let dispatchQueue: DispatchQueue let dispatchGroup: DispatchGroup? - public init(_ instrumentation: Instrumentation, label: String = "GraphQL instrumentation wrapper", qos: DispatchQoS = .utility, attributes: DispatchQueue.Attributes = [], dispatchGroup: DispatchGroup? = nil ) { + public init( + _ instrumentation: Instrumentation, + label: String = "GraphQL instrumentation wrapper", + qos: DispatchQoS = .utility, + attributes: DispatchQueue.Attributes = [], + dispatchGroup: DispatchGroup? = nil + ) { self.instrumentation = instrumentation - self.dispatchQueue = DispatchQueue(label: label, qos: qos, attributes: attributes) + dispatchQueue = DispatchQueue(label: label, qos: qos, attributes: attributes) self.dispatchGroup = dispatchGroup } - public init(_ instrumentation: Instrumentation, dispatchQueue: DispatchQueue, dispatchGroup: DispatchGroup? = nil ) { + public init( + _ instrumentation: Instrumentation, + dispatchQueue: DispatchQueue, + dispatchGroup: DispatchGroup? = nil + ) { self.instrumentation = instrumentation self.dispatchQueue = dispatchQueue self.dispatchGroup = dispatchGroup @@ -28,29 +37,103 @@ public class DispatchQueueInstrumentationWrapper: Instrumentation { return instrumentation.now } - public func queryParsing(processId: Int, threadId: Int, started: DispatchTime, finished: DispatchTime, source: Source, result: Result) { + public func queryParsing( + processId: Int, + threadId: Int, + started: DispatchTime, + finished: DispatchTime, + source: Source, + result: Result + ) { dispatchQueue.async(group: dispatchGroup) { - self.instrumentation.queryParsing(processId: processId, threadId: threadId, started: started, finished: finished, source: source, result: result) + self.instrumentation.queryParsing( + processId: processId, + threadId: threadId, + started: started, + finished: finished, + source: source, + result: result + ) } } - public func queryValidation(processId: Int, threadId: Int, started: DispatchTime, finished: DispatchTime, schema: GraphQLSchema, document: Document, errors: [GraphQLError]) { + public func queryValidation( + processId: Int, + threadId: Int, + started: DispatchTime, + finished: DispatchTime, + schema: GraphQLSchema, + document: Document, + errors: [GraphQLError] + ) { dispatchQueue.async(group: dispatchGroup) { - self.instrumentation.queryValidation(processId: processId, threadId: threadId, started: started, finished: finished, schema: schema, document: document, errors: errors) + self.instrumentation.queryValidation( + processId: processId, + threadId: threadId, + started: started, + finished: finished, + schema: schema, + document: document, + errors: errors + ) } } - public func operationExecution(processId: Int, threadId: Int, started: DispatchTime, finished: DispatchTime, schema: GraphQLSchema, document: Document, rootValue: Any, eventLoopGroup: EventLoopGroup, variableValues: [String : Map], operation: OperationDefinition?, errors: [GraphQLError], result: Map) { + public func operationExecution( + processId: Int, + threadId: Int, + started: DispatchTime, + finished: DispatchTime, + schema: GraphQLSchema, + document: Document, + rootValue: Any, + eventLoopGroup: EventLoopGroup, + variableValues: [String: Map], + operation: OperationDefinition?, + errors: [GraphQLError], + result: Map + ) { dispatchQueue.async(group: dispatchGroup) { - self.instrumentation.operationExecution(processId: processId, threadId: threadId, started: started, finished: finished, schema: schema, document: document, rootValue: rootValue, eventLoopGroup: eventLoopGroup, variableValues: variableValues, operation: operation, errors: errors, result: result) + self.instrumentation.operationExecution( + processId: processId, + threadId: threadId, + started: started, + finished: finished, + schema: schema, + document: document, + rootValue: rootValue, + eventLoopGroup: eventLoopGroup, + variableValues: variableValues, + operation: operation, + errors: errors, + result: result + ) } } - public func fieldResolution(processId: Int, threadId: Int, started: DispatchTime, finished: DispatchTime, source: Any, args: Map, eventLoopGroup: EventLoopGroup, info: GraphQLResolveInfo, result: Result, Error>) { + public func fieldResolution( + processId: Int, + threadId: Int, + started: DispatchTime, + finished: DispatchTime, + source: Any, + args: Map, + eventLoopGroup: EventLoopGroup, + info: GraphQLResolveInfo, + result: Result, Error> + ) { dispatchQueue.async(group: dispatchGroup) { - self.instrumentation.fieldResolution(processId: processId, threadId: threadId, started: started, finished: finished, source: source, args: args, eventLoopGroup: eventLoopGroup, info: info, result: result) + self.instrumentation.fieldResolution( + processId: processId, + threadId: threadId, + started: started, + finished: finished, + source: source, + args: args, + eventLoopGroup: eventLoopGroup, + info: info, + result: result + ) } } - } - diff --git a/Sources/GraphQL/Instrumentation/Instrumentation.swift b/Sources/GraphQL/Instrumentation/Instrumentation.swift index 88db2e22..c80e0051 100644 --- a/Sources/GraphQL/Instrumentation/Instrumentation.swift +++ b/Sources/GraphQL/Instrumentation/Instrumentation.swift @@ -1,12 +1,11 @@ -import Foundation import Dispatch +import Foundation import NIO /// Provides the capability to instrument the execution steps of a GraphQL query. /// /// A working implementation of `now` is also provided by default. public protocol Instrumentation { - var now: DispatchTime { get } func queryParsing( @@ -54,11 +53,10 @@ public protocol Instrumentation { info: GraphQLResolveInfo, result: Result, Error> ) - } -extension Instrumentation { - public var now: DispatchTime { +public extension Instrumentation { + var now: DispatchTime { return DispatchTime.now() } } @@ -76,16 +74,53 @@ func processId() -> Int { } /// Does nothing -public let NoOpInstrumentation:Instrumentation = noOpInstrumentation() +public let NoOpInstrumentation: Instrumentation = noOpInstrumentation() struct noOpInstrumentation: Instrumentation { public let now = DispatchTime(uptimeNanoseconds: 0) - public func queryParsing(processId: Int, threadId: Int, started: DispatchTime, finished: DispatchTime, source: Source, result: Result) { - } - public func queryValidation(processId: Int, threadId: Int, started: DispatchTime, finished: DispatchTime, schema: GraphQLSchema, document: Document, errors: [GraphQLError]) { - } - public func operationExecution(processId: Int, threadId: Int, started: DispatchTime, finished: DispatchTime, schema: GraphQLSchema, document: Document, rootValue: Any, eventLoopGroup: EventLoopGroup, variableValues: [String : Map], operation: OperationDefinition?, errors: [GraphQLError], result: Map) { - } - public func fieldResolution(processId: Int, threadId: Int, started: DispatchTime, finished: DispatchTime, source: Any, args: Map, eventLoopGroup: EventLoopGroup, info: GraphQLResolveInfo, result: Result, Error>) { - } + public func queryParsing( + processId _: Int, + threadId _: Int, + started _: DispatchTime, + finished _: DispatchTime, + source _: Source, + result _: Result + ) {} + + public func queryValidation( + processId _: Int, + threadId _: Int, + started _: DispatchTime, + finished _: DispatchTime, + schema _: GraphQLSchema, + document _: Document, + errors _: [GraphQLError] + ) {} + + public func operationExecution( + processId _: Int, + threadId _: Int, + started _: DispatchTime, + finished _: DispatchTime, + schema _: GraphQLSchema, + document _: Document, + rootValue _: Any, + eventLoopGroup _: EventLoopGroup, + variableValues _: [String: Map], + operation _: OperationDefinition?, + errors _: [GraphQLError], + result _: Map + ) {} + + public func fieldResolution( + processId _: Int, + threadId _: Int, + started _: DispatchTime, + finished _: DispatchTime, + source _: Any, + args _: Map, + eventLoopGroup _: EventLoopGroup, + info _: GraphQLResolveInfo, + result _: Result, Error> + ) {} } diff --git a/Sources/GraphQL/Language/AST.swift b/Sources/GraphQL/Language/AST.swift index 51ba839f..69d68497 100644 --- a/Sources/GraphQL/Language/AST.swift +++ b/Sources/GraphQL/Language/AST.swift @@ -3,7 +3,6 @@ * identify the region of the source from which the AST derived. */ public struct Location { - /** * The character offset at which this Node begins. */ @@ -34,8 +33,8 @@ public struct Location { * Represents a range of characters represented by a lexical token * within a Source. */ -final public class Token { - public enum Kind : String, CustomStringConvertible { +public final class Token { + public enum Kind: String, CustomStringConvertible { case sof = "" case eof = "" case bang = "!" @@ -96,7 +95,16 @@ final public class Token { public internal(set) weak var prev: Token? public internal(set) var next: Token? - init(kind: Kind, start: Int, end: Int, line: Int, column: Int, value: String? = nil, prev: Token? = nil, next: Token? = nil) { + init( + kind: Kind, + start: Int, + end: Int, + line: Int, + column: Int, + value: String? = nil, + prev: Token? = nil, + next: Token? = nil + ) { self.kind = kind self.start = start self.end = end @@ -108,18 +116,18 @@ final public class Token { } } -extension Token : Equatable { +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 && + 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 + lhs.value == rhs.value } } -extension Token : CustomStringConvertible { +extension Token: CustomStringConvertible { public var description: String { var description = "Token(kind: \(kind)" @@ -162,52 +170,50 @@ public protocol Node { func set(value: Node?, key: String) } -extension Node { - public func get(key: String) -> NodeResult? { +public extension Node { + func get(key _: String) -> NodeResult? { return nil } - public func set(value: Node?, key: String) { - - } -} - -extension Name : Node {} -extension Document : Node {} -extension OperationDefinition : Node {} -extension VariableDefinition : Node {} -extension Variable : Node {} -extension SelectionSet : Node {} -extension Field : Node {} -extension Argument : Node {} -extension FragmentSpread : Node {} -extension InlineFragment : Node {} -extension FragmentDefinition : Node {} -extension IntValue : Node {} -extension FloatValue : Node {} -extension StringValue : Node {} -extension BooleanValue : Node {} -extension EnumValue : Node {} -extension ListValue : Node {} -extension ObjectValue : Node {} -extension ObjectField : Node {} -extension Directive : Node {} -extension NamedType : Node {} -extension ListType : Node {} -extension NonNullType : Node {} -extension SchemaDefinition : Node {} -extension OperationTypeDefinition : Node {} -extension ScalarTypeDefinition : Node {} -extension ObjectTypeDefinition : Node {} -extension FieldDefinition : Node {} -extension InputValueDefinition : Node {} -extension InterfaceTypeDefinition : Node {} -extension UnionTypeDefinition : Node {} -extension EnumTypeDefinition : Node {} -extension EnumValueDefinition : Node {} -extension InputObjectTypeDefinition : Node {} -extension TypeExtensionDefinition : Node {} -extension DirectiveDefinition : Node {} + func set(value _: Node?, key _: String) {} +} + +extension Name: Node {} +extension Document: Node {} +extension OperationDefinition: Node {} +extension VariableDefinition: Node {} +extension Variable: Node {} +extension SelectionSet: Node {} +extension Field: Node {} +extension Argument: Node {} +extension FragmentSpread: Node {} +extension InlineFragment: Node {} +extension FragmentDefinition: Node {} +extension IntValue: Node {} +extension FloatValue: Node {} +extension StringValue: Node {} +extension BooleanValue: Node {} +extension EnumValue: Node {} +extension ListValue: Node {} +extension ObjectValue: Node {} +extension ObjectField: Node {} +extension Directive: Node {} +extension NamedType: Node {} +extension ListType: Node {} +extension NonNullType: Node {} +extension SchemaDefinition: Node {} +extension OperationTypeDefinition: Node {} +extension ScalarTypeDefinition: Node {} +extension ObjectTypeDefinition: Node {} +extension FieldDefinition: Node {} +extension InputValueDefinition: Node {} +extension InterfaceTypeDefinition: Node {} +extension UnionTypeDefinition: Node {} +extension EnumTypeDefinition: Node {} +extension EnumValueDefinition: Node {} +extension InputObjectTypeDefinition: Node {} +extension TypeExtensionDefinition: Node {} +extension DirectiveDefinition: Node {} public final class Name { public let kind: Kind = .name @@ -220,7 +226,7 @@ public final class Name { } } -extension Name : Equatable { +extension Name: Equatable { public static func == (lhs: Name, rhs: Name) -> Bool { return lhs.value == rhs.value } @@ -249,7 +255,7 @@ public final class Document { } } -extension Document : Equatable { +extension Document: Equatable { public static func == (lhs: Document, rhs: Document) -> Bool { guard lhs.definitions.count == rhs.definitions.count else { return false @@ -265,9 +271,9 @@ extension Document : Equatable { } } -public protocol Definition : Node {} -extension OperationDefinition : Definition {} -extension FragmentDefinition : Definition {} +public protocol Definition: Node {} +extension OperationDefinition: Definition {} +extension FragmentDefinition: Definition {} public func == (lhs: Definition, rhs: Definition) -> Bool { switch lhs { @@ -290,11 +296,11 @@ public func == (lhs: Definition, rhs: Definition) -> Bool { return false } -public enum OperationType : String { - case query = "query" - case mutation = "mutation" +public enum OperationType: String { + case query + case mutation // Note: subscription is an experimental non-spec addition. - case subscription = "subscription" + case subscription } public final class OperationDefinition { @@ -306,7 +312,14 @@ public final class OperationDefinition { public let directives: [Directive] public let selectionSet: SelectionSet - init(loc: Location? = nil, operation: OperationType, name: Name? = nil, variableDefinitions: [VariableDefinition] = [], directives: [Directive] = [], selectionSet: SelectionSet) { + init( + loc: Location? = nil, + operation: OperationType, + name: Name? = nil, + variableDefinitions: [VariableDefinition] = [], + directives: [Directive] = [], + selectionSet: SelectionSet + ) { self.loc = loc self.operation = operation self.name = name @@ -318,7 +331,7 @@ public final class OperationDefinition { public func get(key: String) -> NodeResult? { switch key { case "name": - return name.map({ .node($0) }) + return name.map { .node($0) } case "variableDefinitions": guard !variableDefinitions.isEmpty else { return nil @@ -337,7 +350,7 @@ public final class OperationDefinition { } } -extension OperationDefinition : Hashable { +extension OperationDefinition: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } @@ -372,14 +385,14 @@ public final class VariableDefinition { case "type": return .node(type) case "defaultValue": - return defaultValue.map({ .node($0) }) + return defaultValue.map { .node($0) } default: return nil } } } -extension VariableDefinition : Equatable { +extension VariableDefinition: Equatable { public static func == (lhs: VariableDefinition, rhs: VariableDefinition) -> Bool { guard lhs.variable == rhs.variable else { return false @@ -389,7 +402,7 @@ extension VariableDefinition : Equatable { return false } - if lhs.defaultValue == nil && rhs.defaultValue == nil { + if lhs.defaultValue == nil, rhs.defaultValue == nil { return true } @@ -421,8 +434,8 @@ public final class Variable { } } -extension Variable : Equatable { - static public func == (lhs: Variable, rhs: Variable) -> Bool { +extension Variable: Equatable { + public static func == (lhs: Variable, rhs: Variable) -> Bool { return lhs.name == rhs.name } } @@ -450,7 +463,7 @@ public final class SelectionSet { } } -extension SelectionSet : Hashable { +extension SelectionSet: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } @@ -470,10 +483,10 @@ extension SelectionSet : Hashable { } } -public protocol Selection : Node {} -extension Field : Selection {} -extension FragmentSpread : Selection {} -extension InlineFragment : Selection {} +public protocol Selection: Node {} +extension Field: Selection {} +extension FragmentSpread: Selection {} +extension InlineFragment: Selection {} public func == (lhs: Selection, rhs: Selection) -> Bool { switch lhs { @@ -505,7 +518,14 @@ public final class Field { public let directives: [Directive] public let selectionSet: SelectionSet? - init(loc: Location? = nil, alias: Name? = nil, name: Name, arguments: [Argument] = [], directives: [Directive] = [], selectionSet: SelectionSet? = nil) { + init( + loc: Location? = nil, + alias: Name? = nil, + name: Name, + arguments: [Argument] = [], + directives: [Directive] = [], + selectionSet: SelectionSet? = nil + ) { self.loc = loc self.alias = alias self.name = name @@ -517,7 +537,7 @@ public final class Field { public func get(key: String) -> NodeResult? { switch key { case "alias": - return alias.map({ .node($0) }) + return alias.map { .node($0) } case "name": return .node(name) case "arguments": @@ -531,14 +551,14 @@ public final class Field { } return .array(directives) case "selectionSet": - return selectionSet.map({ .node($0) }) + return selectionSet.map { .node($0) } default: return nil } } } -extension Field : Equatable { +extension Field: Equatable { public static func == (lhs: Field, rhs: Field) -> Bool { return lhs.alias == rhs.alias && lhs.name == rhs.name && @@ -572,16 +592,16 @@ public final class Argument { } } -extension Argument : Equatable { +extension Argument: Equatable { public static func == (lhs: Argument, rhs: Argument) -> Bool { return lhs.name == rhs.name && lhs.value == rhs.value } } -public protocol Fragment : Selection {} -extension FragmentSpread : Fragment {} -extension InlineFragment : Fragment {} +public protocol Fragment: Selection {} +extension FragmentSpread: Fragment {} +extension InlineFragment: Fragment {} public final class FragmentSpread { public let kind: Kind = .fragmentSpread @@ -610,7 +630,7 @@ public final class FragmentSpread { } } -extension FragmentSpread : Equatable { +extension FragmentSpread: Equatable { public static func == (lhs: FragmentSpread, rhs: FragmentSpread) -> Bool { return lhs.name == rhs.name && lhs.directives == rhs.directives @@ -621,13 +641,13 @@ public protocol HasTypeCondition { func getTypeCondition() -> NamedType? } -extension InlineFragment : HasTypeCondition { +extension InlineFragment: HasTypeCondition { public func getTypeCondition() -> NamedType? { return typeCondition } } -extension FragmentDefinition : HasTypeCondition { +extension FragmentDefinition: HasTypeCondition { public func getTypeCondition() -> NamedType? { return typeCondition } @@ -640,7 +660,12 @@ public final class InlineFragment { public let directives: [Directive] public let selectionSet: SelectionSet - init(loc: Location? = nil, typeCondition: NamedType? = nil, directives: [Directive] = [], selectionSet: SelectionSet) { + init( + loc: Location? = nil, + typeCondition: NamedType? = nil, + directives: [Directive] = [], + selectionSet: SelectionSet + ) { self.loc = loc self.typeCondition = typeCondition self.directives = directives @@ -648,11 +673,11 @@ public final class InlineFragment { } } -extension InlineFragment { - public func get(key: String) -> NodeResult? { +public extension InlineFragment { + func get(key: String) -> NodeResult? { switch key { case "typeCondition": - return typeCondition.map({ .node($0) }) + return typeCondition.map { .node($0) } case "directives": guard !directives.isEmpty else { return nil @@ -666,11 +691,11 @@ extension InlineFragment { } } -extension InlineFragment : Equatable { +extension InlineFragment: Equatable { public static func == (lhs: InlineFragment, rhs: InlineFragment) -> Bool { return lhs.typeCondition == rhs.typeCondition && - lhs.directives == rhs.directives && - lhs.selectionSet == rhs.selectionSet + lhs.directives == rhs.directives && + lhs.selectionSet == rhs.selectionSet } } @@ -682,7 +707,13 @@ public final class FragmentDefinition { public let directives: [Directive] public let selectionSet: SelectionSet - init(loc: Location? = nil, name: Name, typeCondition: NamedType, directives: [Directive] = [], selectionSet: SelectionSet) { + init( + loc: Location? = nil, + name: Name, + typeCondition: NamedType, + directives: [Directive] = [], + selectionSet: SelectionSet + ) { self.loc = loc self.name = name self.typeCondition = typeCondition @@ -709,29 +740,29 @@ public final class FragmentDefinition { } } -extension FragmentDefinition : Hashable { +extension FragmentDefinition: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } 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 + lhs.typeCondition == rhs.typeCondition && + lhs.directives == rhs.directives && + lhs.selectionSet == rhs.selectionSet } } -public protocol Value : Node {} -extension Variable : Value {} -extension IntValue : Value {} -extension FloatValue : Value {} -extension StringValue : Value {} -extension BooleanValue : Value {} -extension NullValue : Value {} -extension EnumValue : Value {} -extension ListValue : Value {} -extension ObjectValue : Value {} +public protocol Value: Node {} +extension Variable: Value {} +extension IntValue: Value {} +extension FloatValue: Value {} +extension StringValue: Value {} +extension BooleanValue: Value {} +extension NullValue: Value {} +extension EnumValue: Value {} +extension ListValue: Value {} +extension ObjectValue: Value {} public func == (lhs: Value, rhs: Value) -> Bool { switch lhs { @@ -789,7 +820,7 @@ public final class IntValue { } } -extension IntValue : Equatable { +extension IntValue: Equatable { public static func == (lhs: IntValue, rhs: IntValue) -> Bool { return lhs.value == rhs.value } @@ -806,7 +837,7 @@ public final class FloatValue { } } -extension FloatValue : Equatable { +extension FloatValue: Equatable { public static func == (lhs: FloatValue, rhs: FloatValue) -> Bool { return lhs.value == rhs.value } @@ -825,7 +856,7 @@ public final class StringValue { } } -extension StringValue : Equatable { +extension StringValue: Equatable { public static func == (lhs: StringValue, rhs: StringValue) -> Bool { return lhs.value == rhs.value && lhs.block == rhs.block } @@ -842,7 +873,7 @@ public final class BooleanValue { } } -extension BooleanValue : Equatable { +extension BooleanValue: Equatable { public static func == (lhs: BooleanValue, rhs: BooleanValue) -> Bool { return lhs.value == rhs.value } @@ -857,8 +888,8 @@ public final class NullValue { } } -extension NullValue : Equatable { - public static func == (lhs: NullValue, rhs: NullValue) -> Bool { +extension NullValue: Equatable { + public static func == (_: NullValue, _: NullValue) -> Bool { return true } } @@ -874,7 +905,7 @@ public final class EnumValue { } } -extension EnumValue : Equatable { +extension EnumValue: Equatable { public static func == (lhs: EnumValue, rhs: EnumValue) -> Bool { return lhs.value == rhs.value } @@ -891,7 +922,7 @@ public final class ListValue { } } -extension ListValue : Equatable { +extension ListValue: Equatable { public static func == (lhs: ListValue, rhs: ListValue) -> Bool { guard lhs.values.count == rhs.values.count else { return false @@ -918,7 +949,7 @@ public final class ObjectValue { } } -extension ObjectValue : Equatable { +extension ObjectValue: Equatable { public static func == (lhs: ObjectValue, rhs: ObjectValue) -> Bool { return lhs.fields == rhs.fields } @@ -937,7 +968,7 @@ public final class ObjectField { } } -extension ObjectField : Equatable { +extension ObjectField: Equatable { public static func == (lhs: ObjectField, rhs: ObjectField) -> Bool { return lhs.name == rhs.name && lhs.value == rhs.value @@ -957,17 +988,17 @@ public final class Directive { } } -extension Directive : Equatable { +extension Directive: Equatable { public static func == (lhs: Directive, rhs: Directive) -> Bool { return lhs.name == rhs.name && lhs.arguments == rhs.arguments } } -public protocol Type : Node {} -extension NamedType : Type {} -extension ListType : Type {} -extension NonNullType : Type {} +public protocol Type: Node {} +extension NamedType: Type {} +extension ListType: Type {} +extension NonNullType: Type {} public func == (lhs: Type, rhs: Type) -> Bool { switch lhs { @@ -1010,7 +1041,7 @@ public final class NamedType { } } -extension NamedType : Equatable { +extension NamedType: Equatable { public static func == (lhs: NamedType, rhs: NamedType) -> Bool { return lhs.name == rhs.name } @@ -1027,15 +1058,15 @@ public final class ListType { } } -extension ListType : Equatable { +extension ListType: Equatable { public static func == (lhs: ListType, rhs: ListType) -> Bool { return lhs.type == rhs.type } } -public protocol NonNullableType : Type {} -extension ListType : NonNullableType {} -extension NamedType : NonNullableType {} +public protocol NonNullableType: Type {} +extension ListType: NonNullableType {} +extension NamedType: NonNullableType {} public final class NonNullType { public let kind: Kind = .nonNullType @@ -1057,7 +1088,7 @@ public final class NonNullType { } } -extension NonNullType : Equatable { +extension NonNullType: Equatable { public static func == (lhs: NonNullType, rhs: NonNullType) -> Bool { return lhs.type == rhs.type } @@ -1065,10 +1096,10 @@ extension NonNullType : Equatable { // Type System Definition // experimental non-spec addition. -public protocol TypeSystemDefinition : Definition {} -extension SchemaDefinition : TypeSystemDefinition {} -extension TypeExtensionDefinition : TypeSystemDefinition {} -extension DirectiveDefinition : TypeSystemDefinition {} +public protocol TypeSystemDefinition: Definition {} +extension SchemaDefinition: TypeSystemDefinition {} +extension TypeExtensionDefinition: TypeSystemDefinition {} +extension DirectiveDefinition: TypeSystemDefinition {} public func == (lhs: TypeSystemDefinition, rhs: TypeSystemDefinition) -> Bool { switch lhs { @@ -1102,7 +1133,12 @@ public final class SchemaDefinition { public let directives: [Directive] public let operationTypes: [OperationTypeDefinition] - init(loc: Location? = nil, description: StringValue? = nil, directives: [Directive], operationTypes: [OperationTypeDefinition]) { + init( + loc: Location? = nil, + description: StringValue? = nil, + directives: [Directive], + operationTypes: [OperationTypeDefinition] + ) { self.loc = loc self.description = description self.directives = directives @@ -1110,7 +1146,7 @@ public final class SchemaDefinition { } } -extension SchemaDefinition : Equatable { +extension SchemaDefinition: Equatable { public static func == (lhs: SchemaDefinition, rhs: SchemaDefinition) -> Bool { return lhs.description == rhs.description && lhs.directives == rhs.directives && @@ -1131,20 +1167,20 @@ public final class OperationTypeDefinition { } } -extension OperationTypeDefinition : Equatable { +extension OperationTypeDefinition: Equatable { public static func == (lhs: OperationTypeDefinition, rhs: OperationTypeDefinition) -> Bool { return lhs.operation == rhs.operation && lhs.type == rhs.type } } -public protocol TypeDefinition : TypeSystemDefinition {} -extension ScalarTypeDefinition : TypeDefinition {} -extension ObjectTypeDefinition : TypeDefinition {} -extension InterfaceTypeDefinition : TypeDefinition {} -extension UnionTypeDefinition : TypeDefinition {} -extension EnumTypeDefinition : TypeDefinition {} -extension InputObjectTypeDefinition : TypeDefinition {} +public protocol TypeDefinition: TypeSystemDefinition {} +extension ScalarTypeDefinition: TypeDefinition {} +extension ObjectTypeDefinition: TypeDefinition {} +extension InterfaceTypeDefinition: TypeDefinition {} +extension UnionTypeDefinition: TypeDefinition {} +extension EnumTypeDefinition: TypeDefinition {} +extension InputObjectTypeDefinition: TypeDefinition {} public func == (lhs: TypeDefinition, rhs: TypeDefinition) -> Bool { switch lhs { @@ -1186,7 +1222,12 @@ public final class ScalarTypeDefinition { public let name: Name public let directives: [Directive] - init(loc: Location? = nil, description: StringValue? = nil, name: Name, directives: [Directive] = []) { + init( + loc: Location? = nil, + description: StringValue? = nil, + name: Name, + directives: [Directive] = [] + ) { self.loc = loc self.description = description self.name = name @@ -1194,7 +1235,7 @@ public final class ScalarTypeDefinition { } } -extension ScalarTypeDefinition : Equatable { +extension ScalarTypeDefinition: Equatable { public static func == (lhs: ScalarTypeDefinition, rhs: ScalarTypeDefinition) -> Bool { return lhs.description == rhs.description && lhs.name == rhs.name && @@ -1211,7 +1252,14 @@ public final class ObjectTypeDefinition { public let directives: [Directive] public let fields: [FieldDefinition] - init(loc: Location? = nil, description: StringValue? = nil, name: Name, interfaces: [NamedType] = [], directives: [Directive] = [], fields: [FieldDefinition] = []) { + init( + loc: Location? = nil, + description: StringValue? = nil, + name: Name, + interfaces: [NamedType] = [], + directives: [Directive] = [], + fields: [FieldDefinition] = [] + ) { self.loc = loc self.description = description self.name = name @@ -1221,7 +1269,7 @@ public final class ObjectTypeDefinition { } } -extension ObjectTypeDefinition : Equatable { +extension ObjectTypeDefinition: Equatable { public static func == (lhs: ObjectTypeDefinition, rhs: ObjectTypeDefinition) -> Bool { return lhs.description == rhs.description && lhs.name == rhs.name && @@ -1240,7 +1288,14 @@ public final class FieldDefinition { public let type: Type public let directives: [Directive] - init(loc: Location? = nil, description: StringValue? = nil, name: Name, arguments: [InputValueDefinition] = [], type: Type, directives: [Directive] = []) { + init( + loc: Location? = nil, + description: StringValue? = nil, + name: Name, + arguments: [InputValueDefinition] = [], + type: Type, + directives: [Directive] = [] + ) { self.loc = loc self.description = description self.name = name @@ -1250,7 +1305,7 @@ public final class FieldDefinition { } } -extension FieldDefinition : Equatable { +extension FieldDefinition: Equatable { public static func == (lhs: FieldDefinition, rhs: FieldDefinition) -> Bool { return lhs.description == rhs.description && lhs.name == rhs.name && @@ -1269,7 +1324,14 @@ public final class InputValueDefinition { public let defaultValue: Value? public let directives: [Directive] - init(loc: Location? = nil, description: StringValue? = nil, name: Name, type: Type, defaultValue: Value? = nil, directives: [Directive] = []) { + init( + loc: Location? = nil, + description: StringValue? = nil, + name: Name, + type: Type, + defaultValue: Value? = nil, + directives: [Directive] = [] + ) { self.loc = loc self.description = description self.name = name @@ -1279,7 +1341,7 @@ public final class InputValueDefinition { } } -extension InputValueDefinition : Equatable { +extension InputValueDefinition: Equatable { public static func == (lhs: InputValueDefinition, rhs: InputValueDefinition) -> Bool { guard lhs.name == rhs.name else { return false @@ -1293,14 +1355,14 @@ extension InputValueDefinition : Equatable { return false } - if lhs.defaultValue == nil && rhs.defaultValue == nil { + if lhs.defaultValue == nil, rhs.defaultValue == nil { return true } guard let l = lhs.defaultValue, let r = rhs.defaultValue else { return false } - + return l == r } } @@ -1331,7 +1393,7 @@ public final class InterfaceTypeDefinition { } } -extension InterfaceTypeDefinition : Equatable { +extension InterfaceTypeDefinition: Equatable { public static func == (lhs: InterfaceTypeDefinition, rhs: InterfaceTypeDefinition) -> Bool { return lhs.description == rhs.description && lhs.name == rhs.name && @@ -1348,7 +1410,13 @@ public final class UnionTypeDefinition { public let directives: [Directive] public let types: [NamedType] - init(loc: Location? = nil, description: StringValue? = nil, name: Name, directives: [Directive] = [], types: [NamedType]) { + init( + loc: Location? = nil, + description: StringValue? = nil, + name: Name, + directives: [Directive] = [], + types: [NamedType] + ) { self.loc = loc self.description = description self.name = name @@ -1357,7 +1425,7 @@ public final class UnionTypeDefinition { } } -extension UnionTypeDefinition : Equatable { +extension UnionTypeDefinition: Equatable { public static func == (lhs: UnionTypeDefinition, rhs: UnionTypeDefinition) -> Bool { return lhs.description == rhs.description && lhs.name == rhs.name && @@ -1374,7 +1442,13 @@ public final class EnumTypeDefinition { public let directives: [Directive] public let values: [EnumValueDefinition] - init(loc: Location? = nil, description: StringValue? = nil, name: Name, directives: [Directive] = [], values: [EnumValueDefinition]) { + init( + loc: Location? = nil, + description: StringValue? = nil, + name: Name, + directives: [Directive] = [], + values: [EnumValueDefinition] + ) { self.loc = loc self.description = description self.name = name @@ -1383,7 +1457,7 @@ public final class EnumTypeDefinition { } } -extension EnumTypeDefinition : Equatable { +extension EnumTypeDefinition: Equatable { public static func == (lhs: EnumTypeDefinition, rhs: EnumTypeDefinition) -> Bool { return lhs.description == rhs.description && lhs.name == rhs.name && @@ -1399,7 +1473,12 @@ public final class EnumValueDefinition { public let name: Name public let directives: [Directive] - init(loc: Location? = nil, description: StringValue? = nil, name: Name, directives: [Directive] = []) { + init( + loc: Location? = nil, + description: StringValue? = nil, + name: Name, + directives: [Directive] = [] + ) { self.loc = loc self.description = description self.name = name @@ -1407,7 +1486,7 @@ public final class EnumValueDefinition { } } -extension EnumValueDefinition : Equatable { +extension EnumValueDefinition: Equatable { public static func == (lhs: EnumValueDefinition, rhs: EnumValueDefinition) -> Bool { return lhs.description == rhs.description && lhs.name == rhs.name && @@ -1423,7 +1502,13 @@ public final class InputObjectTypeDefinition { public let directives: [Directive] public let fields: [InputValueDefinition] - init(loc: Location? = nil, description: StringValue? = nil, name: Name, directives: [Directive] = [], fields: [InputValueDefinition]) { + init( + loc: Location? = nil, + description: StringValue? = nil, + name: Name, + directives: [Directive] = [], + fields: [InputValueDefinition] + ) { self.loc = loc self.description = description self.name = name @@ -1432,7 +1517,7 @@ public final class InputObjectTypeDefinition { } } -extension InputObjectTypeDefinition : Equatable { +extension InputObjectTypeDefinition: Equatable { public static func == (lhs: InputObjectTypeDefinition, rhs: InputObjectTypeDefinition) -> Bool { return lhs.description == rhs.description && lhs.name == rhs.name && @@ -1452,7 +1537,7 @@ public final class TypeExtensionDefinition { } } -extension TypeExtensionDefinition : Equatable { +extension TypeExtensionDefinition: Equatable { public static func == (lhs: TypeExtensionDefinition, rhs: TypeExtensionDefinition) -> Bool { return lhs.definition == rhs.definition } @@ -1465,8 +1550,14 @@ public final class DirectiveDefinition { public let name: Name public let arguments: [InputValueDefinition] public let locations: [Name] - - init(loc: Location? = nil, description: StringValue? = nil, name: Name, arguments: [InputValueDefinition] = [], locations: [Name]) { + + init( + loc: Location? = nil, + description: StringValue? = nil, + name: Name, + arguments: [InputValueDefinition] = [], + locations: [Name] + ) { self.loc = loc self.name = name self.description = description @@ -1475,7 +1566,7 @@ public final class DirectiveDefinition { } } -extension DirectiveDefinition : Equatable { +extension DirectiveDefinition: Equatable { public static func == (lhs: DirectiveDefinition, rhs: DirectiveDefinition) -> Bool { return lhs.description == rhs.description && lhs.name == rhs.name && diff --git a/Sources/GraphQL/Language/Lexer.swift b/Sources/GraphQL/Language/Lexer.swift index f476b26c..6e45463d 100644 --- a/Sources/GraphQL/Language/Lexer.swift +++ b/Sources/GraphQL/Language/Lexer.swift @@ -16,7 +16,7 @@ func createLexer(source: Source, noLocation: Bool = false) -> Lexer { value: nil ) - let lexer: Lexer = Lexer( + let lexer = Lexer( source: source, noLocation: noLocation, lastToken: startOfFileToken, @@ -78,45 +78,52 @@ final class Lexer { */ let advanceFunction: (Lexer) throws -> Token - init(source: Source, noLocation: Bool, lastToken: Token, token: Token, line: Int, lineStart: Int, advance: @escaping (Lexer) throws -> Token) { + init( + source: Source, + noLocation: Bool, + lastToken: Token, + token: Token, + line: Int, + lineStart: Int, + advance: @escaping (Lexer) throws -> Token + ) { self.source = source self.noLocation = noLocation self.lastToken = lastToken self.token = token self.line = line self.lineStart = lineStart - self.advanceFunction = advance + advanceFunction = advance } @discardableResult func advance() throws -> Token { return try advanceFunction(self) } - + /** * Looks ahead and returns the next non-ignored token, but does not change * the state of Lexer. */ func lookahead() throws -> Token { var startToken = token - let savedLine = self.line - let savedLineStart = self.lineStart - + let savedLine = line + let savedLineStart = lineStart + 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` // can potentially modify them and commment for `lookahead` says no lexer modification. // (the latter is true in the canonical js lexer also and is likely a bug) - self.line = savedLine - self.lineStart = savedLineStart - + line = savedLine + lineStart = savedLineStart + return startToken } } @@ -154,7 +161,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.. Token { } // SourceCharacter - if code < 0x0020 && code != 0x0009 && code != 0x000A && code != 0x000D { + if code < 0x0020, code != 0x0009, code != 0x000A, code != 0x000D { throw syntaxError( source: source, position: position, @@ -259,7 +266,7 @@ func readToken(lexer: Lexer, prev: Token) throws -> Token { ) // . case 46: - if body.charCode(at: position + 1) == 46 && body.charCode(at: position + 2) == 46 { + if body.charCode(at: position + 1) == 46, body.charCode(at: position + 2) == 46 { return Token( kind: .spread, start: position, @@ -350,13 +357,17 @@ func readToken(lexer: Lexer, prev: Token) throws -> Token { prev: prev ) // 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: + 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: return readName( source: source, position: position, line: line, col: col, - prev: prev) + prev: prev + ) // - 0-9 case 45, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57: return try readNumber( @@ -369,14 +380,18 @@ func readToken(lexer: Lexer, prev: Token) throws -> Token { ) // " case 34: - if body.charCode(at: position + 1) == 34 && - body.charCode(at: position + 2) == 34 { - return try readBlockString(lexer: lexer, - source: source, - start: position, - line: line, - col: col, - prev: prev) + if + body.charCode(at: position + 1) == 34, + body.charCode(at: position + 2) == 34 + { + return try readBlockString( + lexer: lexer, + source: source, + start: position, + line: line, + col: col, + prev: prev + ) } return try readString( source: source, @@ -388,7 +403,7 @@ func readToken(lexer: Lexer, prev: Token) throws -> Token { default: break } - + throw syntaxError( source: source, position: position, @@ -409,7 +424,10 @@ 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.charCode(at: position + 2) == 191 { + 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 position += 1 @@ -448,7 +466,7 @@ func readComment(source: Source, start: Int, line: Int, col: Int, prev: Token) - code = body.charCode(at: position) // SourceCharacter but not LineTerminator - if let code = code, (code > 0x001F || code == 0x0009) { + if let code = code, code > 0x001F || code == 0x0009 { continue } else { break @@ -473,7 +491,14 @@ func readComment(source: Source, start: Int, line: Int, col: Int, prev: Token) - * Int: -?(0|[1-9][0-9]*) * Float: -?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)? */ -func readNumber(source: Source, start: Int, firstCode: UInt8, line: Int, col: Int, prev: Token) throws -> Token { +func readNumber( + source: Source, + start: Int, + firstCode: UInt8, + line: Int, + col: Int, + prev: Token +) throws -> Token { let body = source.body var code: UInt8? = firstCode var position = start @@ -488,7 +513,7 @@ func readNumber(source: Source, start: Int, firstCode: UInt8, line: Int, col: In position += 1 code = body.charCode(at: position) - if let c = code, c >= 48 && c <= 57 { + if let c = code, c >= 48, c <= 57 { throw syntaxError( source: source, position: position, @@ -556,10 +581,10 @@ 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 @@ -592,12 +617,12 @@ func readString(source: Source, start: Int, line: Int, col: Int, prev: Token) th currentCode = body.charCode(at: positionIndex) // not LineTerminator not Quote (") - guard let code = currentCode, code != 0x000A && code != 0x000D && code != 34 else { + guard let code = currentCode, code != 0x000A, code != 0x000D, code != 34 else { break } // SourceCharacter - if code < 0x0020 && code != 0x0009 { + if code < 0x0020, code != 0x0009 { throw syntaxError( source: source, position: body.offset(of: positionIndex), @@ -609,11 +634,11 @@ func readString(source: Source, start: Int, line: Int, col: Int, prev: Token) th positionIndex = body.utf8.index(after: positionIndex) if code == 92 { // \ - guard let chunk = String(body.utf8[chunkStartIndex.. Token { +func readBlockString( + lexer: Lexer, + 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 + 3) var chunkStartIndex = positionIndex var code: UInt8 = 0 var rawValue = "" - + while positionIndex < body.utf8.endIndex { code = body.utf8[positionIndex] - - if code == 34, - body.utf8.distance(from: positionIndex, to: body.utf8.endIndex) > 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.. 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 { throw syntaxError( source: source, position: body.offset(of: positionIndex), - description: "Unable to initialize String from chunk: \(body.utf8[chunkStartIndex.. 4, - body.utf8[body.utf8.index(positionIndex, offsetBy: 1)] == 34, - body.utf8[body.utf8.index(positionIndex, offsetBy: 2)] == 34, - body.utf8[body.utf8.index(positionIndex, offsetBy: 3)] == 34 { + } else if + code == 92, + body.utf8.distance(from: positionIndex, to: body.utf8.endIndex) > 4, + body.utf8[body.utf8.index(positionIndex, offsetBy: 1)] == 34, + body.utf8[body.utf8.index(positionIndex, offsetBy: 2)] == 34, + body.utf8[body.utf8.index(positionIndex, offsetBy: 3)] == 34 + { // escaped triple quote (\""") - - guard let chunk = String(body.utf8[chunkStartIndex.. String { - var lines = rawValue.utf8.split(omittingEmptySubsequences: false) { (code) -> Bool in - return code == 0x000A || code == 0x000D + var lines = rawValue.utf8.split(omittingEmptySubsequences: false) { code -> Bool in + code == 0x000A || code == 0x000D } - var commonIndent: Int = 0 + var commonIndent = 0 for idx in lines.indices { let line = lines[idx] @@ -846,7 +889,7 @@ func blockStringValue(rawValue: String) -> String { } } } - + var newLines: [String.UTF8View.SubSequence] = [] if commonIndent != 0 { for idx in lines.indices { @@ -860,11 +903,13 @@ func blockStringValue(rawValue: String) -> String { lines = newLines newLines.removeAll() } - + for idx in lines.indices { let line = lines[idx] - if newLines.count == 0, - line.firstIndex(where: { $0 != 0x0009 && $0 != 0x0020 }) == nil { + if + newLines.count == 0, + line.firstIndex(where: { $0 != 0x0009 && $0 != 0x0020 }) == nil + { continue } newLines.append(line) @@ -874,15 +919,17 @@ func blockStringValue(rawValue: String) -> String { newLines.removeAll() for idx in lines.indices.reversed() { let line = lines[idx] - if newLines.count == 0, - line.firstIndex(where: { $0 != 0x0009 && $0 != 0x0020 }) == nil { + if + newLines.count == 0, + line.firstIndex(where: { $0 != 0x0009 && $0 != 0x0020 }) == nil + { continue } newLines.insert(line, at: newLines.startIndex) } lines = newLines - var result: Substring = Substring() + var result = Substring() for idx in lines.indices { if idx == lines.startIndex { result.append(contentsOf: Substring(lines[idx])) @@ -935,13 +982,15 @@ func readName(source: Source, position: Int, line: Int, col: Int, prev: Token) - 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 - end += 1 + code == 95 || // _ + code >= 48 && code <= 57 || // 0-9 + code >= 65 && code <= 90 || // A-Z + code >= 97 && code <= 122 + { // a-z + end += 1 } return Token( diff --git a/Sources/GraphQL/Language/Location.swift b/Sources/GraphQL/Language/Location.swift index 1c7275c5..25f2950c 100644 --- a/Sources/GraphQL/Language/Location.swift +++ b/Sources/GraphQL/Language/Location.swift @@ -1,9 +1,9 @@ import Foundation -public struct SourceLocation : Codable, Equatable { +public struct SourceLocation: Codable, Equatable { public let line: Int public let column: Int - + public init(line: Int, column: Int) { self.line = line self.column = column @@ -20,7 +20,11 @@ func getLocation(source: Source, position: Int) -> SourceLocation { do { let regex = try NSRegularExpression(pattern: "\r\n|[\n\r]", options: []) - let matches = regex.matches(in: source.body, options: [], range: NSRange(0.. Type { let lexer = createLexer(source: source, noLocation: noLocation) try expect(lexer: lexer, kind: .sof) let type = try parseTypeReference(lexer: lexer) - try expect(lexer: lexer,kind: .eof) + try expect(lexer: lexer, kind: .eof) return type } @@ -142,7 +142,6 @@ func parseDescription(lexer: Lexer) throws -> StringValue? { return nil } - // Implements the parsing rules in the Document section. /** @@ -173,18 +172,19 @@ func parseDefinition(lexer: Lexer) throws -> Definition { if peek(lexer: lexer, kind: .openingBrace) { return try parseOperationDefinition(lexer: lexer) } - + if peek(lexer: lexer, kind: .name) { guard let value = lexer.token.value else { throw GraphQLError(message: "Expected name token to have value: \(lexer.token)") } switch value { case "query", "mutation", "subscription": - return try parseOperationDefinition(lexer: lexer); + return try parseOperationDefinition(lexer: lexer) case "fragment": return try parseFragmentDefinition(lexer: lexer) // Note: the Type System IDL is an experimental non-spec addition. - case "schema", "scalar", "type", "interface", "union", "enum", "input", "extend", "directive": + case "schema", "scalar", "type", "interface", "union", "enum", "input", "extend", + "directive": return try parseTypeSystemDefinition(lexer: lexer) default: break @@ -196,7 +196,6 @@ func parseDefinition(lexer: Lexer) throws -> Definition { throw unexpected(lexer: lexer) } - // Implements the parsing rules in the Operations section. /** @@ -220,7 +219,7 @@ func parseOperationDefinition(lexer: Lexer) throws -> OperationDefinition { let operation = try parseOperationType(lexer: lexer) - var name: Name? = nil + var name: Name? if peek(lexer: lexer, kind: .name) { name = try parseName(lexer: lexer) @@ -276,7 +275,8 @@ func parseVariableDefinition(lexer: Lexer) throws -> VariableDefinition { loc: loc(lexer: lexer, startToken: start), variable: try parseVariable(lexer: lexer), type: (try expect(lexer: lexer, kind: .colon), try parseTypeReference(lexer: lexer)).1, - defaultValue: try skip(lexer: lexer, kind: .equals) ? parseValueLiteral(lexer: lexer, isConst: true) : nil + defaultValue: try skip(lexer: lexer, kind: .equals) ? + parseValueLiteral(lexer: lexer, isConst: true) : nil ) } @@ -284,7 +284,7 @@ func parseVariableDefinition(lexer: Lexer) throws -> VariableDefinition { * Variable : $ Name */ func parseVariable(lexer: Lexer) throws -> Variable { - let start = lexer.token; + let start = lexer.token try expect(lexer: lexer, kind: .dollar) return Variable( loc: loc(lexer: lexer, startToken: start), @@ -296,7 +296,7 @@ func parseVariable(lexer: Lexer) throws -> Variable { * SelectionSet : { Selection+ } */ func parseSelectionSet(lexer: Lexer) throws -> SelectionSet { - let start = lexer.token; + let start = lexer.token return SelectionSet( loc: loc(lexer: lexer, startToken: start), selections: try many( @@ -326,10 +326,10 @@ func parseSelection(lexer: Lexer) throws -> Selection { * Alias : Name : */ func parseField(lexer: Lexer) throws -> Field { - let start = lexer.token; + let start = lexer.token let nameOrAlias = try parseName(lexer: lexer) - var alias: Name? = nil + var alias: Name? var name: Name if try skip(lexer: lexer, kind: .colon) { @@ -346,7 +346,9 @@ func parseField(lexer: Lexer) throws -> Field { name: name, arguments: try parseArguments(lexer: lexer), directives: try parseDirectives(lexer: lexer), - selectionSet: peek(lexer: lexer, kind: .openingBrace) ? try parseSelectionSet(lexer: lexer) : nil + selectionSet: peek(lexer: lexer, kind: .openingBrace) ? + try parseSelectionSet(lexer: lexer) : + nil ) } @@ -367,15 +369,17 @@ func parseArguments(lexer: Lexer) throws -> [Argument] { * Argument : Name : Value */ func parseArgument(lexer: Lexer) throws -> Argument { - let start = lexer.token; + let start = lexer.token return Argument( loc: loc(lexer: lexer, startToken: start), name: try parseName(lexer: lexer), - value: (try expect(lexer: lexer, kind: .colon), try parseValueLiteral(lexer: lexer, isConst: false)).1 + value: ( + try expect(lexer: lexer, kind: .colon), + try parseValueLiteral(lexer: lexer, isConst: false) + ).1 ) } - // Implements the parsing rules in the Fragments section. /** @@ -388,7 +392,7 @@ func parseArgument(lexer: Lexer) throws -> Argument { func parseFragment(lexer: Lexer) throws -> Fragment { let start = lexer.token try expect(lexer: lexer, kind: .spread) - if peek(lexer: lexer, kind: .name) && lexer.token.value != "on" { + if peek(lexer: lexer, kind: .name), lexer.token.value != "on" { return FragmentSpread( loc: loc(lexer: lexer, startToken: start), name: try parseFragmentName(lexer: lexer), @@ -396,7 +400,7 @@ func parseFragment(lexer: Lexer) throws -> Fragment { ) } - var typeCondition: NamedType? = nil + var typeCondition: NamedType? if lexer.token.value == "on" { try lexer.advance() @@ -422,7 +426,10 @@ func parseFragmentDefinition(lexer: Lexer) throws -> FragmentDefinition { return FragmentDefinition( loc: loc(lexer: lexer, startToken: start), name: try parseFragmentName(lexer: lexer), - typeCondition: (try expectKeyword(lexer: lexer, value: "on"), try parseNamedType(lexer: lexer)).1, + typeCondition: ( + try expectKeyword(lexer: lexer, value: "on"), + try parseNamedType(lexer: lexer) + ).1, directives: try parseDirectives(lexer: lexer), selectionSet: try parseSelectionSet(lexer: lexer) ) @@ -438,7 +445,6 @@ func parseFragmentName(lexer: Lexer) throws -> Name { return try parseName(lexer: lexer) } - // Implements the parsing rules in the Values section. /** @@ -487,7 +493,7 @@ func parseValueLiteral(lexer: Lexer, isConst: Bool) throws -> Value { guard let value = token.value else { throw GraphQLError(message: "Expected name token to have value: \(token)") } - if (value == "true" || value == "false") { + if value == "true" || value == "false" { try lexer.advance() return BooleanValue( loc: loc(lexer: lexer, startToken: token), @@ -549,7 +555,7 @@ func parseList(lexer: Lexer, isConst: Bool) throws -> ListValue { * - { ObjectField[?Const]+ } */ func parseObject(lexer: Lexer, isConst: Bool) throws -> ObjectValue { - let start = lexer.token; + let start = lexer.token try expect(lexer: lexer, kind: .openingBrace) var fields: [ObjectField] = [] @@ -571,7 +577,10 @@ func parseObjectField(lexer: Lexer, isConst: Bool) throws -> ObjectField { return ObjectField( loc: loc(lexer: lexer, startToken: start), name: try parseName(lexer: lexer), - value: (try expect(lexer: lexer, kind: .colon), try parseValueLiteral(lexer: lexer, isConst: isConst)).1 + value: ( + try expect(lexer: lexer, kind: .colon), + try parseValueLiteral(lexer: lexer, isConst: isConst) + ).1 ) } @@ -610,8 +619,8 @@ func parseDirectives(lexer: Lexer) throws -> [Directive] { * Directive : @ Name Arguments? */ func parseDirective(lexer: Lexer) throws -> Directive { - let start = lexer.token; - try expect(lexer: lexer, kind: .at); + let start = lexer.token + try expect(lexer: lexer, kind: .at) return Directive( loc: loc(lexer: lexer, startToken: start), name: try parseName(lexer: lexer), @@ -619,7 +628,6 @@ func parseDirective(lexer: Lexer) throws -> Directive { ) } - // Implements the parsing rules in the Types section. /** @@ -631,7 +639,7 @@ func parseDirective(lexer: Lexer) throws -> Directive { func parseTypeReference(lexer: Lexer) throws -> Type { let start = lexer.token var type: Type - + if try skip(lexer: lexer, kind: .openingBracket) { type = try parseTypeReference(lexer: lexer) try expect(lexer: lexer, kind: .closingBracket) @@ -685,21 +693,21 @@ func parseTypeSystemDefinition(lexer: Lexer) throws -> TypeSystemDefinition { let keywordToken = peekDescription(lexer: lexer) ? try lexer.lookahead() : lexer.token - + if keywordToken.kind == .name { guard let value = keywordToken.value else { throw GraphQLError(message: "Expected keyword token to have value: \(keywordToken)") } switch value { - case "schema": return try parseSchemaDefinition(lexer: lexer); - case "scalar": return try parseScalarTypeDefinition(lexer: lexer); - case "type": return try parseObjectTypeDefinition(lexer: lexer); - case "interface": return try parseInterfaceTypeDefinition(lexer: lexer); - case "union": return try parseUnionTypeDefinition(lexer: lexer); - case "enum": return try parseEnumTypeDefinition(lexer: lexer); - case "input": return try parseInputObjectTypeDefinition(lexer: lexer); - case "extend": return try parseTypeExtensionDefinition(lexer: lexer); - case "directive": return try parseDirectiveDefinition(lexer: lexer); + case "schema": return try parseSchemaDefinition(lexer: lexer) + case "scalar": return try parseScalarTypeDefinition(lexer: lexer) + case "type": return try parseObjectTypeDefinition(lexer: lexer) + case "interface": return try parseInterfaceTypeDefinition(lexer: lexer) + case "union": return try parseUnionTypeDefinition(lexer: lexer) + case "enum": return try parseEnumTypeDefinition(lexer: lexer) + case "input": return try parseInputObjectTypeDefinition(lexer: lexer) + case "extend": return try parseTypeExtensionDefinition(lexer: lexer) + case "directive": return try parseDirectiveDefinition(lexer: lexer) default: break } } @@ -732,10 +740,10 @@ func parseSchemaDefinition(lexer: Lexer) throws -> SchemaDefinition { } func parseOperationTypeDefinition(lexer: Lexer) throws -> OperationTypeDefinition { - let start = lexer.token; + let start = lexer.token let operation = try parseOperationType(lexer: lexer) - try expect(lexer: lexer, kind: .colon); - let type = try parseNamedType(lexer: lexer); + try expect(lexer: lexer, kind: .colon) + let type = try parseNamedType(lexer: lexer) return OperationTypeDefinition( loc: loc(lexer: lexer, startToken: start), operation: operation, @@ -765,12 +773,12 @@ func parseScalarTypeDefinition(lexer: Lexer) throws -> ScalarTypeDefinition { * - type Name ImplementsInterfaces? Directives? { FieldDefinition+ } */ func parseObjectTypeDefinition(lexer: Lexer) throws -> ObjectTypeDefinition { - let start = lexer.token; + let start = lexer.token let description = try parseDescription(lexer: lexer) try expectKeyword(lexer: lexer, value: "type") - let name = try parseName(lexer: lexer); - let interfaces = try parseImplementsInterfaces(lexer: lexer); - let directives = try parseDirectives(lexer: lexer); + let name = try parseName(lexer: lexer) + let interfaces = try parseImplementsInterfaces(lexer: lexer) + let directives = try parseDirectives(lexer: lexer) let fields = try any( lexer: lexer, openKind: .openingBrace, @@ -849,12 +857,12 @@ func parseInputValueDef(lexer: Lexer) throws -> InputValueDefinition { let name = try parseName(lexer: lexer) try expect(lexer: lexer, kind: .colon) let type = try parseTypeReference(lexer: lexer) - var defaultValue: Value? = nil + var defaultValue: Value? if try skip(lexer: lexer, kind: .equals) { defaultValue = try parseConstValue(lexer: lexer) } - + let directives = try parseDirectives(lexer: lexer) return InputValueDefinition( @@ -897,7 +905,7 @@ func parseInterfaceTypeDefinition(lexer: Lexer) throws -> InterfaceTypeDefinitio * UnionTypeDefinition : union Name Directives? = UnionMembers */ func parseUnionTypeDefinition(lexer: Lexer) throws -> UnionTypeDefinition { - let start = lexer.token; + let start = lexer.token let description = try parseDescription(lexer: lexer) try expectKeyword(lexer: lexer, value: "union") let name = try parseName(lexer: lexer) @@ -932,11 +940,11 @@ func parseUnionMembers(lexer: Lexer) throws -> [NamedType] { * EnumTypeDefinition : enum Name Directives? { EnumValueDefinition+ } */ func parseEnumTypeDefinition(lexer: Lexer) throws -> EnumTypeDefinition { - let start = lexer.token; + let start = lexer.token let description = try parseDescription(lexer: lexer) - try expectKeyword(lexer: lexer, value: "enum"); - let name = try parseName(lexer: lexer); - let directives = try parseDirectives(lexer: lexer); + try expectKeyword(lexer: lexer, value: "enum") + let name = try parseName(lexer: lexer) + let directives = try parseDirectives(lexer: lexer) let values = try many( lexer: lexer, openKind: .openingBrace, @@ -958,10 +966,10 @@ func parseEnumTypeDefinition(lexer: Lexer) throws -> EnumTypeDefinition { * EnumValue : Name */ func parseEnumValueDefinition(lexer: Lexer) throws -> EnumValueDefinition { - let start = lexer.token; + let start = lexer.token let description = try parseDescription(lexer: lexer) - let name = try parseName(lexer: lexer); - let directives = try parseDirectives(lexer: lexer); + let name = try parseName(lexer: lexer) + let directives = try parseDirectives(lexer: lexer) return EnumValueDefinition( loc: loc(lexer: lexer, startToken: start), description: description, @@ -998,9 +1006,9 @@ func parseInputObjectTypeDefinition(lexer: Lexer) throws -> InputObjectTypeDefin * TypeExtensionDefinition : extend ObjectTypeDefinition */ func parseTypeExtensionDefinition(lexer: Lexer) throws -> TypeExtensionDefinition { - let start = lexer.token; - try expectKeyword(lexer: lexer, value: "extend"); - let definition = try parseObjectTypeDefinition(lexer: lexer); + let start = lexer.token + try expectKeyword(lexer: lexer, value: "extend") + let definition = try parseObjectTypeDefinition(lexer: lexer) return TypeExtensionDefinition( loc: loc(lexer: lexer, startToken: start), definition: definition @@ -1012,14 +1020,14 @@ func parseTypeExtensionDefinition(lexer: Lexer) throws -> TypeExtensionDefinitio * - directive @ Name ArgumentsDefinition? on DirectiveLocations */ func parseDirectiveDefinition(lexer: Lexer) throws -> DirectiveDefinition { - let start = lexer.token; + let start = lexer.token let description = try parseDescription(lexer: lexer) - try expectKeyword(lexer: lexer, value: "directive"); + try expectKeyword(lexer: lexer, value: "directive") try expect(lexer: lexer, kind: .at) - let name = try parseName(lexer: lexer); - let args = try parseArgumentDefs(lexer: lexer); - try expectKeyword(lexer: lexer, value: "on"); - let locations = try parseDirectiveLocations(lexer: lexer); + let name = try parseName(lexer: lexer) + let args = try parseArgumentDefs(lexer: lexer) + try expectKeyword(lexer: lexer, value: "on") + let locations = try parseDirectiveLocations(lexer: lexer) return DirectiveDefinition( loc: loc(lexer: lexer, startToken: start), description: description, @@ -1115,7 +1123,7 @@ func expect(lexer: Lexer, kind: Token.Kind) throws -> Token { func expectKeyword(lexer: Lexer, value: String) throws -> Token { let token = lexer.token - guard token.kind == .name && token.value == value else { + guard token.kind == .name, token.value == value else { throw syntaxError( source: lexer.source, position: token.start, @@ -1131,7 +1139,7 @@ func expectKeyword(lexer: Lexer, value: String) throws -> Token { * Helper func for creating an error when an unexpected lexed token * is encountered. */ -func unexpected(lexer: Lexer, atToken: Token? = nil) -> Error { //GraphQLError { +func unexpected(lexer: Lexer, atToken: Token? = nil) -> Error { // GraphQLError { let token = atToken ?? lexer.token return syntaxError( source: lexer.source, diff --git a/Sources/GraphQL/Language/Source.swift b/Sources/GraphQL/Language/Source.swift index d366cb20..00d05035 100644 --- a/Sources/GraphQL/Language/Source.swift +++ b/Sources/GraphQL/Language/Source.swift @@ -14,9 +14,9 @@ public struct Source { } } -extension Source : Equatable { +extension Source: Equatable { public static func == (lhs: Source, rhs: Source) -> Bool { return lhs.body == rhs.body && - lhs.name == rhs.name + lhs.name == rhs.name } } diff --git a/Sources/GraphQL/Language/Visitor.swift b/Sources/GraphQL/Language/Visitor.swift index 04642dbd..97f0cac0 100644 --- a/Sources/GraphQL/Language/Visitor.swift +++ b/Sources/GraphQL/Language/Visitor.swift @@ -83,12 +83,12 @@ let QueryDocumentKeys: [Kind: [String]] = [ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node { let visitorKeys = keyMap.isEmpty ? QueryDocumentKeys : keyMap - var stack: Stack? = nil + var stack: Stack? var inArray = false var keys: [IndexPathElement] = ["root"] var index: Int = -1 var edits: [(key: IndexPathElement, node: Node)] = [] - var parent: NodeResult? = nil + var parent: NodeResult? var path: [IndexPathElement] = [] var ancestors: [NodeResult] = [] var newRoot = root @@ -96,8 +96,8 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node repeat { index += 1 let isLeaving = index == keys.count - var key: IndexPathElement? = nil - var node: NodeResult? = nil + var key: IndexPathElement? + var node: NodeResult? let isEdited = isLeaving && !edits.isEmpty if !isLeaving { @@ -105,9 +105,9 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node if let parent = parent { switch parent { - case .node(let parent): + case let .node(parent): node = parent.get(key: key!.keyValue!) - case .array(let parent): + case let .array(parent): node = .node(parent[key!.indexValue!]) } } else { @@ -165,7 +165,7 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node var result: VisitResult - if case .node(let n) = node! { + if case let .node(n) = node! { if !isLeaving { result = visitor.enter( node: n, @@ -191,7 +191,7 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node if case .skip = result, !isLeaving { _ = path.popLast() continue - } else if case .node(let n) = result { + } else if case let .node(n) = result { edits.append((key!, n!)) if !isLeaving { @@ -214,10 +214,10 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node inArray = node!.isArray switch node! { - case .node(let node): + case let .node(node): keys = visitorKeys[node.kind] ?? [] - case .array(let array): - keys = array.map({ _ in "root" }) + case let .array(array): + keys = array.map { _ in "root" } } index = -1 @@ -229,7 +229,8 @@ func visit(root: Node, visitor: Visitor, keyMap: [Kind: [String]] = [:]) -> Node parent = node } - } while stack != nil + } while + stack != nil if !edits.isEmpty { newRoot = edits[edits.count - 1].node @@ -245,7 +246,13 @@ final class Stack { let inArray: Bool let prev: Stack? - init(index: Int, keys: [IndexPathElement], edits: [(key: IndexPathElement, node: Node)], inArray: Bool, prev: Stack?) { + init( + index: Int, + keys: [IndexPathElement], + edits: [(key: IndexPathElement, node: Node)], + inArray: Bool, + prev: Stack? + ) { self.index = index self.keys = keys self.edits = edits @@ -261,11 +268,11 @@ final class Stack { * If a prior visitor edits a node, no following visitors will see that node. */ func visitInParallel(visitors: [Visitor]) -> Visitor { - var skipping: [Node?] = [Node?](repeating: nil, count: visitors.count) + var skipping = [Node?](repeating: nil, count: visitors.count) return Visitor( enter: { node, key, parent, path, ancestors in - for i in 0.. Visitor { return .continue }, leave: { node, key, parent, path, ancestors in - for i in 0.. Visitor { } else if case .node = result { return result } - } //else if skipping[i] == node { + } // else if skipping[i] == node { // skipping[i] = nil // } } @@ -331,7 +338,13 @@ public enum VisitResult { /// relevant functions to be called during the visitor's traversal. public struct Visitor { /// A visitor is comprised of visit functions, which are called on each node during the visitor's traversal. - public typealias Visit = (Node, IndexPathElement?, NodeResult?, [IndexPathElement], [NodeResult]) -> VisitResult + public typealias Visit = ( + Node, + IndexPathElement?, + NodeResult?, + [IndexPathElement], + [NodeResult] + ) -> VisitResult private let enter: Visit private let leave: Visit @@ -340,20 +353,37 @@ public struct Visitor { self.leave = leave } - public func enter(node: Node, key: IndexPathElement?, parent: NodeResult?, path: [IndexPathElement], ancestors: [NodeResult]) -> VisitResult { + public func enter( + node: Node, + key: IndexPathElement?, + parent: NodeResult?, + path: [IndexPathElement], + ancestors: [NodeResult] + ) -> VisitResult { return enter(node, key, parent, path, ancestors) } - public func leave(node: Node, key: IndexPathElement?, parent: NodeResult?, path: [IndexPathElement], ancestors: [NodeResult]) -> VisitResult { + public func leave( + node: Node, + key: IndexPathElement?, + parent: NodeResult?, + path: [IndexPathElement], + ancestors: [NodeResult] + ) -> VisitResult { return leave(node, key, parent, path, ancestors) } } -public func ignore(node: Node, key: IndexPathElement?, parent: NodeResult?, path: [IndexPathElement], ancestors: [NodeResult]) -> VisitResult { +public func ignore( + node _: Node, + key _: IndexPathElement?, + parent _: NodeResult?, + path _: [IndexPathElement], + ancestors _: [NodeResult] +) -> VisitResult { return .continue } - /** * Creates a new visitor instance which maintains a provided TypeInfo instance * along with visiting visitor. @@ -374,7 +404,7 @@ func visitWithTypeInfo(typeInfo: TypeInfo, visitor: Visitor) -> Visitor { if !result.isContinue { typeInfo.leave(node: node) - if case .node(let node) = result, let n = node { + if case let .node(node) = result, let n = node { typeInfo.enter(node: n) } } diff --git a/Sources/GraphQL/Map/AnyCoder.swift b/Sources/GraphQL/Map/AnyCoder.swift index 458c479e..542d25e0 100644 --- a/Sources/GraphQL/Map/AnyCoder.swift +++ b/Sources/GraphQL/Map/AnyCoder.swift @@ -4,9 +4,9 @@ import Foundation /// A marker protocol used to determine whether a value is a `String`-keyed `Dictionary` /// containing `Encodable` values (in which case it should be exempt from key conversion strategies). /// -fileprivate protocol _AnyStringDictionaryEncodableMarker { } +private protocol _AnyStringDictionaryEncodableMarker {} -extension Dictionary : _AnyStringDictionaryEncodableMarker where Key == String, Value: Encodable { } +extension Dictionary: _AnyStringDictionaryEncodableMarker where Key == String, Value: Encodable {} /// A marker protocol used to determine whether a value is a `String`-keyed `Dictionary` /// containing `Decodable` values (in which case it should be exempt from key conversion strategies). @@ -14,11 +14,10 @@ extension Dictionary : _AnyStringDictionaryEncodableMarker where Key == String, /// The marker protocol also provides access to the type of the `Decodable` values, /// which is needed for the implementation of the key conversion strategy exemption. /// -fileprivate protocol _AnyStringDictionaryDecodableMarker { +private protocol _AnyStringDictionaryDecodableMarker { static var elementType: Decodable.Type { get } } - //===----------------------------------------------------------------------===// // Any Encoder //===----------------------------------------------------------------------===// @@ -28,7 +27,7 @@ open class AnyEncoder { // MARK: Options /// The formatting of the output Any data. - public struct OutputFormatting : OptionSet { + public struct OutputFormatting: OptionSet { /// The format's default value. public let rawValue: UInt @@ -42,7 +41,7 @@ open class AnyEncoder { /// Produce Any with dictionary keys sorted in lexicographic order. @available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) - public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) + public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) } /// The strategy to use for encoding `Date` values. @@ -121,7 +120,7 @@ open class AnyEncoder { fileprivate static func _convertToSnakeCase(_ stringKey: String) -> String { guard !stringKey.isEmpty else { return stringKey } - var words : [Range] = [] + var words: [Range] = [] // The general idea of this algorithm is to split words on transition from lower to upper case, then on transition of >1 upper case characters to lowercase // // myProperty -> my_property @@ -129,16 +128,28 @@ 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)..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..(_ value: T) throws -> Any { - let encoder = _AnyEncoder(options: self.options) - + open func encode(_ value: T) throws -> Any { + let encoder = _AnyEncoder(options: options) + guard let topLevel = try encoder.box_(value) else { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Top-level \(T.self) did not encode any values.")) + throw EncodingError.invalidValue( + value, + EncodingError + .Context( + codingPath: [], + debugDescription: "Top-level \(T.self) did not encode any values." + ) + ) } return try AnySerialization.map(with: topLevel) @@ -230,7 +250,7 @@ open class AnyEncoder { // MARK: - _AnyEncoder -fileprivate class _AnyEncoder : Encoder { +private class _AnyEncoder: Encoder { // MARK: Properties /// The encoder's storage. @@ -243,8 +263,8 @@ fileprivate class _AnyEncoder : Encoder { public var codingPath: [CodingKey] /// Contextual user-provided information for use during encoding. - public var userInfo: [CodingUserInfoKey : Any] { - return self.options.userInfo + public var userInfo: [CodingUserInfoKey: Any] { + return options.userInfo } // MARK: - Initialization @@ -252,7 +272,7 @@ fileprivate class _AnyEncoder : Encoder { /// Initializes `self` with the given top-level encoder options. fileprivate init(options: AnyEncoder._Options, codingPath: [CodingKey] = []) { self.options = options - self.storage = _AnyEncodingStorage() + storage = _AnyEncodingStorage() self.codingPath = codingPath } @@ -266,43 +286,56 @@ fileprivate class _AnyEncoder : Encoder { // // This means that anytime something that can request a new container goes onto the stack, we MUST push a key onto the coding path. // Things which will not request containers do not need to have the coding path extended for them (but it doesn't matter if it is, because they will not reach here). - return self.storage.count == self.codingPath.count + return storage.count == codingPath.count } // MARK: - Encoder Methods - public func container(keyedBy: Key.Type) -> KeyedEncodingContainer { + + public func container(keyedBy _: Key.Type) -> KeyedEncodingContainer { // If an existing keyed container was already requested, return that one. let topContainer: NSMutableDictionary - if self.canEncodeNewValue { + if canEncodeNewValue { // We haven't yet pushed a container at this level; do so here. - topContainer = self.storage.pushKeyedContainer() + topContainer = storage.pushKeyedContainer() } else { - guard let container = self.storage.containers.last as? NSMutableDictionary else { - preconditionFailure("Attempt to push new keyed encoding container when already previously encoded at this path.") + guard let container = storage.containers.last as? NSMutableDictionary else { + preconditionFailure( + "Attempt to push new keyed encoding container when already previously encoded at this path." + ) } topContainer = container } - let container = _AnyKeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) + let container = _AnyKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: topContainer + ) return KeyedEncodingContainer(container) } public func unkeyedContainer() -> UnkeyedEncodingContainer { // If an existing unkeyed container was already requested, return that one. let topContainer: NSMutableArray - if self.canEncodeNewValue { + if canEncodeNewValue { // We haven't yet pushed a container at this level; do so here. - topContainer = self.storage.pushUnkeyedContainer() + topContainer = storage.pushUnkeyedContainer() } else { - guard let container = self.storage.containers.last as? NSMutableArray else { - preconditionFailure("Attempt to push new unkeyed encoding container when already previously encoded at this path.") + guard let container = storage.containers.last as? NSMutableArray else { + preconditionFailure( + "Attempt to push new unkeyed encoding container when already previously encoded at this path." + ) } topContainer = container } - return _AnyUnkeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) + return _AnyUnkeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: topContainer + ) } public func singleValueContainer() -> SingleValueEncodingContainer { @@ -312,12 +345,12 @@ fileprivate class _AnyEncoder : Encoder { // MARK: - Encoding Storage and Containers -fileprivate struct _AnyEncodingStorage { +private struct _AnyEncodingStorage { // MARK: Properties /// The container stack. /// Elements may be any one of the Any types (NSNull, NSNumber, NSString, NSArray, NSDictionary). - private(set) fileprivate var containers: [NSObject] = [] + fileprivate private(set) var containers: [NSObject] = [] // MARK: - Initialization @@ -327,34 +360,34 @@ fileprivate struct _AnyEncodingStorage { // MARK: - Modifying the Stack fileprivate var count: Int { - return self.containers.count + return containers.count } fileprivate mutating func pushKeyedContainer() -> NSMutableDictionary { let dictionary = NSMutableDictionary() - self.containers.append(dictionary) + containers.append(dictionary) return dictionary } fileprivate mutating func pushUnkeyedContainer() -> NSMutableArray { let array = NSMutableArray() - self.containers.append(array) + containers.append(array) return array } fileprivate mutating func push(container: NSObject) { - self.containers.append(container) + containers.append(container) } fileprivate mutating func popContainer() -> NSObject { - precondition(!self.containers.isEmpty, "Empty container stack.") - return self.containers.popLast()! + precondition(!containers.isEmpty, "Empty container stack.") + return containers.popLast()! } } // MARK: - Encoding Containers -fileprivate struct _AnyKeyedEncodingContainer : KeyedEncodingContainerProtocol { +private struct _AnyKeyedEncodingContainer: KeyedEncodingContainerProtocol { typealias Key = K // MARK: Properties @@ -366,12 +399,16 @@ fileprivate struct _AnyKeyedEncodingContainer : KeyedEncodingCont private let container: NSMutableDictionary /// The path of coding keys taken to get to this point in encoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] // MARK: - Initialization /// Initializes `self` with the given references. - fileprivate init(referencing encoder: _AnyEncoder, codingPath: [CodingKey], wrapping container: NSMutableDictionary) { + fileprivate init( + referencing encoder: _AnyEncoder, + codingPath: [CodingKey], + wrapping container: NSMutableDictionary + ) { self.encoder = encoder self.codingPath = codingPath self.container = container @@ -386,97 +423,146 @@ fileprivate struct _AnyKeyedEncodingContainer : KeyedEncodingCont case .convertToSnakeCase: let newKeyString = AnyEncoder.KeyEncodingStrategy._convertToSnakeCase(key.stringValue) return _AnyKey(stringValue: newKeyString, intValue: key.intValue) - case .custom(let converter): + case let .custom(converter): return converter(codingPath + [key]) } } // MARK: - KeyedEncodingContainerProtocol Methods - public mutating func encodeNil(forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = NSNull() } - public mutating func encode(_ value: Bool, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: Int, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: Int8, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: Int16, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: Int32, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: Int64, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: UInt, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: UInt8, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: UInt16, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: UInt32, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: UInt64, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: String, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - - public mutating func encode(_ value: Float, forKey key: Key) throws { + public mutating func encodeNil(forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = NSNull() + } + + public mutating func encode(_ value: Bool, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: Int, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: Int8, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: Int16, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: Int32, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: Int64, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: UInt, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: UInt8, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: UInt16, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: UInt32, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: UInt64, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: String, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: Float, forKey key: Key) throws { // Since the float may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } #if DEPLOYMENT_RUNTIME_SWIFT - self.container[_converted(key).stringValue._bridgeToObjectiveC()] = try self.encoder.box(value) + container[_converted(key).stringValue._bridgeToObjectiveC()] = try encoder.box(value) #else - self.container[_converted(key).stringValue] = try self.encoder.box(value) + container[_converted(key).stringValue] = try encoder.box(value) #endif } public mutating func encode(_ value: Double, forKey key: Key) throws { // Since the double may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } #if DEPLOYMENT_RUNTIME_SWIFT - self.container[_converted(key).stringValue._bridgeToObjectiveC()] = try self.encoder.box(value) + container[_converted(key).stringValue._bridgeToObjectiveC()] = try encoder.box(value) #else - self.container[_converted(key).stringValue] = try self.encoder.box(value) + container[_converted(key).stringValue] = try encoder.box(value) #endif } - public mutating func encode(_ value: T, forKey key: Key) throws { - self.encoder.codingPath.append(key) + public mutating func encode(_ value: T, forKey key: Key) throws { + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } #if DEPLOYMENT_RUNTIME_SWIFT - self.container[_converted(key).stringValue._bridgeToObjectiveC()] = try self.encoder.box(value) + container[_converted(key).stringValue._bridgeToObjectiveC()] = try encoder.box(value) #else - self.container[_converted(key).stringValue] = try self.encoder.box(value) + container[_converted(key).stringValue] = try encoder.box(value) #endif } - public mutating func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer { + public mutating func nestedContainer( + keyedBy _: NestedKey.Type, + forKey key: Key + ) -> KeyedEncodingContainer { let dictionary = NSMutableDictionary() #if DEPLOYMENT_RUNTIME_SWIFT - self.container[_converted(key).stringValue._bridgeToObjectiveC()] = dictionary + self.container[_converted(key).stringValue._bridgeToObjectiveC()] = dictionary #else - self.container[_converted(key).stringValue] = dictionary + self.container[_converted(key).stringValue] = dictionary #endif - self.codingPath.append(key) + codingPath.append(key) defer { self.codingPath.removeLast() } - let container = _AnyKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) + let container = _AnyKeyedEncodingContainer( + referencing: encoder, + codingPath: codingPath, + wrapping: dictionary + ) return KeyedEncodingContainer(container) } public mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { let array = NSMutableArray() #if DEPLOYMENT_RUNTIME_SWIFT - self.container[_converted(key).stringValue._bridgeToObjectiveC()] = array + container[_converted(key).stringValue._bridgeToObjectiveC()] = array #else - self.container[_converted(key).stringValue] = array + container[_converted(key).stringValue] = array #endif - self.codingPath.append(key) + codingPath.append(key) defer { self.codingPath.removeLast() } - return _AnyUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) + return _AnyUnkeyedEncodingContainer( + referencing: encoder, + codingPath: codingPath, + wrapping: array + ) } public mutating func superEncoder() -> Encoder { - return _AnyReferencingEncoder(referencing: self.encoder, at: _AnyKey.super, wrapping: self.container) + return _AnyReferencingEncoder(referencing: encoder, at: _AnyKey.super, wrapping: container) } public mutating func superEncoder(forKey key: Key) -> Encoder { - return _AnyReferencingEncoder(referencing: self.encoder, at: key, wrapping: self.container) + return _AnyReferencingEncoder(referencing: encoder, at: key, wrapping: container) } } -fileprivate struct _AnyUnkeyedEncodingContainer : UnkeyedEncodingContainer { +private struct _AnyUnkeyedEncodingContainer: UnkeyedEncodingContainer { // MARK: Properties /// A reference to the encoder we're writing to. @@ -486,17 +572,21 @@ fileprivate struct _AnyUnkeyedEncodingContainer : UnkeyedEncodingContainer { private let container: NSMutableArray /// The path of coding keys taken to get to this point in encoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] /// The number of elements encoded into the container. public var count: Int { - return self.container.count + return container.count } // MARK: - Initialization /// Initializes `self` with the given references. - fileprivate init(referencing encoder: _AnyEncoder, codingPath: [CodingKey], wrapping container: NSMutableArray) { + fileprivate init( + referencing encoder: _AnyEncoder, + codingPath: [CodingKey], + wrapping container: NSMutableArray + ) { self.encoder = encoder self.codingPath = codingPath self.container = container @@ -504,176 +594,198 @@ fileprivate struct _AnyUnkeyedEncodingContainer : UnkeyedEncodingContainer { // MARK: - UnkeyedEncodingContainer Methods - public mutating func encodeNil() throws { self.container.add(NSNull()) } - public mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) } - - public mutating func encode(_ value: Float) throws { + public mutating func encodeNil() throws { container.add(NSNull()) } + public mutating func encode(_ value: Bool) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int8) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int16) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int32) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int64) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt8) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt16) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt32) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt64) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: String) throws { container.add(encoder.box(value)) } + + public mutating func encode(_ value: Float) throws { // Since the float may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(_AnyKey(index: self.count)) + encoder.codingPath.append(_AnyKey(index: count)) defer { self.encoder.codingPath.removeLast() } - self.container.add(try self.encoder.box(value)) + container.add(try encoder.box(value)) } public mutating func encode(_ value: Double) throws { // Since the double may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(_AnyKey(index: self.count)) + encoder.codingPath.append(_AnyKey(index: count)) defer { self.encoder.codingPath.removeLast() } - self.container.add(try self.encoder.box(value)) + container.add(try encoder.box(value)) } - public mutating func encode(_ value: T) throws { - self.encoder.codingPath.append(_AnyKey(index: self.count)) + public mutating func encode(_ value: T) throws { + encoder.codingPath.append(_AnyKey(index: count)) defer { self.encoder.codingPath.removeLast() } - self.container.add(try self.encoder.box(value)) + container.add(try encoder.box(value)) } - public mutating func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer { - self.codingPath.append(_AnyKey(index: self.count)) + public mutating func nestedContainer( + keyedBy _: NestedKey + .Type + ) -> KeyedEncodingContainer { + codingPath.append(_AnyKey(index: count)) defer { self.codingPath.removeLast() } let dictionary = NSMutableDictionary() self.container.add(dictionary) - let container = _AnyKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) + let container = _AnyKeyedEncodingContainer( + referencing: encoder, + codingPath: codingPath, + wrapping: dictionary + ) return KeyedEncodingContainer(container) } public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { - self.codingPath.append(_AnyKey(index: self.count)) + codingPath.append(_AnyKey(index: count)) defer { self.codingPath.removeLast() } - + let array = NSMutableArray() - self.container.add(array) - return _AnyUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) + container.add(array) + return _AnyUnkeyedEncodingContainer( + referencing: encoder, + codingPath: codingPath, + wrapping: array + ) } public mutating func superEncoder() -> Encoder { - return _AnyReferencingEncoder(referencing: self.encoder, at: self.container.count, wrapping: self.container) + return _AnyReferencingEncoder( + referencing: encoder, + at: container.count, + wrapping: container + ) } } -extension _AnyEncoder : SingleValueEncodingContainer { +extension _AnyEncoder: SingleValueEncodingContainer { // MARK: - SingleValueEncodingContainer Methods fileprivate func assertCanEncodeNewValue() { - precondition(self.canEncodeNewValue, "Attempt to encode value through single value container when previously value already encoded.") + precondition( + canEncodeNewValue, + "Attempt to encode value through single value container when previously value already encoded." + ) } public func encodeNil() throws { assertCanEncodeNewValue() - self.storage.push(container: NSNull()) + storage.push(container: NSNull()) } public func encode(_ value: Bool) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int8) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int16) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int32) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int64) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt8) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt16) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt32) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt64) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: String) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Float) throws { assertCanEncodeNewValue() - try self.storage.push(container: self.box(value)) + try storage.push(container: box(value)) } public func encode(_ value: Double) throws { assertCanEncodeNewValue() - try self.storage.push(container: self.box(value)) + try storage.push(container: box(value)) } - public func encode(_ value: T) throws { + public func encode(_ value: T) throws { assertCanEncodeNewValue() - try self.storage.push(container: self.box(value)) + try storage.push(container: box(value)) } } // MARK: - Concrete Value Representations -extension _AnyEncoder { +private extension _AnyEncoder { /// Returns the given value boxed in a container appropriate for pushing onto the container stack. - 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) = self.options.nonConformingFloatEncodingStrategy else { - throw EncodingError._invalidFloatingPointValue(float, at: codingPath) + 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 { + guard !float.isInfinite, !float.isNaN else { + guard + case let .convertToString( + positiveInfinity: posInfString, + negativeInfinity: negInfString, + nan: nanString + ) = options.nonConformingFloatEncodingStrategy + else { + throw EncodingError._invalidFloatingPointValue(float, at: codingPath) } if float == Float.infinity { @@ -688,12 +800,16 @@ extension _AnyEncoder { return NSNumber(value: float) } - fileprivate func box(_ double: Double) throws -> NSObject { - guard !double.isInfinite && !double.isNaN else { - guard case let .convertToString(positiveInfinity: posInfString, - negativeInfinity: negInfString, - nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { - throw EncodingError._invalidFloatingPointValue(double, at: codingPath) + func box(_ double: Double) throws -> NSObject { + guard !double.isInfinite, !double.isNaN else { + guard + case let .convertToString( + positiveInfinity: posInfString, + negativeInfinity: negInfString, + nan: nanString + ) = options.nonConformingFloatEncodingStrategy + else { + throw EncodingError._invalidFloatingPointValue(double, at: codingPath) } if double == Double.infinity { @@ -708,13 +824,13 @@ extension _AnyEncoder { return NSNumber(value: double) } - fileprivate func box(_ date: Date) throws -> NSObject { - switch self.options.dateEncodingStrategy { + func box(_ date: Date) throws -> NSObject { + switch options.dateEncodingStrategy { case .deferredToDate: // Must be called with a surrounding with(pushedKey:) call. // Dates encode as single-value objects; this can't both throw and push a container, so no need to catch the error. try date.encode(to: self) - return self.storage.popContainer() + return storage.popContainer() case .secondsSince1970: return NSNumber(value: date.timeIntervalSince1970) @@ -729,158 +845,158 @@ extension _AnyEncoder { fatalError("ISO8601DateFormatter is unavailable on this platform.") } - case .formatted(let formatter): + case let .formatted(formatter): return NSString(string: formatter.string(from: date)) - case .custom(let closure): - let depth = self.storage.count + case let .custom(closure): + let depth = storage.count do { try closure(date, self) } catch { // If the value pushed a container before throwing, pop it back off to restore state. - if self.storage.count > depth { - let _ = self.storage.popContainer() + if storage.count > depth { + _ = storage.popContainer() } throw error } - - guard self.storage.count > depth else { + + guard storage.count > depth else { // The closure didn't encode anything. Return the default keyed container. return NSDictionary() } // We can pop because the closure encoded something. - return self.storage.popContainer() + return storage.popContainer() } } - fileprivate func box(_ data: Data) throws -> NSObject { - switch self.options.dataEncodingStrategy { + func box(_ data: Data) throws -> NSObject { + switch options.dataEncodingStrategy { case .deferredToData: // Must be called with a surrounding with(pushedKey:) call. - let depth = self.storage.count + let depth = storage.count do { try data.encode(to: self) } catch { // If the value pushed a container before throwing, pop it back off to restore state. // This shouldn't be possible for Data (which encodes as an array of bytes), but it can't hurt to catch a failure. - if self.storage.count > depth { - let _ = self.storage.popContainer() + if storage.count > depth { + _ = storage.popContainer() } throw error } - return self.storage.popContainer() + return storage.popContainer() case .base64: return NSString(string: data.base64EncodedString()) - case .custom(let closure): - let depth = self.storage.count + case let .custom(closure): + let depth = storage.count do { try closure(data, self) } catch { // If the value pushed a container before throwing, pop it back off to restore state. - if self.storage.count > depth { - let _ = self.storage.popContainer() + if storage.count > depth { + _ = storage.popContainer() } throw error } - guard self.storage.count > depth else { + guard storage.count > depth else { // The closure didn't encode anything. Return the default keyed container. return NSDictionary() } // We can pop because the closure encoded something. - return self.storage.popContainer() + return storage.popContainer() } } - fileprivate func box(_ dict: [String : Encodable]) throws -> NSObject? { - let depth = self.storage.count - let result = self.storage.pushKeyedContainer() + func box(_ dict: [String: Encodable]) throws -> NSObject? { + let depth = storage.count + let result = storage.pushKeyedContainer() do { for (key, value) in dict { - self.codingPath.append(_AnyKey(stringValue: key, intValue: nil)) + codingPath.append(_AnyKey(stringValue: key, intValue: nil)) defer { self.codingPath.removeLast() } result[key] = try box(value) } } catch { // If the value pushed a container before throwing, pop it back off to restore state. - if self.storage.count > depth { - let _ = self.storage.popContainer() + if storage.count > depth { + let _ = storage.popContainer() } throw error } // The top container should be a new container. - guard self.storage.count > depth else { + guard storage.count > depth else { return nil } - return self.storage.popContainer() + return storage.popContainer() } - fileprivate func box(_ value: Encodable) throws -> NSObject { - return try self.box_(value) ?? NSDictionary() + 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. - fileprivate func box_(_ value: Encodable) throws -> NSObject? { + func box_(_ value: Encodable) throws -> NSObject? { let type = Swift.type(of: value) #if DEPLOYMENT_RUNTIME_SWIFT - if type == Date.self { - // Respect Date encoding strategy - return try self.box((value as! Date)) - } else if type == Data.self { - // Respect Data encoding strategy - return try self.box((value as! Data)) - } else if type == URL.self { - // Encode URLs as single strings. - return self.box((value as! URL).absoluteString) - } else if type == Decimal.self { - // AnySerialization can consume NSDecimalNumber values. - return NSDecimalNumber(decimal: value as! Decimal) - } else if value is _AnyStringDictionaryEncodableMarker { - return try box((value as Any) as! [String : Encodable]) - } - + if type == Date.self { + // Respect Date encoding strategy + return try box(value as! Date) + } else if type == Data.self { + // Respect Data encoding strategy + return try box(value as! Data) + } else if type == URL.self { + // Encode URLs as single strings. + return box((value as! URL).absoluteString) + } else if type == Decimal.self { + // AnySerialization can consume NSDecimalNumber values. + return NSDecimalNumber(decimal: value as! Decimal) + } else if value is _AnyStringDictionaryEncodableMarker { + return try box((value as Any) as! [String: Encodable]) + } + #else - if type == Date.self || type == NSDate.self { - // Respect Date encoding strategy - return try self.box((value as! Date)) - } else if type == Data.self || type == NSData.self { - // Respect Data encoding strategy - return try self.box((value as! Data)) - } else if type == URL.self || type == NSURL.self { - // Encode URLs as single strings. - return self.box((value as! URL).absoluteString) - } else if type == Decimal.self { - // AnySerialization can consume NSDecimalNumber values. - return NSDecimalNumber(decimal: value as! Decimal) - } else if value is _AnyStringDictionaryEncodableMarker { - return try box((value as Any) as! [String : Encodable]) - } + if type == Date.self || type == NSDate.self { + // Respect Date encoding strategy + return try box(value as! Date) + } else if type == Data.self || type == NSData.self { + // Respect Data encoding strategy + return try box(value as! Data) + } else if type == URL.self || type == NSURL.self { + // Encode URLs as single strings. + return box((value as! URL).absoluteString) + } else if type == Decimal.self { + // AnySerialization can consume NSDecimalNumber values. + return NSDecimalNumber(decimal: value as! Decimal) + } else if value is _AnyStringDictionaryEncodableMarker { + return try box((value as Any) as! [String: Encodable]) + } #endif - + // The value should request a container from the _AnyEncoder. - let depth = self.storage.count + let depth = storage.count do { try value.encode(to: self) } catch { // If the value pushed a container before throwing, pop it back off to restore state. - if self.storage.count > depth { - let _ = self.storage.popContainer() + if storage.count > depth { + let _ = storage.popContainer() } throw error } - + // The top container should be a new container. - guard self.storage.count > depth else { + guard storage.count > depth else { return nil } - return self.storage.popContainer() + return storage.popContainer() } } @@ -888,7 +1004,7 @@ extension _AnyEncoder { /// _AnyReferencingEncoder is a special subclass of _AnyEncoder which has its own storage, but references the contents of a different encoder. /// It's used in superEncoder(), which returns a new encoder for encoding a superclass -- the lifetime of the encoder should not escape the scope it's created in, but it doesn't necessarily know when it's done being used (to write to the original container). -fileprivate class _AnyReferencingEncoder : _AnyEncoder { +private class _AnyReferencingEncoder: _AnyEncoder { // MARK: Reference types. /// The type of container we're referencing. @@ -911,30 +1027,38 @@ fileprivate class _AnyReferencingEncoder : _AnyEncoder { // MARK: - Initialization /// Initializes `self` by referencing the given array container in the given encoder. - fileprivate init(referencing encoder: _AnyEncoder, at index: Int, wrapping array: NSMutableArray) { + fileprivate init( + referencing encoder: _AnyEncoder, + at index: Int, + wrapping array: NSMutableArray + ) { self.encoder = encoder - self.reference = .array(array, index) + reference = .array(array, index) super.init(options: encoder.options, codingPath: encoder.codingPath) - self.codingPath.append(_AnyKey(index: index)) + codingPath.append(_AnyKey(index: index)) } /// Initializes `self` by referencing the given dictionary container in the given encoder. - fileprivate init(referencing encoder: _AnyEncoder, at key: CodingKey, wrapping dictionary: NSMutableDictionary) { + fileprivate init( + referencing encoder: _AnyEncoder, + at key: CodingKey, + wrapping dictionary: NSMutableDictionary + ) { self.encoder = encoder - self.reference = .dictionary(dictionary, key.stringValue) + reference = .dictionary(dictionary, key.stringValue) super.init(options: encoder.options, codingPath: encoder.codingPath) - self.codingPath.append(key) + codingPath.append(key) } // MARK: - Coding Path Operations - fileprivate override var canEncodeNewValue: Bool { + override fileprivate var canEncodeNewValue: Bool { // With a regular encoder, the storage and coding path grow together. // A referencing encoder, however, inherits its parents coding path, as well as the key it was created for. // We have to take this into account. - return self.storage.count == self.codingPath.count - self.encoder.codingPath.count - 1 + return storage.count == codingPath.count - encoder.codingPath.count - 1 } // MARK: - Deinitialization @@ -949,10 +1073,10 @@ fileprivate class _AnyReferencingEncoder : _AnyEncoder { } switch self.reference { - case .array(let array, let index): + case let .array(array, index): array.insert(value, at: index) - case .dictionary(let dictionary, let key): + case let .dictionary(dictionary, key): dictionary[NSString(string: key)] = value } } @@ -1008,12 +1132,12 @@ open class AnyDecoder { /// Decode the values from the given representation strings. case convertFromString(positiveInfinity: String, negativeInfinity: String, nan: String) } - + /// The strategy to use for automatically changing the value of keys before decoding. public enum KeyDecodingStrategy { /// Use the keys specified by each type. This is the default strategy. case useDefaultKeys - + /// Convert from "snake_case_keys" to "camelCaseKeys" before attempting to match a key with the one specified by each type. /// /// The conversion to upper case uses `Locale.system`, also known as the ICU "root" locale. This means the result is consistent regardless of the current user's locale and language preferences. @@ -1026,48 +1150,53 @@ open class AnyDecoder { /// /// - Note: Using a key decoding strategy has a nominal performance cost, as each string key has to be inspected for the `_` character. case convertFromSnakeCase - + /// Provide a custom conversion from the key in the encoded Any to the keys specified by the decoded types. /// The full path to the current decoding position is provided for context (in case you need to locate this key within the payload). The returned key is used in place of the last component in the coding path before decoding. /// If the result of the conversion is a duplicate key, then only one value will be present in the container for the type to decode from. case custom((_ codingPath: [CodingKey]) -> CodingKey) - + fileprivate static func _convertFromSnakeCase(_ stringKey: String) -> String { guard !stringKey.isEmpty else { return stringKey } - + // Find the first non-underscore character guard let firstNonUnderscore = stringKey.firstIndex(where: { $0 != "_" }) else { // Reached the end without finding an _ return stringKey } - + // Find the last non-underscore character var lastNonUnderscore = stringKey.index(before: stringKey.endIndex) - while lastNonUnderscore > firstNonUnderscore && stringKey[lastNonUnderscore] == "_" { + while lastNonUnderscore > firstNonUnderscore, stringKey[lastNonUnderscore] == "_" { stringKey.formIndex(before: &lastNonUnderscore) } - - let keyRange = firstNonUnderscore...lastNonUnderscore - let leadingUnderscoreRange = stringKey.startIndex..(_ type: T.Type, from map: Any) throws -> T { + open func decode(_ type: T.Type, from map: Any) throws -> T { let topLevel = try AnySerialization.object(with: map) - let decoder = _AnyDecoder(referencing: topLevel, options: self.options) - + let decoder = _AnyDecoder(referencing: topLevel, options: options) + guard let value = try decoder.unbox(topLevel, as: type) else { throw DecodingError.valueNotFound( type, @@ -1145,7 +1276,7 @@ open class AnyDecoder { // MARK: - _AnyDecoder -fileprivate class _AnyDecoder : Decoder { +private class _AnyDecoder: Decoder { // MARK: Properties /// The decoder's storage. @@ -1155,37 +1286,45 @@ fileprivate class _AnyDecoder : Decoder { fileprivate let options: AnyDecoder._Options /// The path to the current point in encoding. - fileprivate(set) public var codingPath: [CodingKey] + public fileprivate(set) var codingPath: [CodingKey] /// Contextual user-provided information for use during encoding. - public var userInfo: [CodingUserInfoKey : Any] { - return self.options.userInfo + public var userInfo: [CodingUserInfoKey: Any] { + return options.userInfo } // MARK: - Initialization /// Initializes `self` with the given top-level container and options. - fileprivate init(referencing container: Any, at codingPath: [CodingKey] = [], options: AnyDecoder._Options) { - self.storage = _AnyDecodingStorage() - self.storage.push(container: container) + fileprivate init( + referencing container: Any, + at codingPath: [CodingKey] = [], + options: AnyDecoder._Options + ) { + storage = _AnyDecodingStorage() + storage.push(container: container) self.codingPath = codingPath self.options = options } // MARK: - Decoder Methods - public func container(keyedBy type: Key.Type) throws -> KeyedDecodingContainer { - guard !(self.storage.topContainer is NSNull) else { - throw DecodingError.valueNotFound(KeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead.")) + public func container(keyedBy _: Key.Type) throws -> KeyedDecodingContainer { + guard !(storage.topContainer is NSNull) else { + throw DecodingError.valueNotFound( + KeyedDecodingContainer.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead." + ) + ) } - guard let topContainer = self.storage.topContainer as? [String : Any] else { + guard let topContainer = storage.topContainer as? [String: Any] else { throw DecodingError._typeMismatch( - at: self.codingPath, - expectation: [String : Any].self, - reality: self.storage.topContainer + at: codingPath, + expectation: [String: Any].self, + reality: storage.topContainer ) } @@ -1194,14 +1333,22 @@ fileprivate class _AnyDecoder : Decoder { } public func unkeyedContainer() throws -> UnkeyedDecodingContainer { - guard !(self.storage.topContainer is NSNull) else { - throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get unkeyed decoding container -- found null value instead.")) + guard !(storage.topContainer is NSNull) else { + throw DecodingError.valueNotFound( + UnkeyedDecodingContainer.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get unkeyed decoding container -- found null value instead." + ) + ) } - guard let topContainer = self.storage.topContainer as? [Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: self.storage.topContainer) + guard let topContainer = storage.topContainer as? [Any] else { + throw DecodingError._typeMismatch( + at: codingPath, + expectation: [Any].self, + reality: storage.topContainer + ) } return _AnyUnkeyedDecodingContainer(referencing: self, wrapping: topContainer) @@ -1214,12 +1361,12 @@ fileprivate class _AnyDecoder : Decoder { // MARK: - Decoding Storage -fileprivate struct _AnyDecodingStorage { +private struct _AnyDecodingStorage { // MARK: Properties /// The container stack. /// Elements may be any one of the Any types (NSNull, NSNumber, String, Array, [String : Any]). - private(set) fileprivate var containers: [Any] = [] + fileprivate private(set) var containers: [Any] = [] // MARK: - Initialization @@ -1229,27 +1376,27 @@ fileprivate struct _AnyDecodingStorage { // MARK: - Modifying the Stack fileprivate var count: Int { - return self.containers.count + return containers.count } fileprivate var topContainer: Any { - precondition(!self.containers.isEmpty, "Empty container stack.") - return self.containers.last! + precondition(!containers.isEmpty, "Empty container stack.") + return containers.last! } fileprivate mutating func push(container: Any) { - self.containers.append(container) + containers.append(container) } fileprivate mutating func popContainer() { - precondition(!self.containers.isEmpty, "Empty container stack.") - self.containers.removeLast() + precondition(!containers.isEmpty, "Empty container stack.") + containers.removeLast() } } // MARK: Decoding Containers -fileprivate struct _AnyKeyedDecodingContainer : KeyedDecodingContainerProtocol { +private struct _AnyKeyedDecodingContainer: KeyedDecodingContainerProtocol { typealias Key = K // MARK: Properties @@ -1258,15 +1405,15 @@ fileprivate struct _AnyKeyedDecodingContainer : KeyedDecodingCont private let decoder: _AnyDecoder /// A reference to the container we're reading from. - private let container: [String : Any] + private let container: [String: Any] /// The path of coding keys taken to get to this point in decoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] // MARK: - Initialization /// Initializes `self` by referencing the given decoder and container. - fileprivate init(referencing decoder: _AnyDecoder, wrapping container: [String : Any]) { + fileprivate init(referencing decoder: _AnyDecoder, wrapping container: [String: Any]) { self.decoder = decoder switch decoder.options.keyDecodingStrategy { case .useDefaultKeys: @@ -1276,23 +1423,27 @@ fileprivate struct _AnyKeyedDecodingContainer : KeyedDecodingCont // 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 .custom(let converter): + }, 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 }) + key, value in ( + converter(decoder.codingPath + [_AnyKey(stringValue: key, intValue: nil)]) + .stringValue, + value + ) + }, uniquingKeysWith: { first, _ in first }) } - self.codingPath = decoder.codingPath + codingPath = decoder.codingPath } // MARK: - KeyedDecodingContainerProtocol Methods public var allKeys: [Key] { - return self.container.keys.compactMap { Key(stringValue: $0) } + return container.keys.compactMap { Key(stringValue: $0) } } public func contains(_ key: Key) -> Bool { - return self.container[key.stringValue] != nil + return container[key.stringValue] != nil } private func _errorDescription(of key: CodingKey) -> String { @@ -1313,279 +1464,520 @@ fileprivate struct _AnyKeyedDecodingContainer : KeyedDecodingCont } public func decodeNil(forKey key: Key) throws -> Bool { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } return entry is NSNull } public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Bool.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Bool.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Int.Type, forKey key: Key) throws -> Int { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Int.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Int.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Int8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Int8.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Int16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Int16.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Int32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Int32.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Int64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Int64.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } - + return value } - + public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: UInt.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: UInt.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: UInt8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: UInt8.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: UInt16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: UInt16.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: UInt32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: UInt32.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: UInt64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: UInt64.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Float.Type, forKey key: Key) throws -> Float { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Float.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Float.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Double.Type, forKey key: Key) throws -> Double { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Double.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Double.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: String.Type, forKey key: Key) throws -> String { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: String.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: String.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } - public func decode(_ type: T.Type, forKey key: Key) throws -> T { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + public func decode(_ type: T.Type, forKey key: Key) throws -> T { + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: type) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: type) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } - public func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer { - self.decoder.codingPath.append(key) + public func nestedContainer( + keyedBy _: NestedKey.Type, + forKey key: Key + ) throws + -> KeyedDecodingContainer + { + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \(_errorDescription(of: key))")) + throw DecodingError.keyNotFound( + key, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \(_errorDescription(of: key))" + ) + ) } - guard let dictionary = value as? [String : Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) + guard let dictionary = value as? [String: Any] else { + throw DecodingError._typeMismatch( + at: codingPath, + expectation: [String: Any].self, + reality: value + ) } - let container = _AnyKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) + let container = _AnyKeyedDecodingContainer( + referencing: decoder, + wrapping: dictionary + ) return KeyedDecodingContainer(container) } public func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get UnkeyedDecodingContainer -- no value found for key \(_errorDescription(of: key))")) + guard let value = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get UnkeyedDecodingContainer -- no value found for key \(_errorDescription(of: key))" + ) + ) } guard let array = value as? [Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: value) + throw DecodingError._typeMismatch( + at: codingPath, + expectation: [Any].self, + reality: value + ) } - return _AnyUnkeyedDecodingContainer(referencing: self.decoder, wrapping: array) + return _AnyUnkeyedDecodingContainer(referencing: decoder, wrapping: array) } private func _superDecoder(forKey key: CodingKey) throws -> Decoder { - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - let value: Any = self.container[key.stringValue] ?? NSNull() - return _AnyDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options) + let value: Any = container[key.stringValue] ?? NSNull() + return _AnyDecoder(referencing: value, at: decoder.codingPath, options: decoder.options) } public func superDecoder() throws -> Decoder { @@ -1597,7 +1989,7 @@ fileprivate struct _AnyKeyedDecodingContainer : KeyedDecodingCont } } -fileprivate struct _AnyUnkeyedDecodingContainer : UnkeyedDecodingContainer { +private struct _AnyUnkeyedDecodingContainer: UnkeyedDecodingContainer { // MARK: Properties /// A reference to the decoder we're reading from. @@ -1607,10 +1999,10 @@ fileprivate struct _AnyUnkeyedDecodingContainer : UnkeyedDecodingContainer { private let container: [Any] /// The path of coding keys taken to get to this point in decoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] /// The index of the element we're about to decode. - private(set) public var currentIndex: Int + public private(set) var currentIndex: Int // MARK: - Initialization @@ -1618,27 +2010,34 @@ fileprivate struct _AnyUnkeyedDecodingContainer : UnkeyedDecodingContainer { fileprivate init(referencing decoder: _AnyDecoder, wrapping container: [Any]) { self.decoder = decoder self.container = container - self.codingPath = decoder.codingPath - self.currentIndex = 0 + codingPath = decoder.codingPath + currentIndex = 0 } // MARK: - UnkeyedDecodingContainer Methods public var count: Int? { - return self.container.count + return container.count } public var isAtEnd: Bool { - return self.currentIndex >= self.count! + return currentIndex >= count! } public mutating func decodeNil() throws -> Bool { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(Any?.self, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + Any?.self, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - if self.container[self.currentIndex] is NSNull { - self.currentIndex += 1 + if container[currentIndex] is NSNull { + currentIndex += 1 return true } else { return false @@ -1646,594 +2045,907 @@ fileprivate struct _AnyUnkeyedDecodingContainer : UnkeyedDecodingContainer { } public mutating func decode(_ type: Bool.Type) throws -> Bool { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Bool.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Bool.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int.Type) throws -> Int { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Int.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int8.Type) throws -> Int8 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Int8.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int16.Type) throws -> Int16 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Int16.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int32.Type) throws -> Int32 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Int32.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int64.Type) throws -> Int64 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Int64.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt.Type) throws -> UInt { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: UInt.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt8.Type) throws -> UInt8 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: UInt8.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt16.Type) throws -> UInt16 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: UInt16.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt32.Type) throws -> UInt32 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: UInt32.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt64.Type) throws -> UInt64 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + + guard let decoded = try decoder.unbox(container[currentIndex], as: UInt64.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Float.Type) throws -> Float { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Float.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Float.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Double.Type) throws -> Double { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Double.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Double.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: String.Type) throws -> String { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: String.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: String.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } - public mutating func decode(_ type: T.Type) throws -> T { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + public mutating func decode(_ type: T.Type) throws -> T { + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: type) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_AnyKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: type) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_AnyKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } - public mutating func nestedContainer(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer { - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + public mutating func nestedContainer( + keyedBy _: NestedKey + .Type + ) throws -> KeyedDecodingContainer { + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(KeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + KeyedDecodingContainer.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get nested keyed container -- unkeyed container is at end." + ) + ) } - let value = self.container[self.currentIndex] + let value = self.container[currentIndex] guard !(value is NSNull) else { - throw DecodingError.valueNotFound(KeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead.")) + throw DecodingError.valueNotFound( + KeyedDecodingContainer.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead." + ) + ) } - guard let dictionary = value as? [String : Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) + guard let dictionary = value as? [String: Any] else { + throw DecodingError._typeMismatch( + at: codingPath, + expectation: [String: Any].self, + reality: value + ) } - self.currentIndex += 1 - let container = _AnyKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) + currentIndex += 1 + let container = _AnyKeyedDecodingContainer( + referencing: decoder, + wrapping: dictionary + ) return KeyedDecodingContainer(container) } public mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer { - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + UnkeyedDecodingContainer.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get nested keyed container -- unkeyed container is at end." + ) + ) } - let value = self.container[self.currentIndex] + let value = container[currentIndex] guard !(value is NSNull) else { - throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead.")) + throw DecodingError.valueNotFound( + UnkeyedDecodingContainer.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead." + ) + ) } guard let array = value as? [Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: value) + throw DecodingError._typeMismatch( + at: codingPath, + expectation: [Any].self, + reality: value + ) } - self.currentIndex += 1 - return _AnyUnkeyedDecodingContainer(referencing: self.decoder, wrapping: array) + currentIndex += 1 + return _AnyUnkeyedDecodingContainer(referencing: decoder, wrapping: array) } public mutating func superDecoder() throws -> Decoder { - self.decoder.codingPath.append(_AnyKey(index: self.currentIndex)) + decoder.codingPath.append(_AnyKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(Decoder.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get superDecoder() -- unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + Decoder.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get superDecoder() -- unkeyed container is at end." + ) + ) } - let value = self.container[self.currentIndex] - self.currentIndex += 1 - return _AnyDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options) + let value = container[currentIndex] + currentIndex += 1 + return _AnyDecoder(referencing: value, at: decoder.codingPath, options: decoder.options) } } -extension _AnyDecoder : SingleValueDecodingContainer { +extension _AnyDecoder: SingleValueDecodingContainer { // MARK: SingleValueDecodingContainer Methods private func expectNonNull(_ type: T.Type) throws { - guard !self.decodeNil() else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "Expected \(type) but found null value instead.")) + guard !decodeNil() else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: codingPath, + debugDescription: "Expected \(type) but found null value instead." + ) + ) } } public func decodeNil() -> Bool { - return self.storage.topContainer is NSNull + return storage.topContainer is NSNull } - public func decode(_ type: Bool.Type) throws -> Bool { + public func decode(_: Bool.Type) throws -> Bool { try expectNonNull(Bool.self) - return try self.unbox(self.storage.topContainer, as: Bool.self)! + return try unbox(storage.topContainer, as: Bool.self)! } - public func decode(_ type: Int.Type) throws -> Int { + public func decode(_: Int.Type) throws -> Int { try expectNonNull(Int.self) - return try self.unbox(self.storage.topContainer, as: Int.self)! + return try unbox(storage.topContainer, as: Int.self)! } - public func decode(_ type: Int8.Type) throws -> Int8 { + public func decode(_: Int8.Type) throws -> Int8 { try expectNonNull(Int8.self) - return try self.unbox(self.storage.topContainer, as: Int8.self)! + return try unbox(storage.topContainer, as: Int8.self)! } - public func decode(_ type: Int16.Type) throws -> Int16 { + public func decode(_: Int16.Type) throws -> Int16 { try expectNonNull(Int16.self) - return try self.unbox(self.storage.topContainer, as: Int16.self)! + return try unbox(storage.topContainer, as: Int16.self)! } - public func decode(_ type: Int32.Type) throws -> Int32 { + public func decode(_: Int32.Type) throws -> Int32 { try expectNonNull(Int32.self) - return try self.unbox(self.storage.topContainer, as: Int32.self)! + return try unbox(storage.topContainer, as: Int32.self)! } - public func decode(_ type: Int64.Type) throws -> Int64 { + public func decode(_: Int64.Type) throws -> Int64 { try expectNonNull(Int64.self) - return try self.unbox(self.storage.topContainer, as: Int64.self)! + return try unbox(storage.topContainer, as: Int64.self)! } - public func decode(_ type: UInt.Type) throws -> UInt { + public func decode(_: UInt.Type) throws -> UInt { try expectNonNull(UInt.self) - return try self.unbox(self.storage.topContainer, as: UInt.self)! + return try unbox(storage.topContainer, as: UInt.self)! } - public func decode(_ type: UInt8.Type) throws -> UInt8 { + public func decode(_: UInt8.Type) throws -> UInt8 { try expectNonNull(UInt8.self) - return try self.unbox(self.storage.topContainer, as: UInt8.self)! + return try unbox(storage.topContainer, as: UInt8.self)! } - public func decode(_ type: UInt16.Type) throws -> UInt16 { + public func decode(_: UInt16.Type) throws -> UInt16 { try expectNonNull(UInt16.self) - return try self.unbox(self.storage.topContainer, as: UInt16.self)! + return try unbox(storage.topContainer, as: UInt16.self)! } - public func decode(_ type: UInt32.Type) throws -> UInt32 { + public func decode(_: UInt32.Type) throws -> UInt32 { try expectNonNull(UInt32.self) - return try self.unbox(self.storage.topContainer, as: UInt32.self)! + return try unbox(storage.topContainer, as: UInt32.self)! } - public func decode(_ type: UInt64.Type) throws -> UInt64 { + public func decode(_: UInt64.Type) throws -> UInt64 { try expectNonNull(UInt64.self) - return try self.unbox(self.storage.topContainer, as: UInt64.self)! + return try unbox(storage.topContainer, as: UInt64.self)! } - public func decode(_ type: Float.Type) throws -> Float { + public func decode(_: Float.Type) throws -> Float { try expectNonNull(Float.self) - return try self.unbox(self.storage.topContainer, as: Float.self)! + return try unbox(storage.topContainer, as: Float.self)! } - public func decode(_ type: Double.Type) throws -> Double { + public func decode(_: Double.Type) throws -> Double { try expectNonNull(Double.self) - return try self.unbox(self.storage.topContainer, as: Double.self)! + return try unbox(storage.topContainer, as: Double.self)! } - public func decode(_ type: String.Type) throws -> String { + public func decode(_: String.Type) throws -> String { try expectNonNull(String.self) - return try self.unbox(self.storage.topContainer, as: String.self)! + return try unbox(storage.topContainer, as: String.self)! } - public func decode(_ type: T.Type) throws -> T { + public func decode(_ type: T.Type) throws -> T { try expectNonNull(type) - return try self.unbox(self.storage.topContainer, as: type)! + return try unbox(storage.topContainer, as: type)! } } // MARK: - Concrete Value Representations -extension _AnyDecoder { +private extension _AnyDecoder { /// Returns the given value unboxed from a container. - fileprivate func unbox(_ value: Any, as type: Bool.Type) throws -> Bool? { + func unbox(_ value: Any, as type: Bool.Type) throws -> Bool? { guard !(value is NSNull) else { return nil } #if DEPLOYMENT_RUNTIME_SWIFT || os(Linux) - // Bridging differences require us to split implementations here - guard let number = __SwiftValue.store(value) as? NSNumber else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) - } - - // TODO: Add a flag to coerce non-boolean numbers into Bools? - guard CFGetTypeID(number) == CFBooleanGetTypeID() else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) - } + // Bridging differences require us to split implementations here + guard let number = __SwiftValue.store(value) as? NSNumber else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) + } - return number.boolValue - #else - if let number = value as? NSNumber { // TODO: Add a flag to coerce non-boolean numbers into Bools? - if number === kCFBooleanTrue as NSNumber { - return true - } else if number === kCFBooleanFalse as NSNumber { - return false + guard CFGetTypeID(number) == CFBooleanGetTypeID() else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } - /* FIXME: If swift-corelibs-foundation doesn't change to use NSNumber, this code path will need to be included and tested: - } else if let bool = value as? Bool { - return bool - */ + return number.boolValue + #else + if let number = value as? NSNumber { + // TODO: Add a flag to coerce non-boolean numbers into Bools? + if number === kCFBooleanTrue as NSNumber { + return true + } else if number === kCFBooleanFalse as NSNumber { + return false + } - } + /* FIXME: If swift-corelibs-foundation doesn't change to use NSNumber, this code path will need to be included and tested: + } else if let bool = value as? Bool { + return bool + */ + } - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) #endif } - fileprivate func unbox(_ value: Any, as type: Int.Type) throws -> Int? { + func unbox(_ value: Any, as type: Int.Type) throws -> Int? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int = number.intValue guard NSNumber(value: int) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: Int8.Type) throws -> Int8? { + func unbox(_ value: Any, as type: Int8.Type) throws -> Int8? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int8 = number.int8Value guard NSNumber(value: int8) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: Int16.Type) throws -> Int16? { + func unbox(_ value: Any, as type: Int16.Type) throws -> Int16? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int16 = number.int16Value guard NSNumber(value: int16) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: Int32.Type) throws -> Int32? { + func unbox(_ value: Any, as type: Int32.Type) throws -> Int32? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int32 = number.int32Value guard NSNumber(value: int32) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: Int64.Type) throws -> Int64? { + func unbox(_ value: Any, as type: Int64.Type) throws -> Int64? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int64 = number.int64Value guard NSNumber(value: int64) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: UInt.Type) throws -> UInt? { + func unbox(_ value: Any, as type: UInt.Type) throws -> UInt? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint = number.uintValue guard NSNumber(value: uint) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: UInt8.Type) throws -> UInt8? { + func unbox(_ value: Any, as type: UInt8.Type) throws -> UInt8? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint8 = number.uint8Value guard NSNumber(value: uint8) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: UInt16.Type) throws -> UInt16? { + func unbox(_ value: Any, as type: UInt16.Type) throws -> UInt16? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint16 = number.uint16Value guard NSNumber(value: uint16) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? { + func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint32 = number.uint32Value guard NSNumber(value: uint32) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: UInt64.Type) throws -> UInt64? { + func unbox(_ value: Any, as type: UInt64.Type) throws -> UInt64? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint64 = number.uint64Value guard NSNumber(value: uint64) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: Float.Type) throws -> Float? { + 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, number !== kCFBooleanFalse { + if + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + { // We are willing to return a Float by losing precision: // * If the original value was integral, // * and the integral value was > Float.greatestFiniteMagnitude, we will fail @@ -2242,27 +2954,33 @@ 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: self.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) /* FIXME: If swift-corelibs-foundation doesn't change to use NSNumber, this code path will need to be included and tested: - } else if let double = value as? Double { - if abs(double) <= Double(Float.max) { - return Float(double) - } - overflow = true - } else if let int = value as? Int { - if let float = Float(exactly: int) { - return float - } + } else if let double = value as? Double { + if abs(double) <= Double(Float.max) { + return Float(double) + } + overflow = true + } else if let int = value as? Int { + if let float = Float(exactly: int) { + return float + } + + overflow = true + */ - overflow = true - */ - - } else if let string = value as? String, - case .convertFromString(let posInfString, let negInfString, let nanString) = self.options.nonConformingFloatDecodingStrategy { + } else if + let string = value as? String, + case let .convertFromString(posInfString, negInfString, nanString) = options + .nonConformingFloatDecodingStrategy + { if string == posInfString { return Float.infinity } else if string == negInfString { @@ -2272,13 +2990,16 @@ extension _AnyDecoder { } } - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } - fileprivate func unbox(_ value: Any, as type: Double.Type) throws -> Double? { + 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, number !== kCFBooleanFalse { + if + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + { // We are always willing to return the number as a Double: // * If the original value was integral, it is guaranteed to fit in a Double; we are willing to lose precision past 2^53 if you encoded a UInt64 but requested a Double // * If it was a Float or Double, you will get back the precise value @@ -2286,18 +3007,21 @@ extension _AnyDecoder { return number.doubleValue /* FIXME: If swift-corelibs-foundation doesn't change to use NSNumber, this code path will need to be included and tested: - } else if let double = value as? Double { - return double - } else if let int = value as? Int { - if let double = Double(exactly: int) { - return double - } - - overflow = true - */ - - } else if let string = value as? String, - case .convertFromString(let posInfString, let negInfString, let nanString) = self.options.nonConformingFloatDecodingStrategy { + } else if let double = value as? Double { + return double + } else if let int = value as? Int { + if let double = Double(exactly: int) { + return double + } + + overflow = true + */ + + } else if + let string = value as? String, + case let .convertFromString(posInfString, negInfString, nanString) = options + .nonConformingFloatDecodingStrategy + { if string == posInfString { return Double.infinity } else if string == negInfString { @@ -2307,41 +3031,44 @@ extension _AnyDecoder { } } - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } - fileprivate func unbox(_ value: Any, as type: String.Type) throws -> String? { + func unbox(_ value: Any, as type: String.Type) throws -> String? { guard !(value is NSNull) else { return nil } guard let string = value as? String else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } return string } - fileprivate func unbox(_ value: Any, as type: Date.Type) throws -> Date? { + func unbox(_ value: Any, as _: Date.Type) throws -> Date? { guard !(value is NSNull) else { return nil } - switch self.options.dateDecodingStrategy { + switch options.dateDecodingStrategy { case .deferredToDate: - self.storage.push(container: value) + storage.push(container: value) defer { self.storage.popContainer() } return try Date(from: self) case .secondsSince1970: - let double = try self.unbox(value, as: Double.self)! + let double = try unbox(value, as: Double.self)! return Date(timeIntervalSince1970: double) case .millisecondsSince1970: - let double = try self.unbox(value, as: Double.self)! + let double = try unbox(value, as: Double.self)! return Date(timeIntervalSince1970: double / 1000.0) case .iso8601: 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 @@ -2349,71 +3076,77 @@ extension _AnyDecoder { fatalError("ISO8601DateFormatter is unavailable on this platform.") } - case .formatted(let formatter): - let string = try self.unbox(value, as: String.self)! + case let .formatted(formatter): + let string = try unbox(value, as: String.self)! guard let date = formatter.date(from: string) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 .custom(let closure): - self.storage.push(container: value) + case let .custom(closure): + storage.push(container: value) defer { self.storage.popContainer() } return try closure(self) } } - fileprivate func unbox(_ value: Any, as type: Data.Type) throws -> Data? { + func unbox(_ value: Any, as type: Data.Type) throws -> Data? { guard !(value is NSNull) else { return nil } - switch self.options.dataDecodingStrategy { + switch options.dataDecodingStrategy { case .deferredToData: - self.storage.push(container: value) + storage.push(container: value) defer { self.storage.popContainer() } return try Data(from: self) case .base64: guard let string = value as? String else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } guard let data = Data(base64Encoded: string) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 .custom(let closure): - self.storage.push(container: value) + case let .custom(closure): + storage.push(container: value) defer { self.storage.popContainer() } return try closure(self) } } - fileprivate func unbox(_ value: Any, as type: Decimal.Type) throws -> Decimal? { + func unbox(_ value: Any, as _: Decimal.Type) throws -> Decimal? { guard !(value is NSNull) else { return nil } // Attempt to bridge from NSDecimalNumber. if let decimal = value as? Decimal { return decimal } else { - let doubleValue = try self.unbox(value, as: Double.self)! + let doubleValue = try unbox(value, as: Double.self)! return Decimal(doubleValue) } } - fileprivate func unbox(_ value: Any, as type: _AnyStringDictionaryDecodableMarker.Type) throws -> T? { + func unbox(_ value: Any, as type: _AnyStringDictionaryDecodableMarker.Type) throws -> T? { guard !(value is NSNull) else { return nil } - var result = [String : Any]() + var result = [String: Any]() guard let dict = value as? NSDictionary else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let elementType = type.elementType for (key, value) in dict { let key = key as! String - self.codingPath.append(_AnyKey(stringValue: key, intValue: nil)) + codingPath.append(_AnyKey(stringValue: key, intValue: nil)) defer { self.codingPath.removeLast() } result[key] = try unbox_(value, as: elementType) @@ -2422,64 +3155,68 @@ extension _AnyDecoder { return result as? T } - fileprivate func unbox(_ value: Any, as type: T.Type) throws -> T? { + func unbox(_ value: Any, as type: T.Type) throws -> T? { return try unbox_(value, as: type) as? T } - fileprivate func unbox_(_ value: Any, as type: Decodable.Type) throws -> Any? { + 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 { - guard let date = try self.unbox(value, as: Date.self) else { return nil } - return date - } else if type == Data.self { - guard let data = try self.unbox(value, as: Data.self) else { return nil } - return data - } else if type == URL.self { - guard let urlString = try self.unbox(value, as: String.self) else { - return nil - } + // Bridging differences require us to split implementations here + if type == Date.self { + guard let date = try unbox(value, as: Date.self) else { return nil } + return date + } else if type == Data.self { + guard let data = try unbox(value, as: Data.self) else { return nil } + return data + } else if type == URL.self { + guard let urlString = try unbox(value, as: String.self) else { + return nil + } - guard let url = URL(string: urlString) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Invalid URL string.")) + guard let url = URL(string: urlString) else { + throw DecodingError.dataCorrupted(DecodingError.Context( + codingPath: codingPath, + debugDescription: "Invalid URL string." + )) + } + return url + } else if type == Decimal.self { + guard let decimal = try unbox(value, as: Decimal.self) else { return nil } + return decimal + } else if let stringKeyedDictType = type as? _AnyStringDictionaryDecodableMarker.Type { + return try unbox(value, as: stringKeyedDictType) + } else { + storage.push(container: value) + defer { self.storage.popContainer() } + return try type.init(from: self) } - return url - } else if type == Decimal.self { - guard let decimal = try self.unbox(value, as: Decimal.self) else { return nil } - return decimal - } else if let stringKeyedDictType = type as? _AnyStringDictionaryDecodableMarker.Type { - return try self.unbox(value, as: stringKeyedDictType) - } else { - self.storage.push(container: value) - defer { self.storage.popContainer() } - return try type.init(from: self) - } #else - if type == Date.self || type == NSDate.self { - return try self.unbox(value, as: Date.self) - } else if type == Data.self || type == NSData.self { - return try self.unbox(value, as: Data.self) - } else if type == URL.self || type == NSURL.self { - guard let urlString = try self.unbox(value, as: String.self) else { - return nil - } - - guard let url = URL(string: urlString) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Invalid URL string.")) + if type == Date.self || type == NSDate.self { + return try unbox(value, as: Date.self) + } else if type == Data.self || type == NSData.self { + return try unbox(value, as: Data.self) + } else if type == URL.self || type == NSURL.self { + guard let urlString = try unbox(value, as: String.self) else { + return nil + } + + guard let url = URL(string: urlString) else { + throw DecodingError.dataCorrupted(DecodingError.Context( + codingPath: codingPath, + debugDescription: "Invalid URL string." + )) + } + + return url + } else if type == Decimal.self || type == NSDecimalNumber.self { + return try unbox(value, as: Decimal.self) + } else if let stringKeyedDictType = type as? _AnyStringDictionaryDecodableMarker.Type { + return try unbox(value, as: stringKeyedDictType) + } else { + storage.push(container: value) + defer { self.storage.popContainer() } + return try type.init(from: self) } - - return url - } else if type == Decimal.self || type == NSDecimalNumber.self { - return try self.unbox(value, as: Decimal.self) - } else if let stringKeyedDictType = type as? _AnyStringDictionaryDecodableMarker.Type { - return try self.unbox(value, as: stringKeyedDictType) - } else { - self.storage.push(container: value) - defer { self.storage.popContainer() } - return try type.init(from: self) - } #endif } } @@ -2488,17 +3225,17 @@ extension _AnyDecoder { // Shared Key Types //===----------------------------------------------------------------------===// -fileprivate struct _AnyKey : CodingKey { +private struct _AnyKey: CodingKey { public var stringValue: String public var intValue: Int? public init?(stringValue: String) { self.stringValue = stringValue - self.intValue = nil + intValue = nil } public init?(intValue: Int) { - self.stringValue = "\(intValue)" + stringValue = "\(intValue)" self.intValue = intValue } @@ -2506,9 +3243,10 @@ fileprivate struct _AnyKey : CodingKey { self.stringValue = stringValue self.intValue = intValue } + fileprivate init(index: Int) { - self.stringValue = "Index \(index)" - self.intValue = index + stringValue = "Index \(index)" + intValue = index } fileprivate static let `super` = _AnyKey(stringValue: "super")! @@ -2520,7 +3258,7 @@ fileprivate struct _AnyKey : CodingKey { // NOTE: This value is implicitly lazy and _must_ be lazy. We're compiled against the latest SDK (w/ ISO8601DateFormatter), but linked against whichever Foundation the user has. ISO8601DateFormatter might not exist, so we better not hit this code path on an older OS. @available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -fileprivate var _iso8601Formatter: ISO8601DateFormatter = { +private var _iso8601Formatter: ISO8601DateFormatter = { let formatter = ISO8601DateFormatter() formatter.formatOptions = .withInternetDateTime return formatter @@ -2530,14 +3268,17 @@ fileprivate var _iso8601Formatter: ISO8601DateFormatter = { // Error Utilities //===----------------------------------------------------------------------===// -extension EncodingError { +private 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. - fileprivate static func _invalidFloatingPointValue(_ value: T, at codingPath: [CodingKey]) -> EncodingError { + static func _invalidFloatingPointValue( + _ value: T, + at codingPath: [CodingKey] + ) -> EncodingError { let valueDescription: String if value == T.infinity { valueDescription = "\(T.self).infinity" @@ -2547,12 +3288,16 @@ extension EncodingError { valueDescription = "\(T.self).nan" } - let debugDescription = "Unable to encode \(valueDescription) directly in Any. Use AnyEncoder.NonConformingFloatEncodingStrategy.convertToString to specify how the value should be encoded." - return .invalidValue(value, EncodingError.Context(codingPath: codingPath, debugDescription: debugDescription)) + let debugDescription = + "Unable to encode \(valueDescription) directly in Any. Use AnyEncoder.NonConformingFloatEncodingStrategy.convertToString to specify how the value should be encoded." + return .invalidValue( + value, + EncodingError.Context(codingPath: codingPath, debugDescription: debugDescription) + ) } } -private struct __SwiftValue { +private enum __SwiftValue { fileprivate static func store(_ any: Any) -> Any { return any } diff --git a/Sources/GraphQL/Map/AnySerialization.swift b/Sources/GraphQL/Map/AnySerialization.swift index da30a51c..9520d9f3 100644 --- a/Sources/GraphQL/Map/AnySerialization.swift +++ b/Sources/GraphQL/Map/AnySerialization.swift @@ -1,10 +1,10 @@ import Foundation -public struct AnySerialization { +public enum AnySerialization { static func map(with object: NSObject) throws -> Any { return object } - + static func object(with map: Any) throws -> NSObject { guard let result = map as? NSObject else { throw EncodingError.invalidValue( diff --git a/Sources/GraphQL/Map/GraphQLJSONEncoder.swift b/Sources/GraphQL/Map/GraphQLJSONEncoder.swift index 7b94b99c..135a1c46 100644 --- a/Sources/GraphQL/Map/GraphQLJSONEncoder.swift +++ b/Sources/GraphQL/Map/GraphQLJSONEncoder.swift @@ -2,14 +2,15 @@ import Foundation import OrderedCollections // MARK: Copied from JSONEncoder.swift + // https://github.com/apple/swift-corelibs-foundation/blob/eec4b26deee34edb7664ddd9c1222492a399d122/Sources/Foundation/JSONEncoder.swift /// A marker protocol used to determine whether a value is a `String`-keyed `Dictionary` /// containing `Encodable` values (in which case it should be exempt from key conversion strategies). /// -fileprivate protocol _JSONStringDictionaryEncodableMarker { } +private protocol _JSONStringDictionaryEncodableMarker {} -extension Dictionary: _JSONStringDictionaryEncodableMarker where Key == String, Value: Encodable { } +extension Dictionary: _JSONStringDictionaryEncodableMarker where Key == String, Value: Encodable {} //===----------------------------------------------------------------------===// // GraphQL JSON Encoder @@ -22,83 +23,83 @@ extension Dictionary: _JSONStringDictionaryEncodableMarker where Key == String, /// except with all Dictionary objects replaced with OrderedDictionary, and the name changed from JSONEncoder to GraphQLJSONEncoder open class GraphQLJSONEncoder { // MARK: Options - + /// The formatting of the output JSON data. public struct OutputFormatting: OptionSet { /// The format's default value. public let rawValue: UInt - + /// Creates an OutputFormatting value with the given raw value. public init(rawValue: UInt) { self.rawValue = rawValue } - + /// Produce human-readable JSON with indented output. public static let prettyPrinted = OutputFormatting(rawValue: 1 << 0) - + /// Produce JSON with dictionary keys sorted in lexicographic order. @available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) - public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) - + public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) + /// By default slashes get escaped ("/" → "\/", "http://apple.com/" → "http:\/\/apple.com\/") /// for security reasons, allowing outputted JSON to be safely embedded within HTML/XML. /// In contexts where this escaping is unnecessary, the JSON is known to not be embedded, /// or is intended only for display, this option avoids this escaping. public static let withoutEscapingSlashes = OutputFormatting(rawValue: 1 << 3) } - + /// The strategy to use for encoding `Date` values. public enum DateEncodingStrategy { /// Defer to `Date` for choosing an encoding. This is the default strategy. case deferredToDate - + /// Encode the `Date` as a UNIX timestamp (as a JSON number). case secondsSince1970 - + /// Encode the `Date` as UNIX millisecond timestamp (as a JSON number). case millisecondsSince1970 - + /// Encode the `Date` as an ISO-8601-formatted string (in RFC 3339 format). @available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) case iso8601 - + /// Encode the `Date` as a string formatted by the given formatter. case formatted(DateFormatter) - + /// Encode the `Date` as a custom value encoded by the given closure. /// /// If the closure fails to encode a value into the given encoder, the encoder will encode an empty automatic container in its place. case custom((Date, Encoder) throws -> Void) } - + /// The strategy to use for encoding `Data` values. public enum DataEncodingStrategy { /// Defer to `Data` for choosing an encoding. case deferredToData - + /// Encoded the `Data` as a Base64-encoded string. This is the default strategy. case base64 - + /// Encode the `Data` as a custom value encoded by the given closure. /// /// If the closure fails to encode a value into the given encoder, the encoder will encode an empty automatic container in its place. case custom((Data, Encoder) throws -> Void) } - + /// The strategy to use for non-JSON-conforming floating-point values (IEEE 754 infinity and NaN). public enum NonConformingFloatEncodingStrategy { /// Throw upon encountering non-conforming values. This is the default strategy. case `throw` - + /// Encode the values using the given representation strings. case convertToString(positiveInfinity: String, negativeInfinity: String, nan: String) } - + /// The strategy to use for automatically changing the value of keys before encoding. public enum KeyEncodingStrategy { /// Use the keys specified by each type. This is the default strategy. case useDefaultKeys - + /// Convert from "camelCaseKeys" to "snake_case_keys" before writing a key to JSON payload. /// /// Capital characters are determined by testing membership in `CharacterSet.uppercaseLetters` and `CharacterSet.lowercaseLetters` (Unicode General Categories Lu and Lt). @@ -114,15 +115,15 @@ open class GraphQLJSONEncoder { /// /// - Note: Using a key encoding strategy has a nominal performance cost, as each string key has to be converted. case convertToSnakeCase - + /// Provide a custom conversion to the key in the encoded JSON from the keys specified by the encoded types. /// The full path to the current encoding position is provided for context (in case you need to locate this key within the payload). The returned key is used in place of the last component in the coding path before encoding. /// If the result of the conversion is a duplicate key, then only one value will be present in the result. case custom((_ codingPath: [CodingKey]) -> CodingKey) - + fileprivate static func _convertToSnakeCase(_ stringKey: String) -> String { guard !stringKey.isEmpty else { return stringKey } - + var words: [Range] = [] // The general idea of this algorithm is to split words on transition from lower to upper case, then on transition of >1 upper case characters to lowercase // @@ -131,21 +132,33 @@ open class GraphQLJSONEncoder { // // 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)..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..(_ value: T) throws -> Data { let value: JSONValue = try encodeAsJSONValue(value) - let writer = JSONValue.Writer(options: self.outputFormatting) + let writer = JSONValue.Writer(options: outputFormatting) let bytes = writer.writeValue(value) - + return Data(bytes) } - + func encodeAsJSONValue(_ value: T) throws -> JSONValue { - let encoder = JSONEncoderImpl(options: self.options, codingPath: []) + let encoder = JSONEncoderImpl(options: options, codingPath: []) guard let topLevel = try encoder.wrapEncodable(value, for: nil) else { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Top-level \(T.self) did not encode any values.")) + throw EncodingError.invalidValue( + value, + EncodingError + .Context( + codingPath: [], + debugDescription: "Top-level \(T.self) did not encode any values." + ) + ) } - + return topLevel } } @@ -244,68 +266,70 @@ private enum JSONFuture { case encoder(JSONEncoderImpl) case nestedArray(RefArray) case nestedObject(RefObject) - + class RefArray { private(set) var array: [JSONFuture] = [] - + init() { - self.array.reserveCapacity(10) + array.reserveCapacity(10) } - + @inline(__always) func append(_ element: JSONValue) { - self.array.append(.value(element)) + array.append(.value(element)) } - + @inline(__always) func append(_ encoder: JSONEncoderImpl) { - self.array.append(.encoder(encoder)) + array.append(.encoder(encoder)) } - + @inline(__always) func appendArray() -> RefArray { let array = RefArray() self.array.append(.nestedArray(array)) return array } - + @inline(__always) func appendObject() -> RefObject { let object = RefObject() - self.array.append(.nestedObject(object)) + array.append(.nestedObject(object)) return object } - + var values: [JSONValue] { - self.array.map { (future) -> JSONValue in + array.map { future -> JSONValue in switch future { - case .value(let value): + case let .value(value): return value - case .nestedArray(let array): + case let .nestedArray(array): return .array(array.values) - case .nestedObject(let object): + case let .nestedObject(object): return .object(object.values) - case .encoder(let encoder): + case let .encoder(encoder): return encoder.value ?? .object([:]) } } } } - + class RefObject { private(set) var dict: OrderedDictionary = [:] - + init() { - self.dict.reserveCapacity(20) + dict.reserveCapacity(20) } - + @inline(__always) func set(_ value: JSONValue, for key: String) { - self.dict[key] = .value(value) + dict[key] = .value(value) } - + @inline(__always) func setArray(for key: String) -> RefArray { - switch self.dict[key] { + switch dict[key] { case .encoder: preconditionFailure("For key \"\(key)\" an encoder has already been created.") case .nestedObject: - preconditionFailure("For key \"\(key)\" a keyed container has already been created.") - case .nestedArray(let array): + preconditionFailure( + "For key \"\(key)\" a keyed container has already been created." + ) + case let .nestedArray(array): return array case .none, .value: let array = RefArray() @@ -313,45 +337,51 @@ private enum JSONFuture { return array } } - + @inline(__always) func setObject(for key: String) -> RefObject { - switch self.dict[key] { + switch dict[key] { case .encoder: preconditionFailure("For key \"\(key)\" an encoder has already been created.") - case .nestedObject(let object): + case let .nestedObject(object): return object case .nestedArray: - preconditionFailure("For key \"\(key)\" a unkeyed container has already been created.") + preconditionFailure( + "For key \"\(key)\" a unkeyed container has already been created." + ) case .none, .value: let object = RefObject() dict[key] = .nestedObject(object) return object } } - + @inline(__always) func set(_ encoder: JSONEncoderImpl, for key: String) { - switch self.dict[key] { + switch dict[key] { case .encoder: preconditionFailure("For key \"\(key)\" an encoder has already been created.") case .nestedObject: - preconditionFailure("For key \"\(key)\" a keyed container has already been created.") + preconditionFailure( + "For key \"\(key)\" a keyed container has already been created." + ) case .nestedArray: - preconditionFailure("For key \"\(key)\" a unkeyed container has already been created.") + preconditionFailure( + "For key \"\(key)\" a unkeyed container has already been created." + ) case .none, .value: dict[key] = .encoder(encoder) } } - + var values: OrderedDictionary { - self.dict.mapValues { (future) -> JSONValue in + dict.mapValues { future -> JSONValue in switch future { - case .value(let value): + case let .value(value): return value - case .nestedArray(let array): + case let .nestedArray(array): return .array(array.values) - case .nestedObject(let object): + case let .nestedObject(object): return .object(object.values) - case .encoder(let encoder): + case let .encoder(encoder): return encoder.value ?? .object([:]) } } @@ -365,21 +395,21 @@ private class JSONEncoderImpl { var userInfo: [CodingUserInfoKey: Any] { options.userInfo } - + var singleValue: JSONValue? var array: JSONFuture.RefArray? var object: JSONFuture.RefObject? - + var value: JSONValue? { - if let object = self.object { + if let object = object { return .object(object.values) } - if let array = self.array { + if let array = array { return .array(array.values) } - return self.singleValue + return singleValue } - + init(options: GraphQLJSONEncoder._Options, codingPath: [CodingKey]) { self.options = options self.codingPath = codingPath @@ -392,35 +422,35 @@ extension JSONEncoderImpl: Encoder { let container = JSONKeyedEncodingContainer(impl: self, codingPath: codingPath) return KeyedEncodingContainer(container) } - - guard self.singleValue == nil, self.array == nil else { + + guard singleValue == nil, array == nil else { preconditionFailure() } - - self.object = JSONFuture.RefObject() + + object = JSONFuture.RefObject() let container = JSONKeyedEncodingContainer(impl: self, codingPath: codingPath) return KeyedEncodingContainer(container) } - + func unkeyedContainer() -> UnkeyedEncodingContainer { if let _ = array { - return JSONUnkeyedEncodingContainer(impl: self, codingPath: self.codingPath) + return JSONUnkeyedEncodingContainer(impl: self, codingPath: codingPath) } - - guard self.singleValue == nil, self.object == nil else { + + guard singleValue == nil, object == nil else { preconditionFailure() } - - self.array = JSONFuture.RefArray() - return JSONUnkeyedEncodingContainer(impl: self, codingPath: self.codingPath) + + array = JSONFuture.RefArray() + return JSONUnkeyedEncodingContainer(impl: self, codingPath: codingPath) } - + func singleValueContainer() -> SingleValueEncodingContainer { - guard self.object == nil, self.array == nil else { + guard object == nil, array == nil else { preconditionFailure() } - - return JSONSingleValueEncodingContainer(impl: self, codingPath: self.codingPath) + + return JSONSingleValueEncodingContainer(impl: self, codingPath: codingPath) } } @@ -430,25 +460,28 @@ extension JSONEncoderImpl: _SpecialTreatmentEncoder { var impl: JSONEncoderImpl { return self } - + // untyped escape hatch. needed for `wrapObject` func wrapUntyped(_ encodable: Encodable) throws -> JSONValue { switch encodable { case let date as Date: - return try self.wrapDate(date, for: nil) + return try wrapDate(date, for: nil) case let data as Data: - return try self.wrapData(data, for: nil) + return try wrapData(data, for: nil) case let url as URL: return .string(url.absoluteString) case let decimal as Decimal: return .number(decimal.description) - case let object as OrderedDictionary: // this emits a warning, but it works perfectly - return try self.wrapObject(object, for: nil) + case let object as OrderedDictionary< + String, + Encodable + >: // this emits a warning, but it works perfectly + return try wrapObject(object, for: nil) case let date as Date: - return try self.wrapDate(date, for: nil) + return try wrapDate(date, for: nil) default: try encodable.encode(to: self) - return self.value ?? .object([:]) + return value ?? .object([:]) } } } @@ -460,9 +493,15 @@ private protocol _SpecialTreatmentEncoder { } extension _SpecialTreatmentEncoder { - @inline(__always) fileprivate func wrapFloat(_ float: F, for additionalKey: CodingKey?) throws -> JSONValue { + @inline(__always) fileprivate func wrapFloat< + F: FloatingPoint & + CustomStringConvertible + >(_ float: F, for additionalKey: CodingKey?) throws -> JSONValue { guard !float.isNaN, !float.isInfinite else { - if case .convertToString(let posInfString, let negInfString, let nanString) = self.options.nonConformingFloatEncodingStrategy { + if + case let .convertToString(posInfString, negInfString, nanString) = options + .nonConformingFloatEncodingStrategy + { switch float { case F.infinity: return .string(posInfString) @@ -473,267 +512,290 @@ extension _SpecialTreatmentEncoder { return .string(nanString) } } - - var path = self.codingPath + + var path = codingPath if let additionalKey = additionalKey { path.append(additionalKey) } - + throw EncodingError.invalidValue(float, .init( codingPath: path, debugDescription: "Unable to encode \(F.self).\(float) directly in JSON." )) } - + var string = float.description if string.hasSuffix(".0") { string.removeLast(2) } return .number(string) } - - fileprivate func wrapEncodable(_ encodable: E, for additionalKey: CodingKey?) throws -> JSONValue? { + + fileprivate func wrapEncodable( + _ encodable: E, + for additionalKey: CodingKey? + ) throws -> JSONValue? { switch encodable { case let date as Date: - return try self.wrapDate(date, for: additionalKey) + return try wrapDate(date, for: additionalKey) case let data as Data: - return try self.wrapData(data, for: additionalKey) + return try wrapData(data, for: additionalKey) case let url as URL: return .string(url.absoluteString) case let decimal as Decimal: return .number(decimal.description) case let object as OrderedDictionary: - return try self.wrapObject(object, for: additionalKey) + return try wrapObject(object, for: additionalKey) default: - let encoder = self.getEncoder(for: additionalKey) + let encoder = getEncoder(for: additionalKey) try encodable.encode(to: encoder) return encoder.value } } - + func wrapDate(_ date: Date, for additionalKey: CodingKey?) throws -> JSONValue { - switch self.options.dateEncodingStrategy { + switch options.dateEncodingStrategy { case .deferredToDate: - let encoder = self.getEncoder(for: additionalKey) + let encoder = getEncoder(for: additionalKey) try date.encode(to: encoder) return encoder.value ?? .null - + case .secondsSince1970: return .number(date.timeIntervalSince1970.description) - + case .millisecondsSince1970: return .number((date.timeIntervalSince1970 * 1000).description) - + case .iso8601: if #available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { return .string(_iso8601Formatter.string(from: date)) } else { fatalError("ISO8601DateFormatter is unavailable on this platform.") } - - case .formatted(let formatter): + + case let .formatted(formatter): return .string(formatter.string(from: date)) - - case .custom(let closure): - let encoder = self.getEncoder(for: additionalKey) + + case let .custom(closure): + let encoder = getEncoder(for: additionalKey) try closure(date, encoder) // The closure didn't encode anything. Return the default keyed container. return encoder.value ?? .object([:]) } } - + func wrapData(_ data: Data, for additionalKey: CodingKey?) throws -> JSONValue { - switch self.options.dataEncodingStrategy { + switch options.dataEncodingStrategy { case .deferredToData: - let encoder = self.getEncoder(for: additionalKey) + let encoder = getEncoder(for: additionalKey) try data.encode(to: encoder) return encoder.value ?? .null - + case .base64: let base64 = data.base64EncodedString() return .string(base64) - - case .custom(let closure): - let encoder = self.getEncoder(for: additionalKey) + + case let .custom(closure): + let encoder = getEncoder(for: additionalKey) try closure(data, encoder) // The closure didn't encode anything. Return the default keyed container. return encoder.value ?? .object([:]) } } - - func wrapObject(_ object: OrderedDictionary, for additionalKey: CodingKey?) throws -> JSONValue { - var baseCodingPath = self.codingPath + + func wrapObject( + _ object: OrderedDictionary, + for additionalKey: CodingKey? + ) throws -> JSONValue { + var baseCodingPath = codingPath if let additionalKey = additionalKey { baseCodingPath.append(additionalKey) } var result = OrderedDictionary() result.reserveCapacity(object.count) - - try object.forEach { (key, value) in + + try object.forEach { key, value in var elemCodingPath = baseCodingPath elemCodingPath.append(_JSONKey(stringValue: key, intValue: nil)) let encoder = JSONEncoderImpl(options: self.options, codingPath: elemCodingPath) - + result[key] = try encoder.wrapUntyped(value) } - + return .object(result) } - + fileprivate func getEncoder(for additionalKey: CodingKey?) -> JSONEncoderImpl { if let additionalKey = additionalKey { - var newCodingPath = self.codingPath + var newCodingPath = codingPath newCodingPath.append(additionalKey) - return JSONEncoderImpl(options: self.options, codingPath: newCodingPath) + return JSONEncoderImpl(options: options, codingPath: newCodingPath) } - - return self.impl + + return impl } } -private struct JSONKeyedEncodingContainer: KeyedEncodingContainerProtocol, _SpecialTreatmentEncoder { +private struct JSONKeyedEncodingContainer: KeyedEncodingContainerProtocol, + _SpecialTreatmentEncoder +{ typealias Key = K - + let impl: JSONEncoderImpl let object: JSONFuture.RefObject let codingPath: [CodingKey] - + private var firstValueWritten: Bool = false fileprivate var options: GraphQLJSONEncoder._Options { - return self.impl.options + return impl.options } - + init(impl: JSONEncoderImpl, codingPath: [CodingKey]) { self.impl = impl - self.object = impl.object! + object = impl.object! self.codingPath = codingPath } - + // used for nested containers init(impl: JSONEncoderImpl, object: JSONFuture.RefObject, codingPath: [CodingKey]) { self.impl = impl self.object = object self.codingPath = codingPath } - + private func _converted(_ key: Key) -> CodingKey { - switch self.options.keyEncodingStrategy { + switch options.keyEncodingStrategy { case .useDefaultKeys: return key case .convertToSnakeCase: - let newKeyString = GraphQLJSONEncoder.KeyEncodingStrategy._convertToSnakeCase(key.stringValue) + let newKeyString = GraphQLJSONEncoder.KeyEncodingStrategy + ._convertToSnakeCase(key.stringValue) return _JSONKey(stringValue: newKeyString, intValue: key.intValue) - case .custom(let converter): + case let .custom(converter): return converter(codingPath + [key]) } } - + mutating func encodeNil(forKey key: Self.Key) throws { - self.object.set(.null, for: self._converted(key).stringValue) + object.set(.null, for: _converted(key).stringValue) } - + mutating func encode(_ value: Bool, forKey key: Self.Key) throws { - self.object.set(.bool(value), for: self._converted(key).stringValue) + object.set(.bool(value), for: _converted(key).stringValue) } - + mutating func encode(_ value: String, forKey key: Self.Key) throws { - self.object.set(.string(value), for: self._converted(key).stringValue) + object.set(.string(value), for: _converted(key).stringValue) } - + mutating func encode(_ value: Double, forKey key: Self.Key) throws { - try encodeFloatingPoint(value, key: self._converted(key)) + try encodeFloatingPoint(value, key: _converted(key)) } - + mutating func encode(_ value: Float, forKey key: Self.Key) throws { - try encodeFloatingPoint(value, key: self._converted(key)) + try encodeFloatingPoint(value, key: _converted(key)) } - + mutating func encode(_ value: Int, forKey key: Self.Key) throws { - try encodeFixedWidthInteger(value, key: self._converted(key)) + try encodeFixedWidthInteger(value, key: _converted(key)) } - + mutating func encode(_ value: Int8, forKey key: Self.Key) throws { - try encodeFixedWidthInteger(value, key: self._converted(key)) + try encodeFixedWidthInteger(value, key: _converted(key)) } - + mutating func encode(_ value: Int16, forKey key: Self.Key) throws { - try encodeFixedWidthInteger(value, key: self._converted(key)) + try encodeFixedWidthInteger(value, key: _converted(key)) } - + mutating func encode(_ value: Int32, forKey key: Self.Key) throws { - try encodeFixedWidthInteger(value, key: self._converted(key)) + try encodeFixedWidthInteger(value, key: _converted(key)) } - + mutating func encode(_ value: Int64, forKey key: Self.Key) throws { - try encodeFixedWidthInteger(value, key: self._converted(key)) + try encodeFixedWidthInteger(value, key: _converted(key)) } - + mutating func encode(_ value: UInt, forKey key: Self.Key) throws { - try encodeFixedWidthInteger(value, key: self._converted(key)) + try encodeFixedWidthInteger(value, key: _converted(key)) } - + mutating func encode(_ value: UInt8, forKey key: Self.Key) throws { - try encodeFixedWidthInteger(value, key: self._converted(key)) + try encodeFixedWidthInteger(value, key: _converted(key)) } - + mutating func encode(_ value: UInt16, forKey key: Self.Key) throws { - try encodeFixedWidthInteger(value, key: self._converted(key)) + try encodeFixedWidthInteger(value, key: _converted(key)) } - + mutating func encode(_ value: UInt32, forKey key: Self.Key) throws { - try encodeFixedWidthInteger(value, key: self._converted(key)) + try encodeFixedWidthInteger(value, key: _converted(key)) } - + mutating func encode(_ value: UInt64, forKey key: Self.Key) throws { - try encodeFixedWidthInteger(value, key: self._converted(key)) + try encodeFixedWidthInteger(value, key: _converted(key)) } - + mutating func encode(_ value: T, forKey key: Self.Key) throws where T: Encodable { - let convertedKey = self._converted(key) - let encoded = try self.wrapEncodable(value, for: convertedKey) - self.object.set(encoded ?? .object([:]), for: convertedKey.stringValue) + let convertedKey = _converted(key) + let encoded = try wrapEncodable(value, for: convertedKey) + object.set(encoded ?? .object([:]), for: convertedKey.stringValue) } - + mutating func nestedContainer(keyedBy _: NestedKey.Type, forKey key: Self.Key) -> - KeyedEncodingContainer where NestedKey: CodingKey + KeyedEncodingContainer where NestedKey: CodingKey { - let convertedKey = self._converted(key) - let newPath = self.codingPath + [convertedKey] + let convertedKey = _converted(key) + let newPath = codingPath + [convertedKey] let object = self.object.setObject(for: convertedKey.stringValue) - let nestedContainer = JSONKeyedEncodingContainer(impl: impl, object: object, codingPath: newPath) + let nestedContainer = JSONKeyedEncodingContainer( + impl: impl, + object: object, + codingPath: newPath + ) return KeyedEncodingContainer(nestedContainer) } - + mutating func nestedUnkeyedContainer(forKey key: Self.Key) -> UnkeyedEncodingContainer { - let convertedKey = self._converted(key) - let newPath = self.codingPath + [convertedKey] - let array = self.object.setArray(for: convertedKey.stringValue) - let nestedContainer = JSONUnkeyedEncodingContainer(impl: impl, array: array, codingPath: newPath) + let convertedKey = _converted(key) + let newPath = codingPath + [convertedKey] + let array = object.setArray(for: convertedKey.stringValue) + let nestedContainer = JSONUnkeyedEncodingContainer( + impl: impl, + array: array, + codingPath: newPath + ) return nestedContainer } - + mutating func superEncoder() -> Encoder { - let newEncoder = self.getEncoder(for: _JSONKey.super) - self.object.set(newEncoder, for: _JSONKey.super.stringValue) + let newEncoder = getEncoder(for: _JSONKey.super) + object.set(newEncoder, for: _JSONKey.super.stringValue) return newEncoder } - + mutating func superEncoder(forKey key: Self.Key) -> Encoder { - let convertedKey = self._converted(key) - let newEncoder = self.getEncoder(for: convertedKey) - self.object.set(newEncoder, for: convertedKey.stringValue) + let convertedKey = _converted(key) + let newEncoder = getEncoder(for: convertedKey) + object.set(newEncoder, for: convertedKey.stringValue) return newEncoder } } extension JSONKeyedEncodingContainer { - @inline(__always) private mutating func encodeFloatingPoint(_ float: F, key: CodingKey) throws { - let value = try self.wrapFloat(float, for: key) - self.object.set(value, for: key.stringValue) + @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) } - - @inline(__always) private mutating func encodeFixedWidthInteger(_ value: N, key: CodingKey) throws { - self.object.set(.number(value.description), for: key.stringValue) + + @inline(__always) private mutating func encodeFixedWidthInteger( + _ value: N, + key: CodingKey + ) throws { + object.set(.number(value.description), for: key.stringValue) } } @@ -741,248 +803,266 @@ private struct JSONUnkeyedEncodingContainer: UnkeyedEncodingContainer, _SpecialT let impl: JSONEncoderImpl let array: JSONFuture.RefArray let codingPath: [CodingKey] - + var count: Int { - self.array.array.count + array.array.count } + private var firstValueWritten: Bool = false fileprivate var options: GraphQLJSONEncoder._Options { - return self.impl.options + return impl.options } - + init(impl: JSONEncoderImpl, codingPath: [CodingKey]) { self.impl = impl - self.array = impl.array! + array = impl.array! self.codingPath = codingPath } - + // used for nested containers init(impl: JSONEncoderImpl, array: JSONFuture.RefArray, codingPath: [CodingKey]) { self.impl = impl self.array = array self.codingPath = codingPath } - + mutating func encodeNil() throws { - self.array.append(.null) + array.append(.null) } - + mutating func encode(_ value: Bool) throws { - self.array.append(.bool(value)) + array.append(.bool(value)) } - + mutating func encode(_ value: String) throws { - self.array.append(.string(value)) + array.append(.string(value)) } - + mutating func encode(_ value: Double) throws { try encodeFloatingPoint(value) } - + mutating func encode(_ value: Float) throws { try encodeFloatingPoint(value) } - + mutating func encode(_ value: Int) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: Int8) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: Int16) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: Int32) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: Int64) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: UInt) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: UInt8) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: UInt16) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: UInt32) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: UInt64) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: T) throws where T: Encodable { - let key = _JSONKey(stringValue: "Index \(self.count)", intValue: self.count) - let encoded = try self.wrapEncodable(value, for: key) - self.array.append(encoded ?? .object([:])) + let key = _JSONKey(stringValue: "Index \(count)", intValue: count) + let encoded = try wrapEncodable(value, for: key) + array.append(encoded ?? .object([:])) } - + mutating func nestedContainer(keyedBy _: NestedKey.Type) -> - KeyedEncodingContainer where NestedKey: CodingKey + KeyedEncodingContainer where NestedKey: CodingKey { - let newPath = self.codingPath + [_JSONKey(index: self.count)] - let object = self.array.appendObject() - let nestedContainer = JSONKeyedEncodingContainer(impl: impl, object: object, codingPath: newPath) + let newPath = codingPath + [_JSONKey(index: count)] + let object = array.appendObject() + let nestedContainer = JSONKeyedEncodingContainer( + impl: impl, + object: object, + codingPath: newPath + ) return KeyedEncodingContainer(nestedContainer) } - + mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { - let newPath = self.codingPath + [_JSONKey(index: self.count)] + let newPath = codingPath + [_JSONKey(index: count)] let array = self.array.appendArray() - let nestedContainer = JSONUnkeyedEncodingContainer(impl: impl, array: array, codingPath: newPath) + let nestedContainer = JSONUnkeyedEncodingContainer( + impl: impl, + array: array, + codingPath: newPath + ) return nestedContainer } - + mutating func superEncoder() -> Encoder { - let encoder = self.getEncoder(for: _JSONKey(index: self.count)) - self.array.append(encoder) + let encoder = getEncoder(for: _JSONKey(index: count)) + array.append(encoder) return encoder } } extension JSONUnkeyedEncodingContainer { @inline(__always) private mutating func encodeFixedWidthInteger(_ value: N) throws { - self.array.append(.number(value.description)) + array.append(.number(value.description)) } - - @inline(__always) private mutating func encodeFloatingPoint(_ float: F) throws { - let value = try self.wrapFloat(float, for: _JSONKey(index: self.count)) - self.array.append(value) + + @inline(__always) private mutating func encodeFloatingPoint< + F: FloatingPoint & + CustomStringConvertible + >(_ float: F) throws { + let value = try wrapFloat(float, for: _JSONKey(index: count)) + array.append(value) } } -private struct JSONSingleValueEncodingContainer: SingleValueEncodingContainer, _SpecialTreatmentEncoder { +private struct JSONSingleValueEncodingContainer: SingleValueEncodingContainer, + _SpecialTreatmentEncoder +{ let impl: JSONEncoderImpl let codingPath: [CodingKey] - + private var firstValueWritten: Bool = false fileprivate var options: GraphQLJSONEncoder._Options { - return self.impl.options + return impl.options } - + init(impl: JSONEncoderImpl, codingPath: [CodingKey]) { self.impl = impl self.codingPath = codingPath } - + mutating func encodeNil() throws { - self.preconditionCanEncodeNewValue() - self.impl.singleValue = .null + preconditionCanEncodeNewValue() + impl.singleValue = .null } - + mutating func encode(_ value: Bool) throws { - self.preconditionCanEncodeNewValue() - self.impl.singleValue = .bool(value) + preconditionCanEncodeNewValue() + impl.singleValue = .bool(value) } - + mutating func encode(_ value: Int) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: Int8) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: Int16) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: Int32) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: Int64) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: UInt) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: UInt8) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: UInt16) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: UInt32) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: UInt64) throws { try encodeFixedWidthInteger(value) } - + mutating func encode(_ value: Float) throws { try encodeFloatingPoint(value) } - + mutating func encode(_ value: Double) throws { try encodeFloatingPoint(value) } - + mutating func encode(_ value: String) throws { - self.preconditionCanEncodeNewValue() - self.impl.singleValue = .string(value) + preconditionCanEncodeNewValue() + impl.singleValue = .string(value) } - + mutating func encode(_ value: T) throws { - self.preconditionCanEncodeNewValue() - self.impl.singleValue = try self.wrapEncodable(value, for: nil) + preconditionCanEncodeNewValue() + impl.singleValue = try wrapEncodable(value, for: nil) } - + func preconditionCanEncodeNewValue() { - precondition(self.impl.singleValue == nil, "Attempt to encode value through single value container when previously value already encoded.") + precondition( + impl.singleValue == nil, + "Attempt to encode value through single value container when previously value already encoded." + ) } } extension JSONSingleValueEncodingContainer { @inline(__always) private mutating func encodeFixedWidthInteger(_ value: N) throws { - self.preconditionCanEncodeNewValue() - self.impl.singleValue = .number(value.description) + preconditionCanEncodeNewValue() + impl.singleValue = .number(value.description) } - - @inline(__always) private mutating func encodeFloatingPoint(_ float: F) throws { - self.preconditionCanEncodeNewValue() - let value = try self.wrapFloat(float, for: nil) - self.impl.singleValue = value + + @inline(__always) private mutating func encodeFloatingPoint< + F: FloatingPoint & + CustomStringConvertible + >(_ float: F) throws { + preconditionCanEncodeNewValue() + let value = try wrapFloat(float, for: nil) + impl.singleValue = value } } -extension JSONValue { - - fileprivate struct Writer { +private extension JSONValue { + struct Writer { let options: GraphQLJSONEncoder.OutputFormatting - + init(options: GraphQLJSONEncoder.OutputFormatting) { self.options = options } - + func writeValue(_ value: JSONValue) -> [UInt8] { var bytes = [UInt8]() - if self.options.contains(.prettyPrinted) { - self.writeValuePretty(value, into: &bytes) - } - else { - self.writeValue(value, into: &bytes) + if options.contains(.prettyPrinted) { + writeValuePretty(value, into: &bytes) + } else { + writeValue(value, into: &bytes) } return bytes } - + private func writeValue(_ value: JSONValue, into bytes: inout [UInt8]) { switch value { case .null: @@ -991,58 +1071,66 @@ extension JSONValue { bytes.append(contentsOf: [UInt8]._true) case .bool(false): bytes.append(contentsOf: [UInt8]._false) - case .string(let string): - self.encodeString(string, to: &bytes) - case .number(let string): + case let .string(string): + encodeString(string, to: &bytes) + case let .number(string): bytes.append(contentsOf: string.utf8) - case .array(let array): + case let .array(array): var iterator = array.makeIterator() bytes.append(._openbracket) // we don't like branching, this is why we have this extra if let first = iterator.next() { - self.writeValue(first, into: &bytes) + writeValue(first, into: &bytes) } while let item = iterator.next() { bytes.append(._comma) - self.writeValue(item, into:&bytes) + writeValue(item, into: &bytes) } bytes.append(._closebracket) - case .object(let dict): + case let .object(dict): if #available(OSX 10.13, *), options.contains(.sortedKeys) { let sorted = dict.sorted { $0.key < $1.key } self.writeObject(sorted, into: &bytes) } else { - self.writeObject(dict, into: &bytes) + writeObject(dict, into: &bytes) } } } - - private func writeObject(_ object: Object, into bytes: inout [UInt8], depth: Int = 0) - where Object.Element == (key: String, value: JSONValue) + + private func writeObject( + _ object: Object, + into bytes: inout [UInt8], + depth _: Int = 0 + ) + where Object.Element == (key: String, value: JSONValue) { var iterator = object.makeIterator() bytes.append(._openbrace) if let (key, value) = iterator.next() { - self.encodeString(key, to: &bytes) + encodeString(key, to: &bytes) bytes.append(._colon) - self.writeValue(value, into: &bytes) + writeValue(value, into: &bytes) } while let (key, value) = iterator.next() { bytes.append(._comma) // key - self.encodeString(key, to: &bytes) + encodeString(key, to: &bytes) bytes.append(._colon) - - self.writeValue(value, into: &bytes) + + writeValue(value, into: &bytes) } bytes.append(._closebrace) } - + private func addInset(to bytes: inout [UInt8], depth: Int) { bytes.append(contentsOf: [UInt8](repeating: ._space, count: depth * 2)) } - - private func writeValuePretty(_ value: JSONValue, into bytes: inout [UInt8], depth: Int = 0) { + + private func writeValuePretty( + _ value: JSONValue, + into bytes: inout [UInt8], + depth: Int = 0 + ) { switch value { case .null: bytes.append(contentsOf: [UInt8]._null) @@ -1050,66 +1138,70 @@ extension JSONValue { bytes.append(contentsOf: [UInt8]._true) case .bool(false): bytes.append(contentsOf: [UInt8]._false) - case .string(let string): - self.encodeString(string, to: &bytes) - case .number(let string): + case let .string(string): + encodeString(string, to: &bytes) + case let .number(string): bytes.append(contentsOf: string.utf8) - case .array(let array): + case let .array(array): var iterator = array.makeIterator() bytes.append(contentsOf: [._openbracket, ._newline]) if let first = iterator.next() { - self.addInset(to: &bytes, depth: depth + 1) - self.writeValuePretty(first, into: &bytes, depth: depth + 1) + addInset(to: &bytes, depth: depth + 1) + writeValuePretty(first, into: &bytes, depth: depth + 1) } while let item = iterator.next() { bytes.append(contentsOf: [._comma, ._newline]) - self.addInset(to: &bytes, depth: depth + 1) - self.writeValuePretty(item, into: &bytes, depth: depth + 1) + addInset(to: &bytes, depth: depth + 1) + writeValuePretty(item, into: &bytes, depth: depth + 1) } bytes.append(._newline) - self.addInset(to: &bytes, depth: depth) + addInset(to: &bytes, depth: depth) bytes.append(._closebracket) - case .object(let dict): + case let .object(dict): if #available(OSX 10.13, *), options.contains(.sortedKeys) { let sorted = dict.sorted { $0.key < $1.key } self.writePrettyObject(sorted, into: &bytes, depth: depth) } else { - self.writePrettyObject(dict, into: &bytes, depth: depth) + writePrettyObject(dict, into: &bytes, depth: depth) } } } - - private func writePrettyObject(_ object: Object, into bytes: inout [UInt8], depth: Int = 0) - where Object.Element == (key: String, value: JSONValue) + + private func writePrettyObject( + _ object: Object, + into bytes: inout [UInt8], + depth: Int = 0 + ) + where Object.Element == (key: String, value: JSONValue) { var iterator = object.makeIterator() bytes.append(contentsOf: [._openbrace, ._newline]) if let (key, value) = iterator.next() { - self.addInset(to: &bytes, depth: depth + 1) - self.encodeString(key, to: &bytes) + addInset(to: &bytes, depth: depth + 1) + encodeString(key, to: &bytes) bytes.append(contentsOf: [._space, ._colon, ._space]) - self.writeValuePretty(value, into: &bytes, depth: depth + 1) + writeValuePretty(value, into: &bytes, depth: depth + 1) } while let (key, value) = iterator.next() { bytes.append(contentsOf: [._comma, ._newline]) - self.addInset(to: &bytes, depth: depth + 1) + addInset(to: &bytes, depth: depth + 1) // key - self.encodeString(key, to: &bytes) + encodeString(key, to: &bytes) bytes.append(contentsOf: [._space, ._colon, ._space]) // value - self.writeValuePretty(value, into: &bytes, depth: depth + 1) + writeValuePretty(value, into: &bytes, depth: depth + 1) } bytes.append(._newline) - self.addInset(to: &bytes, depth: depth) + addInset(to: &bytes, depth: depth) bytes.append(._closebrace) } - + private func encodeString(_ string: String, to bytes: inout [UInt8]) { bytes.append(UInt8(ascii: "\"")) let stringBytes = string.utf8 var startCopyIndex = stringBytes.startIndex var nextIndex = startCopyIndex - + while nextIndex != stringBytes.endIndex { switch stringBytes[nextIndex] { case 0 ..< 32, UInt8(ascii: "\""), UInt8(ascii: "\\"): @@ -1118,7 +1210,7 @@ extension JSONValue { // quotation mark, reverse solidus, and the control characters (U+0000 // through U+001F). // https://tools.ietf.org/html/rfc8259#section-7 - + // copy the current range over bytes.append(contentsOf: stringBytes[startCopyIndex ..< nextIndex]) switch stringBytes[nextIndex] { @@ -1156,7 +1248,7 @@ extension JSONValue { bytes.append(valueToAscii(first)) bytes.append(valueToAscii(remaining)) } - + nextIndex = stringBytes.index(after: nextIndex) startCopyIndex = nextIndex case UInt8(ascii: "/") where options.contains(.withoutEscapingSlashes) == false: @@ -1168,7 +1260,7 @@ extension JSONValue { nextIndex = stringBytes.index(after: nextIndex) } } - + // copy everything, that hasn't been copied yet bytes.append(contentsOf: stringBytes[startCopyIndex ..< nextIndex]) bytes.append(UInt8(ascii: "\"")) @@ -1176,7 +1268,6 @@ extension JSONValue { } } - //===----------------------------------------------------------------------===// // Shared Key Types //===----------------------------------------------------------------------===// @@ -1184,27 +1275,27 @@ extension JSONValue { internal struct _JSONKey: CodingKey { public var stringValue: String public var intValue: Int? - + public init?(stringValue: String) { self.stringValue = stringValue - self.intValue = nil + intValue = nil } - + public init?(intValue: Int) { - self.stringValue = "\(intValue)" + stringValue = "\(intValue)" self.intValue = intValue } - + public init(stringValue: String, intValue: Int?) { self.stringValue = stringValue self.intValue = intValue } - + internal init(index: Int) { - self.stringValue = "Index \(index)" - self.intValue = index + stringValue = "Index \(index)" + intValue = index } - + internal static let `super` = _JSONKey(stringValue: "super")! } @@ -1214,7 +1305,7 @@ internal struct _JSONKey: CodingKey { // NOTE: This value is implicitly lazy and _must_ be lazy. We're compiled against the latest SDK (w/ ISO8601DateFormatter), but linked against whichever Foundation the user has. ISO8601DateFormatter might not exist, so we better not hit this code path on an older OS. @available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -fileprivate var _iso8601Formatter: ISO8601DateFormatter = { +private var _iso8601Formatter: ISO8601DateFormatter = { let formatter = ISO8601DateFormatter() formatter.formatOptions = .withInternetDateTime return formatter @@ -1224,14 +1315,17 @@ fileprivate var _iso8601Formatter: ISO8601DateFormatter = { // Error Utilities //===----------------------------------------------------------------------===// -extension EncodingError { +private 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. - fileprivate static func _invalidFloatingPointValue(_ value: T, at codingPath: [CodingKey]) -> EncodingError { + static func _invalidFloatingPointValue( + _ value: T, + at codingPath: [CodingKey] + ) -> EncodingError { let valueDescription: String if value == T.infinity { valueDescription = "\(T.self).infinity" @@ -1240,13 +1334,18 @@ extension EncodingError { } else { valueDescription = "\(T.self).nan" } - - let debugDescription = "Unable to encode \(valueDescription) directly in JSON. Use GraphQLJSONEncoder.NonConformingFloatEncodingStrategy.convertToString to specify how the value should be encoded." - return .invalidValue(value, EncodingError.Context(codingPath: codingPath, debugDescription: debugDescription)) + + let debugDescription = + "Unable to encode \(valueDescription) directly in JSON. Use GraphQLJSONEncoder.NonConformingFloatEncodingStrategy.convertToString to specify how the value should be encoded." + return .invalidValue( + value, + EncodingError.Context(codingPath: codingPath, debugDescription: debugDescription) + ) } } // MARK: Copied from JSONSerialization.swift + // Imported from https://github.com/apple/swift-corelibs-foundation/blob/ee856f110177289af602c4040a996507f7d1b3ce/Sources/Foundation/JSONSerialization.swift#L625 enum JSONValue: Equatable { @@ -1254,39 +1353,42 @@ enum JSONValue: Equatable { case number(String) case bool(Bool) case null - + case array([JSONValue]) case object(OrderedDictionary) } // MARK: Copied from JSONSerialization+Parser.swift + // Imported from https://github.com/apple/swift-corelibs-foundation/blob/eec4b26deee34edb7664ddd9c1222492a399d122/Sources/Foundation/JSONSerialization%2BParser.swift#L625 extension UInt8 { - - internal static let _space = UInt8(ascii: " ") - internal static let _return = UInt8(ascii: "\r") - internal static let _newline = UInt8(ascii: "\n") - internal static let _tab = UInt8(ascii: "\t") - - internal static let _colon = UInt8(ascii: ":") - internal static let _comma = UInt8(ascii: ",") - - internal static let _openbrace = UInt8(ascii: "{") - internal static let _closebrace = UInt8(ascii: "}") - - internal static let _openbracket = UInt8(ascii: "[") - internal static let _closebracket = UInt8(ascii: "]") - - internal static let _quote = UInt8(ascii: "\"") - internal static let _backslash = UInt8(ascii: "\\") - + static let _space = UInt8(ascii: " ") + static let _return = UInt8(ascii: "\r") + static let _newline = UInt8(ascii: "\n") + static let _tab = UInt8(ascii: "\t") + + static let _colon = UInt8(ascii: ":") + static let _comma = UInt8(ascii: ",") + + static let _openbrace = UInt8(ascii: "{") + static let _closebrace = UInt8(ascii: "}") + + static let _openbracket = UInt8(ascii: "[") + static let _closebracket = UInt8(ascii: "]") + + static let _quote = UInt8(ascii: "\"") + static let _backslash = UInt8(ascii: "\\") } extension Array where Element == UInt8 { - - internal static let _true = [UInt8(ascii: "t"), UInt8(ascii: "r"), UInt8(ascii: "u"), UInt8(ascii: "e")] - internal static let _false = [UInt8(ascii: "f"), UInt8(ascii: "a"), UInt8(ascii: "l"), UInt8(ascii: "s"), UInt8(ascii: "e")] - internal static let _null = [UInt8(ascii: "n"), UInt8(ascii: "u"), UInt8(ascii: "l"), UInt8(ascii: "l")] - + static let _true = [UInt8(ascii: "t"), UInt8(ascii: "r"), UInt8(ascii: "u"), UInt8(ascii: "e")] + static let _false = [ + UInt8(ascii: "f"), + UInt8(ascii: "a"), + UInt8(ascii: "l"), + UInt8(ascii: "s"), + UInt8(ascii: "e"), + ] + static let _null = [UInt8(ascii: "n"), UInt8(ascii: "u"), UInt8(ascii: "l"), UInt8(ascii: "l")] } diff --git a/Sources/GraphQL/Map/Map.swift b/Sources/GraphQL/Map/Map.swift index 4e8b3d40..604c0aea 100644 --- a/Sources/GraphQL/Map/Map.swift +++ b/Sources/GraphQL/Map/Map.swift @@ -3,7 +3,7 @@ import OrderedCollections // MARK: MapError -public enum MapError : Error { +public enum MapError: Error { case incompatibleType case outOfBounds case valueNotFound @@ -19,11 +19,11 @@ public enum Map { case string(String) case array([Map]) case dictionary(OrderedDictionary) - + public static func int(_ value: Int) -> Map { return .number(Number(value)) } - + public static func double(_ value: Double) -> Map { return .number(Number(value)) } @@ -31,67 +31,67 @@ public enum Map { // MARK: Initializers -extension Map { - public static let encoder = MapEncoder() +public extension Map { + static let encoder = MapEncoder() - public init(_ encodable: T, encoder: MapEncoder = Map.encoder) throws { + init(_ encodable: T, encoder: MapEncoder = Map.encoder) throws { self = try encoder.encode(encodable) } - - public init(_ number: Number) { + + init(_ number: Number) { self = .number(number) } - - public init(_ bool: Bool) { + + init(_ bool: Bool) { self = .bool(bool) } - - public init(_ int: Int) { + + init(_ int: Int) { self.init(Number(int)) } - - public init(_ double: Double) { + + init(_ double: Double) { self.init(Number(double)) } - - public init(_ string: String) { + + init(_ string: String) { self = .string(string) } - - public init(_ array: [Map]) { + + init(_ array: [Map]) { self = .array(array) } - - public init(_ dictionary: OrderedDictionary) { + + init(_ dictionary: OrderedDictionary) { self = .dictionary(dictionary) } - - public init(_ number: Number?) { - self = number.map({ Map($0) }) ?? .null + + init(_ number: Number?) { + self = number.map { Map($0) } ?? .null } - - public init(_ bool: Bool?) { - self.init(bool.map({ Number($0) })) + + init(_ bool: Bool?) { + self.init(bool.map { Number($0) }) } - - public init(_ int: Int?) { - self.init(int.map({ Number($0) })) + + init(_ int: Int?) { + self.init(int.map { Number($0) }) } - - public init(_ double: Double?) { - self.init(double.map({ Number($0) })) + + init(_ double: Double?) { + self.init(double.map { Number($0) }) } - - public init(_ string: String?) { - self = string.map({ Map($0) }) ?? .null + + init(_ string: String?) { + self = string.map { Map($0) } ?? .null } - - public init(_ array: [Map]?) { - self = array.map({ Map($0) }) ?? .null + + init(_ array: [Map]?) { + self = array.map { Map($0) } ?? .null } - - public init(_ dictionary: OrderedDictionary?) { - self = dictionary.map({ Map($0) }) ?? .null + + init(_ dictionary: OrderedDictionary?) { + self = dictionary.map { Map($0) } ?? .null } } @@ -101,20 +101,21 @@ public func map(from value: Any?) throws -> Map { guard let value = value else { return .null } - + if let map = value as? Map { return map } - + if let map = try? Map(any: value) { 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) - }) + let dictionary: OrderedDictionary = try? value + .reduce(into: [:], { result, pair in + result[pair.key] = try map(from: pair.value) + }) { return .dictionary(dictionary) } @@ -128,7 +129,6 @@ public func map(from value: Any?) throws -> Map { return .array(array) } - if let value = value as? Encodable, let map = try? Map(AnyEncodable(value)) @@ -139,8 +139,8 @@ public func map(from value: Any?) throws -> Map { throw MapError.incompatibleType } -extension Map { - public init(any: Any?) throws { +public extension Map { + init(any: Any?) throws { switch any { case .none: self = .null @@ -166,43 +166,43 @@ extension Map { // MARK: is -extension Map { - public var isUndefined: Bool { +public extension Map { + var isUndefined: Bool { if case .undefined = self { return true } return false } - - public var isNull: Bool { + + var isNull: Bool { if case .null = self { return true } return false } - public var isNumber: Bool { + var isNumber: Bool { if case .number = self { return true } return false } - public var isString: Bool { + var isString: Bool { if case .string = self { return true } return false } - public var isArray: Bool { + var isArray: Bool { if case .array = self { return true } return false } - public var isDictionary: Bool { + var isDictionary: Bool { if case .dictionary = self { return true } @@ -212,8 +212,8 @@ extension Map { // MARK: is -extension Map { - public var typeDescription: String { +public extension Map { + var typeDescription: String { switch self { case .undefined: return "undefined" @@ -235,36 +235,36 @@ extension Map { // MARK: as? -extension Map { - public var bool: Bool? { +public extension Map { + var bool: Bool? { return try? boolValue() } - - public var int: Int? { + + var int: Int? { return try? intValue() } - public var double: Double? { + var double: Double? { return try? doubleValue() } - public var string: String? { + var string: String? { return try? stringValue() } - public var array: [Map]? { + var array: [Map]? { return try? arrayValue() } - public var dictionary: OrderedDictionary? { + var dictionary: OrderedDictionary? { return try? dictionaryValue() } } // MARK: try as() -extension Map { - public func boolValue(converting: Bool = false) throws -> Bool { +public extension Map { + func boolValue(converting: Bool = false) throws -> Bool { guard converting else { return try get() } @@ -272,13 +272,13 @@ extension Map { switch self { case .undefined: return false - + case .null: return false case let .bool(value): return value - + case let .number(number): return number.boolValue @@ -297,7 +297,7 @@ extension Map { } } - public func intValue(converting: Bool = false) throws -> Int { + func intValue(converting: Bool = false) throws -> Int { guard converting else { return try (get() as Number).intValue } @@ -305,7 +305,7 @@ extension Map { switch self { case .null: return 0 - + case let .number(number): return number.intValue @@ -313,7 +313,7 @@ extension Map { guard let value = Int(value) else { throw MapError.incompatibleType } - + return value default: @@ -321,7 +321,7 @@ extension Map { } } - public func doubleValue(converting: Bool = false) throws -> Double { + func doubleValue(converting: Bool = false) throws -> Double { guard converting else { return try (get() as Number).doubleValue } @@ -329,7 +329,7 @@ extension Map { switch self { case .null: return 0 - + case let .number(number): return number.doubleValue @@ -337,7 +337,7 @@ extension Map { guard let value = Double(value) else { throw MapError.incompatibleType } - + return value default: @@ -345,7 +345,7 @@ extension Map { } } - public func stringValue(converting: Bool = false) throws -> String { + func stringValue(converting: Bool = false) throws -> String { guard converting else { return try get() } @@ -353,13 +353,13 @@ extension Map { switch self { case .undefined: return "undefined" - + case .null: return "null" case let .bool(value): return "\(value)" - + case let .number(number): return number.stringValue @@ -374,7 +374,7 @@ extension Map { } } - public func arrayValue(converting: Bool = false) throws -> [Map] { + func arrayValue(converting: Bool = false) throws -> [Map] { guard converting else { return try get() } @@ -391,7 +391,7 @@ extension Map { } } - public func dictionaryValue(converting: Bool = false) throws -> OrderedDictionary { + func dictionaryValue(converting: Bool = false) throws -> OrderedDictionary { guard converting else { return try get() } @@ -411,8 +411,8 @@ extension Map { // MARK: Get -extension Map { - public func get(_ indexPath: IndexPathElement...) throws -> T { +public extension Map { + func get(_ indexPath: IndexPathElement...) throws -> T { if indexPath.isEmpty { switch self { case let .number(value as T): @@ -429,31 +429,31 @@ extension Map { throw MapError.incompatibleType } } - + return try get(IndexPath(indexPath)).get() } - - public func get(_ indexPath: IndexPathElement...) throws -> Map { + + func get(_ indexPath: IndexPathElement...) throws -> Map { return try get(IndexPath(indexPath)) } - public func get(_ indexPath: IndexPath) throws -> Map { + func get(_ indexPath: IndexPath) throws -> Map { var value: Map = self for element in indexPath.elements { switch element { - case .index(let index): + case let .index(index): let array = try value.arrayValue() - + if array.indices.contains(index) { value = array[index] } else { throw MapError.outOfBounds } - case .key(let key): + case let .key(key): let dictionary = try value.dictionaryValue() - + if let newValue = dictionary[key] { value = newValue } else { @@ -468,12 +468,12 @@ extension Map { // MARK: Set -extension Map { - public mutating func set(_ value: Map, for indexPath: IndexPathElement...) throws { +public extension Map { + mutating func set(_ value: Map, for indexPath: IndexPathElement...) throws { try set(value, for: indexPath) } - public mutating func set(_ value: Map, for indexPath: [IndexPathElement]) throws { + mutating func set(_ value: Map, for indexPath: [IndexPathElement]) throws { try set(value, for: IndexPath(indexPath), merging: true) } @@ -488,24 +488,26 @@ extension Map { if elements.isEmpty { switch first { - case .index(let index): - if case .array(var array) = self { + case let .index(index): + if case var .array(array) = self { if !array.indices.contains(index) { throw MapError.outOfBounds } - + array[index] = value self = .array(array) } else { throw MapError.incompatibleType } - case .key(let key): - if case .dictionary(var dictionary) = self { + case let .key(key): + if case var .dictionary(dictionary) = self { let newValue = value - - if let existingDictionary = dictionary[key]?.dictionary, + + if + let existingDictionary = dictionary[key]?.dictionary, let newDictionary = newValue.dictionary, - merging { + merging + { var combinedDictionary: OrderedDictionary = [:] for (key, value) in existingDictionary { @@ -520,28 +522,28 @@ extension Map { } else { dictionary[key] = newValue } - + self = .dictionary(dictionary) } else { throw MapError.incompatibleType } } } else { - var next = (try? self.get(first)) ?? first.constructEmptyContainer + var next = (try? get(first)) ?? first.constructEmptyContainer try next.set(value, for: indexPath, merging: true) - try self.set(next, for: [first]) + try set(next, for: [first]) } } } // MARK: Remove -extension Map { - public mutating func remove(_ indexPath: IndexPathElement...) throws { - try self.remove(indexPath) +public extension Map { + mutating func remove(_ indexPath: IndexPathElement...) throws { + try remove(indexPath) } - public mutating func remove(_ indexPath: [IndexPathElement]) throws { + mutating func remove(_ indexPath: [IndexPathElement]) throws { var indexPath = indexPath guard let first = indexPath.first else { @@ -551,26 +553,29 @@ extension Map { indexPath.removeFirst() if indexPath.isEmpty { - guard case .dictionary(var dictionary) = self, case .key(let key) = first.indexPathValue else { + guard + case var .dictionary(dictionary) = self, + case let .key(key) = first.indexPathValue + else { throw MapError.incompatibleType } dictionary[key] = nil self = .dictionary(dictionary) } else { - guard var next = try? self.get(first) else { + guard var next = try? get(first) else { throw MapError.valueNotFound } try next.remove(indexPath) - try self.set(next, for: [first], merging: false) + try set(next, for: [first], merging: false) } } } // MARK: Subscripts -extension Map { - public subscript(indexPath: IndexPathElement...) -> Map { +public extension Map { + subscript(indexPath: IndexPathElement...) -> Map { get { return self[IndexPath(indexPath)] } @@ -580,14 +585,14 @@ extension Map { } } - public subscript(indexPath: IndexPath) -> Map { + subscript(indexPath: IndexPath) -> Map { get { - return (try? self.get(indexPath)) ?? nil + return (try? get(indexPath)) ?? nil } set(value) { do { - try self.set(value, for: indexPath, merging: true) + try set(value, for: indexPath, merging: true) } catch { fatalError(String(describing: error)) } @@ -595,7 +600,7 @@ extension Map { } } -extension String : CodingKey { +extension String: CodingKey { public var stringValue: String { return self } @@ -603,41 +608,31 @@ extension String : CodingKey { public init?(stringValue: String) { self = stringValue } - + public var intValue: Int? { return nil } - - public init?(intValue: Int) { + + public init?(intValue _: Int) { return nil } } -extension Map : Codable { +extension Map: Codable { public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() - + if container.decodeNil() { self = .null - } - - else if let bool = try? container.decode(Bool.self) { + } else if let bool = try? container.decode(Bool.self) { self = .bool(bool) - } - - else if let double = try? container.decode(Double.self) { + } else if let double = try? container.decode(Double.self) { self = .number(Number(double)) - } - - else if let string = try? container.decode(String.self) { + } else if let string = try? container.decode(String.self) { self = .string(string) - } - - else if let array = try? container.decode([Map].self) { + } else if let array = try? container.decode([Map].self) { self = .array(array) - } - - else if let _ = try? container.decode([String: Map].self) { + } else if let _ = try? container.decode([String: Map].self) { // Override OrderedDictionary default (unkeyed alternating key-value) // Instead decode as a keyed container (like normal Dictionary) but use the order of the input let container = try decoder.container(keyedBy: _DictionaryCodingKey.self) @@ -647,20 +642,19 @@ extension Map : Codable { orderedDictionary[key.stringValue] = value } self = .dictionary(orderedDictionary) - } - - else if let dictionary = try? container.decode(OrderedDictionary.self) { + } else if let dictionary = try? container.decode(OrderedDictionary.self) { self = .dictionary(dictionary) - } - - else { - throw DecodingError.dataCorruptedError(in: container, debugDescription: "Corrupted data") + } else { + throw DecodingError.dataCorruptedError( + in: container, + debugDescription: "Corrupted data" + ) } } - + public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() - + switch self { case .undefined: throw EncodingError.invalidValue( @@ -701,27 +695,28 @@ extension Map : Codable { } } } - + /// A wrapper for dictionary keys which are Strings or Ints. /// This is copied from Swift core: https://github.com/apple/swift/blob/256a9c5ad96378daa03fa2d5197b4201bf16db27/stdlib/public/core/Codable.swift#L5508 internal struct _DictionaryCodingKey: CodingKey { - internal let stringValue: String - internal let intValue: Int? + internal let stringValue: String + internal let intValue: Int? - internal init?(stringValue: String) { - self.stringValue = stringValue - self.intValue = Int(stringValue) - } + internal init?(stringValue: String) { + self.stringValue = stringValue + intValue = Int(stringValue) + } - internal init?(intValue: Int) { - self.stringValue = "\(intValue)" - self.intValue = intValue - } + internal init?(intValue: Int) { + stringValue = "\(intValue)" + self.intValue = intValue + } } } + // MARK: Equatable -extension Map : Equatable {} +extension Map: Equatable {} public func == (lhs: Map, rhs: Map) -> Bool { switch (lhs, rhs) { @@ -746,7 +741,7 @@ public func == (lhs: Map, rhs: Map) -> Bool { // MARK: Hashable -extension Map : Hashable { +extension Map: Hashable { public func hash(into hasher: inout Hasher) { switch self { case .undefined: @@ -769,65 +764,65 @@ extension Map : Hashable { // MARK: Literal Convertibles -extension Map : ExpressibleByNilLiteral { - public init(nilLiteral value: Void) { +extension Map: ExpressibleByNilLiteral { + public init(nilLiteral _: Void) { self = .null } } -extension Map : ExpressibleByBooleanLiteral { +extension Map: ExpressibleByBooleanLiteral { public init(booleanLiteral value: BooleanLiteralType) { self = .bool(value) } } -extension Map : ExpressibleByIntegerLiteral { +extension Map: ExpressibleByIntegerLiteral { public init(integerLiteral value: IntegerLiteralType) { self = .number(Number(value)) } } -extension Map : ExpressibleByFloatLiteral { +extension Map: ExpressibleByFloatLiteral { public init(floatLiteral value: FloatLiteralType) { self = .number(Number(value)) } } -extension Map : ExpressibleByStringLiteral { +extension Map: ExpressibleByStringLiteral { public init(unicodeScalarLiteral value: String) { self = .string(value) } - + public init(extendedGraphemeClusterLiteral value: String) { self = .string(value) } - + public init(stringLiteral value: StringLiteralType) { self = .string(value) } } -extension Map : ExpressibleByArrayLiteral { +extension Map: ExpressibleByArrayLiteral { public init(arrayLiteral elements: Map...) { self = .array(elements) } } -extension Map : ExpressibleByDictionaryLiteral { +extension Map: ExpressibleByDictionaryLiteral { public init(dictionaryLiteral elements: (String, Map)...) { var dictionary = OrderedDictionary(minimumCapacity: elements.count) - + for (key, value) in elements { dictionary[key] = value } - + self = .dictionary(dictionary) } } // MARK: CustomStringConvertible -extension Map : CustomStringConvertible { +extension Map: CustomStringConvertible { public var description: String { return self.description(debug: false) } @@ -835,16 +830,16 @@ extension Map : CustomStringConvertible { // MARK: CustomDebugStringConvertible -extension Map:CustomDebugStringConvertible { - public var debugDescription:String { - return self.description(debug: true) +extension Map: CustomDebugStringConvertible { + public var debugDescription: String { + return description(debug: true) } } - // MARK: Generic Description -extension Map { - public func description(debug: Bool) -> String { + +public extension Map { + func description(debug: Bool) -> String { var indentLevel = 0 let escapeMapping: [Character: String] = [ @@ -857,7 +852,7 @@ extension Map { "\u{2028}": "\\u2028", "\u{2029}": "\\u2029", - "\r\n": "\\r\\n" + "\r\n": "\\r\\n", ] func escape(_ source: String) -> String { @@ -933,12 +928,12 @@ extension Map { if debug { indentLevel += 1 } - - let filtered = dictionary.filter({ item in + + let filtered = dictionary.filter { item in !item.value.isUndefined - }) + } - for (key, value) in filtered.sorted(by: {$0.0 < $1.0}) { + for (key, value) in filtered.sorted(by: { $0.0 < $1.0 }) { if debug { string += "\n" string += indent() @@ -965,11 +960,11 @@ extension Map { return string + "}" } } - + func indent() -> String { return String(repeating: " ", count: indentLevel) } - + return serialize(map: self) } } diff --git a/Sources/GraphQL/Map/MapCoder.swift b/Sources/GraphQL/Map/MapCoder.swift index f80301ac..b577dada 100644 --- a/Sources/GraphQL/Map/MapCoder.swift +++ b/Sources/GraphQL/Map/MapCoder.swift @@ -2,13 +2,13 @@ import CoreFoundation import Foundation import OrderedCollections - /// A marker protocol used to determine whether a value is a `String`-keyed `OrderedDictionary` /// containing `Encodable` values (in which case it should be exempt from key conversion strategies). /// -fileprivate protocol _MapStringDictionaryEncodableMarker { } +private protocol _MapStringDictionaryEncodableMarker {} -extension OrderedDictionary : _MapStringDictionaryEncodableMarker where Key == String, Value: Encodable { } +extension OrderedDictionary: _MapStringDictionaryEncodableMarker where Key == String, +Value: Encodable {} /// A marker protocol used to determine whether a value is a `String`-keyed `OrderedDictionary` /// containing `Decodable` values (in which case it should be exempt from key conversion strategies). @@ -16,11 +16,13 @@ extension OrderedDictionary : _MapStringDictionaryEncodableMarker where Key == S /// The marker protocol also provides access to the type of the `Decodable` values, /// which is needed for the implementation of the key conversion strategy exemption. /// -fileprivate protocol _MapStringDictionaryDecodableMarker { +private protocol _MapStringDictionaryDecodableMarker { static var elementType: Decodable.Type { get } } -extension OrderedDictionary : _MapStringDictionaryDecodableMarker where Key == String, Value: Decodable { +extension OrderedDictionary: _MapStringDictionaryDecodableMarker where Key == String, + Value: Decodable +{ static var elementType: Decodable.Type { return Value.self } } @@ -33,7 +35,7 @@ open class MapEncoder { // MARK: Options /// The formatting of the output Map data. - public struct OutputFormatting : OptionSet { + public struct OutputFormatting: OptionSet { /// The format's default value. public let rawValue: UInt @@ -47,7 +49,7 @@ open class MapEncoder { /// Produce Map with dictionary keys sorted in lexicographic order. @available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) - public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) + public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) } /// The strategy to use for encoding `Date` values. @@ -126,7 +128,7 @@ open class MapEncoder { fileprivate static func _convertToSnakeCase(_ stringKey: String) -> String { guard !stringKey.isEmpty else { return stringKey } - var words : [Range] = [] + var words: [Range] = [] // The general idea of this algorithm is to split words on transition from lower to upper case, then on transition of >1 upper case characters to lowercase // // myProperty -> my_property @@ -134,16 +136,28 @@ open class MapEncoder { // // 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)..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..(_ value: T) throws -> Map { - let encoder = _MapEncoder(options: self.options) - + open func encode(_ value: T) throws -> Map { + let encoder = _MapEncoder(options: options) + guard let topLevel = try encoder.box_(value) else { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Top-level \(T.self) did not encode any values.")) + throw EncodingError.invalidValue( + value, + EncodingError + .Context( + codingPath: [], + debugDescription: "Top-level \(T.self) did not encode any values." + ) + ) } return try MapSerialization.map(with: topLevel) @@ -235,7 +258,7 @@ open class MapEncoder { // MARK: - _MapEncoder -fileprivate class _MapEncoder : Encoder { +private class _MapEncoder: Encoder { // MARK: Properties /// The encoder's storage. @@ -248,8 +271,8 @@ fileprivate class _MapEncoder : Encoder { public var codingPath: [CodingKey] /// Contextual user-provided information for use during encoding. - public var userInfo: [CodingUserInfoKey : Any] { - return self.options.userInfo + public var userInfo: [CodingUserInfoKey: Any] { + return options.userInfo } // MARK: - Initialization @@ -257,7 +280,7 @@ fileprivate class _MapEncoder : Encoder { /// Initializes `self` with the given top-level encoder options. fileprivate init(options: MapEncoder._Options, codingPath: [CodingKey] = []) { self.options = options - self.storage = _MapEncodingStorage() + storage = _MapEncodingStorage() self.codingPath = codingPath } @@ -271,43 +294,56 @@ fileprivate class _MapEncoder : Encoder { // // This means that anytime something that can request a new container goes onto the stack, we MUST push a key onto the coding path. // Things which will not request containers do not need to have the coding path extended for them (but it doesn't matter if it is, because they will not reach here). - return self.storage.count == self.codingPath.count + return storage.count == codingPath.count } // MARK: - Encoder Methods - public func container(keyedBy: Key.Type) -> KeyedEncodingContainer { + + public func container(keyedBy _: Key.Type) -> KeyedEncodingContainer { // If an existing keyed container was already requested, return that one. let topContainer: NSMutableDictionary - if self.canEncodeNewValue { + if canEncodeNewValue { // We haven't yet pushed a container at this level; do so here. - topContainer = self.storage.pushKeyedContainer() + topContainer = storage.pushKeyedContainer() } else { - guard let container = self.storage.containers.last as? NSMutableDictionary else { - preconditionFailure("Attempt to push new keyed encoding container when already previously encoded at this path.") + guard let container = storage.containers.last as? NSMutableDictionary else { + preconditionFailure( + "Attempt to push new keyed encoding container when already previously encoded at this path." + ) } topContainer = container } - let container = _MapKeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) + let container = _MapKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: topContainer + ) return KeyedEncodingContainer(container) } public func unkeyedContainer() -> UnkeyedEncodingContainer { // If an existing unkeyed container was already requested, return that one. let topContainer: NSMutableArray - if self.canEncodeNewValue { + if canEncodeNewValue { // We haven't yet pushed a container at this level; do so here. - topContainer = self.storage.pushUnkeyedContainer() + topContainer = storage.pushUnkeyedContainer() } else { - guard let container = self.storage.containers.last as? NSMutableArray else { - preconditionFailure("Attempt to push new unkeyed encoding container when already previously encoded at this path.") + guard let container = storage.containers.last as? NSMutableArray else { + preconditionFailure( + "Attempt to push new unkeyed encoding container when already previously encoded at this path." + ) } topContainer = container } - return _MapUnkeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) + return _MapUnkeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: topContainer + ) } public func singleValueContainer() -> SingleValueEncodingContainer { @@ -317,12 +353,12 @@ fileprivate class _MapEncoder : Encoder { // MARK: - Encoding Storage and Containers -fileprivate struct _MapEncodingStorage { +private struct _MapEncodingStorage { // MARK: Properties /// The container stack. /// Elements may be any one of the Map types (NSNull, NSNumber, NSString, NSArray, NSDictionary). - private(set) fileprivate var containers: [NSObject] = [] + fileprivate private(set) var containers: [NSObject] = [] // MARK: - Initialization @@ -332,34 +368,34 @@ fileprivate struct _MapEncodingStorage { // MARK: - Modifying the Stack fileprivate var count: Int { - return self.containers.count + return containers.count } fileprivate mutating func pushKeyedContainer() -> NSMutableDictionary { let dictionary = NSMutableDictionary() - self.containers.append(dictionary) + containers.append(dictionary) return dictionary } fileprivate mutating func pushUnkeyedContainer() -> NSMutableArray { let array = NSMutableArray() - self.containers.append(array) + containers.append(array) return array } fileprivate mutating func push(container: NSObject) { - self.containers.append(container) + containers.append(container) } fileprivate mutating func popContainer() -> NSObject { - precondition(!self.containers.isEmpty, "Empty container stack.") - return self.containers.popLast()! + precondition(!containers.isEmpty, "Empty container stack.") + return containers.popLast()! } } // MARK: - Encoding Containers -fileprivate struct _MapKeyedEncodingContainer : KeyedEncodingContainerProtocol { +private struct _MapKeyedEncodingContainer: KeyedEncodingContainerProtocol { typealias Key = K // MARK: Properties @@ -371,12 +407,16 @@ fileprivate struct _MapKeyedEncodingContainer : KeyedEncodingCont private let container: NSMutableDictionary /// The path of coding keys taken to get to this point in encoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] // MARK: - Initialization /// Initializes `self` with the given references. - fileprivate init(referencing encoder: _MapEncoder, codingPath: [CodingKey], wrapping container: NSMutableDictionary) { + fileprivate init( + referencing encoder: _MapEncoder, + codingPath: [CodingKey], + wrapping container: NSMutableDictionary + ) { self.encoder = encoder self.codingPath = codingPath self.container = container @@ -391,97 +431,146 @@ fileprivate struct _MapKeyedEncodingContainer : KeyedEncodingCont case .convertToSnakeCase: let newKeyString = MapEncoder.KeyEncodingStrategy._convertToSnakeCase(key.stringValue) return _MapKey(stringValue: newKeyString, intValue: key.intValue) - case .custom(let converter): + case let .custom(converter): return converter(codingPath + [key]) } } // MARK: - KeyedEncodingContainerProtocol Methods - public mutating func encodeNil(forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = NSNull() } - public mutating func encode(_ value: Bool, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: Int, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: Int8, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: Int16, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: Int32, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: Int64, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: UInt, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: UInt8, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: UInt16, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: UInt32, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: UInt64, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - public mutating func encode(_ value: String, forKey key: Key) throws { self.container[_converted(key).stringValue._bridgeToObjectiveC()] = self.encoder.box(value) } - - public mutating func encode(_ value: Float, forKey key: Key) throws { + public mutating func encodeNil(forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = NSNull() + } + + public mutating func encode(_ value: Bool, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: Int, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: Int8, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: Int16, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: Int32, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: Int64, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: UInt, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: UInt8, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: UInt16, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: UInt32, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: UInt64, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: String, forKey key: Key) throws { + container[_converted(key).stringValue._bridgeToObjectiveC()] = encoder.box(value) + } + + public mutating func encode(_ value: Float, forKey key: Key) throws { // Since the float may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } #if DEPLOYMENT_RUNTIME_SWIFT - self.container[_converted(key).stringValue._bridgeToObjectiveC()] = try self.encoder.box(value) + container[_converted(key).stringValue._bridgeToObjectiveC()] = try encoder.box(value) #else - self.container[_converted(key).stringValue] = try self.encoder.box(value) + container[_converted(key).stringValue] = try encoder.box(value) #endif } public mutating func encode(_ value: Double, forKey key: Key) throws { // Since the double may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(key) + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } #if DEPLOYMENT_RUNTIME_SWIFT - self.container[_converted(key).stringValue._bridgeToObjectiveC()] = try self.encoder.box(value) + container[_converted(key).stringValue._bridgeToObjectiveC()] = try encoder.box(value) #else - self.container[_converted(key).stringValue] = try self.encoder.box(value) + container[_converted(key).stringValue] = try encoder.box(value) #endif } - public mutating func encode(_ value: T, forKey key: Key) throws { - self.encoder.codingPath.append(key) + public mutating func encode(_ value: T, forKey key: Key) throws { + encoder.codingPath.append(key) defer { self.encoder.codingPath.removeLast() } #if DEPLOYMENT_RUNTIME_SWIFT - self.container[_converted(key).stringValue._bridgeToObjectiveC()] = try self.encoder.box(value) + container[_converted(key).stringValue._bridgeToObjectiveC()] = try encoder.box(value) #else - self.container[_converted(key).stringValue] = try self.encoder.box(value) + container[_converted(key).stringValue] = try encoder.box(value) #endif } - public mutating func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer { + public mutating func nestedContainer( + keyedBy _: NestedKey.Type, + forKey key: Key + ) -> KeyedEncodingContainer { let dictionary = NSMutableDictionary() #if DEPLOYMENT_RUNTIME_SWIFT - self.container[_converted(key).stringValue._bridgeToObjectiveC()] = dictionary + self.container[_converted(key).stringValue._bridgeToObjectiveC()] = dictionary #else - self.container[_converted(key).stringValue] = dictionary + self.container[_converted(key).stringValue] = dictionary #endif - self.codingPath.append(key) + codingPath.append(key) defer { self.codingPath.removeLast() } - let container = _MapKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) + let container = _MapKeyedEncodingContainer( + referencing: encoder, + codingPath: codingPath, + wrapping: dictionary + ) return KeyedEncodingContainer(container) } public mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { let array = NSMutableArray() #if DEPLOYMENT_RUNTIME_SWIFT - self.container[_converted(key).stringValue._bridgeToObjectiveC()] = array + container[_converted(key).stringValue._bridgeToObjectiveC()] = array #else - self.container[_converted(key).stringValue] = array + container[_converted(key).stringValue] = array #endif - self.codingPath.append(key) + codingPath.append(key) defer { self.codingPath.removeLast() } - return _MapUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) + return _MapUnkeyedEncodingContainer( + referencing: encoder, + codingPath: codingPath, + wrapping: array + ) } public mutating func superEncoder() -> Encoder { - return _MapReferencingEncoder(referencing: self.encoder, at: _MapKey.super, wrapping: self.container) + return _MapReferencingEncoder(referencing: encoder, at: _MapKey.super, wrapping: container) } public mutating func superEncoder(forKey key: Key) -> Encoder { - return _MapReferencingEncoder(referencing: self.encoder, at: key, wrapping: self.container) + return _MapReferencingEncoder(referencing: encoder, at: key, wrapping: container) } } -fileprivate struct _MapUnkeyedEncodingContainer : UnkeyedEncodingContainer { +private struct _MapUnkeyedEncodingContainer: UnkeyedEncodingContainer { // MARK: Properties /// A reference to the encoder we're writing to. @@ -491,17 +580,21 @@ fileprivate struct _MapUnkeyedEncodingContainer : UnkeyedEncodingContainer { private let container: NSMutableArray /// The path of coding keys taken to get to this point in encoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] /// The number of elements encoded into the container. public var count: Int { - return self.container.count + return container.count } // MARK: - Initialization /// Initializes `self` with the given references. - fileprivate init(referencing encoder: _MapEncoder, codingPath: [CodingKey], wrapping container: NSMutableArray) { + fileprivate init( + referencing encoder: _MapEncoder, + codingPath: [CodingKey], + wrapping container: NSMutableArray + ) { self.encoder = encoder self.codingPath = codingPath self.container = container @@ -509,176 +602,198 @@ fileprivate struct _MapUnkeyedEncodingContainer : UnkeyedEncodingContainer { // MARK: - UnkeyedEncodingContainer Methods - public mutating func encodeNil() throws { self.container.add(NSNull()) } - public mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) } - - public mutating func encode(_ value: Float) throws { + public mutating func encodeNil() throws { container.add(NSNull()) } + public mutating func encode(_ value: Bool) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int8) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int16) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int32) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: Int64) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt8) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt16) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt32) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: UInt64) throws { container.add(encoder.box(value)) } + public mutating func encode(_ value: String) throws { container.add(encoder.box(value)) } + + public mutating func encode(_ value: Float) throws { // Since the float may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(_MapKey(index: self.count)) + encoder.codingPath.append(_MapKey(index: count)) defer { self.encoder.codingPath.removeLast() } - self.container.add(try self.encoder.box(value)) + container.add(try encoder.box(value)) } public mutating func encode(_ value: Double) throws { // Since the double may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(_MapKey(index: self.count)) + encoder.codingPath.append(_MapKey(index: count)) defer { self.encoder.codingPath.removeLast() } - self.container.add(try self.encoder.box(value)) + container.add(try encoder.box(value)) } - public mutating func encode(_ value: T) throws { - self.encoder.codingPath.append(_MapKey(index: self.count)) + public mutating func encode(_ value: T) throws { + encoder.codingPath.append(_MapKey(index: count)) defer { self.encoder.codingPath.removeLast() } - self.container.add(try self.encoder.box(value)) + container.add(try encoder.box(value)) } - public mutating func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer { - self.codingPath.append(_MapKey(index: self.count)) + public mutating func nestedContainer( + keyedBy _: NestedKey + .Type + ) -> KeyedEncodingContainer { + codingPath.append(_MapKey(index: count)) defer { self.codingPath.removeLast() } let dictionary = NSMutableDictionary() self.container.add(dictionary) - let container = _MapKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) + let container = _MapKeyedEncodingContainer( + referencing: encoder, + codingPath: codingPath, + wrapping: dictionary + ) return KeyedEncodingContainer(container) } public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { - self.codingPath.append(_MapKey(index: self.count)) + codingPath.append(_MapKey(index: count)) defer { self.codingPath.removeLast() } - + let array = NSMutableArray() - self.container.add(array) - return _MapUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) + container.add(array) + return _MapUnkeyedEncodingContainer( + referencing: encoder, + codingPath: codingPath, + wrapping: array + ) } public mutating func superEncoder() -> Encoder { - return _MapReferencingEncoder(referencing: self.encoder, at: self.container.count, wrapping: self.container) + return _MapReferencingEncoder( + referencing: encoder, + at: container.count, + wrapping: container + ) } } -extension _MapEncoder : SingleValueEncodingContainer { +extension _MapEncoder: SingleValueEncodingContainer { // MARK: - SingleValueEncodingContainer Methods fileprivate func assertCanEncodeNewValue() { - precondition(self.canEncodeNewValue, "Attempt to encode value through single value container when previously value already encoded.") + precondition( + canEncodeNewValue, + "Attempt to encode value through single value container when previously value already encoded." + ) } public func encodeNil() throws { assertCanEncodeNewValue() - self.storage.push(container: NSNull()) + storage.push(container: NSNull()) } public func encode(_ value: Bool) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int8) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int16) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int32) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Int64) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt8) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt16) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt32) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: UInt64) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: String) throws { assertCanEncodeNewValue() - self.storage.push(container: self.box(value)) + storage.push(container: box(value)) } public func encode(_ value: Float) throws { assertCanEncodeNewValue() - try self.storage.push(container: self.box(value)) + try storage.push(container: box(value)) } public func encode(_ value: Double) throws { assertCanEncodeNewValue() - try self.storage.push(container: self.box(value)) + try storage.push(container: box(value)) } - public func encode(_ value: T) throws { + public func encode(_ value: T) throws { assertCanEncodeNewValue() - try self.storage.push(container: self.box(value)) + try storage.push(container: box(value)) } } // MARK: - Concrete Value Representations -extension _MapEncoder { +private extension _MapEncoder { /// Returns the given value boxed in a container appropriate for pushing onto the container stack. - 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) = self.options.nonConformingFloatEncodingStrategy else { - throw EncodingError._invalidFloatingPointValue(float, at: codingPath) + 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 { + guard !float.isInfinite, !float.isNaN else { + guard + case let .convertToString( + positiveInfinity: posInfString, + negativeInfinity: negInfString, + nan: nanString + ) = options.nonConformingFloatEncodingStrategy + else { + throw EncodingError._invalidFloatingPointValue(float, at: codingPath) } if float == Float.infinity { @@ -693,12 +808,16 @@ extension _MapEncoder { return NSNumber(value: float) } - fileprivate func box(_ double: Double) throws -> NSObject { - guard !double.isInfinite && !double.isNaN else { - guard case let .convertToString(positiveInfinity: posInfString, - negativeInfinity: negInfString, - nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { - throw EncodingError._invalidFloatingPointValue(double, at: codingPath) + func box(_ double: Double) throws -> NSObject { + guard !double.isInfinite, !double.isNaN else { + guard + case let .convertToString( + positiveInfinity: posInfString, + negativeInfinity: negInfString, + nan: nanString + ) = options.nonConformingFloatEncodingStrategy + else { + throw EncodingError._invalidFloatingPointValue(double, at: codingPath) } if double == Double.infinity { @@ -713,13 +832,13 @@ extension _MapEncoder { return NSNumber(value: double) } - fileprivate func box(_ date: Date) throws -> NSObject { - switch self.options.dateEncodingStrategy { + func box(_ date: Date) throws -> NSObject { + switch options.dateEncodingStrategy { case .deferredToDate: // Must be called with a surrounding with(pushedKey:) call. // Dates encode as single-value objects; this can't both throw and push a container, so no need to catch the error. try date.encode(to: self) - return self.storage.popContainer() + return storage.popContainer() case .secondsSince1970: return NSNumber(value: date.timeIntervalSince1970) @@ -734,158 +853,158 @@ extension _MapEncoder { fatalError("ISO8601DateFormatter is unavailable on this platform.") } - case .formatted(let formatter): + case let .formatted(formatter): return NSString(string: formatter.string(from: date)) - case .custom(let closure): - let depth = self.storage.count + case let .custom(closure): + let depth = storage.count do { try closure(date, self) } catch { // If the value pushed a container before throwing, pop it back off to restore state. - if self.storage.count > depth { - let _ = self.storage.popContainer() + if storage.count > depth { + _ = storage.popContainer() } throw error } - - guard self.storage.count > depth else { + + guard storage.count > depth else { // The closure didn't encode anything. Return the default keyed container. return NSDictionary() } // We can pop because the closure encoded something. - return self.storage.popContainer() + return storage.popContainer() } } - fileprivate func box(_ data: Data) throws -> NSObject { - switch self.options.dataEncodingStrategy { + func box(_ data: Data) throws -> NSObject { + switch options.dataEncodingStrategy { case .deferredToData: // Must be called with a surrounding with(pushedKey:) call. - let depth = self.storage.count + let depth = storage.count do { try data.encode(to: self) } catch { // If the value pushed a container before throwing, pop it back off to restore state. // This shouldn't be possible for Data (which encodes as an array of bytes), but it can't hurt to catch a failure. - if self.storage.count > depth { - let _ = self.storage.popContainer() + if storage.count > depth { + _ = storage.popContainer() } throw error } - return self.storage.popContainer() + return storage.popContainer() case .base64: return NSString(string: data.base64EncodedString()) - case .custom(let closure): - let depth = self.storage.count + case let .custom(closure): + let depth = storage.count do { try closure(data, self) } catch { // If the value pushed a container before throwing, pop it back off to restore state. - if self.storage.count > depth { - let _ = self.storage.popContainer() + if storage.count > depth { + _ = storage.popContainer() } throw error } - guard self.storage.count > depth else { + guard storage.count > depth else { // The closure didn't encode anything. Return the default keyed container. return NSDictionary() } // We can pop because the closure encoded something. - return self.storage.popContainer() + return storage.popContainer() } } - fileprivate func box(_ dict: OrderedDictionary) throws -> NSObject? { - let depth = self.storage.count - let result = self.storage.pushKeyedContainer() + func box(_ dict: OrderedDictionary) throws -> NSObject? { + let depth = storage.count + let result = storage.pushKeyedContainer() do { for (key, value) in dict { - self.codingPath.append(_MapKey(stringValue: key, intValue: nil)) + codingPath.append(_MapKey(stringValue: key, intValue: nil)) defer { self.codingPath.removeLast() } result[key] = try box(value) } } catch { // If the value pushed a container before throwing, pop it back off to restore state. - if self.storage.count > depth { - let _ = self.storage.popContainer() + if storage.count > depth { + let _ = storage.popContainer() } throw error } // The top container should be a new container. - guard self.storage.count > depth else { + guard storage.count > depth else { return nil } - return self.storage.popContainer() + return storage.popContainer() } - fileprivate func box(_ value: Encodable) throws -> NSObject { - return try self.box_(value) ?? NSDictionary() + 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. - fileprivate func box_(_ value: Encodable) throws -> NSObject? { + func box_(_ value: Encodable) throws -> NSObject? { let type = Swift.type(of: value) #if DEPLOYMENT_RUNTIME_SWIFT - if type == Date.self { - // Respect Date encoding strategy - return try self.box((value as! Date)) - } else if type == Data.self { - // Respect Data encoding strategy - return try self.box((value as! Data)) - } else if type == URL.self { - // Encode URLs as single strings. - return self.box((value as! URL).absoluteString) - } else if type == Decimal.self { - // MapSerialization can consume NSDecimalNumber values. - return NSDecimalNumber(decimal: value as! Decimal) - } else if value is _MapStringDictionaryEncodableMarker { - return try box((value as Any) as! OrderedDictionary) - } - + if type == Date.self { + // Respect Date encoding strategy + return try box(value as! Date) + } else if type == Data.self { + // Respect Data encoding strategy + return try box(value as! Data) + } else if type == URL.self { + // Encode URLs as single strings. + return box((value as! URL).absoluteString) + } else if type == Decimal.self { + // MapSerialization can consume NSDecimalNumber values. + return NSDecimalNumber(decimal: value as! Decimal) + } else if value is _MapStringDictionaryEncodableMarker { + return try box((value as Any) as! OrderedDictionary) + } + #else - if type == Date.self || type == NSDate.self { - // Respect Date encoding strategy - return try self.box((value as! Date)) - } else if type == Data.self || type == NSData.self { - // Respect Data encoding strategy - return try self.box((value as! Data)) - } else if type == URL.self || type == NSURL.self { - // Encode URLs as single strings. - return self.box((value as! URL).absoluteString) - } else if type == Decimal.self { - // MapSerialization can consume NSDecimalNumber values. - return NSDecimalNumber(decimal: value as! Decimal) - } else if value is _MapStringDictionaryEncodableMarker { - return try box((value as Any) as! OrderedDictionary) - } + if type == Date.self || type == NSDate.self { + // Respect Date encoding strategy + return try box(value as! Date) + } else if type == Data.self || type == NSData.self { + // Respect Data encoding strategy + return try box(value as! Data) + } else if type == URL.self || type == NSURL.self { + // Encode URLs as single strings. + return box((value as! URL).absoluteString) + } else if type == Decimal.self { + // MapSerialization can consume NSDecimalNumber values. + return NSDecimalNumber(decimal: value as! Decimal) + } else if value is _MapStringDictionaryEncodableMarker { + return try box((value as Any) as! OrderedDictionary) + } #endif - + // The value should request a container from the _MapEncoder. - let depth = self.storage.count + let depth = storage.count do { try value.encode(to: self) } catch { // If the value pushed a container before throwing, pop it back off to restore state. - if self.storage.count > depth { - let _ = self.storage.popContainer() + if storage.count > depth { + let _ = storage.popContainer() } throw error } - + // The top container should be a new container. - guard self.storage.count > depth else { + guard storage.count > depth else { return nil } - return self.storage.popContainer() + return storage.popContainer() } } @@ -893,7 +1012,7 @@ extension _MapEncoder { /// _MapReferencingEncoder is a special subclass of _MapEncoder which has its own storage, but references the contents of a different encoder. /// It's used in superEncoder(), which returns a new encoder for encoding a superclass -- the lifetime of the encoder should not escape the scope it's created in, but it doesn't necessarily know when it's done being used (to write to the original container). -fileprivate class _MapReferencingEncoder : _MapEncoder { +private class _MapReferencingEncoder: _MapEncoder { // MARK: Reference types. /// The type of container we're referencing. @@ -916,30 +1035,38 @@ fileprivate class _MapReferencingEncoder : _MapEncoder { // MARK: - Initialization /// Initializes `self` by referencing the given array container in the given encoder. - fileprivate init(referencing encoder: _MapEncoder, at index: Int, wrapping array: NSMutableArray) { + fileprivate init( + referencing encoder: _MapEncoder, + at index: Int, + wrapping array: NSMutableArray + ) { self.encoder = encoder - self.reference = .array(array, index) + reference = .array(array, index) super.init(options: encoder.options, codingPath: encoder.codingPath) - self.codingPath.append(_MapKey(index: index)) + codingPath.append(_MapKey(index: index)) } /// Initializes `self` by referencing the given dictionary container in the given encoder. - fileprivate init(referencing encoder: _MapEncoder, at key: CodingKey, wrapping dictionary: NSMutableDictionary) { + fileprivate init( + referencing encoder: _MapEncoder, + at key: CodingKey, + wrapping dictionary: NSMutableDictionary + ) { self.encoder = encoder - self.reference = .dictionary(dictionary, key.stringValue) + reference = .dictionary(dictionary, key.stringValue) super.init(options: encoder.options, codingPath: encoder.codingPath) - self.codingPath.append(key) + codingPath.append(key) } // MARK: - Coding Path Operations - fileprivate override var canEncodeNewValue: Bool { + override fileprivate var canEncodeNewValue: Bool { // With a regular encoder, the storage and coding path grow together. // A referencing encoder, however, inherits its parents coding path, as well as the key it was created for. // We have to take this into account. - return self.storage.count == self.codingPath.count - self.encoder.codingPath.count - 1 + return storage.count == codingPath.count - encoder.codingPath.count - 1 } // MARK: - Deinitialization @@ -954,10 +1081,10 @@ fileprivate class _MapReferencingEncoder : _MapEncoder { } switch self.reference { - case .array(let array, let index): + case let .array(array, index): array.insert(value, at: index) - case .dictionary(let dictionary, let key): + case let .dictionary(dictionary, key): dictionary[NSString(string: key)] = value } } @@ -1013,12 +1140,12 @@ open class MapDecoder { /// Decode the values from the given representation strings. case convertFromString(positiveInfinity: String, negativeInfinity: String, nan: String) } - + /// The strategy to use for automatically changing the value of keys before decoding. public enum KeyDecodingStrategy { /// Use the keys specified by each type. This is the default strategy. case useDefaultKeys - + /// Convert from "snake_case_keys" to "camelCaseKeys" before attempting to match a key with the one specified by each type. /// /// The conversion to upper case uses `Locale.system`, also known as the ICU "root" locale. This means the result is consistent regardless of the current user's locale and language preferences. @@ -1031,48 +1158,53 @@ open class MapDecoder { /// /// - Note: Using a key decoding strategy has a nominal performance cost, as each string key has to be inspected for the `_` character. case convertFromSnakeCase - + /// Provide a custom conversion from the key in the encoded Map to the keys specified by the decoded types. /// The full path to the current decoding position is provided for context (in case you need to locate this key within the payload). The returned key is used in place of the last component in the coding path before decoding. /// If the result of the conversion is a duplicate key, then only one value will be present in the container for the type to decode from. case custom((_ codingPath: [CodingKey]) -> CodingKey) - + fileprivate static func _convertFromSnakeCase(_ stringKey: String) -> String { guard !stringKey.isEmpty else { return stringKey } - + // Find the first non-underscore character guard let firstNonUnderscore = stringKey.firstIndex(where: { $0 != "_" }) else { // Reached the end without finding an _ return stringKey } - + // Find the last non-underscore character var lastNonUnderscore = stringKey.index(before: stringKey.endIndex) - while lastNonUnderscore > firstNonUnderscore && stringKey[lastNonUnderscore] == "_" { + while lastNonUnderscore > firstNonUnderscore, stringKey[lastNonUnderscore] == "_" { stringKey.formIndex(before: &lastNonUnderscore) } - - let keyRange = firstNonUnderscore...lastNonUnderscore - let leadingUnderscoreRange = stringKey.startIndex..(_ type: T.Type, from map: Map) throws -> T { + open func decode(_ type: T.Type, from map: Map) throws -> T { let topLevel = try MapSerialization.object(with: map) - let decoder = _MapDecoder(referencing: topLevel, options: self.options) - + let decoder = _MapDecoder(referencing: topLevel, options: options) + guard let value = try decoder.unbox(topLevel, as: type) else { throw DecodingError.valueNotFound( type, @@ -1150,7 +1284,7 @@ open class MapDecoder { // MARK: - _MapDecoder -fileprivate class _MapDecoder : Decoder { +private class _MapDecoder: Decoder { // MARK: Properties /// The decoder's storage. @@ -1160,37 +1294,45 @@ fileprivate class _MapDecoder : Decoder { fileprivate let options: MapDecoder._Options /// The path to the current point in encoding. - fileprivate(set) public var codingPath: [CodingKey] + public fileprivate(set) var codingPath: [CodingKey] /// Contextual user-provided information for use during encoding. - public var userInfo: [CodingUserInfoKey : Any] { - return self.options.userInfo + public var userInfo: [CodingUserInfoKey: Any] { + return options.userInfo } // MARK: - Initialization /// Initializes `self` with the given top-level container and options. - fileprivate init(referencing container: Any, at codingPath: [CodingKey] = [], options: MapDecoder._Options) { - self.storage = _MapDecodingStorage() - self.storage.push(container: container) + fileprivate init( + referencing container: Any, + at codingPath: [CodingKey] = [], + options: MapDecoder._Options + ) { + storage = _MapDecodingStorage() + storage.push(container: container) self.codingPath = codingPath self.options = options } // MARK: - Decoder Methods - public func container(keyedBy type: Key.Type) throws -> KeyedDecodingContainer { - guard !(self.storage.topContainer is NSNull) else { - throw DecodingError.valueNotFound(KeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead.")) + public func container(keyedBy _: Key.Type) throws -> KeyedDecodingContainer { + guard !(storage.topContainer is NSNull) else { + throw DecodingError.valueNotFound( + KeyedDecodingContainer.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead." + ) + ) } - guard let topContainer = self.storage.topContainer as? [String : Any] else { + guard let topContainer = storage.topContainer as? [String: Any] else { throw DecodingError._typeMismatch( - at: self.codingPath, - expectation: [String : Any].self, - reality: self.storage.topContainer + at: codingPath, + expectation: [String: Any].self, + reality: storage.topContainer ) } @@ -1199,14 +1341,22 @@ fileprivate class _MapDecoder : Decoder { } public func unkeyedContainer() throws -> UnkeyedDecodingContainer { - guard !(self.storage.topContainer is NSNull) else { - throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get unkeyed decoding container -- found null value instead.")) + guard !(storage.topContainer is NSNull) else { + throw DecodingError.valueNotFound( + UnkeyedDecodingContainer.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get unkeyed decoding container -- found null value instead." + ) + ) } - guard let topContainer = self.storage.topContainer as? [Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: self.storage.topContainer) + guard let topContainer = storage.topContainer as? [Any] else { + throw DecodingError._typeMismatch( + at: codingPath, + expectation: [Any].self, + reality: storage.topContainer + ) } return _MapUnkeyedDecodingContainer(referencing: self, wrapping: topContainer) @@ -1219,12 +1369,12 @@ fileprivate class _MapDecoder : Decoder { // MARK: - Decoding Storage -fileprivate struct _MapDecodingStorage { +private struct _MapDecodingStorage { // MARK: Properties /// The container stack. /// Elements may be any one of the Map types (NSNull, NSNumber, String, Array, [String : Any]). - private(set) fileprivate var containers: [Any] = [] + fileprivate private(set) var containers: [Any] = [] // MARK: - Initialization @@ -1234,27 +1384,27 @@ fileprivate struct _MapDecodingStorage { // MARK: - Modifying the Stack fileprivate var count: Int { - return self.containers.count + return containers.count } fileprivate var topContainer: Any { - precondition(!self.containers.isEmpty, "Empty container stack.") - return self.containers.last! + precondition(!containers.isEmpty, "Empty container stack.") + return containers.last! } fileprivate mutating func push(container: Any) { - self.containers.append(container) + containers.append(container) } fileprivate mutating func popContainer() { - precondition(!self.containers.isEmpty, "Empty container stack.") - self.containers.removeLast() + precondition(!containers.isEmpty, "Empty container stack.") + containers.removeLast() } } // MARK: Decoding Containers -fileprivate struct _MapKeyedDecodingContainer : KeyedDecodingContainerProtocol { +private struct _MapKeyedDecodingContainer: KeyedDecodingContainerProtocol { typealias Key = K // MARK: Properties @@ -1263,15 +1413,15 @@ fileprivate struct _MapKeyedDecodingContainer : KeyedDecodingCont private let decoder: _MapDecoder /// A reference to the container we're reading from. - private let container: [String : Any] + private let container: [String: Any] /// The path of coding keys taken to get to this point in decoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] // MARK: - Initialization /// Initializes `self` by referencing the given decoder and container. - fileprivate init(referencing decoder: _MapDecoder, wrapping container: [String : Any]) { + fileprivate init(referencing decoder: _MapDecoder, wrapping container: [String: Any]) { self.decoder = decoder switch decoder.options.keyDecodingStrategy { case .useDefaultKeys: @@ -1281,23 +1431,27 @@ fileprivate struct _MapKeyedDecodingContainer : KeyedDecodingCont // 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 .custom(let converter): + }, 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 }) + key, value in ( + converter(decoder.codingPath + [_MapKey(stringValue: key, intValue: nil)]) + .stringValue, + value + ) + }, uniquingKeysWith: { first, _ in first }) } - self.codingPath = decoder.codingPath + codingPath = decoder.codingPath } // MARK: - KeyedDecodingContainerProtocol Methods public var allKeys: [Key] { - return self.container.keys.compactMap { Key(stringValue: $0) } + return container.keys.compactMap { Key(stringValue: $0) } } public func contains(_ key: Key) -> Bool { - return self.container[key.stringValue] != nil + return container[key.stringValue] != nil } private func _errorDescription(of key: CodingKey) -> String { @@ -1318,279 +1472,520 @@ fileprivate struct _MapKeyedDecodingContainer : KeyedDecodingCont } public func decodeNil(forKey key: Key) throws -> Bool { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } return entry is NSNull } public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Bool.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Bool.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Int.Type, forKey key: Key) throws -> Int { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Int.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Int.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Int8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Int8.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Int16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Int16.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Int32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Int32.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Int64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Int64.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } - + return value } - + public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: UInt.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: UInt.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: UInt8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: UInt8.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: UInt16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: UInt16.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: UInt32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: UInt32.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: UInt64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: UInt64.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Float.Type, forKey key: Key) throws -> Float { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Float.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Float.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: Double.Type, forKey key: Key) throws -> Double { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: Double.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: Double.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } public func decode(_ type: String.Type, forKey key: Key) throws -> String { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: String.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: String.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } - public func decode(_ type: T.Type, forKey key: Key) throws -> T { - guard let entry = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + public func decode(_ type: T.Type, forKey key: Key) throws -> T { + guard let entry = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + ) + ) } - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = try self.decoder.unbox(entry, as: type) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + guard let value = try decoder.unbox(entry, as: type) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + ) + ) } return value } - public func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer { - self.decoder.codingPath.append(key) + public func nestedContainer( + keyedBy _: NestedKey.Type, + forKey key: Key + ) throws + -> KeyedDecodingContainer + { + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } guard let value = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \(_errorDescription(of: key))")) + throw DecodingError.keyNotFound( + key, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \(_errorDescription(of: key))" + ) + ) } - guard let dictionary = value as? [String : Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) + guard let dictionary = value as? [String: Any] else { + throw DecodingError._typeMismatch( + at: codingPath, + expectation: [String: Any].self, + reality: value + ) } - let container = _MapKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) + let container = _MapKeyedDecodingContainer( + referencing: decoder, + wrapping: dictionary + ) return KeyedDecodingContainer(container) } public func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - guard let value = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get UnkeyedDecodingContainer -- no value found for key \(_errorDescription(of: key))")) + guard let value = container[key.stringValue] else { + throw DecodingError.keyNotFound( + key, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get UnkeyedDecodingContainer -- no value found for key \(_errorDescription(of: key))" + ) + ) } guard let array = value as? [Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: value) + throw DecodingError._typeMismatch( + at: codingPath, + expectation: [Any].self, + reality: value + ) } - return _MapUnkeyedDecodingContainer(referencing: self.decoder, wrapping: array) + return _MapUnkeyedDecodingContainer(referencing: decoder, wrapping: array) } private func _superDecoder(forKey key: CodingKey) throws -> Decoder { - self.decoder.codingPath.append(key) + decoder.codingPath.append(key) defer { self.decoder.codingPath.removeLast() } - let value: Any = self.container[key.stringValue] ?? NSNull() - return _MapDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options) + let value: Any = container[key.stringValue] ?? NSNull() + return _MapDecoder(referencing: value, at: decoder.codingPath, options: decoder.options) } public func superDecoder() throws -> Decoder { @@ -1602,7 +1997,7 @@ fileprivate struct _MapKeyedDecodingContainer : KeyedDecodingCont } } -fileprivate struct _MapUnkeyedDecodingContainer : UnkeyedDecodingContainer { +private struct _MapUnkeyedDecodingContainer: UnkeyedDecodingContainer { // MARK: Properties /// A reference to the decoder we're reading from. @@ -1612,10 +2007,10 @@ fileprivate struct _MapUnkeyedDecodingContainer : UnkeyedDecodingContainer { private let container: [Any] /// The path of coding keys taken to get to this point in decoding. - private(set) public var codingPath: [CodingKey] + public private(set) var codingPath: [CodingKey] /// The index of the element we're about to decode. - private(set) public var currentIndex: Int + public private(set) var currentIndex: Int // MARK: - Initialization @@ -1623,27 +2018,34 @@ fileprivate struct _MapUnkeyedDecodingContainer : UnkeyedDecodingContainer { fileprivate init(referencing decoder: _MapDecoder, wrapping container: [Any]) { self.decoder = decoder self.container = container - self.codingPath = decoder.codingPath - self.currentIndex = 0 + codingPath = decoder.codingPath + currentIndex = 0 } // MARK: - UnkeyedDecodingContainer Methods public var count: Int? { - return self.container.count + return container.count } public var isAtEnd: Bool { - return self.currentIndex >= self.count! + return currentIndex >= count! } public mutating func decodeNil() throws -> Bool { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(Any?.self, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + Any?.self, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - if self.container[self.currentIndex] is NSNull { - self.currentIndex += 1 + if container[currentIndex] is NSNull { + currentIndex += 1 return true } else { return false @@ -1651,594 +2053,907 @@ fileprivate struct _MapUnkeyedDecodingContainer : UnkeyedDecodingContainer { } public mutating func decode(_ type: Bool.Type) throws -> Bool { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Bool.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Bool.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int.Type) throws -> Int { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Int.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int8.Type) throws -> Int8 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Int8.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int16.Type) throws -> Int16 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Int16.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int32.Type) throws -> Int32 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Int32.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Int64.Type) throws -> Int64 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Int64.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt.Type) throws -> UInt { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: UInt.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt8.Type) throws -> UInt8 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: UInt8.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt16.Type) throws -> UInt16 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: UInt16.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt32.Type) throws -> UInt32 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: UInt32.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: UInt64.Type) throws -> UInt64 { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + + guard let decoded = try decoder.unbox(container[currentIndex], as: UInt64.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Float.Type) throws -> Float { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Float.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Float.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: Double.Type) throws -> Double { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Double.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: Double.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } public mutating func decode(_ type: String.Type) throws -> String { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: String.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: String.self) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } - public mutating func decode(_ type: T.Type) throws -> T { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + public mutating func decode(_ type: T.Type) throws -> T { + guard !isAtEnd else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Unkeyed container is at end." + ) + ) } - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: type) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_MapKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + guard let decoded = try decoder.unbox(container[currentIndex], as: type) else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: decoder.codingPath + [_MapKey(index: currentIndex)], + debugDescription: "Expected \(type) but found null instead." + ) + ) } - self.currentIndex += 1 + currentIndex += 1 return decoded } - public mutating func nestedContainer(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer { - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + public mutating func nestedContainer( + keyedBy _: NestedKey + .Type + ) throws -> KeyedDecodingContainer { + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(KeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + KeyedDecodingContainer.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get nested keyed container -- unkeyed container is at end." + ) + ) } - let value = self.container[self.currentIndex] + let value = self.container[currentIndex] guard !(value is NSNull) else { - throw DecodingError.valueNotFound(KeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead.")) + throw DecodingError.valueNotFound( + KeyedDecodingContainer.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead." + ) + ) } - guard let dictionary = value as? [String : Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) + guard let dictionary = value as? [String: Any] else { + throw DecodingError._typeMismatch( + at: codingPath, + expectation: [String: Any].self, + reality: value + ) } - self.currentIndex += 1 - let container = _MapKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) + currentIndex += 1 + let container = _MapKeyedDecodingContainer( + referencing: decoder, + wrapping: dictionary + ) return KeyedDecodingContainer(container) } public mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer { - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + UnkeyedDecodingContainer.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get nested keyed container -- unkeyed container is at end." + ) + ) } - let value = self.container[self.currentIndex] + let value = container[currentIndex] guard !(value is NSNull) else { - throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead.")) + throw DecodingError.valueNotFound( + UnkeyedDecodingContainer.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead." + ) + ) } guard let array = value as? [Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: value) + throw DecodingError._typeMismatch( + at: codingPath, + expectation: [Any].self, + reality: value + ) } - self.currentIndex += 1 - return _MapUnkeyedDecodingContainer(referencing: self.decoder, wrapping: array) + currentIndex += 1 + return _MapUnkeyedDecodingContainer(referencing: decoder, wrapping: array) } public mutating func superDecoder() throws -> Decoder { - self.decoder.codingPath.append(_MapKey(index: self.currentIndex)) + decoder.codingPath.append(_MapKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(Decoder.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get superDecoder() -- unkeyed container is at end.")) + guard !isAtEnd else { + throw DecodingError.valueNotFound( + Decoder.self, + DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get superDecoder() -- unkeyed container is at end." + ) + ) } - let value = self.container[self.currentIndex] - self.currentIndex += 1 - return _MapDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options) + let value = container[currentIndex] + currentIndex += 1 + return _MapDecoder(referencing: value, at: decoder.codingPath, options: decoder.options) } } -extension _MapDecoder : SingleValueDecodingContainer { +extension _MapDecoder: SingleValueDecodingContainer { // MARK: SingleValueDecodingContainer Methods private func expectNonNull(_ type: T.Type) throws { - guard !self.decodeNil() else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "Expected \(type) but found null value instead.")) + guard !decodeNil() else { + throw DecodingError.valueNotFound( + type, + DecodingError + .Context( + codingPath: codingPath, + debugDescription: "Expected \(type) but found null value instead." + ) + ) } } public func decodeNil() -> Bool { - return self.storage.topContainer is NSNull + return storage.topContainer is NSNull } - public func decode(_ type: Bool.Type) throws -> Bool { + public func decode(_: Bool.Type) throws -> Bool { try expectNonNull(Bool.self) - return try self.unbox(self.storage.topContainer, as: Bool.self)! + return try unbox(storage.topContainer, as: Bool.self)! } - public func decode(_ type: Int.Type) throws -> Int { + public func decode(_: Int.Type) throws -> Int { try expectNonNull(Int.self) - return try self.unbox(self.storage.topContainer, as: Int.self)! + return try unbox(storage.topContainer, as: Int.self)! } - public func decode(_ type: Int8.Type) throws -> Int8 { + public func decode(_: Int8.Type) throws -> Int8 { try expectNonNull(Int8.self) - return try self.unbox(self.storage.topContainer, as: Int8.self)! + return try unbox(storage.topContainer, as: Int8.self)! } - public func decode(_ type: Int16.Type) throws -> Int16 { + public func decode(_: Int16.Type) throws -> Int16 { try expectNonNull(Int16.self) - return try self.unbox(self.storage.topContainer, as: Int16.self)! + return try unbox(storage.topContainer, as: Int16.self)! } - public func decode(_ type: Int32.Type) throws -> Int32 { + public func decode(_: Int32.Type) throws -> Int32 { try expectNonNull(Int32.self) - return try self.unbox(self.storage.topContainer, as: Int32.self)! + return try unbox(storage.topContainer, as: Int32.self)! } - public func decode(_ type: Int64.Type) throws -> Int64 { + public func decode(_: Int64.Type) throws -> Int64 { try expectNonNull(Int64.self) - return try self.unbox(self.storage.topContainer, as: Int64.self)! + return try unbox(storage.topContainer, as: Int64.self)! } - public func decode(_ type: UInt.Type) throws -> UInt { + public func decode(_: UInt.Type) throws -> UInt { try expectNonNull(UInt.self) - return try self.unbox(self.storage.topContainer, as: UInt.self)! + return try unbox(storage.topContainer, as: UInt.self)! } - public func decode(_ type: UInt8.Type) throws -> UInt8 { + public func decode(_: UInt8.Type) throws -> UInt8 { try expectNonNull(UInt8.self) - return try self.unbox(self.storage.topContainer, as: UInt8.self)! + return try unbox(storage.topContainer, as: UInt8.self)! } - public func decode(_ type: UInt16.Type) throws -> UInt16 { + public func decode(_: UInt16.Type) throws -> UInt16 { try expectNonNull(UInt16.self) - return try self.unbox(self.storage.topContainer, as: UInt16.self)! + return try unbox(storage.topContainer, as: UInt16.self)! } - public func decode(_ type: UInt32.Type) throws -> UInt32 { + public func decode(_: UInt32.Type) throws -> UInt32 { try expectNonNull(UInt32.self) - return try self.unbox(self.storage.topContainer, as: UInt32.self)! + return try unbox(storage.topContainer, as: UInt32.self)! } - public func decode(_ type: UInt64.Type) throws -> UInt64 { + public func decode(_: UInt64.Type) throws -> UInt64 { try expectNonNull(UInt64.self) - return try self.unbox(self.storage.topContainer, as: UInt64.self)! + return try unbox(storage.topContainer, as: UInt64.self)! } - public func decode(_ type: Float.Type) throws -> Float { + public func decode(_: Float.Type) throws -> Float { try expectNonNull(Float.self) - return try self.unbox(self.storage.topContainer, as: Float.self)! + return try unbox(storage.topContainer, as: Float.self)! } - public func decode(_ type: Double.Type) throws -> Double { + public func decode(_: Double.Type) throws -> Double { try expectNonNull(Double.self) - return try self.unbox(self.storage.topContainer, as: Double.self)! + return try unbox(storage.topContainer, as: Double.self)! } - public func decode(_ type: String.Type) throws -> String { + public func decode(_: String.Type) throws -> String { try expectNonNull(String.self) - return try self.unbox(self.storage.topContainer, as: String.self)! + return try unbox(storage.topContainer, as: String.self)! } - public func decode(_ type: T.Type) throws -> T { + public func decode(_ type: T.Type) throws -> T { try expectNonNull(type) - return try self.unbox(self.storage.topContainer, as: type)! + return try unbox(storage.topContainer, as: type)! } } // MARK: - Concrete Value Representations -extension _MapDecoder { +private extension _MapDecoder { /// Returns the given value unboxed from a container. - fileprivate func unbox(_ value: Any, as type: Bool.Type) throws -> Bool? { + func unbox(_ value: Any, as type: Bool.Type) throws -> Bool? { guard !(value is NSNull) else { return nil } #if DEPLOYMENT_RUNTIME_SWIFT || os(Linux) - // Bridging differences require us to split implementations here - guard let number = __SwiftValue.store(value) as? NSNumber else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) - } - - // TODO: Add a flag to coerce non-boolean numbers into Bools? - guard CFGetTypeID(number) == CFBooleanGetTypeID() else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) - } + // Bridging differences require us to split implementations here + guard let number = __SwiftValue.store(value) as? NSNumber else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) + } - return number.boolValue - #else - if let number = value as? NSNumber { // TODO: Add a flag to coerce non-boolean numbers into Bools? - if number === kCFBooleanTrue as NSNumber { - return true - } else if number === kCFBooleanFalse as NSNumber { - return false + guard CFGetTypeID(number) == CFBooleanGetTypeID() else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } - /* FIXME: If swift-corelibs-foundation doesn't change to use NSNumber, this code path will need to be included and tested: - } else if let bool = value as? Bool { - return bool - */ + return number.boolValue + #else + if let number = value as? NSNumber { + // TODO: Add a flag to coerce non-boolean numbers into Bools? + if number === kCFBooleanTrue as NSNumber { + return true + } else if number === kCFBooleanFalse as NSNumber { + return false + } - } + /* FIXME: If swift-corelibs-foundation doesn't change to use NSNumber, this code path will need to be included and tested: + } else if let bool = value as? Bool { + return bool + */ + } - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) #endif } - fileprivate func unbox(_ value: Any, as type: Int.Type) throws -> Int? { + func unbox(_ value: Any, as type: Int.Type) throws -> Int? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int = number.intValue guard NSNumber(value: int) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: Int8.Type) throws -> Int8? { + func unbox(_ value: Any, as type: Int8.Type) throws -> Int8? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int8 = number.int8Value guard NSNumber(value: int8) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: Int16.Type) throws -> Int16? { + func unbox(_ value: Any, as type: Int16.Type) throws -> Int16? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int16 = number.int16Value guard NSNumber(value: int16) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: Int32.Type) throws -> Int32? { + func unbox(_ value: Any, as type: Int32.Type) throws -> Int32? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int32 = number.int32Value guard NSNumber(value: int32) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: Int64.Type) throws -> Int64? { + func unbox(_ value: Any, as type: Int64.Type) throws -> Int64? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let int64 = number.int64Value guard NSNumber(value: int64) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: UInt.Type) throws -> UInt? { + func unbox(_ value: Any, as type: UInt.Type) throws -> UInt? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint = number.uintValue guard NSNumber(value: uint) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: UInt8.Type) throws -> UInt8? { + func unbox(_ value: Any, as type: UInt8.Type) throws -> UInt8? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint8 = number.uint8Value guard NSNumber(value: uint8) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: UInt16.Type) throws -> UInt16? { + func unbox(_ value: Any, as type: UInt16.Type) throws -> UInt16? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint16 = number.uint16Value guard NSNumber(value: uint16) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? { + func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint32 = number.uint32Value guard NSNumber(value: uint32) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: UInt64.Type) throws -> UInt64? { + func unbox(_ value: Any, as type: UInt64.Type) throws -> UInt64? { guard !(value is NSNull) else { return nil } - guard let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + guard + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + else { + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let uint64 = number.uint64Value guard NSNumber(value: uint64) == number else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 } - fileprivate func unbox(_ value: Any, as type: Float.Type) throws -> Float? { + 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, number !== kCFBooleanFalse { + if + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + { // We are willing to return a Float by losing precision: // * If the original value was integral, // * and the integral value was > Float.greatestFiniteMagnitude, we will fail @@ -2247,27 +2962,33 @@ 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: self.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) /* FIXME: If swift-corelibs-foundation doesn't change to use NSNumber, this code path will need to be included and tested: - } else if let double = value as? Double { - if abs(double) <= Double(Float.max) { - return Float(double) - } - overflow = true - } else if let int = value as? Int { - if let float = Float(exactly: int) { - return float - } + } else if let double = value as? Double { + if abs(double) <= Double(Float.max) { + return Float(double) + } + overflow = true + } else if let int = value as? Int { + if let float = Float(exactly: int) { + return float + } - overflow = true - */ - - } else if let string = value as? String, - case .convertFromString(let posInfString, let negInfString, let nanString) = self.options.nonConformingFloatDecodingStrategy { + overflow = true + */ + + } else if + let string = value as? String, + case let .convertFromString(posInfString, negInfString, nanString) = options + .nonConformingFloatDecodingStrategy + { if string == posInfString { return Float.infinity } else if string == negInfString { @@ -2277,13 +2998,16 @@ extension _MapDecoder { } } - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } - fileprivate func unbox(_ value: Any, as type: Double.Type) throws -> Double? { + 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, number !== kCFBooleanFalse { + if + let number = __SwiftValue.store(value) as? NSNumber, number !== kCFBooleanTrue, + number !== kCFBooleanFalse + { // We are always willing to return the number as a Double: // * If the original value was integral, it is guaranteed to fit in a Double; we are willing to lose precision past 2^53 if you encoded a UInt64 but requested a Double // * If it was a Float or Double, you will get back the precise value @@ -2291,18 +3015,21 @@ extension _MapDecoder { return number.doubleValue /* FIXME: If swift-corelibs-foundation doesn't change to use NSNumber, this code path will need to be included and tested: - } else if let double = value as? Double { - return double - } else if let int = value as? Int { - if let double = Double(exactly: int) { - return double - } - - overflow = true - */ - - } else if let string = value as? String, - case .convertFromString(let posInfString, let negInfString, let nanString) = self.options.nonConformingFloatDecodingStrategy { + } else if let double = value as? Double { + return double + } else if let int = value as? Int { + if let double = Double(exactly: int) { + return double + } + + overflow = true + */ + + } else if + let string = value as? String, + case let .convertFromString(posInfString, negInfString, nanString) = options + .nonConformingFloatDecodingStrategy + { if string == posInfString { return Double.infinity } else if string == negInfString { @@ -2312,41 +3039,44 @@ extension _MapDecoder { } } - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } - fileprivate func unbox(_ value: Any, as type: String.Type) throws -> String? { + func unbox(_ value: Any, as type: String.Type) throws -> String? { guard !(value is NSNull) else { return nil } guard let string = value as? String else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } return string } - fileprivate func unbox(_ value: Any, as type: Date.Type) throws -> Date? { + func unbox(_ value: Any, as _: Date.Type) throws -> Date? { guard !(value is NSNull) else { return nil } - switch self.options.dateDecodingStrategy { + switch options.dateDecodingStrategy { case .deferredToDate: - self.storage.push(container: value) + storage.push(container: value) defer { self.storage.popContainer() } return try Date(from: self) case .secondsSince1970: - let double = try self.unbox(value, as: Double.self)! + let double = try unbox(value, as: Double.self)! return Date(timeIntervalSince1970: double) case .millisecondsSince1970: - let double = try self.unbox(value, as: Double.self)! + let double = try unbox(value, as: Double.self)! return Date(timeIntervalSince1970: double / 1000.0) case .iso8601: 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 @@ -2354,71 +3084,77 @@ extension _MapDecoder { fatalError("ISO8601DateFormatter is unavailable on this platform.") } - case .formatted(let formatter): - let string = try self.unbox(value, as: String.self)! + case let .formatted(formatter): + let string = try unbox(value, as: String.self)! guard let date = formatter.date(from: string) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 .custom(let closure): - self.storage.push(container: value) + case let .custom(closure): + storage.push(container: value) defer { self.storage.popContainer() } return try closure(self) } } - fileprivate func unbox(_ value: Any, as type: Data.Type) throws -> Data? { + func unbox(_ value: Any, as type: Data.Type) throws -> Data? { guard !(value is NSNull) else { return nil } - switch self.options.dataDecodingStrategy { + switch options.dataDecodingStrategy { case .deferredToData: - self.storage.push(container: value) + storage.push(container: value) defer { self.storage.popContainer() } return try Data(from: self) case .base64: guard let string = value as? String else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } guard let data = Data(base64Encoded: string) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.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 .custom(let closure): - self.storage.push(container: value) + case let .custom(closure): + storage.push(container: value) defer { self.storage.popContainer() } return try closure(self) } } - fileprivate func unbox(_ value: Any, as type: Decimal.Type) throws -> Decimal? { + func unbox(_ value: Any, as _: Decimal.Type) throws -> Decimal? { guard !(value is NSNull) else { return nil } // Attempt to bridge from NSDecimalNumber. if let decimal = value as? Decimal { return decimal } else { - let doubleValue = try self.unbox(value, as: Double.self)! + let doubleValue = try unbox(value, as: Double.self)! return Decimal(doubleValue) } } - - fileprivate func unbox(_ value: Any, as type: _MapStringDictionaryDecodableMarker.Type) throws -> T? { + + func unbox(_ value: Any, as type: _MapStringDictionaryDecodableMarker.Type) throws -> T? { guard !(value is NSNull) else { return nil } var result: OrderedDictionary = [:] guard let dict = value as? NSDictionary else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + throw DecodingError._typeMismatch(at: codingPath, expectation: type, reality: value) } let elementType = type.elementType for (key, value) in dict { let key = key as! String - self.codingPath.append(_MapKey(stringValue: key, intValue: nil)) + codingPath.append(_MapKey(stringValue: key, intValue: nil)) defer { self.codingPath.removeLast() } result[key] = try unbox_(value, as: elementType) @@ -2427,64 +3163,68 @@ extension _MapDecoder { return result as? T } - fileprivate func unbox(_ value: Any, as type: T.Type) throws -> T? { + func unbox(_ value: Any, as type: T.Type) throws -> T? { return try unbox_(value, as: type) as? T } - fileprivate func unbox_(_ value: Any, as type: Decodable.Type) throws -> Any? { + 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 { - guard let date = try self.unbox(value, as: Date.self) else { return nil } - return date - } else if type == Data.self { - guard let data = try self.unbox(value, as: Data.self) else { return nil } - return data - } else if type == URL.self { - guard let urlString = try self.unbox(value, as: String.self) else { - return nil - } + // Bridging differences require us to split implementations here + if type == Date.self { + guard let date = try unbox(value, as: Date.self) else { return nil } + return date + } else if type == Data.self { + guard let data = try unbox(value, as: Data.self) else { return nil } + return data + } else if type == URL.self { + guard let urlString = try unbox(value, as: String.self) else { + return nil + } - guard let url = URL(string: urlString) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Invalid URL string.")) + guard let url = URL(string: urlString) else { + throw DecodingError.dataCorrupted(DecodingError.Context( + codingPath: codingPath, + debugDescription: "Invalid URL string." + )) + } + return url + } else if type == Decimal.self { + guard let decimal = try unbox(value, as: Decimal.self) else { return nil } + return decimal + } else if let stringKeyedDictType = type as? _MapStringDictionaryDecodableMarker.Type { + return try unbox(value, as: stringKeyedDictType) + } else { + storage.push(container: value) + defer { self.storage.popContainer() } + return try type.init(from: self) } - return url - } else if type == Decimal.self { - guard let decimal = try self.unbox(value, as: Decimal.self) else { return nil } - return decimal - } else if let stringKeyedDictType = type as? _MapStringDictionaryDecodableMarker.Type { - return try self.unbox(value, as: stringKeyedDictType) - } else { - self.storage.push(container: value) - defer { self.storage.popContainer() } - return try type.init(from: self) - } #else - if type == Date.self || type == NSDate.self { - return try self.unbox(value, as: Date.self) - } else if type == Data.self || type == NSData.self { - return try self.unbox(value, as: Data.self) - } else if type == URL.self || type == NSURL.self { - guard let urlString = try self.unbox(value, as: String.self) else { - return nil - } - - guard let url = URL(string: urlString) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Invalid URL string.")) + if type == Date.self || type == NSDate.self { + return try unbox(value, as: Date.self) + } else if type == Data.self || type == NSData.self { + return try unbox(value, as: Data.self) + } else if type == URL.self || type == NSURL.self { + guard let urlString = try unbox(value, as: String.self) else { + return nil + } + + guard let url = URL(string: urlString) else { + throw DecodingError.dataCorrupted(DecodingError.Context( + codingPath: codingPath, + debugDescription: "Invalid URL string." + )) + } + + return url + } else if type == Decimal.self || type == NSDecimalNumber.self { + return try unbox(value, as: Decimal.self) + } else if let stringKeyedDictType = type as? _MapStringDictionaryDecodableMarker.Type { + return try unbox(value, as: stringKeyedDictType) + } else { + storage.push(container: value) + defer { self.storage.popContainer() } + return try type.init(from: self) } - - return url - } else if type == Decimal.self || type == NSDecimalNumber.self { - return try self.unbox(value, as: Decimal.self) - } else if let stringKeyedDictType = type as? _MapStringDictionaryDecodableMarker.Type { - return try self.unbox(value, as: stringKeyedDictType) - } else { - self.storage.push(container: value) - defer { self.storage.popContainer() } - return try type.init(from: self) - } #endif } } @@ -2493,17 +3233,17 @@ extension _MapDecoder { // Shared Key Types //===----------------------------------------------------------------------===// -fileprivate struct _MapKey : CodingKey { +private struct _MapKey: CodingKey { public var stringValue: String public var intValue: Int? public init?(stringValue: String) { self.stringValue = stringValue - self.intValue = nil + intValue = nil } public init?(intValue: Int) { - self.stringValue = "\(intValue)" + stringValue = "\(intValue)" self.intValue = intValue } @@ -2511,9 +3251,10 @@ fileprivate struct _MapKey : CodingKey { self.stringValue = stringValue self.intValue = intValue } + fileprivate init(index: Int) { - self.stringValue = "Index \(index)" - self.intValue = index + stringValue = "Index \(index)" + intValue = index } fileprivate static let `super` = _MapKey(stringValue: "super")! @@ -2525,7 +3266,7 @@ fileprivate struct _MapKey : CodingKey { // NOTE: This value is implicitly lazy and _must_ be lazy. We're compiled against the latest SDK (w/ ISO8601DateFormatter), but linked against whichever Foundation the user has. ISO8601DateFormatter might not exist, so we better not hit this code path on an older OS. @available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -fileprivate var _iso8601Formatter: ISO8601DateFormatter = { +private var _iso8601Formatter: ISO8601DateFormatter = { let formatter = ISO8601DateFormatter() formatter.formatOptions = .withInternetDateTime return formatter @@ -2535,14 +3276,17 @@ fileprivate var _iso8601Formatter: ISO8601DateFormatter = { // Error Utilities //===----------------------------------------------------------------------===// -extension EncodingError { +private 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. - fileprivate static func _invalidFloatingPointValue(_ value: T, at codingPath: [CodingKey]) -> EncodingError { + static func _invalidFloatingPointValue( + _ value: T, + at codingPath: [CodingKey] + ) -> EncodingError { let valueDescription: String if value == T.infinity { valueDescription = "\(T.self).infinity" @@ -2552,8 +3296,12 @@ extension EncodingError { valueDescription = "\(T.self).nan" } - let debugDescription = "Unable to encode \(valueDescription) directly in Map. Use MapEncoder.NonConformingFloatEncodingStrategy.convertToString to specify how the value should be encoded." - return .invalidValue(value, EncodingError.Context(codingPath: codingPath, debugDescription: debugDescription)) + let debugDescription = + "Unable to encode \(valueDescription) directly in Map. Use MapEncoder.NonConformingFloatEncodingStrategy.convertToString to specify how the value should be encoded." + return .invalidValue( + value, + EncodingError.Context(codingPath: codingPath, debugDescription: debugDescription) + ) } } @@ -2569,10 +3317,11 @@ extension DecodingError { expectation: Any.Type, reality: Any ) -> DecodingError { - let description = "Expected to decode \(expectation) but found \(_typeDescription(of: reality)) instead." + let description = + "Expected to decode \(expectation) but found \(_typeDescription(of: reality)) instead." return .typeMismatch(expectation, Context(codingPath: path, debugDescription: description)) } - + /// Returns a description of the type of `value` appropriate for an error message. /// /// - parameter value: The value whose type to describe. @@ -2587,7 +3336,7 @@ extension DecodingError { return "a string/data" } else if value is [Any] { return "an array" - } else if value is [String : Any] { + } else if value is [String: Any] { return "a dictionary" } else { return "\(type(of: value))" @@ -2595,7 +3344,7 @@ extension DecodingError { } } -private struct __SwiftValue { +private enum __SwiftValue { fileprivate static func store(_ any: Any) -> Any { return any } diff --git a/Sources/GraphQL/Map/MapSerialization.swift b/Sources/GraphQL/Map/MapSerialization.swift index 76779dee..e4099cd8 100644 --- a/Sources/GraphQL/Map/MapSerialization.swift +++ b/Sources/GraphQL/Map/MapSerialization.swift @@ -26,27 +26,28 @@ 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.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)" + 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)" + ) ) - ) - } - guard let value = pair.value as? NSObject else{ - throw EncodingError.invalidValue( - dictionary, - EncodingError.Context( - codingPath: [], - debugDescription: "Dictionary value was not an object: \(key) in \(dictionary)" + } + guard let value = pair.value as? NSObject else { + throw EncodingError.invalidValue( + dictionary, + EncodingError.Context( + codingPath: [], + debugDescription: "Dictionary value was not an object: \(key) in \(dictionary)" + ) ) - ) + } + dictionary[key] = try self.map(with: value) } - dictionary[key] = try self.map(with: value) - } return .dictionary(orderedDictionary) default: throw EncodingError.invalidValue( @@ -58,7 +59,7 @@ public struct MapSerialization { ) } } - + static func object(with map: Map) throws -> NSObject { switch map { case .undefined: @@ -78,7 +79,7 @@ public struct MapSerialization { case let .string(string): return string as NSString case let .array(array): - return try array.map({ try object(with: $0) }) as NSArray + return try array.map { try object(with: $0) } as NSArray case let .dictionary(dictionary): // Coerce to an unordered dictionary var unorderedDictionary: [String: NSObject] = [:] diff --git a/Sources/GraphQL/Map/Number.swift b/Sources/GraphQL/Map/Number.swift index b28aa3e4..f7633b2a 100644 --- a/Sources/GraphQL/Map/Number.swift +++ b/Sources/GraphQL/Map/Number.swift @@ -7,195 +7,195 @@ public struct Number { case double case unknown } - + private var _number: NSNumber public var storageType: StorageType - + public var number: NSNumber { mutating get { if !isKnownUniquelyReferenced(&_number) { _number = _number.copy() as! NSNumber } - + return _number } - + set { _number = newValue } } - + public init(_ value: NSNumber) { - self._number = value - self.storageType = .unknown + _number = value + storageType = .unknown } - + public init(_ value: Bool) { - self._number = NSNumber(value: value) - self.storageType = .bool + _number = NSNumber(value: value) + storageType = .bool } - + @available(OSX 10.5, *) public init(_ value: Int) { - self._number = NSNumber(value: value) - self.storageType = .int + _number = NSNumber(value: value) + storageType = .int } - + @available(OSX 10.5, *) public init(_ value: UInt) { - self._number = NSNumber(value: value) - self.storageType = .int + _number = NSNumber(value: value) + storageType = .int } public init(_ value: Int8) { - self._number = NSNumber(value: value) - self.storageType = .int + _number = NSNumber(value: value) + storageType = .int } public init(_ value: UInt8) { - self._number = NSNumber(value: value) - self.storageType = .int + _number = NSNumber(value: value) + storageType = .int } public init(_ value: Int16) { - self._number = NSNumber(value: value) - self.storageType = .int + _number = NSNumber(value: value) + storageType = .int } public init(_ value: UInt16) { - self._number = NSNumber(value: value) - self.storageType = .int + _number = NSNumber(value: value) + storageType = .int } public init(_ value: Int32) { - self._number = NSNumber(value: value) - self.storageType = .int + _number = NSNumber(value: value) + storageType = .int } public init(_ value: UInt32) { - self._number = NSNumber(value: value) - self.storageType = .int + _number = NSNumber(value: value) + storageType = .int } public init(_ value: Int64) { - self._number = NSNumber(value: value) - self.storageType = .int + _number = NSNumber(value: value) + storageType = .int } public init(_ value: UInt64) { - self._number = NSNumber(value: value) - self.storageType = .int + _number = NSNumber(value: value) + storageType = .int } public init(_ value: Float) { - self._number = NSNumber(value: value) - self.storageType = .double + _number = NSNumber(value: value) + storageType = .double } public init(_ value: Double) { - self._number = NSNumber(value: value) - self.storageType = .double + _number = NSNumber(value: value) + storageType = .double } public var boolValue: Bool { - return self._number.boolValue + return _number.boolValue } - + @available(OSX 10.5, *) public var intValue: Int { - return self._number.intValue + return _number.intValue } - + @available(OSX 10.5, *) public var uintValue: UInt { - return self._number.uintValue + return _number.uintValue } - + public var int8Value: Int8 { - return self._number.int8Value + return _number.int8Value } public var uint8Value: UInt8 { - return self._number.uint8Value + return _number.uint8Value } public var int16Value: Int16 { - return self._number.int16Value + return _number.int16Value } public var uint16Value: UInt16 { - return self._number.uint16Value + return _number.uint16Value } public var int32Value: Int32 { - return self._number.int32Value + return _number.int32Value } public var uint32Value: UInt32 { - return self._number.uint32Value + return _number.uint32Value } public var int64Value: Int64 { - return self._number.int64Value + return _number.int64Value } public var uint64Value: UInt64 { - return self._number.uint64Value + return _number.uint64Value } public var floatValue: Float { - return self._number.floatValue + return _number.floatValue } public var doubleValue: Double { - return self._number.doubleValue + return _number.doubleValue } public var stringValue: String { - return self._number.stringValue + return _number.stringValue } } -extension Number : Hashable {} +extension Number: Hashable {} -extension Number : Equatable { +extension Number: Equatable { public static func == (lhs: Self, rhs: Self) -> Bool { return lhs._number == rhs._number } } -extension Number : Comparable { +extension Number: Comparable { public static func < (lhs: Number, rhs: Number) -> Bool { return lhs._number.compare(rhs._number) == .orderedAscending } } -extension Number : ExpressibleByBooleanLiteral { +extension Number: ExpressibleByBooleanLiteral { /// Create an instance initialized to `value`. public init(booleanLiteral value: Bool) { - self._number = NSNumber(value: value) - self.storageType = .bool + _number = NSNumber(value: value) + storageType = .bool } } -extension Number : ExpressibleByIntegerLiteral { +extension Number: ExpressibleByIntegerLiteral { /// Create an instance initialized to `value`. public init(integerLiteral value: Int) { - self._number = NSNumber(value: value) - self.storageType = .int + _number = NSNumber(value: value) + storageType = .int } } -extension Number : ExpressibleByFloatLiteral { +extension Number: ExpressibleByFloatLiteral { /// Create an instance initialized to `value`. public init(floatLiteral value: Double) { - self._number = NSNumber(value: value) - self.storageType = .double + _number = NSNumber(value: value) + storageType = .double } } -extension Number : CustomStringConvertible { +extension Number: CustomStringConvertible { public var description: String { - return self._number.description + return _number.description } } diff --git a/Sources/GraphQL/Subscription/EventStream.swift b/Sources/GraphQL/Subscription/EventStream.swift index 2cebdeb5..d6af2dd4 100644 --- a/Sources/GraphQL/Subscription/EventStream.swift +++ b/Sources/GraphQL/Subscription/EventStream.swift @@ -1,74 +1,80 @@ /// Abstract event stream class - Should be overridden for actual implementations open class EventStream { - public init() { } + public init() {} /// Template method for mapping an event stream to a new generic type - MUST be overridden by implementing types. - open func map(_ closure: @escaping (Element) throws -> To) -> EventStream { + open func map(_: @escaping (Element) throws -> To) -> EventStream { fatalError("This function should be overridden by implementing classes") } } #if compiler(>=5.5) && canImport(_Concurrency) -@available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) -/// Event stream that wraps an `AsyncThrowingStream` from Swift's standard concurrency system. -public class ConcurrentEventStream: EventStream { - public let stream: AsyncThrowingStream + @available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) + /// Event stream that wraps an `AsyncThrowingStream` from Swift's standard concurrency system. + public class ConcurrentEventStream: EventStream { + public let stream: AsyncThrowingStream - public init(_ stream: AsyncThrowingStream) { - self.stream = stream - } - - /// Performs the closure on each event in the current stream and returns a stream of the results. - /// - Parameter closure: The closure to apply to each event in the stream - /// - Returns: A stream of the results - override open func map(_ closure: @escaping (Element) throws -> To) -> ConcurrentEventStream { - let newStream = self.stream.mapStream(closure) - return ConcurrentEventStream.init(newStream) + public init(_ stream: AsyncThrowingStream) { + self.stream = stream + } + + /// Performs the closure on each event in the current stream and returns a stream of the results. + /// - Parameter closure: The closure to apply to each event in the stream + /// - Returns: A stream of the results + override open func map(_ closure: @escaping (Element) throws -> To) + -> ConcurrentEventStream + { + let newStream = stream.mapStream(closure) + return ConcurrentEventStream.init(newStream) + } } -} -@available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) -extension AsyncThrowingStream { - func mapStream(_ closure: @escaping (Element) throws -> To) -> AsyncThrowingStream { - return AsyncThrowingStream { continuation in - let task = Task { - do { - for try await event in self { - let newEvent = try closure(event) - continuation.yield(newEvent) + @available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) + extension AsyncThrowingStream { + func mapStream(_ closure: @escaping (Element) throws -> To) + -> AsyncThrowingStream + { + return AsyncThrowingStream { continuation in + let task = Task { + do { + for try await event in self { + let newEvent = try closure(event) + continuation.yield(newEvent) + } + continuation.finish() + } catch { + continuation.finish(throwing: error) } - continuation.finish() - } catch { - continuation.finish(throwing: error) } - } - continuation.onTermination = { @Sendable reason in - task.cancel() + continuation.onTermination = { @Sendable reason in + task.cancel() + } } } - } - - func filterStream(_ isIncluded: @escaping (Element) throws -> Bool) -> AsyncThrowingStream { - return AsyncThrowingStream { continuation in - let task = Task { - do { - for try await event in self { - if try isIncluded(event) { - continuation.yield(event) + + func filterStream(_ isIncluded: @escaping (Element) throws -> Bool) + -> AsyncThrowingStream + { + return AsyncThrowingStream { continuation in + let task = Task { + do { + for try await event in self { + if try isIncluded(event) { + continuation.yield(event) + } } + continuation.finish() + } catch { + continuation.finish(throwing: error) } - continuation.finish() - } catch { - continuation.finish(throwing: error) } - } - continuation.onTermination = { @Sendable _ in - task.cancel() + continuation.onTermination = { @Sendable _ in + task.cancel() + } } } } -} #endif diff --git a/Sources/GraphQL/Subscription/Subscribe.swift b/Sources/GraphQL/Subscription/Subscribe.swift index b1428a4b..b1cebe95 100644 --- a/Sources/GraphQL/Subscription/Subscribe.swift +++ b/Sources/GraphQL/Subscription/Subscribe.swift @@ -34,7 +34,6 @@ func subscribe( variableValues: [String: Map] = [:], operationName: String? = nil ) -> EventLoopFuture { - let sourceFuture = createSourceEventStream( queryStrategy: queryStrategy, mutationStrategy: mutationStrategy, @@ -48,18 +47,18 @@ func subscribe( variableValues: variableValues, operationName: operationName ) - - return sourceFuture.map{ sourceResult -> SubscriptionResult in + + return sourceFuture.map { sourceResult -> SubscriptionResult in if let sourceStream = sourceResult.stream { let subscriptionStream = sourceStream.map { eventPayload -> Future in - + // For each payload yielded from a subscription, map it over the normal // GraphQL `execute` function, with `payload` as the rootValue. // This implements the "MapSourceToResponseEvent" algorithm described in // the GraphQL specification. The `execute` function provides the // "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the // "ExecuteQuery" algorithm, for which `execute` is also used. - return execute( + execute( queryStrategy: queryStrategy, mutationStrategy: mutationStrategy, subscriptionStrategy: subscriptionStrategy, @@ -120,9 +119,8 @@ func createSourceEventStream( variableValues: [String: Map] = [:], operationName: String? = nil ) -> EventLoopFuture { - let executeStarted = instrumentation.now - + do { // If a valid context cannot be created due to incorrect arguments, // this will throw an error. @@ -158,7 +156,8 @@ func createSourceEventStream( return eventLoopGroup.next().makeSucceededFuture(SourceEventStreamResult(errors: [error])) } catch { - return eventLoopGroup.next().makeSucceededFuture(SourceEventStreamResult(errors: [GraphQLError(error)])) + return eventLoopGroup.next() + .makeSucceededFuture(SourceEventStreamResult(errors: [GraphQLError(error)])) } } @@ -166,11 +165,10 @@ func executeSubscription( context: ExecutionContext, eventLoopGroup: EventLoopGroup ) throws -> EventLoopFuture { - // Get the first node let type = try getOperationRootType(schema: context.schema, operation: context.operation) var inputFields: OrderedDictionary = [:] - var visitedFragmentNames: [String:Bool] = [:] + var visitedFragmentNames: [String: Bool] = [:] let fields = try collectFields( exeContext: context, runtimeType: type, @@ -178,39 +176,46 @@ func executeSubscription( fields: &inputFields, visitedFragmentNames: &visitedFragmentNames ) - + // If query is valid, fields should have at least 1 member - guard let responseName = fields.keys.first, - let fieldNodes = fields[responseName], - let fieldNode = fieldNodes.first else { + guard + let responseName = fields.keys.first, + let fieldNodes = fields[responseName], + let fieldNode = fieldNodes.first + else { throw GraphQLError( message: "Subscription field resolution resulted in no field nodes." ) } - - guard let fieldDef = getFieldDef(schema: context.schema, parentType: type, fieldAST: fieldNode) else { + + guard let fieldDef = getFieldDef(schema: context.schema, parentType: type, fieldAST: fieldNode) + else { throw GraphQLError( message: "The subscription field '\(fieldNode.name.value)' is not defined.", nodes: fieldNodes ) } - + // Implements the "ResolveFieldEventStream" algorithm from GraphQL specification. // It differs from "ResolveFieldValue" due to providing a different `resolveFn`. // Build a map of arguments from the field.arguments AST, using the // variables scope to fulfill any variable references. - let args = try getArgumentValues(argDefs: fieldDef.args, argASTs: fieldNode.arguments, variables: context.variableValues) + let args = try getArgumentValues( + argDefs: fieldDef.args, + argASTs: fieldNode.arguments, + variables: context.variableValues + ) // The resolve function's optional third argument is a context value that // is provided to every resolve function within an execution. It is commonly // used to represent an authenticated user, or request-specific caches. let contextValue = context.context - + // The resolve function's optional fourth argument is a collection of // information about the current execution state. - let path = IndexPath.init().appending(fieldNode.name.value) - let info = GraphQLResolveInfo.init( + let path = IndexPath().appending(fieldNode.name.value) + let info = GraphQLResolveInfo( fieldName: fieldDef.name, fieldASTs: fieldNodes, returnType: fieldDef.type, @@ -226,7 +231,7 @@ func executeSubscription( // Call the `subscribe()` resolver or the default resolver to produce an // Observable yielding raw payloads. let resolve = fieldDef.subscribe ?? defaultResolve - + // Get the resolve func, regardless of if its result is normal // or abrupt (error). let resolvedFutureOrError = resolveOrError( @@ -237,8 +242,8 @@ func executeSubscription( eventLoopGroup: eventLoopGroup, info: info ) - - let resolvedFuture:Future + + let resolvedFuture: Future switch resolvedFutureOrError { case let .failure(error): if let graphQLError = error as? GraphQLError { @@ -258,14 +263,14 @@ func executeSubscription( return SourceEventStreamResult(stream: stream) } else if resolved == nil { return SourceEventStreamResult(errors: [ - GraphQLError(message: "Resolved subscription was nil") + GraphQLError(message: "Resolved subscription was nil"), ]) } else { let resolvedObj = resolved as AnyObject return SourceEventStreamResult(errors: [ GraphQLError( message: "Subscription field resolver must return EventStream. Received: '\(resolvedObj)'" - ) + ), ]) } } @@ -276,7 +281,7 @@ func executeSubscription( struct SourceEventStreamResult { public let stream: EventStream? public let errors: [GraphQLError] - + public init(stream: EventStream? = nil, errors: [GraphQLError] = []) { self.stream = stream self.errors = errors diff --git a/Sources/GraphQL/SwiftUtilities/IsNullish.swift b/Sources/GraphQL/SwiftUtilities/IsNullish.swift index 13d0b4e4..3300ecad 100644 --- a/Sources/GraphQL/SwiftUtilities/IsNullish.swift +++ b/Sources/GraphQL/SwiftUtilities/IsNullish.swift @@ -3,7 +3,7 @@ protocol OptionalProtocol { var isNil: Bool { get } } -extension Optional : OptionalProtocol { +extension Optional: OptionalProtocol { var wrappedType: Any.Type { return Wrapped.self } @@ -21,10 +21,10 @@ extension Optional : OptionalProtocol { /** * Returns true if a value is null, or nil. */ -//func isNullish(_ value: Any?) -> Bool { +// func isNullish(_ value: Any?) -> Bool { // guard value != nil else { // return true // } // // return false -//} +// } diff --git a/Sources/GraphQL/SwiftUtilities/KeyMap.swift b/Sources/GraphQL/SwiftUtilities/KeyMap.swift index d4bbf3c6..76c5046c 100644 --- a/Sources/GraphQL/SwiftUtilities/KeyMap.swift +++ b/Sources/GraphQL/SwiftUtilities/KeyMap.swift @@ -20,7 +20,7 @@ */ extension Array { func keyMap(_ keyFunction: (Element) -> String) -> [String: Element] { - return self.reduce([:]) { map, item in + return reduce([:]) { map, item in var mapCopy = map mapCopy[keyFunction(item)] = item return mapCopy diff --git a/Sources/GraphQL/SwiftUtilities/QuotedOrList.swift b/Sources/GraphQL/SwiftUtilities/QuotedOrList.swift index 24aadb57..c68ec016 100644 --- a/Sources/GraphQL/SwiftUtilities/QuotedOrList.swift +++ b/Sources/GraphQL/SwiftUtilities/QuotedOrList.swift @@ -3,9 +3,9 @@ */ func quotedOrList(items: [String]) -> String { let maxLength = min(5, items.count) - let selected = items[0.. Int { let aLength = a.utf8.count let bLength = b.utf8.count - var d: [[Int]] = [[Int]](repeating: [Int](repeating: 0, count: bLength + 1), count: aLength + 1) + 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) && a.charCode(at: i - 2) == b.charCode(at: j - 1) { + 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) } } } - + return d[aLength][bLength] } diff --git a/Sources/GraphQL/Type/Definition.swift b/Sources/GraphQL/Type/Definition.swift index 57649903..f7ff8ada 100644 --- a/Sources/GraphQL/Type/Definition.swift +++ b/Sources/GraphQL/Type/Definition.swift @@ -4,28 +4,28 @@ import NIO /** * These are all of the possible kinds of types. */ -public protocol GraphQLType : CustomDebugStringConvertible, Encodable, KeySubscriptable {} -extension GraphQLScalarType : GraphQLType {} -extension GraphQLObjectType : GraphQLType {} -extension GraphQLInterfaceType : GraphQLType {} -extension GraphQLUnionType : GraphQLType {} -extension GraphQLEnumType : GraphQLType {} -extension GraphQLInputObjectType : GraphQLType {} -extension GraphQLList : GraphQLType {} -extension GraphQLNonNull : GraphQLType {} +public protocol GraphQLType: CustomDebugStringConvertible, Encodable, KeySubscriptable {} +extension GraphQLScalarType: GraphQLType {} +extension GraphQLObjectType: GraphQLType {} +extension GraphQLInterfaceType: GraphQLType {} +extension GraphQLUnionType: GraphQLType {} +extension GraphQLEnumType: GraphQLType {} +extension GraphQLInputObjectType: GraphQLType {} +extension GraphQLList: GraphQLType {} +extension GraphQLNonNull: GraphQLType {} /** * These types may be used as input types for arguments and directives. */ -public protocol GraphQLInputType : GraphQLType {} -extension GraphQLScalarType : GraphQLInputType {} -extension GraphQLEnumType : GraphQLInputType {} -extension GraphQLInputObjectType : GraphQLInputType {} -extension GraphQLList : GraphQLInputType {} -extension GraphQLNonNull : GraphQLInputType {} +public protocol GraphQLInputType: GraphQLType {} +extension GraphQLScalarType: GraphQLInputType {} +extension GraphQLEnumType: GraphQLInputType {} +extension GraphQLInputObjectType: GraphQLInputType {} +extension GraphQLList: GraphQLInputType {} +extension GraphQLNonNull: GraphQLInputType {} // TODO: Conditional conformances -//extension GraphQLList : GraphQLInputType where Element : GraphQLInputType {} -//extension GraphQLNonNull : GraphQLInputType where Element : (GraphQLScalarType | GraphQLEnumType | GraphQLInputObjectType | GraphQLList) {} +// extension GraphQLList : GraphQLInputType where Element : GraphQLInputType {} +// extension GraphQLNonNull : GraphQLInputType where Element : (GraphQLScalarType | GraphQLEnumType | GraphQLInputObjectType | GraphQLList) {} func isInputType(type: GraphQLType?) -> Bool { let namedType = getNamedType(type: type) @@ -35,73 +35,73 @@ func isInputType(type: GraphQLType?) -> Bool { /** * These types may be used as output types as the result of fields. */ -public protocol GraphQLOutputType : GraphQLType {} -extension GraphQLScalarType : GraphQLOutputType {} -extension GraphQLObjectType : GraphQLOutputType {} -extension GraphQLInterfaceType : GraphQLOutputType {} -extension GraphQLUnionType : GraphQLOutputType {} -extension GraphQLEnumType : GraphQLOutputType {} -extension GraphQLList : GraphQLOutputType {} -extension GraphQLNonNull : GraphQLOutputType {} +public protocol GraphQLOutputType: GraphQLType {} +extension GraphQLScalarType: GraphQLOutputType {} +extension GraphQLObjectType: GraphQLOutputType {} +extension GraphQLInterfaceType: GraphQLOutputType {} +extension GraphQLUnionType: GraphQLOutputType {} +extension GraphQLEnumType: GraphQLOutputType {} +extension GraphQLList: GraphQLOutputType {} +extension GraphQLNonNull: GraphQLOutputType {} // TODO: Conditional conformances -//extension GraphQLList : GraphQLOutputType where Element : GraphQLOutputType {} -//extension GraphQLNonNull : GraphQLInputType where Element : (GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLList) {} +// extension GraphQLList : GraphQLOutputType where Element : GraphQLOutputType {} +// extension GraphQLNonNull : GraphQLInputType where Element : (GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLList) {} /** * These types may describe types which may be leaf values. */ -public protocol GraphQLLeafType : GraphQLNamedType { +public protocol GraphQLLeafType: GraphQLNamedType { func serialize(value: Any) throws -> Map func parseValue(value: Map) throws -> Map func parseLiteral(valueAST: Value) throws -> Map } -extension GraphQLScalarType : GraphQLLeafType {} -extension GraphQLEnumType : GraphQLLeafType {} +extension GraphQLScalarType: GraphQLLeafType {} +extension GraphQLEnumType: GraphQLLeafType {} func isLeafType(type: GraphQLType?) -> Bool { let namedType = getNamedType(type: type) return namedType is GraphQLScalarType || - namedType is GraphQLEnumType + namedType is GraphQLEnumType } /** * 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 {} +public protocol GraphQLCompositeType: GraphQLNamedType, GraphQLOutputType {} +extension GraphQLObjectType: GraphQLCompositeType {} +extension GraphQLInterfaceType: GraphQLCompositeType {} +extension GraphQLUnionType: GraphQLCompositeType {} -protocol GraphQLTypeReferenceContainer : GraphQLNamedType { +protocol GraphQLTypeReferenceContainer: GraphQLNamedType { func replaceTypeReferences(typeMap: TypeMap) throws } -extension GraphQLObjectType : GraphQLTypeReferenceContainer {} -extension GraphQLInterfaceType : GraphQLTypeReferenceContainer {} -extension GraphQLInputObjectType : GraphQLTypeReferenceContainer {} +extension GraphQLObjectType: GraphQLTypeReferenceContainer {} +extension GraphQLInterfaceType: GraphQLTypeReferenceContainer {} +extension GraphQLInputObjectType: GraphQLTypeReferenceContainer {} /** * These types may describe the parent context of a selection set. */ -public protocol GraphQLAbstractType : GraphQLNamedType { +public protocol GraphQLAbstractType: GraphQLNamedType { var resolveType: GraphQLTypeResolve? { get } } -extension GraphQLInterfaceType : GraphQLAbstractType {} -extension GraphQLUnionType : GraphQLAbstractType {} +extension GraphQLInterfaceType: GraphQLAbstractType {} +extension GraphQLUnionType: GraphQLAbstractType {} /** * These types can all accept null as a value. */ -public protocol GraphQLNullableType : GraphQLType {} -extension GraphQLScalarType : GraphQLNullableType {} -extension GraphQLObjectType : GraphQLNullableType {} -extension GraphQLInterfaceType : GraphQLNullableType {} -extension GraphQLUnionType : GraphQLNullableType {} -extension GraphQLEnumType : GraphQLNullableType {} -extension GraphQLInputObjectType : GraphQLNullableType {} -extension GraphQLList : GraphQLNullableType {} +public protocol GraphQLNullableType: GraphQLType {} +extension GraphQLScalarType: GraphQLNullableType {} +extension GraphQLObjectType: GraphQLNullableType {} +extension GraphQLInterfaceType: GraphQLNullableType {} +extension GraphQLUnionType: GraphQLNullableType {} +extension GraphQLEnumType: GraphQLNullableType {} +extension GraphQLInputObjectType: GraphQLNullableType {} +extension GraphQLList: GraphQLNullableType {} func getNullableType(type: GraphQLType?) -> GraphQLNullableType? { if let type = type as? GraphQLNonNull { @@ -114,16 +114,16 @@ func getNullableType(type: GraphQLType?) -> GraphQLNullableType? { /** * These named types do not include modifiers like List or NonNull. */ -public protocol GraphQLNamedType : GraphQLNullableType { +public protocol GraphQLNamedType: GraphQLNullableType { var name: String { get } } -extension GraphQLScalarType : GraphQLNamedType {} -extension GraphQLObjectType : GraphQLNamedType {} -extension GraphQLInterfaceType : GraphQLNamedType {} -extension GraphQLUnionType : GraphQLNamedType {} -extension GraphQLEnumType : GraphQLNamedType {} -extension GraphQLInputObjectType : GraphQLNamedType {} +extension GraphQLScalarType: GraphQLNamedType {} +extension GraphQLObjectType: GraphQLNamedType {} +extension GraphQLInterfaceType: GraphQLNamedType {} +extension GraphQLUnionType: GraphQLNamedType {} +extension GraphQLEnumType: GraphQLNamedType {} +extension GraphQLInputObjectType: GraphQLNamedType {} public func getNamedType(type: GraphQLType?) -> GraphQLNamedType? { var unmodifiedType = type @@ -138,12 +138,12 @@ public func getNamedType(type: GraphQLType?) -> GraphQLNamedType? { /** * These types wrap other types. */ -protocol GraphQLWrapperType : GraphQLType { +protocol GraphQLWrapperType: GraphQLType { var wrappedType: GraphQLType { get } } -extension GraphQLList : GraphQLWrapperType {} -extension GraphQLNonNull : GraphQLWrapperType {} +extension GraphQLList: GraphQLWrapperType {} +extension GraphQLNonNull: GraphQLWrapperType {} /** * Scalar Type Definition @@ -166,7 +166,7 @@ public final class GraphQLScalarType { public let name: String public let description: String? public let kind: TypeKind = .scalar - + let serialize: (Any) throws -> Map let parseValue: ((Map) throws -> Map)? let parseLiteral: ((Value) throws -> Map)? @@ -180,8 +180,8 @@ public final class GraphQLScalarType { self.name = name self.description = description self.serialize = serialize - self.parseValue = nil - self.parseLiteral = nil + parseValue = nil + parseLiteral = nil } public init( @@ -201,50 +201,50 @@ public final class GraphQLScalarType { // Serializes an internal value to include in a response. public func serialize(value: Any) throws -> Map { - return try self.serialize(value) + return try serialize(value) } // Parses an externally provided value to use as an input. public func parseValue(value: Map) throws -> Map { - return try self.parseValue?(value) ?? Map.null + return try parseValue?(value) ?? Map.null } // Parses an externally provided literal value to use as an input. public func parseLiteral(valueAST: Value) throws -> Map { - return try self.parseLiteral?(valueAST) ?? Map.null + return try parseLiteral?(valueAST) ?? Map.null } } -extension GraphQLScalarType : Encodable { - private enum CodingKeys : String, CodingKey { +extension GraphQLScalarType: Encodable { + private enum CodingKeys: String, CodingKey { case name case description case kind } } -extension GraphQLScalarType : KeySubscriptable { +extension GraphQLScalarType: KeySubscriptable { public subscript(key: String) -> Any? { switch key { case CodingKeys.name.rawValue: - return self.name + return name case CodingKeys.description.rawValue: - return self.description + return description case CodingKeys.kind.rawValue: - return self.kind + return kind default: return nil } } } -extension GraphQLScalarType : CustomDebugStringConvertible { +extension GraphQLScalarType: CustomDebugStringConvertible { public var debugDescription: String { return name } } -extension GraphQLScalarType : Hashable { +extension GraphQLScalarType: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } @@ -301,7 +301,7 @@ public final class GraphQLObjectType { public let interfaces: [GraphQLInterfaceType] public let isTypeOf: GraphQLIsTypeOf? public let kind: TypeKind = .object - + public init( name: String, description: String? = nil, @@ -331,8 +331,8 @@ public final class GraphQLObjectType { } } -extension GraphQLObjectType : Encodable { - private enum CodingKeys : String, CodingKey { +extension GraphQLObjectType: Encodable { + private enum CodingKeys: String, CodingKey { case name case description case fields @@ -341,32 +341,32 @@ extension GraphQLObjectType : Encodable { } } -extension GraphQLObjectType : KeySubscriptable { +extension GraphQLObjectType: KeySubscriptable { public subscript(key: String) -> Any? { switch key { case CodingKeys.name.rawValue: - return self.name + return name case CodingKeys.description.rawValue: - return self.description + return description case CodingKeys.fields.rawValue: - return self.fields + return fields case CodingKeys.interfaces.rawValue: - return self.interfaces + return interfaces case CodingKeys.kind.rawValue: - return self.kind.rawValue + return kind.rawValue default: return nil } } } -extension GraphQLObjectType : CustomDebugStringConvertible { +extension GraphQLObjectType: CustomDebugStringConvertible { public var debugDescription: String { return name } } -extension GraphQLObjectType : Hashable { +extension GraphQLObjectType: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } @@ -381,7 +381,7 @@ func defineFieldMap(name: String, fields: GraphQLFieldMap) throws -> GraphQLFiel throw GraphQLError( message: "\(name) fields must be an object with field names as " + - "keys or a function which returns such an object." + "keys or a function which returns such an object." ) } @@ -438,9 +438,9 @@ func defineInterfaces( throw GraphQLError( message: "Interface Type \(interface.name) does not provide a \"resolveType\" " + - "function and implementing Type \(name) does not provide a " + - "\"isTypeOf\" function. There is no way to resolve this implementing " + - "type during execution." + "function and implementing Type \(name) does not provide a " + + "\"isTypeOf\" function. There is no way to resolve this implementing " + + "type during execution." ) } } @@ -453,13 +453,13 @@ public protocol TypeResolveResultRepresentable { var typeResolveResult: TypeResolveResult { get } } -extension GraphQLObjectType : TypeResolveResultRepresentable { +extension GraphQLObjectType: TypeResolveResultRepresentable { public var typeResolveResult: TypeResolveResult { return .type(self) } } -extension String : TypeResolveResultRepresentable { +extension String: TypeResolveResultRepresentable { public var typeResolveResult: TypeResolveResult { return .name(self) } @@ -519,7 +519,7 @@ public struct GraphQLField { public let description: String? public let resolve: GraphQLFieldResolve? public let subscribe: GraphQLFieldResolve? - + public init( type: GraphQLOutputType, description: String? = nil, @@ -530,10 +530,10 @@ public struct GraphQLField { self.args = args self.deprecationReason = deprecationReason self.description = description - self.resolve = nil - self.subscribe = nil + resolve = nil + subscribe = nil } - + public init( type: GraphQLOutputType, description: String? = nil, @@ -549,7 +549,7 @@ public struct GraphQLField { self.resolve = resolve self.subscribe = subscribe } - + public init( type: GraphQLOutputType, description: String? = nil, @@ -561,12 +561,12 @@ public struct GraphQLField { self.args = args self.deprecationReason = deprecationReason self.description = description - + self.resolve = { source, args, context, eventLoopGroup, info in let result = try resolve(source, args, context, info) return eventLoopGroup.next().makeSucceededFuture(result) } - self.subscribe = nil + subscribe = nil } } @@ -598,7 +598,7 @@ public final class GraphQLFieldDefinition { self.resolve = resolve self.subscribe = subscribe self.deprecationReason = deprecationReason - self.isDeprecated = deprecationReason != nil + isDeprecated = deprecationReason != nil } func replaceTypeReferences(typeMap: TypeMap) throws { @@ -610,12 +610,12 @@ public final class GraphQLFieldDefinition { ) } - self.type = outputType + type = outputType } } -extension GraphQLFieldDefinition : Encodable { - private enum CodingKeys : String, CodingKey { +extension GraphQLFieldDefinition: Encodable { + private enum CodingKeys: String, CodingKey { case name case description case type @@ -623,33 +623,33 @@ extension GraphQLFieldDefinition : Encodable { case deprecationReason case isDeprecated } - + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(self.name, forKey: .name) - try container.encode(self.description, forKey: .description) - try container.encode(AnyEncodable(self.type), forKey: .type) - try container.encode(self.args, forKey: .args) - try container.encode(self.deprecationReason, forKey: .deprecationReason) - try container.encode(self.isDeprecated, forKey: .isDeprecated) + try container.encode(name, forKey: .name) + try container.encode(description, forKey: .description) + try container.encode(AnyEncodable(type), forKey: .type) + try container.encode(args, forKey: .args) + try container.encode(deprecationReason, forKey: .deprecationReason) + try container.encode(isDeprecated, forKey: .isDeprecated) } } -extension GraphQLFieldDefinition : KeySubscriptable { +extension GraphQLFieldDefinition: KeySubscriptable { public subscript(key: String) -> Any? { switch key { case CodingKeys.name.rawValue: - return self.name + return name case CodingKeys.description.rawValue: - return self.description + return description case CodingKeys.type.rawValue: - return self.type + return type case CodingKeys.args.rawValue: - return self.args + return args case CodingKeys.deprecationReason.rawValue: - return self.deprecationReason + return deprecationReason case CodingKeys.isDeprecated.rawValue: - return self.isDeprecated + return isDeprecated default: return nil } @@ -697,34 +697,34 @@ public func isRequiredArgument(_ arg: GraphQLArgumentDefinition) -> Bool { return arg.type is GraphQLNonNull && arg.defaultValue == nil } -extension GraphQLArgumentDefinition : Encodable { - private enum CodingKeys : String, CodingKey { +extension GraphQLArgumentDefinition: Encodable { + private enum CodingKeys: String, CodingKey { case name case description case type case defaultValue } - + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(self.name, forKey: .name) - try container.encode(self.description, forKey: .description) - try container.encode(AnyEncodable(self.type), forKey: .type) - try container.encode(self.defaultValue, forKey: .defaultValue) + try container.encode(name, forKey: .name) + try container.encode(description, forKey: .description) + try container.encode(AnyEncodable(type), forKey: .type) + try container.encode(defaultValue, forKey: .defaultValue) } } -extension GraphQLArgumentDefinition : KeySubscriptable { +extension GraphQLArgumentDefinition: KeySubscriptable { public subscript(key: String) -> Any? { switch key { case CodingKeys.name.rawValue: - return self.name + return name case CodingKeys.description.rawValue: - return self.description + return description case CodingKeys.type.rawValue: - return self.type + return type case CodingKeys.defaultValue.rawValue: - return self.defaultValue + return defaultValue default: return nil } @@ -767,12 +767,12 @@ public final class GraphQLInterfaceType { try assertValid(name: name) self.name = name self.description = description - + self.fields = try defineFieldMap( name: name, fields: fields ) - + self.interfaces = interfaces self.resolveType = resolveType } @@ -784,8 +784,8 @@ public final class GraphQLInterfaceType { } } -extension GraphQLInterfaceType : Encodable { - private enum CodingKeys : String, CodingKey { +extension GraphQLInterfaceType: Encodable { + private enum CodingKeys: String, CodingKey { case name case description case fields @@ -793,30 +793,30 @@ extension GraphQLInterfaceType : Encodable { } } -extension GraphQLInterfaceType : KeySubscriptable { +extension GraphQLInterfaceType: KeySubscriptable { public subscript(key: String) -> Any? { switch key { case CodingKeys.name.rawValue: - return self.name + return name case CodingKeys.description.rawValue: - return self.description + return description case CodingKeys.fields.rawValue: - return self.fields + return fields case CodingKeys.kind.rawValue: - return self.kind + return kind default: return nil } } } -extension GraphQLInterfaceType : CustomDebugStringConvertible { +extension GraphQLInterfaceType: CustomDebugStringConvertible { public var debugDescription: String { return name } } -extension GraphQLInterfaceType : Hashable { +extension GraphQLInterfaceType: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } @@ -869,19 +869,19 @@ public final class GraphQLUnionType { self.name = name self.description = description self.resolveType = resolveType - + self.types = try defineTypes( name: name, hasResolve: resolveType != nil, types: types ) - - self.possibleTypeNames = [:] + + possibleTypeNames = [:] } } -extension GraphQLUnionType : Encodable { - private enum CodingKeys : String, CodingKey { +extension GraphQLUnionType: Encodable { + private enum CodingKeys: String, CodingKey { case name case description case types @@ -889,30 +889,30 @@ extension GraphQLUnionType : Encodable { } } -extension GraphQLUnionType : KeySubscriptable { +extension GraphQLUnionType: KeySubscriptable { public subscript(key: String) -> Any? { switch key { case CodingKeys.name.rawValue: - return self.name + return name case CodingKeys.description.rawValue: - return self.description + return description case CodingKeys.types.rawValue: - return self.types + return types case CodingKeys.kind.rawValue: - return self.kind + return kind default: return nil } } } -extension GraphQLUnionType : CustomDebugStringConvertible { +extension GraphQLUnionType: CustomDebugStringConvertible { public var debugDescription: String { return name } } -extension GraphQLUnionType : Hashable { +extension GraphQLUnionType: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } @@ -931,7 +931,7 @@ func defineTypes( throw GraphQLError( message: "Must provide Array of types or a function which returns " + - "such an array for Union \(name)." + "such an array for Union \(name)." ) } @@ -941,9 +941,9 @@ func defineTypes( throw GraphQLError( message: "Union type \"\(name)\" does not provide a \"resolveType\" " + - "function and possible type \"\(type.name)\" does not provide an " + - "\"isTypeOf\" function. There is no way to resolve this possible type " + - "during execution." + "function and possible type \"\(type.name)\" does not provide an " + + "\"isTypeOf\" function. There is no way to resolve this possible type " + + "during execution." ) } } @@ -1012,11 +1012,11 @@ public final class GraphQLEnumType { } public func serialize(value: Any) throws -> Map { - return try valueLookup[map(from: value)].map({ .string($0.name) }) ?? .null + return try valueLookup[map(from: value)].map { .string($0.name) } ?? .null } public func parseValue(value: Map) throws -> Map { - if case .string(let value) = value { + if case let .string(value) = value { return nameLookup[value]?.value ?? .null } @@ -1032,8 +1032,8 @@ public final class GraphQLEnumType { } } -extension GraphQLEnumType : Encodable { - private enum CodingKeys : String, CodingKey { +extension GraphQLEnumType: Encodable { + private enum CodingKeys: String, CodingKey { case name case description case values @@ -1041,30 +1041,30 @@ extension GraphQLEnumType : Encodable { } } -extension GraphQLEnumType : KeySubscriptable { +extension GraphQLEnumType: KeySubscriptable { public subscript(key: String) -> Any? { switch key { case CodingKeys.name.rawValue: - return self.name + return name case CodingKeys.description.rawValue: - return self.description + return description case CodingKeys.values.rawValue: - return self.values + return values case CodingKeys.kind.rawValue: - return self.kind + return kind default: return nil } } } -extension GraphQLEnumType : CustomDebugStringConvertible { +extension GraphQLEnumType: CustomDebugStringConvertible { public var debugDescription: String { return name } } -extension GraphQLEnumType : Hashable { +extension GraphQLEnumType: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } @@ -1121,14 +1121,14 @@ public struct GraphQLEnumValue { } } -public struct GraphQLEnumValueDefinition : Encodable { - private enum CodingKeys : String, CodingKey { +public struct GraphQLEnumValueDefinition: Encodable { + private enum CodingKeys: String, CodingKey { case name case description case deprecationReason case isDeprecated } - + public let name: String public let description: String? public let deprecationReason: String? @@ -1136,17 +1136,17 @@ public struct GraphQLEnumValueDefinition : Encodable { public let value: Map } -extension GraphQLEnumValueDefinition : KeySubscriptable { +extension GraphQLEnumValueDefinition: KeySubscriptable { public subscript(key: String) -> Any? { switch key { case CodingKeys.name.rawValue: - return self.name + return name case CodingKeys.description.rawValue: - return self.description + return description case CodingKeys.deprecationReason.rawValue: - return self.deprecationReason + return deprecationReason case CodingKeys.isDeprecated.rawValue: - return self.isDeprecated + return isDeprecated default: return nil } @@ -1192,7 +1192,7 @@ public final class GraphQLInputObjectType { fields: fields ) } - + func replaceTypeReferences(typeMap: TypeMap) throws { for field in fields { try field.value.replaceTypeReferences(typeMap: typeMap) @@ -1200,8 +1200,8 @@ public final class GraphQLInputObjectType { } } -extension GraphQLInputObjectType : Encodable { - private enum CodingKeys : String, CodingKey { +extension GraphQLInputObjectType: Encodable { + private enum CodingKeys: String, CodingKey { case name case description case fields @@ -1209,30 +1209,30 @@ extension GraphQLInputObjectType : Encodable { } } -extension GraphQLInputObjectType : KeySubscriptable { +extension GraphQLInputObjectType: KeySubscriptable { public subscript(key: String) -> Any? { switch key { case CodingKeys.name.rawValue: - return self.name + return name case CodingKeys.description.rawValue: - return self.description + return description case CodingKeys.fields.rawValue: - return self.fields + return fields case CodingKeys.kind.rawValue: - return self.kind + return kind default: return nil } } } -extension GraphQLInputObjectType : CustomDebugStringConvertible { +extension GraphQLInputObjectType: CustomDebugStringConvertible { public var debugDescription: String { return name } } -extension GraphQLInputObjectType : Hashable { +extension GraphQLInputObjectType: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } @@ -1250,7 +1250,7 @@ func defineInputObjectFieldMap( throw GraphQLError( message: "\(name) fields must be an object with field names as " + - "keys or a function which returns such an object." + "keys or a function which returns such an object." ) } @@ -1276,7 +1276,7 @@ public struct InputObjectField { public let type: GraphQLInputType public let defaultValue: Map? public let description: String? - + public init(type: GraphQLInputType, defaultValue: Map? = nil, description: String? = nil) { self.type = type self.defaultValue = defaultValue @@ -1291,7 +1291,7 @@ public final class InputObjectFieldDefinition { public internal(set) var type: GraphQLInputType public let description: String? public let defaultValue: Map? - + init( name: String, type: GraphQLInputType, @@ -1303,7 +1303,7 @@ public final class InputObjectFieldDefinition { self.description = description self.defaultValue = defaultValue } - + func replaceTypeReferences(typeMap: TypeMap) throws { let resolvedType = try resolveTypeReference(type: type, typeMap: typeMap) @@ -1313,38 +1313,38 @@ public final class InputObjectFieldDefinition { ) } - self.type = inputType + type = inputType } } -extension InputObjectFieldDefinition : Encodable { - private enum CodingKeys : String, CodingKey { +extension InputObjectFieldDefinition: Encodable { + private enum CodingKeys: String, CodingKey { case name case description case type case defaultValue } - + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(self.name, forKey: .name) - try container.encode(self.description, forKey: .description) - try container.encode(AnyEncodable(self.type), forKey: .type) - try container.encode(self.defaultValue, forKey: .defaultValue) + try container.encode(name, forKey: .name) + try container.encode(description, forKey: .description) + try container.encode(AnyEncodable(type), forKey: .type) + try container.encode(defaultValue, forKey: .defaultValue) } } -extension InputObjectFieldDefinition : KeySubscriptable { +extension InputObjectFieldDefinition: KeySubscriptable { public subscript(key: String) -> Any? { switch key { case CodingKeys.name.rawValue: - return self.name + return name case CodingKeys.description.rawValue: - return self.description + return description case CodingKeys.type.rawValue: - return self.type + return type case CodingKeys.defaultValue.rawValue: - return self.defaultValue + return defaultValue default: return nil } @@ -1376,11 +1376,11 @@ public final class GraphQLList { public let kind: TypeKind = .list public init(_ type: GraphQLType) { - self.ofType = type + ofType = type } public init(_ name: String) { - self.ofType = GraphQLTypeReference(name) + ofType = GraphQLTypeReference(name) } var wrappedType: GraphQLType { @@ -1393,39 +1393,39 @@ public final class GraphQLList { } } -extension GraphQLList : Encodable { - private enum CodingKeys : String, CodingKey { +extension GraphQLList: Encodable { + private enum CodingKeys: String, CodingKey { case ofType case kind } - + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(AnyEncodable(self.ofType), forKey: .ofType) - try container.encode(self.kind, forKey: .kind) + try container.encode(AnyEncodable(ofType), forKey: .ofType) + try container.encode(kind, forKey: .kind) } } -extension GraphQLList : KeySubscriptable { +extension GraphQLList: KeySubscriptable { public subscript(key: String) -> Any? { switch key { case CodingKeys.ofType.rawValue: - return self.ofType + return ofType case CodingKeys.kind.rawValue: - return self.kind + return kind default: return nil } } } -extension GraphQLList : CustomDebugStringConvertible { +extension GraphQLList: CustomDebugStringConvertible { public var debugDescription: String { return "[" + ofType.debugDescription + "]" } } -extension GraphQLList : Hashable { +extension GraphQLList: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } @@ -1460,11 +1460,11 @@ public final class GraphQLNonNull { public let kind: TypeKind = .nonNull public init(_ type: GraphQLNullableType) { - self.ofType = type + ofType = type } public init(_ name: String) { - self.ofType = GraphQLTypeReference(name) + ofType = GraphQLTypeReference(name) } var wrappedType: GraphQLType { @@ -1484,39 +1484,39 @@ public final class GraphQLNonNull { } } -extension GraphQLNonNull : Encodable { - private enum CodingKeys : String, CodingKey { +extension GraphQLNonNull: Encodable { + private enum CodingKeys: String, CodingKey { case ofType case kind } - + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(AnyEncodable(self.ofType), forKey: .ofType) - try container.encode(self.kind, forKey: .kind) + try container.encode(AnyEncodable(ofType), forKey: .ofType) + try container.encode(kind, forKey: .kind) } } -extension GraphQLNonNull : KeySubscriptable { +extension GraphQLNonNull: KeySubscriptable { public subscript(key: String) -> Any? { switch key { case CodingKeys.ofType.rawValue: - return self.ofType + return ofType case CodingKeys.kind.rawValue: - return self.kind + return kind default: return nil } } } -extension GraphQLNonNull : CustomDebugStringConvertible { +extension GraphQLNonNull: CustomDebugStringConvertible { public var debugDescription: String { return ofType.debugDescription + "!" } } -extension GraphQLNonNull : Hashable { +extension GraphQLNonNull: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } @@ -1530,7 +1530,9 @@ extension GraphQLNonNull : Hashable { * A special type to allow object/interface/input types to reference itself. It's replaced with the real type * object when the schema is built. */ -public final class GraphQLTypeReference : GraphQLType, GraphQLOutputType, GraphQLInputType, GraphQLNullableType, GraphQLNamedType { +public final class GraphQLTypeReference: GraphQLType, GraphQLOutputType, GraphQLInputType, + GraphQLNullableType, GraphQLNamedType +{ public let name: String public let kind: TypeKind = .typeReference @@ -1539,24 +1541,24 @@ public final class GraphQLTypeReference : GraphQLType, GraphQLOutputType, GraphQ } } -extension GraphQLTypeReference : Encodable { - private enum CodingKeys : String, CodingKey { +extension GraphQLTypeReference: Encodable { + private enum CodingKeys: String, CodingKey { case name } } -extension GraphQLTypeReference : KeySubscriptable { - public subscript(key: String) -> Any? { +extension GraphQLTypeReference: KeySubscriptable { + public subscript(_: String) -> Any? { switch name { case CodingKeys.name.rawValue: - return self.name + return name default: return nil } } } -extension GraphQLTypeReference : CustomDebugStringConvertible { +extension GraphQLTypeReference: CustomDebugStringConvertible { public var debugDescription: String { return name } diff --git a/Sources/GraphQL/Type/Directives.swift b/Sources/GraphQL/Type/Directives.swift index ef6e5722..f9518acf 100644 --- a/Sources/GraphQL/Type/Directives.swift +++ b/Sources/GraphQL/Type/Directives.swift @@ -1,4 +1,4 @@ -public enum DirectiveLocation : String, Encodable { +public enum DirectiveLocation: String, Encodable { // Operations case query = "QUERY" case mutation = "MUTATION" @@ -25,7 +25,7 @@ public enum DirectiveLocation : String, Encodable { * Directives are used by the GraphQL runtime as a way of modifying execution * behavior. Type system creators will usually not create these directly. */ -public struct GraphQLDirective : Encodable { +public struct GraphQLDirective: Encodable { public let name: String public let description: String public let locations: [DirectiveLocation] @@ -52,7 +52,7 @@ public let GraphQLIncludeDirective = try! GraphQLDirective( name: "include", description: "Directs the executor to include this field or fragment only when " + - "the `if` argument is true.", + "the `if` argument is true.", locations: [ .field, .fragmentSpread, @@ -62,7 +62,7 @@ public let GraphQLIncludeDirective = try! GraphQLDirective( "if": GraphQLArgument( type: GraphQLNonNull(GraphQLBoolean), description: "Included when true." - ) + ), ] ) @@ -73,7 +73,7 @@ public let GraphQLSkipDirective = try! GraphQLDirective( name: "skip", description: "Directs the executor to skip this field or fragment when the `if` " + - "argument is true.", + "argument is true.", locations: [ .field, .fragmentSpread, @@ -83,7 +83,7 @@ public let GraphQLSkipDirective = try! GraphQLDirective( "if": GraphQLArgument( type: GraphQLNonNull(GraphQLBoolean), description: "Skipped when true." - ) + ), ] ) @@ -102,16 +102,16 @@ public let GraphQLDeprecatedDirective = try! GraphQLDirective( locations: [ .fieldDefinition, .enumValue, - ], + ], args: [ "reason": GraphQLArgument( type: GraphQLString, description: "Explains why this element was deprecated, usually also including a " + - "suggestion for how to access supported similar data. Formatted " + - "in [Markdown](https://daringfireball.net/projects/markdown/).", + "suggestion for how to access supported similar data. Formatted " + + "in [Markdown](https://daringfireball.net/projects/markdown/).", defaultValue: defaulDeprecationReason - ) + ), ] ) diff --git a/Sources/GraphQL/Type/Introspection.swift b/Sources/GraphQL/Type/Introspection.swift index 1ccb4e97..974c17f7 100644 --- a/Sources/GraphQL/Type/Introspection.swift +++ b/Sources/GraphQL/Type/Introspection.swift @@ -4,8 +4,8 @@ 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.", + "exposes all available types and directives on the server, as well as " + + "the entry points for query, mutation, and subscription operations.", fields: [ "types": GraphQLField( type: GraphQLNonNull(GraphQLList(GraphQLNonNull(__Type))), @@ -34,7 +34,7 @@ let __Schema = try! GraphQLObjectType( type: __Type, description: "If this server supports mutation, the type that " + - "mutation operations will be rooted at.", + "mutation operations will be rooted at.", resolve: { schema, _, _, _ -> GraphQLObjectType? in guard let schema = schema as? GraphQLSchema else { return nil @@ -47,7 +47,7 @@ let __Schema = try! GraphQLObjectType( type: __Type, description: "If this server support subscription, the type that " + - "subscription operations will be rooted at.", + "subscription operations will be rooted at.", resolve: { schema, _, _, _ -> GraphQLObjectType? in guard let schema = schema as? GraphQLSchema else { return nil @@ -66,7 +66,7 @@ let __Schema = try! GraphQLObjectType( return schema.directives } - ) + ), ] ) @@ -74,11 +74,11 @@ 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.", + "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), @@ -92,7 +92,7 @@ let __Directive = try! GraphQLObjectType( return directive.args } - ) + ), ] ) @@ -100,7 +100,7 @@ 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.", + "__DirectiveLocation describes one such possible adjacencies.", values: [ "QUERY": GraphQLEnumValue( value: Map(DirectiveLocation.query.rawValue), @@ -181,13 +181,13 @@ let __Type: GraphQLObjectType = 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 and description, 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.", + "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 and description, 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.", fields: [ "kind": GraphQLField( type: GraphQLNonNull(__TypeKind), @@ -222,7 +222,7 @@ let __Type: GraphQLObjectType = try! GraphQLObjectType( "includeDeprecated": GraphQLArgument( type: GraphQLBoolean, defaultValue: false - ) + ), ], resolve: { type, arguments, _, _ -> [GraphQLFieldDefinition]? in if let type = type as? GraphQLObjectType { @@ -230,7 +230,7 @@ let __Type: GraphQLObjectType = try! GraphQLObjectType( var fields = Array(fieldMap.values).sorted(by: { $0.name < $1.name }) if !(arguments["includeDeprecated"].bool ?? false) { - fields = fields.filter({ !$0.isDeprecated }) + fields = fields.filter { !$0.isDeprecated } } return fields @@ -241,7 +241,7 @@ let __Type: GraphQLObjectType = try! GraphQLObjectType( var fields = Array(fieldMap.values).sorted(by: { $0.name < $1.name }) if !(arguments["includeDeprecated"].bool ?? false) { - fields = fields.filter({ !$0.isDeprecated }) + fields = fields.filter { !$0.isDeprecated } } return fields @@ -256,18 +256,17 @@ let __Type: GraphQLObjectType = try! GraphQLObjectType( if let type = type as? GraphQLObjectType { return type.interfaces } - + if let type = type as? GraphQLInterfaceType { return type.interfaces } - + return nil - } ), "possibleTypes": GraphQLField( type: GraphQLList(GraphQLNonNull(GraphQLTypeReference("__Type"))), - resolve: { type, args, _, info -> [GraphQLObjectType]? in + resolve: { type, _, _, info -> [GraphQLObjectType]? in guard let type = type as? GraphQLAbstractType else { return nil } @@ -281,7 +280,7 @@ let __Type: GraphQLObjectType = try! GraphQLObjectType( "includeDeprecated": GraphQLArgument( type: GraphQLBoolean, defaultValue: false - ) + ), ], resolve: { type, arguments, _, _ -> [GraphQLEnumValueDefinition]? in guard let type = type as? GraphQLEnumType else { @@ -291,7 +290,7 @@ let __Type: GraphQLObjectType = try! GraphQLObjectType( var values = type.values if !(arguments["includeDeprecated"].bool ?? false) { - values = values.filter({ !$0.isDeprecated }) + values = values.filter { !$0.isDeprecated } } return values @@ -303,13 +302,13 @@ let __Type: GraphQLObjectType = try! GraphQLObjectType( guard let type = type as? GraphQLInputObjectType else { return nil } - + let fieldMap = type.fields let fields = Array(fieldMap.values).sorted(by: { $0.name < $1.name }) return fields } ), - "ofType": GraphQLField(type: GraphQLTypeReference("__Type")) + "ofType": GraphQLField(type: GraphQLTypeReference("__Type")), ] ) @@ -317,7 +316,7 @@ 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.", + "which has a name, potentially a list of arguments, and a return type.", fields: [ "name": GraphQLField(type: GraphQLNonNull(GraphQLString)), "description": GraphQLField(type: GraphQLString), @@ -333,7 +332,7 @@ let __Field = try! GraphQLObjectType( ), "type": GraphQLField(type: GraphQLNonNull(GraphQLTypeReference("__Type"))), "isDeprecated": GraphQLField(type: GraphQLNonNull(GraphQLBoolean)), - "deprecationReason": GraphQLField(type: GraphQLString) + "deprecationReason": GraphQLField(type: GraphQLString), ] ) @@ -341,8 +340,8 @@ 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.", + "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), @@ -351,7 +350,7 @@ let __InputValue = try! GraphQLObjectType( type: GraphQLString, description: "A GraphQL-formatted string representing the default value for this " + - "input value.", + "input value.", resolve: { inputValue, _, _, _ -> Map? in guard let inputValue = inputValue as? GraphQLArgumentDefinition, @@ -362,7 +361,7 @@ let __InputValue = try! GraphQLObjectType( return .string(defaultValue.description) } - ) + ), ] ) @@ -370,17 +369,17 @@ 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.", + "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), "isDeprecated": GraphQLField(type: GraphQLNonNull(GraphQLBoolean)), - "deprecationReason": GraphQLField(type: GraphQLString) + "deprecationReason": GraphQLField(type: GraphQLString), ] ) -public enum TypeKind : String, Encodable { +public enum TypeKind: String, Encodable { case scalar = "SCALAR" case object = "OBJECT" case interface = "INTERFACE" @@ -403,37 +402,37 @@ let __TypeKind = try! GraphQLEnumType( "OBJECT": GraphQLEnumValue( value: Map(TypeKind.object.rawValue), description: "Indicates this type is an object. " + - "`fields` and `interfaces` are valid fields." + "`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." + "`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." + "`possibleTypes` is a valid field." ), "ENUM": GraphQLEnumValue( value: Map(TypeKind.enum.rawValue), description: "Indicates this type is an enum. " + - "`enumValues` is a valid field." + "`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." + "`inputFields` is a valid field." ), "LIST": GraphQLEnumValue( value: Map(TypeKind.list.rawValue), description: "Indicates this type is a list. " + - "`ofType` is a valid field." + "`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." + "`ofType` is a valid field." ), ] ) @@ -448,7 +447,7 @@ let SchemaMetaFieldDef = GraphQLFieldDefinition( type: GraphQLNonNull(__Schema), description: "Access the current type schema of this server.", resolve: { _, _, _, eventLoopGroup, info in - return eventLoopGroup.next().makeSucceededFuture(info.schema) + eventLoopGroup.next().makeSucceededFuture(info.schema) } ) @@ -460,7 +459,7 @@ let TypeMetaFieldDef = GraphQLFieldDefinition( GraphQLArgumentDefinition( name: "name", type: GraphQLNonNull(GraphQLString) - ) + ), ], resolve: { _, arguments, _, eventLoopGroup, info in let name = arguments["name"].string! diff --git a/Sources/GraphQL/Type/Scalars.swift b/Sources/GraphQL/Type/Scalars.swift index c04c9baa..256f94d1 100644 --- a/Sources/GraphQL/Type/Scalars.swift +++ b/Sources/GraphQL/Type/Scalars.swift @@ -2,14 +2,14 @@ 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.", - serialize: { try map(from: $0) } , + "values. Int can represent values between -(2^31) and 2^31 - 1.", + serialize: { try map(from: $0) }, parseValue: { try .int($0.intValue(converting: true)) }, parseLiteral: { ast in if let ast = ast as? IntValue, let int = Int(ast.value) { return .int(int) } - + return .null } ) @@ -18,9 +18,9 @@ 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). ", - serialize: { try map(from: $0) } , + "values as specified by " + + "[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", + serialize: { try map(from: $0) }, parseValue: { try .double($0.doubleValue(converting: true)) }, parseLiteral: { ast in if let ast = ast as? FloatValue, let double = Double(ast.value) { @@ -39,9 +39,9 @@ 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.", - serialize: { try map(from: $0) } , + "character sequences. The String type is most often used by GraphQL to " + + "represent free-form human-readable text.", + serialize: { try map(from: $0) }, parseValue: { try .string($0.stringValue(converting: true)) }, parseLiteral: { ast in if let ast = ast as? StringValue { @@ -55,7 +55,7 @@ public let GraphQLString = try! GraphQLScalarType( public let GraphQLBoolean = try! GraphQLScalarType( name: "Boolean", description: "The `Boolean` scalar type represents `true` or `false`.", - serialize: { try map(from: $0) } , + serialize: { try map(from: $0) }, parseValue: { try .bool($0.boolValue(converting: true)) }, parseLiteral: { ast in if let ast = ast as? BooleanValue { @@ -70,10 +70,10 @@ 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.", + "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: { try map(from: $0) }, parseValue: { try .string($0.stringValue(converting: true)) }, parseLiteral: { ast in diff --git a/Sources/GraphQL/Type/Schema.swift b/Sources/GraphQL/Type/Schema.swift index 71a6ea94..55d2ad82 100644 --- a/Sources/GraphQL/Type/Schema.swift +++ b/Sources/GraphQL/Type/Schema.swift @@ -41,9 +41,9 @@ public final class GraphQLSchema { types: [GraphQLNamedType] = [], directives: [GraphQLDirective] = [] ) throws { - self.queryType = query - self.mutationType = mutation - self.subscriptionType = subscription + queryType = query + mutationType = mutation + subscriptionType = subscription // Provide specified directives (e.g. @include and @skip) by default. self.directives = directives.isEmpty ? specifiedDirectives : directives @@ -77,7 +77,7 @@ public final class GraphQLSchema { try replaceTypeReferences(typeMap: typeMap) // Keep track of all implementations by interface name. - self.implementations = collectImplementations(types: Array(typeMap.values)) + implementations = collectImplementations(types: Array(typeMap.values)) // Enforce correct interface implementations. for (_, type) in typeMap { @@ -97,20 +97,22 @@ public final class GraphQLSchema { if let unionType = abstractType as? GraphQLUnionType { return unionType.types } - + if let interfaceType = abstractType as? GraphQLInterfaceType { return getImplementations(interfaceType: interfaceType).objects } - - fatalError("Should be impossible. Only UnionType and InterfaceType should conform to AbstractType") + + fatalError( + "Should be impossible. Only UnionType and InterfaceType should conform to AbstractType" + ) } - + public func getImplementations( interfaceType: GraphQLInterfaceType ) -> InterfaceImplementations { guard let matchingImplementations = implementations[interfaceType.name] else { // If we ask for an interface that hasn't been defined, just return no types. - return InterfaceImplementations.init() + return InterfaceImplementations() } return matchingImplementations } @@ -122,10 +124,10 @@ public final class GraphQLSchema { ) throws -> Bool { isSubType(abstractType: abstractType, maybeSubType: possibleType) } - + public func isSubType( - abstractType: GraphQLAbstractType, - maybeSubType: GraphQLNamedType + abstractType: GraphQLAbstractType, + maybeSubType: GraphQLNamedType ) -> Bool { var map = subTypeMap[abstractType.name] @@ -137,19 +139,19 @@ public final class GraphQLSchema { map?[type.name] = true } } - + if let interfaceType = abstractType as? GraphQLInterfaceType { let implementations = getImplementations(interfaceType: interfaceType) - + for type in implementations.objects { map?[type.name] = true } - + for type in implementations.interfaces { map?[type.name] = true } } - + subTypeMap[abstractType.name] = map } @@ -161,13 +163,13 @@ public final class GraphQLSchema { for directive in directives where directive.name == name { return directive } - + return nil } } -extension GraphQLSchema : Encodable { - private enum CodingKeys : String, CodingKey { +extension GraphQLSchema: Encodable { + private enum CodingKeys: String, CodingKey { case queryType case mutationType case subscriptionType @@ -180,7 +182,7 @@ public typealias TypeMap = [String: GraphQLNamedType] public struct InterfaceImplementations { public let objects: [GraphQLObjectType] public let interfaces: [GraphQLInterfaceType] - + public init( objects: [GraphQLObjectType] = [], interfaces: [GraphQLInterfaceType] = [] @@ -191,8 +193,8 @@ public struct InterfaceImplementations { } func collectImplementations( - types: [GraphQLNamedType] -) -> [String : InterfaceImplementations] { + types: [GraphQLNamedType] +) -> [String: InterfaceImplementations] { var implementations: [String: InterfaceImplementations] = [:] for type in types { @@ -208,7 +210,7 @@ func collectImplementations( ) } } - + if let type = type as? GraphQLObjectType { // Store implementations by objects. for iface in type.interfaces { @@ -238,7 +240,7 @@ func typeMapReducer(typeMap: TypeMap, type: GraphQLType) throws -> TypeMap { throw GraphQLError( message: "Schema must contain unique named types but contains multiple " + - "types named \"\(type.name)\"." + "types named \"\(type.name)\"." ) } @@ -255,9 +257,8 @@ func typeMapReducer(typeMap: TypeMap, type: GraphQLType) throws -> TypeMap { typeMap = try type.interfaces.reduce(typeMap, typeMapReducer) for (_, field) in type.fields { - if !field.args.isEmpty { - let fieldArgTypes = field.args.map({ $0.type }) + let fieldArgTypes = field.args.map { $0.type } typeMap = try fieldArgTypes.reduce(typeMap, typeMapReducer) } @@ -267,11 +268,10 @@ func typeMapReducer(typeMap: TypeMap, type: GraphQLType) throws -> TypeMap { if let type = type as? GraphQLInterfaceType { typeMap = try type.interfaces.reduce(typeMap, typeMapReducer) - - for (_, field) in type.fields { + for (_, field) in type.fields { if !field.args.isEmpty { - let fieldArgTypes = field.args.map({ $0.type }) + let fieldArgTypes = field.args.map { $0.type } typeMap = try fieldArgTypes.reduce(typeMap, typeMapReducer) } @@ -284,7 +284,7 @@ func typeMapReducer(typeMap: TypeMap, type: GraphQLType) throws -> TypeMap { typeMap = try typeMapReducer(typeMap: typeMap, type: field.type) } } - + return typeMap } @@ -301,7 +301,7 @@ func assert( throw GraphQLError( message: "\(interface.name) expects field \(fieldName) " + - "but \(object.name) does not provide it." + "but \(object.name) does not provide it." ) } @@ -311,8 +311,8 @@ func assert( throw GraphQLError( message: "\(interface.name).\(fieldName) expects type \"\(interfaceField.type)\" " + - "but " + - "\(object.name).\(fieldName) provides type \"\(objectField.type)\"." + "but " + + "\(object.name).\(fieldName) provides type \"\(objectField.type)\"." ) } @@ -323,7 +323,7 @@ func assert( throw GraphQLError( message: "\(interface.name).\(fieldName) expects argument \"\(argName)\" but " + - "\(object.name).\(fieldName) does not provide it." + "\(object.name).\(fieldName) does not provide it." ) } @@ -333,9 +333,9 @@ func assert( throw GraphQLError( message: "\(interface.name).\(fieldName)(\(argName):) expects type " + - "\"\(interfaceArg.type)\" but " + - "\(object.name).\(fieldName)(\(argName):) provides type " + - "\"\(objectArg.type)\"." + "\"\(interfaceArg.type)\" but " + + "\(object.name).\(fieldName)(\(argName):) provides type " + + "\"\(objectArg.type)\"." ) } } @@ -343,11 +343,14 @@ func assert( // Assert additional arguments must not be required. for objectArg in objectField.args { let argName = objectArg.name - if interfaceField.args.find({ $0.name == argName }) == nil && isRequiredArgument(objectArg) { + if + interfaceField.args.find({ $0.name == argName }) == nil, + isRequiredArgument(objectArg) + { throw GraphQLError( message: "\(object.name).\(fieldName) includes required argument (\(argName):) that is missing " + - "from the Interface field \(interface.name).\(fieldName)." + "from the Interface field \(interface.name).\(fieldName)." ) } } diff --git a/Sources/GraphQL/Utilities/ASTFromValue.swift b/Sources/GraphQL/Utilities/ASTFromValue.swift index 4009d986..92671622 100644 --- a/Sources/GraphQL/Utilities/ASTFromValue.swift +++ b/Sources/GraphQL/Utilities/ASTFromValue.swift @@ -40,7 +40,7 @@ func astFromValue( ) } - if case .array(let value) = value { + if case let .array(value) = value { var valuesASTs: [Value] = [] for item in value { @@ -58,7 +58,7 @@ func astFromValue( // Populate the fields of the input object by creating ASTs from each value // in the JavaScript object according to the fields in the input type. if let type = type as? GraphQLInputObjectType { - guard case .dictionary(let value) = value else { + guard case let .dictionary(value) = value else { return nil } @@ -68,7 +68,12 @@ func astFromValue( for (fieldName, field) in fields { let fieldType = field.type - if let fieldValue = try astFromValue(value: value[fieldName] ?? .null, type: fieldType) { + if + let fieldValue = try astFromValue( + value: value[fieldName] ?? .null, + type: fieldType + ) + { let field = ObjectField(name: Name(value: fieldName), value: fieldValue) fieldASTs.append(field) } @@ -112,16 +117,16 @@ func astFromValue( } // ID types can use Int literals. - if type == GraphQLID && Int(string) != nil { + if type == GraphQLID, Int(string) != nil { return IntValue(value: string) } - + // Use JSON stringify, which uses the same string encoding as GraphQL, // then remove the quotes. - struct Wrapper : Encodable { + struct Wrapper: Encodable { let map: Map } - + let data = try GraphQLJSONEncoder().encode(Wrapper(map: serialized)) guard let string = String(data: data, encoding: .utf8) else { throw GraphQLError( @@ -130,6 +135,6 @@ func astFromValue( } return StringValue(value: String(string.dropFirst(8).dropLast(2))) } - + throw GraphQLError(message: "Cannot convert value to AST: \(serialized)") } diff --git a/Sources/GraphQL/Utilities/AssertValidName.swift b/Sources/GraphQL/Utilities/AssertValidName.swift index a2b75194..6bf3f6ee 100644 --- a/Sources/GraphQL/Utilities/AssertValidName.swift +++ b/Sources/GraphQL/Utilities/AssertValidName.swift @@ -1,21 +1,24 @@ import Foundation -public enum InvalidNameError : Error, CustomStringConvertible { +public enum InvalidNameError: Error, CustomStringConvertible { case invalidName(String) public var description: String { switch self { - case .invalidName(let name): + case let .invalidName(name): return "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \(name) does not." } } } func assertValid(name: String) throws { - let regex = try NSRegularExpression(pattern: "^[_a-zA-Z][_a-zA-Z0-9]*$", options: []) - let range = regex.rangeOfFirstMatch(in: name, options: [], range: NSRange(0.. [String] { guard let wrappedType = nonNullType.ofType as? GraphQLInputType else { throw GraphQLError(message: "Input non-null type must wrap another input type") } - - if value == .null{ + + if value == .null { return ["Expected non-null value, found null."] } if value == .undefined { @@ -19,9 +19,9 @@ func validate(value: Map, forType type: GraphQLInputType) throws -> [String] { return try validate(value: value, forType: wrappedType) } - + // If nullable, either null or undefined are allowed - guard value != .null && value != .undefined else { + guard value != .null, value != .undefined else { return [] } @@ -31,7 +31,7 @@ func validate(value: Map, forType type: GraphQLInputType) throws -> [String] { throw GraphQLError(message: "Input list type must wrap another input type") } - if case .array(let values) = value { + if case let .array(values) = value { var errors: [String] = [] for (index, item) in values.enumerated() { @@ -49,7 +49,7 @@ func validate(value: Map, forType type: GraphQLInputType) throws -> [String] { // Input objects check each defined field. if let objectType = type as? GraphQLInputObjectType { - guard case .dictionary(let dictionary) = value else { + guard case let .dictionary(dictionary) = value else { return ["Expected \"\(objectType.name)\", found not an object."] } @@ -86,9 +86,9 @@ func validate(value: Map, forType type: GraphQLInputType) throws -> [String] { } catch { return ["Expected type \"\(leafType.name)\", found \(value)."] } - + return [] } - + throw GraphQLError(message: "Provided type was not provided") } diff --git a/Sources/GraphQL/Utilities/Keyable.swift b/Sources/GraphQL/Utilities/Keyable.swift index 28f39c69..a7bd7459 100644 --- a/Sources/GraphQL/Utilities/Keyable.swift +++ b/Sources/GraphQL/Utilities/Keyable.swift @@ -1,3 +1,3 @@ public protocol KeySubscriptable { - subscript(key: String) -> Any? { get } + subscript(_: String) -> Any? { get } } diff --git a/Sources/GraphQL/Utilities/NIO+Extensions.swift b/Sources/GraphQL/Utilities/NIO+Extensions.swift index 89da46b1..b8d0fe56 100644 --- a/Sources/GraphQL/Utilities/NIO+Extensions.swift +++ b/Sources/GraphQL/Utilities/NIO+Extensions.swift @@ -11,15 +11,15 @@ import OrderedCollections public typealias Future = EventLoopFuture -extension Collection { - public func flatten(on eventLoopGroup: EventLoopGroup) -> Future<[T]> where Element == Future { +public extension Collection { + func flatten(on eventLoopGroup: EventLoopGroup) -> Future<[T]> where Element == Future { return Future.whenAllSucceed(Array(self), on: eventLoopGroup.next()) } } extension Collection { - internal func flatMap( - to type: T.Type, + func flatMap( + to _: T.Type, on eventLoopGroup: EventLoopGroup, _ callback: @escaping ([S]) throws -> Future ) -> Future where Element == Future { @@ -27,10 +27,10 @@ extension Collection { } } -extension Dictionary where Value : FutureType { +extension Dictionary where Value: FutureType { func flatten(on eventLoopGroup: EventLoopGroup) -> Future<[Key: Value.Expectation]> { // create array of futures with (key,value) tuple - let futures: [Future<(Key, Value.Expectation)>] = self.map { element in + let futures: [Future<(Key, Value.Expectation)>] = map { element in element.value.map(file: #file, line: #line) { (key: element.key, value: $0) } } // when all futures have succeeded convert tuple array back to dictionary @@ -40,32 +40,36 @@ extension Dictionary where Value : FutureType { } } -extension OrderedDictionary where Value : FutureType { - func flatten(on eventLoopGroup: EventLoopGroup) -> Future> { +extension OrderedDictionary where Value: FutureType { + func flatten(on eventLoopGroup: EventLoopGroup) + -> Future> + { let keys = self.keys // create array of futures with (key,value) tuple - let futures: [Future<(Key, Value.Expectation)>] = self.map { element in + let futures: [Future<(Key, Value.Expectation)>] = map { element in element.value.map(file: #file, line: #line) { (key: element.key, value: $0) } } // when all futures have succeeded convert tuple array back to dictionary - return EventLoopFuture.whenAllSucceed(futures, on: eventLoopGroup.next()).map { unorderedResult in - var result: OrderedDictionary = [:] - for key in keys { - // Unwrap is guaranteed because keys are from original dictionary and maps preserve all elements - result[key] = unorderedResult.first(where: { $0.0 == key })!.1 + return EventLoopFuture.whenAllSucceed(futures, on: eventLoopGroup.next()) + .map { unorderedResult in + var result: OrderedDictionary = [:] + for key in keys { + // Unwrap is guaranteed because keys are from original dictionary and maps preserve all elements + result[key] = unorderedResult.first(where: { $0.0 == key })!.1 + } + return result } - return result - } } } + extension Future { - internal func flatMap( - to type: T.Type = T.self, + func flatMap( + to _: T.Type = T.self, _ callback: @escaping (Expectation) throws -> Future ) -> Future { let promise = eventLoop.makePromise(of: T.self) - - self.whenSuccess { expectation in + + whenSuccess { expectation in do { let mapped = try callback(expectation) mapped.cascade(to: promise) @@ -73,11 +77,11 @@ extension Future { promise.fail(error) } } - - self.whenFailure { error in + + whenFailure { error in promise.fail(error) } - + return promise.futureResult } } @@ -86,9 +90,13 @@ public protocol FutureType { associatedtype Expectation func whenSuccess(_ callback: @escaping (Expectation) -> Void) func whenFailure(_ callback: @escaping (Error) -> Void) - func map(file: StaticString, line: UInt, _ callback: @escaping (Expectation) -> (NewValue)) -> EventLoopFuture + func map( + file: StaticString, + line: UInt, + _ callback: @escaping (Expectation) -> (NewValue) + ) -> EventLoopFuture } -extension Future : FutureType { +extension Future: FutureType { public typealias Expectation = Value } diff --git a/Sources/GraphQL/Utilities/TypeComparators.swift b/Sources/GraphQL/Utilities/TypeComparators.swift index 2c686b1a..e3519971 100644 --- a/Sources/GraphQL/Utilities/TypeComparators.swift +++ b/Sources/GraphQL/Utilities/TypeComparators.swift @@ -111,11 +111,11 @@ func isTypeSubTypeOf( schema.isSubType( abstractType: superType, maybeSubType: maybeSubType - ) + ) { return true } - + if let superType = superType as? GraphQLAbstractType, let maybeSubType = maybeSubType as? GraphQLInterfaceType, @@ -181,7 +181,7 @@ func doTypesOverlap( maybeSubType: typeA ) } - + // Otherwise the types do not overlap. return false } diff --git a/Sources/GraphQL/Utilities/TypeFromAST.swift b/Sources/GraphQL/Utilities/TypeFromAST.swift index a90cf735..358b0b09 100644 --- a/Sources/GraphQL/Utilities/TypeFromAST.swift +++ b/Sources/GraphQL/Utilities/TypeFromAST.swift @@ -4,7 +4,7 @@ func typeFromAST(schema: GraphQLSchema, inputTypeAST: Type) -> GraphQLType? { return GraphQLList(innerType) } } - + if let nonNullType = inputTypeAST as? NonNullType { if let innerType = typeFromAST(schema: schema, inputTypeAST: nonNullType.type) { // Non-null types by definition must contain nullable types (since all types are nullable by default) diff --git a/Sources/GraphQL/Utilities/TypeInfo.swift b/Sources/GraphQL/Utilities/TypeInfo.swift index 27ea67bf..ce8e1026 100644 --- a/Sources/GraphQL/Utilities/TypeInfo.swift +++ b/Sources/GraphQL/Utilities/TypeInfo.swift @@ -4,7 +4,7 @@ * AST during a recursive descent by calling `enter(node: node)` and `leave(node: node)`. */ final class TypeInfo { - let schema: GraphQLSchema; + let schema: GraphQLSchema var typeStack: [GraphQLOutputType?] var parentTypeStack: [GraphQLCompositeType?] var inputTypeStack: [GraphQLInputType?] @@ -14,12 +14,12 @@ final class TypeInfo { init(schema: GraphQLSchema) { self.schema = schema - self.typeStack = [] - self.parentTypeStack = [] - self.inputTypeStack = [] - self.fieldDefStack = [] - self.directive = nil - self.argument = nil + typeStack = [] + parentTypeStack = [] + inputTypeStack = [] + fieldDefStack = [] + directive = nil + argument = nil } var type: GraphQLOutputType? { @@ -54,7 +54,7 @@ final class TypeInfo { switch node { case is SelectionSet: let namedType = getNamedType(type: type) - var compositeType: GraphQLCompositeType? = nil + var compositeType: GraphQLCompositeType? if let type = namedType as? GraphQLCompositeType { compositeType = type @@ -63,9 +63,9 @@ final class TypeInfo { parentTypeStack.append(compositeType) case let node as Field: - var fieldDef: GraphQLFieldDefinition? = nil + var fieldDef: GraphQLFieldDefinition? - if let parentType = self.parentType { + if let parentType = parentType { fieldDef = getFieldDef(schema: schema, parentType: parentType, fieldAST: node) } @@ -76,7 +76,7 @@ final class TypeInfo { directive = schema.getDirective(name: node.name.value) case let node as OperationDefinition: - var type: GraphQLOutputType? = nil + var type: GraphQLOutputType? switch node.operation { case .query: @@ -94,7 +94,7 @@ final class TypeInfo { if let typeConditionAST = node.typeCondition { outputType = typeFromAST(schema: schema, inputTypeAST: typeConditionAST) } else { - outputType = self.type + outputType = type } typeStack.append(outputType as? GraphQLOutputType) @@ -107,31 +107,31 @@ final class TypeInfo { inputTypeStack.append(inputType as? GraphQLInputType) case let node as Argument: - var argType: GraphQLInputType? = nil + var argType: GraphQLInputType? - if let directive = self.directive { + if let directive = directive { if let argDef = directive.args.find({ $0.name == node.name.value }) { argType = argDef.type - self.argument = argDef + argument = argDef } - } else if let fieldDef = self.fieldDef { + } else if let fieldDef = fieldDef { if let argDef = fieldDef.args.find({ $0.name == node.name.value }) { argType = argDef.type - self.argument = argDef + argument = argDef } } inputTypeStack.append(argType) case is ListType: // could be ListValue - if let listType = getNullableType(type: self.inputType) as? GraphQLList { + if let listType = getNullableType(type: inputType) as? GraphQLList { inputTypeStack.append(listType.ofType as? GraphQLInputType) } inputTypeStack.append(nil) case let node as ObjectField: - if let objectType = getNamedType(type: self.inputType) as? GraphQLInputObjectType { + if let objectType = getNamedType(type: inputType) as? GraphQLInputObjectType { let inputField = objectType.fields[node.name.value] inputTypeStack.append(inputField?.type) } @@ -177,29 +177,35 @@ final class TypeInfo { * 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, fieldAST: Field) -> GraphQLFieldDefinition? { +func getFieldDef( + schema: GraphQLSchema, + parentType: GraphQLType, + fieldAST: Field +) -> GraphQLFieldDefinition? { let name = fieldAST.name.value if let parentType = parentType as? GraphQLNamedType { - if name == SchemaMetaFieldDef.name && schema.queryType.name == parentType.name { + if name == SchemaMetaFieldDef.name, schema.queryType.name == parentType.name { return SchemaMetaFieldDef } - if name == TypeMetaFieldDef.name && schema.queryType.name == parentType.name { + if name == TypeMetaFieldDef.name, schema.queryType.name == parentType.name { return TypeMetaFieldDef } } - 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 } if let parentType = parentType as? GraphQLObjectType { return parentType.fields[name] } - + if let parentType = parentType as? GraphQLInterfaceType { return parentType.fields[name] } diff --git a/Sources/GraphQL/Utilities/ValueFromAST.swift b/Sources/GraphQL/Utilities/ValueFromAST.swift index 6e92be72..2fc43d2a 100644 --- a/Sources/GraphQL/Utilities/ValueFromAST.swift +++ b/Sources/GraphQL/Utilities/ValueFromAST.swift @@ -17,7 +17,11 @@ import OrderedCollections * | Enum Value | .string | * */ -func valueFromAST(valueAST: Value, type: GraphQLInputType, variables: [String: Map] = [:]) throws -> Map { +func valueFromAST( + valueAST: Value, + type: GraphQLInputType, + variables: [String: Map] = [:] +) throws -> Map { if let nonNull = type as? GraphQLNonNull { // Note: we're not checking that the result of valueFromAST is non-null. // We're assuming that this query has been validated and the value used @@ -59,14 +63,14 @@ func valueFromAST(valueAST: Value, type: GraphQLInputType, variables: [String: M } return .array(values) } - + // Convert solitary value into single-value array return .array([ try valueFromAST( valueAST: valueAST, type: itemType, variables: variables - ) + ), ]) } @@ -76,8 +80,8 @@ func valueFromAST(valueAST: Value, type: GraphQLInputType, variables: [String: M } let fields = objectType.fields - let fieldASTs = objectValue.fields.keyMap({ $0.name.value }) - + let fieldASTs = objectValue.fields.keyMap { $0.name.value } + var object = OrderedDictionary() for (fieldName, field) in fields { if let fieldAST = fieldASTs[fieldName] { @@ -97,10 +101,10 @@ func valueFromAST(valueAST: Value, type: GraphQLInputType, variables: [String: M } return .dictionary(object) } - + if let leafType = type as? GraphQLLeafType { return try leafType.parseLiteral(valueAST: valueAST) } - + throw GraphQLError(message: "Provided type is not an input type") } diff --git a/Sources/GraphQL/Validation/Rules/FieldsOnCorrectTypeRule.swift b/Sources/GraphQL/Validation/Rules/FieldsOnCorrectTypeRule.swift index 71c2af90..cbe276cb 100644 --- a/Sources/GraphQL/Validation/Rules/FieldsOnCorrectTypeRule.swift +++ b/Sources/GraphQL/Validation/Rules/FieldsOnCorrectTypeRule.swift @@ -25,7 +25,7 @@ func undefinedFieldMessage( */ func FieldsOnCorrectTypeRule(context: ValidationContext) -> Visitor { return Visitor( - enter: { node, key, parent, path, ancestors in + enter: { node, _, _, _, _ in if let node = node as? Field { if let type = context.parentType { let fieldDef = context.fieldDef @@ -42,11 +42,12 @@ func FieldsOnCorrectTypeRule(context: ValidationContext) -> Visitor { ) // If there are no suggested types, then perhaps this was a typo? - let suggestedFieldNames = !suggestedTypeNames.isEmpty ? [] : getSuggestedFieldNames( - schema: schema, - type: type, - fieldName: fieldName - ) + let suggestedFieldNames = !suggestedTypeNames + .isEmpty ? [] : getSuggestedFieldNames( + schema: schema, + type: type, + fieldName: fieldName + ) // Report an error, including helpful suggestions. context.report(error: GraphQLError( @@ -83,7 +84,6 @@ func getSuggestedTypeNames( var interfaceUsageCount: [String: Int] = [:] for possibleType in schema.getPossibleTypes(abstractType: type) { - if possibleType.fields[fieldName] == nil { return [] } @@ -96,7 +96,8 @@ func getSuggestedTypeNames( return [] } // This interface type defines this field. - interfaceUsageCount[possibleInterface.name] = (interfaceUsageCount[possibleInterface.name] ?? 0) + 1 + interfaceUsageCount[possibleInterface.name] = + (interfaceUsageCount[possibleInterface.name] ?? 0) + 1 } } @@ -109,7 +110,7 @@ func getSuggestedTypeNames( // Suggest both interface and object types. return suggestedInterfaceTypes + suggestedObjectTypes } - + // Otherwise, must be an Object type, which does not have possible fields. return [] } @@ -119,7 +120,7 @@ func getSuggestedTypeNames( * that may be the result of a typo. */ func getSuggestedFieldNames( - schema: GraphQLSchema, + schema _: GraphQLSchema, type: GraphQLOutputType, fieldName: String ) -> [String] { diff --git a/Sources/GraphQL/Validation/Rules/KnownArgumentNamesRule.swift b/Sources/GraphQL/Validation/Rules/KnownArgumentNamesRule.swift index e9b15925..e7c065af 100644 --- a/Sources/GraphQL/Validation/Rules/KnownArgumentNamesRule.swift +++ b/Sources/GraphQL/Validation/Rules/KnownArgumentNamesRule.swift @@ -1,29 +1,37 @@ import Foundation - func undefinedArgumentMessage( +func undefinedArgumentMessage( fieldName: String, type: String, argumentName: String, suggestedArgumentNames: [String] ) -> String { - var message = "Field \"\(fieldName)\" on type \"\(type)\" does not have argument \"\(argumentName)\"." + var message = + "Field \"\(fieldName)\" on type \"\(type)\" does not have argument \"\(argumentName)\"." - if !suggestedArgumentNames.isEmpty { + if !suggestedArgumentNames.isEmpty { let suggestions = quotedOrList(items: suggestedArgumentNames) message += " Did you mean \(suggestions)?" } - return message + return message } - func KnownArgumentNamesRule(context: ValidationContext) -> Visitor { +func KnownArgumentNamesRule(context: ValidationContext) -> Visitor { return Visitor( - enter: { node, key, parent, path, ancestors in - if let node = node as? Argument, context.argument == nil, let field = context.fieldDef, let type = context.parentType { + enter: { node, _, _, _, _ in + if + let node = node as? Argument, context.argument == nil, let field = context.fieldDef, + let type = context.parentType + { let argumentName = node.name.value - let suggestedArgumentNames = getSuggestedArgumentNames(schema: context.schema, field: field, argumentName: argumentName) + let suggestedArgumentNames = getSuggestedArgumentNames( + schema: context.schema, + field: field, + argumentName: argumentName + ) - context.report(error: GraphQLError( + context.report(error: GraphQLError( message: undefinedArgumentMessage( fieldName: field.name, type: type.name, @@ -34,13 +42,13 @@ import Foundation )) } - return .continue + return .continue } ) } - func getSuggestedArgumentNames( - schema: GraphQLSchema, +func getSuggestedArgumentNames( + schema _: GraphQLSchema, field: GraphQLFieldDefinition, argumentName: String ) -> [String] { diff --git a/Sources/GraphQL/Validation/Rules/NoUnusedVariablesRule.swift b/Sources/GraphQL/Validation/Rules/NoUnusedVariablesRule.swift index 7daa3bd5..3af733a7 100644 --- a/Sources/GraphQL/Validation/Rules/NoUnusedVariablesRule.swift +++ b/Sources/GraphQL/Validation/Rules/NoUnusedVariablesRule.swift @@ -13,29 +13,29 @@ func NoUnusedVariablesRule(context: ValidationContext) -> Visitor { variableDefs = [] return .continue } - + if let def = node as? VariableDefinition { variableDefs.append(def) return .continue } - + return .continue }, leave: { node, _, _, _, _ -> VisitResult in guard let operation = node as? OperationDefinition else { return .continue } - + var variableNameUsed: [String: Bool] = [:] let usages = context.getRecursiveVariableUsages(operation: operation) - + for usage in usages { variableNameUsed[usage.node.name.value] = true } - + for variableDef in variableDefs { let variableName = variableDef.variable.name.value - + if variableNameUsed[variableName] != true { context.report( error: GraphQLError( @@ -47,7 +47,7 @@ func NoUnusedVariablesRule(context: ValidationContext) -> Visitor { ) } } - + return .continue } ) diff --git a/Sources/GraphQL/Validation/Rules/PossibleFragmentSpreadsRule.swift b/Sources/GraphQL/Validation/Rules/PossibleFragmentSpreadsRule.swift index 86b46241..015efd5b 100644 --- a/Sources/GraphQL/Validation/Rules/PossibleFragmentSpreadsRule.swift +++ b/Sources/GraphQL/Validation/Rules/PossibleFragmentSpreadsRule.swift @@ -7,25 +7,25 @@ */ func PossibleFragmentSpreadsRule(context: ValidationContext) -> Visitor { return Visitor( - enter: { node, key, parent, path, ancestors in + enter: { node, _, _, _, _ in if let node = node as? InlineFragment { guard let fragType = context.type as? GraphQLCompositeType, let parentType = context.parentType - else { - return .continue + else { + return .continue } - + let isThereOverlap = doTypesOverlap( schema: context.schema, typeA: fragType, typeB: parentType ) - + guard !isThereOverlap else { return .continue } - + context.report( error: GraphQLError( message: "Fragment cannot be spread here as objects of type \"\(parentType)\" can never be of type \"\(fragType)\".", @@ -33,10 +33,10 @@ func PossibleFragmentSpreadsRule(context: ValidationContext) -> Visitor { ) ) } - + if let node = node as? FragmentSpread { let fragName = node.name.value - + guard let fragType = getFragmentType(context: context, name: fragName), let parentType = context.parentType @@ -49,11 +49,11 @@ func PossibleFragmentSpreadsRule(context: ValidationContext) -> Visitor { typeA: fragType, typeB: parentType ) - + guard !isThereOverlap else { return .continue } - + context.report( error: GraphQLError( message: "Fragment \"\(fragName)\" cannot be spread here as objects of type \"\(parentType)\" can never be of type \"\(fragType)\".", @@ -61,7 +61,7 @@ func PossibleFragmentSpreadsRule(context: ValidationContext) -> Visitor { ) ) } - + return .continue } ) @@ -76,11 +76,11 @@ func getFragmentType( schema: context.schema, inputTypeAST: fragment.typeCondition ) - + if let type = type as? GraphQLCompositeType { return type } } - + return nil } diff --git a/Sources/GraphQL/Validation/Rules/ProvidedNonNullArgumentsRule.swift b/Sources/GraphQL/Validation/Rules/ProvidedNonNullArgumentsRule.swift index c9335e6a..0d20526d 100644 --- a/Sources/GraphQL/Validation/Rules/ProvidedNonNullArgumentsRule.swift +++ b/Sources/GraphQL/Validation/Rules/ProvidedNonNullArgumentsRule.swift @@ -9,10 +9,13 @@ func missingArgumentsMessage( return "Field \"\(fieldName)\" on type \"\(type)\" is missing required arguments \(arguments)." } - func ProvidedNonNullArgumentsRule(context: ValidationContext) -> Visitor { +func ProvidedNonNullArgumentsRule(context: ValidationContext) -> Visitor { return Visitor( - leave: { node, key, parent, path, ancestors in - if let node = node as? Field, let field = context.fieldDef, let type = context.parentType { + leave: { node, _, _, _, _ in + if + let node = node as? Field, let field = context.fieldDef, + let type = context.parentType + { let requiredArguments = Set( field .args @@ -20,9 +23,9 @@ func missingArgumentsMessage( .map { $0.name } ) - let providedArguments = Set(node.arguments.map { $0.name.value }) + let providedArguments = Set(node.arguments.map { $0.name.value }) - let missingArguments = requiredArguments.subtracting(providedArguments) + let missingArguments = requiredArguments.subtracting(providedArguments) if !missingArguments.isEmpty { context.report(error: GraphQLError( message: missingArgumentsMessage( @@ -35,7 +38,7 @@ func missingArgumentsMessage( } } - return .continue + return .continue } ) } diff --git a/Sources/GraphQL/Validation/Rules/ScalarLeafsRule.swift b/Sources/GraphQL/Validation/Rules/ScalarLeafsRule.swift index 2379d7a8..e41dea60 100644 --- a/Sources/GraphQL/Validation/Rules/ScalarLeafsRule.swift +++ b/Sources/GraphQL/Validation/Rules/ScalarLeafsRule.swift @@ -1,11 +1,11 @@ func noSubselectionAllowedMessage(fieldName: String, type: GraphQLType) -> String { return "Field \"\(fieldName)\" must not have a selection since " + - "type \"\(type)\" has no subfields." + "type \"\(type)\" has no subfields." } func requiredSubselectionMessage(fieldName: String, type: GraphQLType) -> String { return "Field \"\(fieldName)\" of type \"\(type)\" must have a " + - "selection of subfields. Did you mean \"\(fieldName) { ... }\"?" + "selection of subfields. Did you mean \"\(fieldName) { ... }\"?" } /** @@ -16,20 +16,26 @@ func requiredSubselectionMessage(fieldName: String, type: GraphQLType) -> String */ func ScalarLeafsRule(context: ValidationContext) -> Visitor { return Visitor( - enter: { node, key, parent, path, ancestors in + enter: { node, _, _, _, _ in if let node = node as? Field { if let type = context.type { if isLeafType(type: getNamedType(type: type)) { if let selectionSet = node.selectionSet { let error = GraphQLError( - message: noSubselectionAllowedMessage(fieldName: node.name.value, type: type), + message: noSubselectionAllowedMessage( + fieldName: node.name.value, + type: type + ), nodes: [selectionSet] ) context.report(error: error) } } else if node.selectionSet == nil { let error = GraphQLError( - message: requiredSubselectionMessage(fieldName: node.name.value, type: type), + message: requiredSubselectionMessage( + fieldName: node.name.value, + type: type + ), nodes: [node] ) context.report(error: error) diff --git a/Sources/GraphQL/Validation/SpecifiedRules.swift b/Sources/GraphQL/Validation/SpecifiedRules.swift index 421bc58f..521abe68 100644 --- a/Sources/GraphQL/Validation/SpecifiedRules.swift +++ b/Sources/GraphQL/Validation/SpecifiedRules.swift @@ -2,7 +2,7 @@ * This set includes all validation rules defined by the GraphQL spec. */ public let specifiedRules: [(ValidationContext) -> Visitor] = [ -// UniqueOperationNames, + // UniqueOperationNames, // LoneAnonymousOperation, // KnownTypeNames, // FragmentsOnCompositeTypes, diff --git a/Sources/GraphQL/Validation/Validate.swift b/Sources/GraphQL/Validation/Validate.swift index 38629264..1720c6f0 100644 --- a/Sources/GraphQL/Validation/Validate.swift +++ b/Sources/GraphQL/Validation/Validate.swift @@ -39,7 +39,15 @@ public func validate( let typeInfo = TypeInfo(schema: schema) let rules = rules.isEmpty ? specifiedRules : rules let errors = visit(usingRules: rules, schema: schema, typeInfo: typeInfo, documentAST: ast) - instrumentation.queryValidation(processId: processId(), threadId: threadId(), started: started, finished: instrumentation.now, schema: schema, document: ast, errors: errors) + instrumentation.queryValidation( + processId: processId(), + threadId: threadId(), + started: started, + finished: instrumentation.now, + schema: schema, + document: ast, + errors: errors + ) return errors } @@ -56,9 +64,12 @@ func visit( documentAST: Document ) -> [GraphQLError] { let context = ValidationContext(schema: schema, ast: documentAST, typeInfo: typeInfo) - let visitors = rules.map({ rule in rule(context) }) + let visitors = rules.map { rule in rule(context) } // Visit the whole document with each instance of all provided rules. - visit(root: documentAST, visitor: visitWithTypeInfo(typeInfo: typeInfo, visitor: visitInParallel(visitors: visitors))) + visit( + root: documentAST, + visitor: visitWithTypeInfo(typeInfo: typeInfo, visitor: visitInParallel(visitors: visitors)) + ) return context.errors } @@ -68,29 +79,29 @@ public enum HasSelectionSet { public var node: Node { switch self { - case .operation(let operation): + case let .operation(operation): return operation - case .fragment(let fragment): + case let .fragment(fragment): return fragment } } } -extension HasSelectionSet : Hashable { +extension HasSelectionSet: Hashable { public func hash(into hasher: inout Hasher) { switch self { - case .operation(let operation): + case let .operation(operation): return hasher.combine(operation.hashValue) - case .fragment(let fragment): + case let .fragment(fragment): return hasher.combine(fragment.hashValue) } } public static func == (lhs: HasSelectionSet, rhs: HasSelectionSet) -> Bool { switch (lhs, rhs) { - case (.operation(let l), .operation(let r)): + case let (.operation(l), .operation(r)): return l == r - case (.fragment(let l), .fragment(let r)): + case let (.fragment(l), .fragment(r)): return l == r default: return false @@ -120,12 +131,12 @@ public final class ValidationContext { self.schema = schema self.ast = ast self.typeInfo = typeInfo - self.errors = [] - self.fragments = [:] - self.fragmentSpreads = [:] - self.recursivelyReferencedFragments = [:] - self.variableUsages = [:] - self.recursiveVariableUsages = [:] + errors = [] + fragments = [:] + fragmentSpreads = [:] + recursivelyReferencedFragments = [:] + variableUsages = [:] + recursiveVariableUsages = [:] } public func report(error: GraphQLError) { @@ -180,11 +191,13 @@ public final class ValidationContext { return spreads } - public func getRecursivelyReferencedFragments(operation: OperationDefinition) -> [FragmentDefinition] { + public func getRecursivelyReferencedFragments(operation: OperationDefinition) + -> [FragmentDefinition] + { if let fragments = recursivelyReferencedFragments[operation] { return fragments } - + var fragments = [FragmentDefinition]() var collectedNames: [String: Bool] = [:] var nodesToVisit: [SelectionSet] = [operation.selectionSet] @@ -203,7 +216,7 @@ public final class ValidationContext { } } } - + recursivelyReferencedFragments[operation] = fragments return fragments } @@ -212,21 +225,31 @@ public final class ValidationContext { if let usages = variableUsages[node] { return usages } - + var usages = [VariableUsage]() let typeInfo = TypeInfo(schema: schema) - visit(root: node.node, visitor: visitWithTypeInfo(typeInfo: typeInfo, visitor: Visitor(enter: { node, _, _, _, _ in - if node is VariableDefinition { - return .skip - } + visit( + root: node.node, + visitor: visitWithTypeInfo( + typeInfo: typeInfo, + visitor: Visitor(enter: { node, _, _, _, _ in + if node is VariableDefinition { + return .skip + } - if let variable = node as? Variable { - usages.append(VariableUsage(node: variable, type: typeInfo.inputType)) - } + if let variable = node as? Variable { + usages + .append(VariableUsage( + node: variable, + type: typeInfo.inputType + )) + } - return .continue - }))) + return .continue + }) + ) + ) variableUsages[node] = usages return usages @@ -236,7 +259,7 @@ public final class ValidationContext { if let usages = recursiveVariableUsages[operation] { return usages } - + var usages = getVariableUsages(node: .operation(operation)) let fragments = getRecursivelyReferencedFragments(operation: operation) diff --git a/Tests/GraphQLTests/FieldExecutionStrategyTests/FieldExecutionStrategyTests.swift b/Tests/GraphQLTests/FieldExecutionStrategyTests/FieldExecutionStrategyTests.swift index 633a74a0..2fea6571 100644 --- a/Tests/GraphQLTests/FieldExecutionStrategyTests/FieldExecutionStrategyTests.swift +++ b/Tests/GraphQLTests/FieldExecutionStrategyTests/FieldExecutionStrategyTests.swift @@ -1,10 +1,10 @@ import Dispatch @testable import GraphQL -import XCTest import NIO +import XCTest class FieldExecutionStrategyTests: XCTestCase { - enum StrategyError : Error { + enum StrategyError: Error { case exampleError(msg: String) } @@ -17,11 +17,11 @@ class FieldExecutionStrategyTests: XCTestCase { resolve: { _, _, _, eventLoopGroup, _ in let group = DispatchGroup() group.enter() - + DispatchQueue.global().asyncAfter(wallDeadline: .now() + 0.1) { group.leave() } - + group.wait() return eventLoopGroup.next().makeSucceededFuture("z") } @@ -31,13 +31,13 @@ class FieldExecutionStrategyTests: XCTestCase { resolve: { (_, _, _, _, info: GraphQLResolveInfo) in let group = DispatchGroup() group.enter() - + DispatchQueue.global().asyncAfter(wallDeadline: .now() + 0.1) { group.leave() } - + group.wait() - + throw StrategyError.exampleError( msg: "\(info.fieldName): \(info.path.elements.last!)" ) @@ -48,32 +48,33 @@ class FieldExecutionStrategyTests: XCTestCase { resolve: { (_, _, _, eventLoopGroup, info: GraphQLResolveInfo) in let g = DispatchGroup() g.enter() - + DispatchQueue.global().asyncAfter(wallDeadline: .now() + 0.1) { g.leave() } - + g.wait() - + return eventLoopGroup.next().makeFailedFuture(StrategyError.exampleError( msg: "\(info.fieldName): \(info.path.elements.last!)" )) } - ) + ), ] ) ) let singleQuery = "{ sleep }" - + let singleExpected = GraphQLResult( data: [ - "sleep": "z" + "sleep": "z", ] ) - let multiQuery = "{ a: sleep b: sleep c: sleep d: sleep e: sleep f: sleep g: sleep h: sleep i: sleep j: sleep }" - + let multiQuery = + "{ a: sleep b: sleep c: sleep d: sleep e: sleep f: sleep g: sleep h: sleep i: sleep j: sleep }" + let multiExpected = GraphQLResult( data: [ "a": "z", @@ -90,37 +91,38 @@ class FieldExecutionStrategyTests: XCTestCase { ) let singleThrowsQuery = "{ bang }" - + let singleThrowsExpected = GraphQLResult( data: [ - "bang": nil + "bang": nil, ], errors: [ GraphQLError( message: "exampleError(msg: \"bang: bang\")", locations: [SourceLocation(line: 1, column: 3)], path: ["bang"] - ) + ), ] ) - + let singleFailedFutureQuery = "{ futureBang }" - + let singleFailedFutureExpected = GraphQLResult( data: [ - "futureBang": nil + "futureBang": nil, ], errors: [ GraphQLError( message: "exampleError(msg: \"futureBang: futureBang\")", locations: [SourceLocation(line: 1, column: 3)], path: ["futureBang"] - ) + ), ] ) - let multiThrowsQuery = "{ a: bang b: bang c: bang d: bang e: bang f: bang g: bang h: bang i: bang j: futureBang }" - + let multiThrowsQuery = + "{ a: bang b: bang c: bang d: bang e: bang f: bang g: bang h: bang i: bang j: futureBang }" + let multiThrowsExpectedData: Map = [ "a": nil, "b": nil, @@ -133,7 +135,7 @@ class FieldExecutionStrategyTests: XCTestCase { "i": nil, "j": nil, ] - + let multiThrowsExpectedErrors: [GraphQLError] = [ GraphQLError( message: "exampleError(msg: \"bang: a\")", @@ -197,133 +199,123 @@ class FieldExecutionStrategyTests: XCTestCase { seconds: seconds ) } - + private var eventLoopGroup: EventLoopGroup! - + override func setUp() { eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) } - + override func tearDown() { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } func testSerialFieldExecutionStrategyWithSingleField() throws { - let result = try timing(try graphql( queryStrategy: SerialFieldExecutionStrategy(), schema: schema, request: singleQuery, eventLoopGroup: eventLoopGroup - ).wait()) + ).wait()) XCTAssertEqual(result.value, singleExpected) - //XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) + // XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) } func testSerialFieldExecutionStrategyWithSingleFieldError() throws { - let result = try timing(try graphql( queryStrategy: SerialFieldExecutionStrategy(), schema: schema, request: singleThrowsQuery, eventLoopGroup: eventLoopGroup - ).wait()) + ).wait()) XCTAssertEqual(result.value, singleThrowsExpected) - //XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) + // XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) } - + func testSerialFieldExecutionStrategyWithSingleFieldFailedFuture() throws { - let result = try timing(try graphql( queryStrategy: SerialFieldExecutionStrategy(), schema: schema, request: singleFailedFutureQuery, eventLoopGroup: eventLoopGroup - ).wait()) + ).wait()) XCTAssertEqual(result.value, singleFailedFutureExpected) - //XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) + // XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) } func testSerialFieldExecutionStrategyWithMultipleFields() throws { - let result = try timing(try graphql( queryStrategy: SerialFieldExecutionStrategy(), schema: schema, request: multiQuery, eventLoopGroup: eventLoopGroup - ).wait()) + ).wait()) XCTAssertEqual(result.value, multiExpected) - //XCTAssertEqualWithAccuracy(1.0, result.seconds, accuracy: 0.5) + // XCTAssertEqualWithAccuracy(1.0, result.seconds, accuracy: 0.5) } func testSerialFieldExecutionStrategyWithMultipleFieldErrors() throws { - let result = try timing(try graphql( queryStrategy: SerialFieldExecutionStrategy(), schema: schema, request: multiThrowsQuery, eventLoopGroup: eventLoopGroup - ).wait()) + ).wait()) XCTAssertEqual(result.value.data, multiThrowsExpectedData) let resultErrors = result.value.errors XCTAssertEqual(resultErrors.count, multiThrowsExpectedErrors.count) - multiThrowsExpectedErrors.forEach { (m) in + multiThrowsExpectedErrors.forEach { m in XCTAssertTrue(resultErrors.contains(m), "Expecting result errors to contain \(m)") } - //XCTAssertEqualWithAccuracy(1.0, result.seconds, accuracy: 0.5) + // XCTAssertEqualWithAccuracy(1.0, result.seconds, accuracy: 0.5) } func testConcurrentDispatchFieldExecutionStrategyWithSingleField() throws { - let result = try timing(try graphql( queryStrategy: ConcurrentDispatchFieldExecutionStrategy(), schema: schema, request: singleQuery, eventLoopGroup: eventLoopGroup - ).wait()) + ).wait()) XCTAssertEqual(result.value, singleExpected) - //XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) + // XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) } func testConcurrentDispatchFieldExecutionStrategyWithSingleFieldError() throws { - let result = try timing(try graphql( queryStrategy: ConcurrentDispatchFieldExecutionStrategy(), schema: schema, request: singleThrowsQuery, eventLoopGroup: eventLoopGroup - ).wait()) + ).wait()) XCTAssertEqual(result.value, singleThrowsExpected) - //XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) + // XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) } func testConcurrentDispatchFieldExecutionStrategyWithMultipleFields() throws { - let result = try timing(try graphql( queryStrategy: ConcurrentDispatchFieldExecutionStrategy(), schema: schema, request: multiQuery, eventLoopGroup: eventLoopGroup - ).wait()) + ).wait()) XCTAssertEqual(result.value, multiExpected) - //XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) + // XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) } func testConcurrentDispatchFieldExecutionStrategyWithMultipleFieldErrors() throws { - let result = try timing(try graphql( queryStrategy: ConcurrentDispatchFieldExecutionStrategy(), schema: schema, request: multiThrowsQuery, eventLoopGroup: eventLoopGroup - ).wait()) + ).wait()) XCTAssertEqual(result.value.data, multiThrowsExpectedData) let resultErrors = result.value.errors XCTAssertEqual(resultErrors.count, multiThrowsExpectedErrors.count) - multiThrowsExpectedErrors.forEach { (m) in + multiThrowsExpectedErrors.forEach { m in XCTAssertTrue(resultErrors.contains(m), "Expecting result errors to contain \(m)") } - //XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) + // XCTAssertEqualWithAccuracy(0.1, result.seconds, accuracy: 0.25) } - } diff --git a/Tests/GraphQLTests/HelloWorldTests/HelloWorldTests.swift b/Tests/GraphQLTests/HelloWorldTests/HelloWorldTests.swift index 5eef5506..b5a5a4f4 100644 --- a/Tests/GraphQLTests/HelloWorldTests/HelloWorldTests.swift +++ b/Tests/GraphQLTests/HelloWorldTests/HelloWorldTests.swift @@ -1,8 +1,8 @@ -import XCTest -import NIO @testable import GraphQL +import NIO +import XCTest -class HelloWorldTests : XCTestCase { +class HelloWorldTests: XCTestCase { let schema = try! GraphQLSchema( query: GraphQLObjectType( name: "RootQueryType", @@ -12,21 +12,21 @@ class HelloWorldTests : XCTestCase { resolve: { _, _, _, _ in "world" } - ) + ), ] ) ) - + func testHello() throws { let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) - + defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) } let query = "{ hello }" let expected = GraphQLResult(data: ["hello": "world"]) - + let result = try graphql( schema: schema, request: query, @@ -38,7 +38,7 @@ class HelloWorldTests : XCTestCase { func testBoyhowdy() throws { let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) - + defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) } @@ -50,7 +50,7 @@ class HelloWorldTests : XCTestCase { GraphQLError( message: "Cannot query field \"boyhowdy\" on type \"RootQueryType\".", locations: [SourceLocation(line: 1, column: 3)] - ) + ), ] ) @@ -59,31 +59,31 @@ class HelloWorldTests : XCTestCase { request: query, eventLoopGroup: group ).wait() - + XCTAssertEqual(result, expected) } - + #if compiler(>=5.5) && canImport(_Concurrency) - @available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) - func testHelloAsync() async throws { - let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) - - defer { - XCTAssertNoThrow(try group.syncShutdownGracefully()) - } + @available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) + func testHelloAsync() async throws { + let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) - let query = "{ hello }" - let expected = GraphQLResult(data: ["hello": "world"]) - - let result = try await graphql( - schema: schema, - request: query, - eventLoopGroup: group - ) + defer { + XCTAssertNoThrow(try group.syncShutdownGracefully()) + } + + let query = "{ hello }" + let expected = GraphQLResult(data: ["hello": "world"]) + + let result = try await graphql( + schema: schema, + request: query, + eventLoopGroup: group + ) + + XCTAssertEqual(result, expected) + } - XCTAssertEqual(result, expected) - } - #endif } diff --git a/Tests/GraphQLTests/InputTests/InputTests.swift b/Tests/GraphQLTests/InputTests/InputTests.swift index 20b0fbaa..23fb6c9b 100644 --- a/Tests/GraphQLTests/InputTests/InputTests.swift +++ b/Tests/GraphQLTests/InputTests/InputTests.swift @@ -1,19 +1,17 @@ -import XCTest -import NIO @testable import GraphQL +import NIO +import XCTest - -class InputTests : XCTestCase { - +class InputTests: XCTestCase { func testArgsNonNullNoDefault() throws { - struct Echo : Codable { + struct Echo: Codable { let field1: String } - - struct EchoArgs : Codable { + + struct EchoArgs: Codable { let field1: String } - + let EchoOutputType = try GraphQLObjectType( name: "Echo", description: "", @@ -26,7 +24,7 @@ class InputTests : XCTestCase { source is Echo } ) - + let schema = try GraphQLSchema( query: try GraphQLObjectType( name: "Query", @@ -36,7 +34,7 @@ class InputTests : XCTestCase { args: [ "field1": GraphQLArgument( type: GraphQLNonNull(GraphQLString) - ) + ), ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -49,12 +47,12 @@ class InputTests : XCTestCase { ), types: [EchoOutputType] ) - + let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) } - + // Test basic functionality XCTAssertEqual( try graphql( @@ -72,8 +70,8 @@ class InputTests : XCTestCase { ).wait(), GraphQLResult(data: [ "echo": [ - "field1": "value1" - ] + "field1": "value1", + ], ]) ) XCTAssertEqual( @@ -90,16 +88,16 @@ class InputTests : XCTestCase { """, eventLoopGroup: group, variableValues: [ - "field1": "value1" + "field1": "value1", ] ).wait(), GraphQLResult(data: [ "echo": [ - "field1": "value1" - ] + "field1": "value1", + ], ]) ) - + // Test providing null results in an error XCTAssertTrue( try graphql( @@ -115,7 +113,7 @@ class InputTests : XCTestCase { """, eventLoopGroup: group ).wait() - .errors.count > 0 + .errors.count > 0 ) XCTAssertTrue( try graphql( @@ -131,12 +129,12 @@ class InputTests : XCTestCase { """, eventLoopGroup: group, variableValues: [ - "field1": .null + "field1": .null, ] ).wait() - .errors.count > 0 + .errors.count > 0 ) - + // Test not providing parameter results in an error XCTAssertTrue( try graphql( @@ -150,7 +148,7 @@ class InputTests : XCTestCase { """, eventLoopGroup: group ).wait() - .errors.count > 0 + .errors.count > 0 ) XCTAssertTrue( try graphql( @@ -167,19 +165,19 @@ class InputTests : XCTestCase { eventLoopGroup: group, variableValues: [:] ).wait() - .errors.count > 0 + .errors.count > 0 ) } - + func testArgsNullNoDefault() throws { - struct Echo : Codable { + struct Echo: Codable { let field1: String? } - - struct EchoArgs : Codable { + + struct EchoArgs: Codable { let field1: String? } - + let EchoOutputType = try GraphQLObjectType( name: "Echo", description: "", @@ -192,7 +190,7 @@ class InputTests : XCTestCase { source is Echo } ) - + let schema = try GraphQLSchema( query: try GraphQLObjectType( name: "Query", @@ -202,7 +200,7 @@ class InputTests : XCTestCase { args: [ "field1": GraphQLArgument( type: GraphQLString - ) + ), ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -215,12 +213,12 @@ class InputTests : XCTestCase { ), types: [EchoOutputType] ) - + let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) } - + // Test basic functionality XCTAssertEqual( try graphql( @@ -238,8 +236,8 @@ class InputTests : XCTestCase { ).wait(), GraphQLResult(data: [ "echo": [ - "field1": "value1" - ] + "field1": "value1", + ], ]) ) XCTAssertEqual( @@ -256,16 +254,16 @@ class InputTests : XCTestCase { """, eventLoopGroup: group, variableValues: [ - "field1": "value1" + "field1": "value1", ] ).wait(), GraphQLResult(data: [ "echo": [ - "field1": "value1" - ] + "field1": "value1", + ], ]) ) - + // Test providing null is accepted XCTAssertEqual( try graphql( @@ -283,8 +281,8 @@ class InputTests : XCTestCase { ).wait(), GraphQLResult(data: [ "echo": [ - "field1": .null - ] + "field1": .null, + ], ]) ) XCTAssertEqual( @@ -301,16 +299,16 @@ class InputTests : XCTestCase { """, eventLoopGroup: group, variableValues: [ - "field1": .null + "field1": .null, ] ).wait(), GraphQLResult(data: [ "echo": [ - "field1": .null - ] + "field1": .null, + ], ]) ) - + // Test not providing parameter is accepted XCTAssertEqual( try graphql( @@ -326,8 +324,8 @@ class InputTests : XCTestCase { ).wait(), GraphQLResult(data: [ "echo": [ - "field1": .null - ] + "field1": .null, + ], ]) ) XCTAssertEqual( @@ -347,21 +345,21 @@ class InputTests : XCTestCase { ).wait(), GraphQLResult(data: [ "echo": [ - "field1": .null - ] + "field1": .null, + ], ]) ) } - + func testArgsNonNullDefault() throws { - struct Echo : Codable { + struct Echo: Codable { let field1: String } - - struct EchoArgs : Codable { + + struct EchoArgs: Codable { let field1: String } - + let EchoOutputType = try GraphQLObjectType( name: "Echo", description: "", @@ -374,7 +372,7 @@ class InputTests : XCTestCase { source is Echo } ) - + let schema = try GraphQLSchema( query: try GraphQLObjectType( name: "Query", @@ -385,7 +383,7 @@ class InputTests : XCTestCase { "field1": GraphQLArgument( type: GraphQLNonNull(GraphQLString), defaultValue: .string("defaultValue1") - ) + ), ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -398,12 +396,12 @@ class InputTests : XCTestCase { ), types: [EchoOutputType] ) - + let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) } - + // Test basic functionality XCTAssertEqual( try graphql( @@ -421,8 +419,8 @@ class InputTests : XCTestCase { ).wait(), GraphQLResult(data: [ "echo": [ - "field1": "value1" - ] + "field1": "value1", + ], ]) ) XCTAssertEqual( @@ -439,16 +437,16 @@ class InputTests : XCTestCase { """, eventLoopGroup: group, variableValues: [ - "field1": "value1" + "field1": "value1", ] ).wait(), GraphQLResult(data: [ "echo": [ - "field1": "value1" - ] + "field1": "value1", + ], ]) ) - + // Test providing null results in an error XCTAssertTrue( try graphql( @@ -464,7 +462,7 @@ class InputTests : XCTestCase { """, eventLoopGroup: group ).wait() - .errors.count > 0 + .errors.count > 0 ) XCTAssertTrue( try graphql( @@ -480,12 +478,12 @@ class InputTests : XCTestCase { """, eventLoopGroup: group, variableValues: [ - "field1": .null + "field1": .null, ] ).wait() - .errors.count > 0 + .errors.count > 0 ) - + // Test not providing parameter results in default XCTAssertEqual( try graphql( @@ -501,8 +499,8 @@ class InputTests : XCTestCase { ).wait(), GraphQLResult(data: [ "echo": [ - "field1": "defaultValue1" - ] + "field1": "defaultValue1", + ], ]) ) XCTAssertEqual( @@ -522,11 +520,11 @@ class InputTests : XCTestCase { ).wait(), GraphQLResult(data: [ "echo": [ - "field1": "defaultValue1" - ] + "field1": "defaultValue1", + ], ]) ) - + // Test variable doesn't get argument default XCTAssertTrue( try graphql( @@ -543,19 +541,19 @@ class InputTests : XCTestCase { eventLoopGroup: group, variableValues: [:] ).wait() - .errors.count > 0 + .errors.count > 0 ) } - + func testArgsNullDefault() throws { - struct Echo : Codable { + struct Echo: Codable { let field1: String? } - - struct EchoArgs : Codable { + + struct EchoArgs: Codable { let field1: String? } - + let EchoOutputType = try GraphQLObjectType( name: "Echo", description: "", @@ -568,7 +566,7 @@ class InputTests : XCTestCase { source is Echo } ) - + let schema = try GraphQLSchema( query: try GraphQLObjectType( name: "Query", @@ -579,7 +577,7 @@ class InputTests : XCTestCase { "field1": GraphQLArgument( type: GraphQLString, defaultValue: .string("defaultValue1") - ) + ), ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -592,12 +590,12 @@ class InputTests : XCTestCase { ), types: [EchoOutputType] ) - + let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) } - + // Test basic functionality XCTAssertEqual( try graphql( @@ -615,8 +613,8 @@ class InputTests : XCTestCase { ).wait(), GraphQLResult(data: [ "echo": [ - "field1": "value1" - ] + "field1": "value1", + ], ]) ) XCTAssertEqual( @@ -633,16 +631,16 @@ class InputTests : XCTestCase { """, eventLoopGroup: group, variableValues: [ - "field1": "value1" + "field1": "value1", ] ).wait(), GraphQLResult(data: [ "echo": [ - "field1": "value1" - ] + "field1": "value1", + ], ]) ) - + // Test providing null results in a null output XCTAssertEqual( try graphql( @@ -660,8 +658,8 @@ class InputTests : XCTestCase { ).wait(), GraphQLResult(data: [ "echo": [ - "field1": .null - ] + "field1": .null, + ], ]) ) XCTAssertEqual( @@ -678,16 +676,16 @@ class InputTests : XCTestCase { """, eventLoopGroup: group, variableValues: [ - "field1": .null + "field1": .null, ] ).wait(), GraphQLResult(data: [ "echo": [ - "field1": .null - ] + "field1": .null, + ], ]) ) - + // Test not providing parameter results in default XCTAssertEqual( try graphql( @@ -703,8 +701,8 @@ class InputTests : XCTestCase { ).wait(), GraphQLResult(data: [ "echo": [ - "field1": "defaultValue1" - ] + "field1": "defaultValue1", + ], ]) ) XCTAssertEqual( @@ -724,11 +722,11 @@ class InputTests : XCTestCase { ).wait(), GraphQLResult(data: [ "echo": [ - "field1": "defaultValue1" - ] + "field1": "defaultValue1", + ], ]) ) - + // Test that nullable unprovided variables are coerced to null XCTAssertEqual( try graphql( @@ -747,23 +745,23 @@ class InputTests : XCTestCase { ).wait(), GraphQLResult(data: [ "echo": [ - "field1": .null - ] + "field1": .null, + ], ]) ) } - + // Test that input objects parse as expected from non-null literals func testInputNoNull() throws { - struct Echo : Codable { + struct Echo: Codable { let field1: String? let field2: String? - + init(field1: String?, field2: String?) { self.field1 = field1 self.field2 = field2 } - + init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) XCTAssertTrue(container.contains(.field1)) @@ -773,7 +771,7 @@ class InputTests : XCTestCase { } } - struct EchoArgs : Codable { + struct EchoArgs: Codable { let input: Echo } @@ -804,7 +802,7 @@ class InputTests : XCTestCase { source is Echo } ) - + let schema = try GraphQLSchema( query: try GraphQLObjectType( name: "Query", @@ -814,7 +812,7 @@ class InputTests : XCTestCase { args: [ "input": GraphQLArgument( type: EchoInputType - ) + ), ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -828,12 +826,12 @@ class InputTests : XCTestCase { ), types: [EchoInputType, EchoOutputType] ) - + let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) } - + // Test in arguments XCTAssertEqual( try graphql( @@ -855,10 +853,10 @@ class InputTests : XCTestCase { "echo": [ "field1": "value1", "field2": "value2", - ] + ], ]) ) - + // Test in variables XCTAssertEqual( try graphql( @@ -875,30 +873,30 @@ class InputTests : XCTestCase { variableValues: [ "input": [ "field1": "value1", - "field2": "value2" - ] + "field2": "value2", + ], ] ).wait(), GraphQLResult(data: [ "echo": [ "field1": "value1", "field2": "value2", - ] + ], ]) ) } - + // Test that inputs parse as expected when null literals are present func testInputParsingDefinedNull() throws { - struct Echo : Codable { + struct Echo: Codable { let field1: String? let field2: String? - + init(field1: String?, field2: String?) { self.field1 = field1 self.field2 = field2 } - + init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) XCTAssertTrue(container.contains(.field1)) @@ -908,7 +906,7 @@ class InputTests : XCTestCase { } } - struct EchoArgs : Codable { + struct EchoArgs: Codable { let input: Echo } @@ -939,7 +937,7 @@ class InputTests : XCTestCase { source is Echo } ) - + let schema = try GraphQLSchema( query: try GraphQLObjectType( name: "Query", @@ -949,7 +947,7 @@ class InputTests : XCTestCase { args: [ "input": GraphQLArgument( type: EchoInputType - ) + ), ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -963,12 +961,12 @@ class InputTests : XCTestCase { ), types: [EchoInputType, EchoOutputType] ) - + let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) } - + // Test in arguments XCTAssertEqual( try graphql( @@ -990,10 +988,10 @@ class InputTests : XCTestCase { "echo": [ "field1": "value1", "field2": nil, - ] + ], ]) ) - + // Test in variables XCTAssertEqual( try graphql( @@ -1010,40 +1008,45 @@ class InputTests : XCTestCase { variableValues: [ "input": [ "field1": "value1", - "field2": .null - ] + "field2": .null, + ], ] ).wait(), GraphQLResult(data: [ "echo": [ "field1": "value1", "field2": nil, - ] + ], ]) ) } - + // Test that input objects parse as expected when there are missing fields with no default func testInputParsingUndefined() throws { - struct Echo : Codable { + struct Echo: Codable { let field1: String? let field2: String? - + init(field1: String?, field2: String?) { self.field1 = field1 self.field2 = field2 } - + init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) XCTAssertTrue(container.contains(.field1)) field1 = try container.decodeIfPresent(String.self, forKey: .field1) - XCTAssertFalse(container.contains(.field2)) // Container should not include field2, since it is undefined + XCTAssertFalse( + container + .contains( + .field2 + ) + ) // Container should not include field2, since it is undefined field2 = try container.decodeIfPresent(String.self, forKey: .field2) } } - struct EchoArgs : Codable { + struct EchoArgs: Codable { let input: Echo } @@ -1074,7 +1077,7 @@ class InputTests : XCTestCase { source is Echo } ) - + let schema = try GraphQLSchema( query: try GraphQLObjectType( name: "Query", @@ -1084,7 +1087,7 @@ class InputTests : XCTestCase { args: [ "input": GraphQLArgument( type: EchoInputType - ) + ), ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -1098,12 +1101,12 @@ class InputTests : XCTestCase { ), types: [EchoInputType, EchoOutputType] ) - + let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) } - + // Test in arguments XCTAssertEqual( try graphql( @@ -1124,10 +1127,10 @@ class InputTests : XCTestCase { "echo": [ "field1": "value1", "field2": nil, - ] + ], ]) ) - + // Test in variables XCTAssertEqual( try graphql( @@ -1143,30 +1146,30 @@ class InputTests : XCTestCase { eventLoopGroup: group, variableValues: [ "input": [ - "field1": "value1" - ] + "field1": "value1", + ], ] ).wait(), GraphQLResult(data: [ "echo": [ "field1": "value1", "field2": nil, - ] + ], ]) ) } - + // Test that input objects parse as expected when there are missing fields with defaults func testInputParsingUndefinedWithDefault() throws { - struct Echo : Codable { + struct Echo: Codable { let field1: String? let field2: String? - + init(field1: String?, field2: String?) { self.field1 = field1 self.field2 = field2 } - + init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) XCTAssertTrue(container.contains(.field1)) @@ -1176,7 +1179,7 @@ class InputTests : XCTestCase { } } - struct EchoArgs : Codable { + struct EchoArgs: Codable { let input: Echo } @@ -1208,7 +1211,7 @@ class InputTests : XCTestCase { source is Echo } ) - + let schema = try GraphQLSchema( query: try GraphQLObjectType( name: "Query", @@ -1218,7 +1221,7 @@ class InputTests : XCTestCase { args: [ "input": GraphQLArgument( type: EchoInputType - ) + ), ], resolve: { _, arguments, _, _ in let args = try MapDecoder().decode(EchoArgs.self, from: arguments) @@ -1232,12 +1235,12 @@ class InputTests : XCTestCase { ), types: [EchoInputType, EchoOutputType] ) - + let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) } - + // Undefined with default gets default XCTAssertEqual( try graphql( @@ -1258,7 +1261,7 @@ class InputTests : XCTestCase { "echo": [ "field1": "value1", "field2": "value2", - ] + ], ]) ) // Null literal with default gets null @@ -1282,10 +1285,10 @@ class InputTests : XCTestCase { "echo": [ "field1": "value1", "field2": nil, - ] + ], ]) ) - + // Test in variable // Undefined with default gets default XCTAssertEqual( @@ -1302,15 +1305,15 @@ class InputTests : XCTestCase { eventLoopGroup: group, variableValues: [ "input": [ - "field1": "value1" - ] + "field1": "value1", + ], ] ).wait(), GraphQLResult(data: [ "echo": [ "field1": "value1", "field2": "value2", - ] + ], ]) ) // Null literal with default gets null @@ -1329,15 +1332,15 @@ class InputTests : XCTestCase { variableValues: [ "input": [ "field1": "value1", - "field2": .null - ] + "field2": .null, + ], ] ).wait(), GraphQLResult(data: [ "echo": [ "field1": "value1", "field2": nil, - ] + ], ]) ) } diff --git a/Tests/GraphQLTests/InstrumentationTests/InstrumentationTests.swift b/Tests/GraphQLTests/InstrumentationTests/InstrumentationTests.swift index d26a2a82..f6811e58 100644 --- a/Tests/GraphQLTests/InstrumentationTests/InstrumentationTests.swift +++ b/Tests/GraphQLTests/InstrumentationTests/InstrumentationTests.swift @@ -1,19 +1,18 @@ -import Foundation import Dispatch +import Foundation import GraphQL -import XCTest import NIO +import XCTest -class InstrumentationTests : XCTestCase, Instrumentation { - +class InstrumentationTests: XCTestCase, Instrumentation { class MyRoot {} class MyCtx {} var query = "query sayHello($name: String) { hello(name: $name) }" var expectedResult: Map = [ "data": [ - "hello": "bob" - ] + "hello": "bob", + ], ] var expectedThreadId = 0 var expectedProcessId = 0 @@ -33,14 +32,14 @@ class InstrumentationTests : XCTestCase, Instrumentation { "hello": GraphQLField( type: GraphQLString, args: [ - "name": GraphQLArgument(type: GraphQLNonNull(GraphQLString)) + "name": GraphQLArgument(type: GraphQLNonNull(GraphQLString)), ], resolve: { inputValue, _, _, _ in print(type(of: inputValue)) return nil } // resolve: { _, args, _, _ in return try! args["name"].asString() } - ) + ), ] ) ) @@ -54,7 +53,14 @@ class InstrumentationTests : XCTestCase, Instrumentation { fieldResolutionCalled = 0 } - func queryParsing(processId: Int, threadId: Int, started: DispatchTime, finished: DispatchTime, source: Source, result: Result) { + func queryParsing( + processId _: Int, + threadId _: Int, + started _: DispatchTime, + finished _: DispatchTime, + source _: Source, + result _: Result + ) { // queryParsingCalled += 1 // XCTAssertEqual(processId, expectedProcessId, "unexpected process id") // XCTAssertEqual(threadId, expectedThreadId, "unexpected thread id") @@ -69,7 +75,15 @@ class InstrumentationTests : XCTestCase, Instrumentation { // XCTAssertEqual(source.name, "GraphQL request") } - func queryValidation(processId: Int, threadId: Int, started: DispatchTime, finished: DispatchTime, schema: GraphQLSchema, document: Document, errors: [GraphQLError]) { + func queryValidation( + processId _: Int, + threadId _: Int, + started _: DispatchTime, + finished _: DispatchTime, + schema _: GraphQLSchema, + document _: Document, + errors _: [GraphQLError] + ) { queryValidationCalled += 1 // XCTAssertEqual(processId, expectedProcessId, "unexpected process id") // XCTAssertEqual(threadId, expectedThreadId, "unexpected thread id") @@ -79,7 +93,20 @@ class InstrumentationTests : XCTestCase, Instrumentation { // XCTAssertEqual(errors, []) } - func operationExecution(processId: Int, threadId: Int, started: DispatchTime, finished: DispatchTime, schema: GraphQLSchema, document: Document, rootValue: Any, eventLoopGroup: EventLoopGroup, variableValues: [String : Map], operation: OperationDefinition?, errors: [GraphQLError], result: Map) { + func operationExecution( + processId _: Int, + threadId _: Int, + started _: DispatchTime, + finished _: DispatchTime, + schema _: GraphQLSchema, + document _: Document, + rootValue _: Any, + eventLoopGroup _: EventLoopGroup, + variableValues _: [String: Map], + operation _: OperationDefinition?, + errors _: [GraphQLError], + result _: Map + ) { // operationExecutionCalled += 1 // XCTAssertEqual(processId, expectedProcessId, "unexpected process id") // XCTAssertEqual(threadId, expectedThreadId, "unexpected thread id") @@ -94,7 +121,17 @@ class InstrumentationTests : XCTestCase, Instrumentation { // XCTAssertEqual(result, expectedResult) } - func fieldResolution(processId: Int, threadId: Int, started: DispatchTime, finished: DispatchTime, source: Any, args: Map, eventLoopGroup: EventLoopGroup, info: GraphQLResolveInfo, result: Result, Error>) { + func fieldResolution( + processId _: Int, + threadId _: Int, + started _: DispatchTime, + finished _: DispatchTime, + source _: Any, + args _: Map, + eventLoopGroup _: EventLoopGroup, + info _: GraphQLResolveInfo, + result _: Result, Error> + ) { fieldResolutionCalled += 1 // XCTAssertEqual(processId, expectedProcessId, "unexpected process id") // XCTAssertEqual(threadId, expectedThreadId, "unexpected thread id") @@ -157,5 +194,4 @@ class InstrumentationTests : XCTestCase, Instrumentation { // XCTAssertEqual(operationExecutionCalled, 1) // XCTAssertEqual(fieldResolutionCalled, 1) } - } diff --git a/Tests/GraphQLTests/LanguageTests/LexerTests.swift b/Tests/GraphQLTests/LanguageTests/LexerTests.swift index 4cbd169b..5b20744d 100644 --- a/Tests/GraphQLTests/LanguageTests/LexerTests.swift +++ b/Tests/GraphQLTests/LanguageTests/LexerTests.swift @@ -1,12 +1,12 @@ -import XCTest @testable import GraphQL +import XCTest func lexOne(_ string: String) throws -> Token { let lexer = createLexer(source: Source(body: string)) return try lexer.advance() } -class LexerTests : XCTestCase { +class LexerTests: XCTestCase { func testInvalidCharacter() throws { XCTAssertThrowsError(try lexOne("\u{0007}")) // 'Syntax Error GraphQL (1:1) Invalid character "\\u0007"' @@ -49,7 +49,13 @@ class LexerTests : XCTestCase { } func testSkipsWhitespace() throws { - let token = try lexOne("\n\n foo\n\n") + let token = try lexOne(""" + + + foo + + + """) let expected = Token( kind: .name, @@ -64,7 +70,10 @@ class LexerTests : XCTestCase { } func testSkipsComments() throws { - let token = try lexOne(" #comment\r\n foo#comment") + let token = try lexOne(""" + #comment\r + foo#comment + """) let expected = Token( kind: .name, @@ -94,7 +103,13 @@ class LexerTests : XCTestCase { } func testErrorsRespectWhitespaces() throws { - XCTAssertThrowsError(try lexOne("\n\n?\n\n")) + XCTAssertThrowsError(try lexOne(""" + + + ? + + + """)) // 'Syntax Error GraphQL (3:5) Unexpected character "?".\n' + // '\n' + // '2: \n' + @@ -201,10 +216,10 @@ class LexerTests : XCTestCase { func testLongStrings() throws { measure { - let token = try! lexOne("\"\(String(repeating: "123456", count: 10_000))\"") + let token = try! lexOne("\"\(String(repeating: "123456", count: 10000))\"") XCTAssertEqual(token.start, 0) - XCTAssertEqual(token.end, 60_002) + XCTAssertEqual(token.end, 60002) } } @@ -218,7 +233,10 @@ class LexerTests : XCTestCase { XCTAssertThrowsError(try lexOne("\"null-byte is not \u{0000} end of file\"")) // "Syntax Error GraphQL (1:19) Invalid character within String: "\\u0000"." - XCTAssertThrowsError(try lexOne("\"multi\nline\"")) + XCTAssertThrowsError(try lexOne(""" + "multi + line" + """)) // "Syntax Error GraphQL (1:7) Unterminated string" XCTAssertThrowsError(try lexOne("\"multi\rline\"")) @@ -700,7 +718,12 @@ class LexerTests : XCTestCase { } func testDoubleLinkedList() throws { - let q = "{\n #comment\n field\n }" + let q = """ + { + #comment + field + } + """ let lexer = createLexer(source: Source(body: q)) let startToken = lexer.token @@ -709,7 +732,8 @@ class LexerTests : XCTestCase { repeat { endToken = try lexer.advance() XCTAssertNotEqual(endToken.kind, .comment) - } while endToken.kind != .eof + } while + endToken.kind != .eof XCTAssertEqual(startToken.prev, nil) XCTAssertEqual(endToken.next, nil) @@ -736,10 +760,10 @@ class LexerTests : XCTestCase { .comment, .name, .closingBrace, - .eof + .eof, ] - XCTAssertEqual(tokens.map({ $0.kind }), expectedKinds) + XCTAssertEqual(tokens.map { $0.kind }, expectedKinds) } // @@ -747,60 +771,141 @@ class LexerTests : XCTestCase { // func testBlockStringIndentAndBlankLine() throws { - let rawString = "\n\n\n TopLevel {\n indented\n alsoIndented\n }\n\n\n\t\t\n" + let rawString = + """ + + + + TopLevel { + indented + alsoIndented + } + + + \t\t + + """ let cleanedString = blockStringValue(rawValue: rawString) - - XCTAssertEqual(cleanedString, "TopLevel {\n indented\n alsoIndented\n}") + + XCTAssertEqual(cleanedString, """ + TopLevel { + indented + alsoIndented + } + """) } - + func testBlockStringDoubleIndentAndBlankLine() throws { - let rawString = "\n\n\n TopLevel {\n indented: {\n foo: String\n }\n alsoIndented\n }\n\n\n\t\t\n" + let rawString = + """ + + + + TopLevel { + indented: { + foo: String + } + alsoIndented + } + + + \t\t + + """ let cleanedString = blockStringValue(rawValue: rawString) - - XCTAssertEqual(cleanedString, "TopLevel {\n indented: {\n foo: String\n }\n alsoIndented\n}") + + XCTAssertEqual( + cleanedString, + """ + TopLevel { + indented: { + foo: String + } + alsoIndented + } + """ + ) } func testBlockStringIndentAndBlankLineFirstLineNotIndent() throws { - let rawString = "\n\n\nTopLevel {\n indented\n alsoIndented\n}\n\n\n\t\t\n" + let rawString = """ + + + + TopLevel { + indented + alsoIndented + } + + + \t\t + + """ let cleanedString = blockStringValue(rawValue: rawString) - - XCTAssertEqual(cleanedString, "TopLevel {\n indented\n alsoIndented\n}") + + XCTAssertEqual(cleanedString, """ + TopLevel { + indented + alsoIndented + } + """) } func testBlockStringIndentBlankLineFirstLineNotIndentWeird() throws { let rawString = """ - - - TopLevel { - indented - alsoIndented - } - - - \t - """ + + + TopLevel { + indented + alsoIndented + } + + + \t + """ let cleanedString = blockStringValue(rawValue: rawString) - - XCTAssertEqual(cleanedString, "TopLevel {\n indented\n alsoIndented\n}") + + XCTAssertEqual(cleanedString, """ + TopLevel { + indented + alsoIndented + } + """) } func testBlockStringIndentMultilineWithSingleSpaceIndent() throws { - let rawString = " Multi-line string\n With Inner \"foo\" \n should be Valid " + let rawString = """ + Multi-line string + With Inner \"foo\" + should be Valid + """ let cleanedString = blockStringValue(rawValue: rawString) - - XCTAssertEqual(cleanedString, " Multi-line string\nWith Inner \"foo\" \nshould be Valid ") + + XCTAssertEqual(cleanedString, """ + Multi-line string + With Inner \"foo\" + should be Valid + """) } - + func testBlockStringIndentMultilineWithSingleSpaceIndentExtraLines() throws { - let rawString = "\n Multi-line string\n With Inner \"foo\" \n should be Valid \n" + let rawString = """ + + Multi-line string + With Inner \"foo\" + should be Valid + """ let cleanedString = blockStringValue(rawValue: rawString) - - XCTAssertEqual(cleanedString, "Multi-line string\nWith Inner \"foo\" \nshould be Valid ") + + XCTAssertEqual(cleanedString, """ + Multi-line string + With Inner \"foo\" + should be Valid + """) } - - + // Lexer tests for Blockstring token parsing - + func testBlockStrings() throws { let token = try lexOne(#" """ Multi-line string\n With Inner "foo" \nshould be Valid """ "#) let expected = Token( @@ -812,72 +917,121 @@ class LexerTests : XCTestCase { value: " Multi-line string\\n With Inner \"foo\" \\nshould be Valid " ) - XCTAssertEqual(token, expected, "\nexpected: \n \(dump(expected))\n\ngot: \n\(dump(token))\n") + XCTAssertEqual( + token, + expected, + """ + + expected: + \(dump(expected)) + + got: + \(dump(token)) + + """ + ) } func testBlockStringSingleSpaceIndent() throws { let token = try lexOne(#""" - """ - Multi-line string - With Inner "foo" - should be Valid - """ - """#) + """ + Multi-line string + With Inner "foo" + should be Valid + """ + """#) let expected = Token( kind: .blockstring, start: 0, end: 61, line: 1, column: 1, - value: "Multi-line string\nWith Inner \"foo\"\nshould be Valid" + value: """ + Multi-line string + With Inner \"foo\" + should be Valid + """ ) - XCTAssertEqual(token, expected, "\nexpected: \n \(dump(expected))\n\ngot: \n\(dump(token))\n") + XCTAssertEqual( + token, + expected, + """ + + expected: + \(dump(expected)) + + got: + \(dump(token)) + + """ + ) } func testBlockStringUnescapedReturns() throws { let token = try lexOne(#""" - """ - Multi-line string - with Inner "foo" - should be valid - """ - """#) - + """ + Multi-line string + with Inner "foo" + should be valid + """ + """#) + let expected = Token( kind: .blockstring, start: 0, end: 59, line: 1, column: 1, - value: " Multi-line string\nwith Inner \"foo\"\nshould be valid" + value: """ + Multi-line string + with Inner "foo" + should be valid + """ ) - XCTAssertEqual(token, expected, "expected: \n \(dump(expected))\ngot: \n\(dump(token))\n") + XCTAssertEqual(token, expected, """ + expected: + \(dump(expected)) + got: + \(dump(token)) + + """) } func testBlockStringUnescapedReturnsIndentTest() throws { let token = try lexOne(#""" - """ - Multi-line string { - with Inner "foo" - should be valid indented - } - """ - """#) - + """ + Multi-line string { + with Inner "foo" + should be valid indented + } + """ + """#) + let expected = Token( kind: .blockstring, start: 0, end: 79, line: 1, column: 1, - value: "Multi-line string {\n with Inner \"foo\"\n should be valid indented\n}" + value: """ + Multi-line string { + with Inner \"foo\" + should be valid indented + } + """ ) - - XCTAssertEqual(token, expected, "expected: \n \(dump(expected))\ngot: \n\(dump(token))\n") + + XCTAssertEqual(token, expected, """ + expected: + \(dump(expected)) + got: + \(dump(token)) + + """) } - + func testIndentedBlockStringWithIndents() throws { let sourceStr = #""" @@ -888,55 +1042,91 @@ class LexerTests : XCTestCase { } """ """# - + let token = try lexOne(sourceStr) - + let expected = Token( kind: .blockstring, start: 4, end: 103, line: 1, column: 5, - value: "Multi-line string {\n with Inner \"foo\"\n should be valid indented\n}" + value: """ + Multi-line string { + with Inner \"foo\" + should be valid indented + } + """ ) - + print(sourceStr) - - XCTAssertEqual(token, expected, "expected: \n \(dump(expected))\ngot: \n\(dump(token))\n") - } + XCTAssertEqual(token, expected, """ + expected: + \(dump(expected)) + got: + \(dump(token)) + + """) + } // Test empty strings & multi-line string lexer token parsing - + func testEmptyQuote() throws { let token = try lexOne(#" "" "#) let expected = Token(kind: .string, start: 1, end: 3, line: 1, column: 2, value: "") - XCTAssertEqual(token, expected, "\n\(dump(expected))\n\(dump(token))\n") + XCTAssertEqual(token, expected, """ + + \(dump(expected)) + \(dump(token)) + + """) } - + func testEmptySimpleBlockString() throws { let token = try lexOne(#" """""" "#) let expected = Token(kind: .blockstring, start: 1, end: 7, line: 1, column: 2, value: "") - XCTAssertEqual(token, expected, "\n\(dump(expected))\n\(dump(token))\n") + XCTAssertEqual(token, expected, """ + + \(dump(expected)) + \(dump(token)) + + """) } - + func testEmptyTrimmedCharactersBlockString() throws { let token = try lexOne(#""" - """ - """ - """#) + """ + """ + """#) let expected = Token(kind: .blockstring, start: 0, end: 7, line: 1, column: 1, value: "") - XCTAssertEqual(token, expected, "\n\(dump(expected))\n\(dump(token))\n") + XCTAssertEqual(token, expected, """ + + \(dump(expected)) + \(dump(token)) + + """) } - - + func testEscapedTripleQuoteInBlockString() throws { let token = try lexOne(#""" - """ - \""" - """ - """#) - let expected = Token(kind: .blockstring, start: 0, end: 12, line: 1, column: 1, value: "\"\"\"") - XCTAssertEqual(token, expected, "\n\(dump(expected))\n\(dump(token))\n") + """ + \""" + """ + """#) + let expected = Token( + kind: .blockstring, + start: 0, + end: 12, + line: 1, + column: 1, + value: "\"\"\"" + ) + XCTAssertEqual(token, expected, """ + + \(dump(expected)) + \(dump(token)) + + """) } } diff --git a/Tests/GraphQLTests/LanguageTests/ParserTests.swift b/Tests/GraphQLTests/LanguageTests/ParserTests.swift index 49260e86..37aa58a6 100644 --- a/Tests/GraphQLTests/LanguageTests/ParserTests.swift +++ b/Tests/GraphQLTests/LanguageTests/ParserTests.swift @@ -1,7 +1,7 @@ -import XCTest @testable import GraphQL +import XCTest -class ParserTests : XCTestCase { +class ParserTests: XCTestCase { func testErrorMessages() throws { var source: String @@ -10,10 +10,15 @@ class ParserTests : XCTestCase { return XCTFail() } - XCTAssertEqual(error.message, - "Syntax Error GraphQL (1:2) Expected Name, found \n\n" + - " 1: {\n" + - " ^\n" + XCTAssertEqual( + error.message, + """ + Syntax Error GraphQL (1:2) Expected Name, found + + 1: { + ^ + + """ ) XCTAssertEqual(error.positions, [1]) @@ -61,7 +66,10 @@ class ParserTests : XCTestCase { )) } - XCTAssertThrowsError(try parse(source: Source(body: "query", name: "MyQuery.graphql"))) { error in + XCTAssertThrowsError(try parse(source: Source( + body: "query", + name: "MyQuery.graphql" + ))) { error in guard let error = error as? GraphQLError else { return XCTFail() } @@ -102,7 +110,6 @@ class ParserTests : XCTestCase { "Syntax Error GraphQL (1:9) Expected Name, found }" )) } - } func testVariableInlineValues() throws { @@ -135,7 +142,7 @@ class ParserTests : XCTestCase { Argument( name: Name(value: "stringArg"), value: StringValue(value: "Hello World", block: false) - ) + ), ] ), Field( @@ -144,7 +151,7 @@ class ParserTests : XCTestCase { Argument( name: Name(value: "intArg"), value: IntValue(value: "1") - ) + ), ] ), Field( @@ -153,7 +160,7 @@ class ParserTests : XCTestCase { Argument( name: Name(value: "floatArg"), value: FloatValue(value: "3.14") - ) + ), ] ), Field( @@ -162,7 +169,7 @@ class ParserTests : XCTestCase { Argument( name: Name(value: "boolArg"), value: BooleanValue(value: false) - ) + ), ] ), Field( @@ -171,7 +178,7 @@ class ParserTests : XCTestCase { Argument( name: Name(value: "boolArg"), value: BooleanValue(value: true) - ) + ), ] ), Field( @@ -180,7 +187,7 @@ class ParserTests : XCTestCase { Argument( name: Name(value: "value"), value: NullValue() - ) + ), ] ), Field( @@ -189,7 +196,7 @@ class ParserTests : XCTestCase { Argument( name: Name(value: "enumArg"), value: EnumValue(value: "VALUE") - ) + ), ] ), Field( @@ -211,7 +218,7 @@ class ParserTests : XCTestCase { ), ] ) - ) + ), ] ) @@ -240,7 +247,7 @@ class ParserTests : XCTestCase { // } // } ] // }); -// }); + // }); func testKitchenSink() throws { // let path = "/Users/paulofaria/Development/Zewo/GraphQL/Tests/GraphQLTests/LanguageTests/kitchen-sink.graphql" @@ -256,7 +263,7 @@ class ParserTests : XCTestCase { "mutation", "subscription", "true", - "false" + "false", ] for nonKeyword in nonKeywords { @@ -266,52 +273,57 @@ class ParserTests : XCTestCase { fragmentName = "a" } - _ = try parse(source: "query \(nonKeyword) {" + - "... \(fragmentName)" + - "... on \(nonKeyword) { field }" + - "}" + - "fragment \(fragmentName) on Type {" + - "\(nonKeyword)(\(nonKeyword): $\(nonKeyword)) @\(nonKeyword)(\(nonKeyword): \(nonKeyword))" + - "}" + _ = try parse( + source: "query \(nonKeyword) {" + + "... \(fragmentName)" + + "... on \(nonKeyword) { field }" + + "}" + + "fragment \(fragmentName) on Type {" + + "\(nonKeyword)(\(nonKeyword): $\(nonKeyword)) @\(nonKeyword)(\(nonKeyword): \(nonKeyword))" + + "}" ) } } func testAnonymousMutationOperation() throws { - _ = try parse(source: "mutation {" + - " mutationField" + - "}" + _ = try parse( + source: "mutation {" + + " mutationField" + + "}" ) } func testAnonymousSubscriptionOperation() throws { - _ = try parse(source: "subscription {" + - " subscriptionField" + - "}" + _ = try parse( + source: "subscription {" + + " subscriptionField" + + "}" ) } func testNamedMutationOperation() throws { - _ = try parse(source: "mutation Foo {" + - " mutationField" + - "}" + _ = try parse( + source: "mutation Foo {" + + " mutationField" + + "}" ) } func testNamedSubscriptionOperation() throws { - _ = try parse(source: "subscription Foo {" + - " subscriptionField" + - "}" + _ = try parse( + source: "subscription Foo {" + + " subscriptionField" + + "}" ) } func testCreateAST() throws { let query = "{" + - " node(id: 4) {" + - " id," + - " name" + - " }" + - "}" + " node(id: 4) {" + + " id," + + " name" + + " }" + + "}" let expected = Document( definitions: [ @@ -325,18 +337,18 @@ class ParserTests : XCTestCase { Argument( name: Name(value: "id"), value: IntValue(value: "4") - ) + ), ], selectionSet: SelectionSet( selections: [ Field(name: Name(value: "id")), - Field(name: Name(value: "name")) + Field(name: Name(value: "name")), ] ) - ) + ), ] ) - ) + ), ] ) @@ -367,7 +379,7 @@ class ParserTests : XCTestCase { let expected: Value = ListValue( values: [ IntValue(value: "123"), - StringValue(value: "abc", block: false) + StringValue(value: "abc", block: false), ] ) @@ -441,16 +453,19 @@ class ParserTests : XCTestCase { name: Name(value: "restricted"), arguments: [ InputValueDefinition( - description: StringValue(value: "The reason for this restriction", block: true), + description: StringValue( + value: "The reason for this restriction", + block: true + ), 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/SchemaParserTests.swift b/Tests/GraphQLTests/LanguageTests/SchemaParserTests.swift index 3a31e617..5ae0cf40 100644 --- a/Tests/GraphQLTests/LanguageTests/SchemaParserTests.swift +++ b/Tests/GraphQLTests/LanguageTests/SchemaParserTests.swift @@ -1,5 +1,5 @@ -import XCTest @testable import GraphQL +import XCTest func nameNode(_ name: String) -> Name { return Name(value: name) @@ -9,7 +9,11 @@ func fieldNode(_ name: Name, _ type: Type) -> FieldDefinition { return FieldDefinition(name: name, type: type) } -func fieldNodeWithDescription(_ description: StringValue? = nil, _ name: Name, _ type: Type) -> FieldDefinition { +func fieldNodeWithDescription( + _ description: StringValue? = nil, + _ name: Name, + _ type: Type +) -> FieldDefinition { return FieldDefinition(description: description, name: name, type: type) } @@ -21,30 +25,48 @@ func enumValueNode(_ name: String) -> EnumValueDefinition { return EnumValueDefinition(name: nameNode(name)) } -func enumValueWithDescriptionNode(_ description: StringValue?, _ name: String) -> EnumValueDefinition { +func enumValueWithDescriptionNode( + _ description: StringValue?, + _ name: String +) -> EnumValueDefinition { return EnumValueDefinition(description: description, name: nameNode(name)) } -func fieldNodeWithArgs(_ name: Name, _ type: Type, _ args: [InputValueDefinition]) -> FieldDefinition { +func fieldNodeWithArgs( + _ name: Name, + _ type: Type, + _ args: [InputValueDefinition] +) -> FieldDefinition { return FieldDefinition(name: name, arguments: args, type: type) } -func inputValueNode(_ name: Name, _ type: Type, _ defaultValue: Value? = nil) -> InputValueDefinition { +func inputValueNode( + _ name: Name, + _ type: Type, + _ defaultValue: Value? = nil +) -> InputValueDefinition { return InputValueDefinition(name: name, type: type, defaultValue: defaultValue) } -func inputValueWithDescriptionNode(_ description: StringValue?, - _ name: Name, - _ type: Type, - _ defaultValue: Value? = nil) -> InputValueDefinition { - return InputValueDefinition(description: description, name: name, type: type, defaultValue: defaultValue) +func inputValueWithDescriptionNode( + _ description: StringValue?, + _ name: Name, + _ type: Type, + _ defaultValue: Value? = nil +) -> InputValueDefinition { + return InputValueDefinition( + description: description, + name: name, + type: type, + defaultValue: defaultValue + ) } -func namedTypeNode(_ name: String ) -> NamedType { +func namedTypeNode(_ name: String) -> NamedType { return NamedType(name: nameNode(name)) } -class SchemaParserTests : XCTestCase { +class SchemaParserTests: XCTestCase { func testSimpleType() throws { let source = "type Hello { world: String }" @@ -56,9 +78,9 @@ class SchemaParserTests : XCTestCase { fieldNode( nameNode("world"), typeNode("String") - ) + ), ] - ) + ), ] ) @@ -78,10 +100,10 @@ class SchemaParserTests : XCTestCase { fieldNode( nameNode("world"), typeNode("String") - ) + ), ] ) - ) + ), ] ) @@ -102,9 +124,9 @@ class SchemaParserTests : XCTestCase { NonNullType( type: typeNode("String") ) - ) + ), ] - ) + ), ] ) @@ -120,7 +142,7 @@ class SchemaParserTests : XCTestCase { ObjectTypeDefinition( name: nameNode("Hello"), interfaces: [typeNode("World")] - ) + ), ] ) @@ -139,7 +161,7 @@ class SchemaParserTests : XCTestCase { typeNode("Wo"), typeNode("rld"), ] - ) + ), ] ) @@ -157,7 +179,7 @@ class SchemaParserTests : XCTestCase { values: [ enumValueNode("WORLD"), ] - ) + ), ] ) @@ -176,7 +198,7 @@ class SchemaParserTests : XCTestCase { enumValueNode("WO"), enumValueNode("RLD"), ] - ) + ), ] ) @@ -195,9 +217,9 @@ class SchemaParserTests : XCTestCase { fieldNode( nameNode("world"), typeNode("String") - ) + ), ] - ) + ), ] ) @@ -220,11 +242,11 @@ class SchemaParserTests : XCTestCase { inputValueNode( nameNode("flag"), typeNode("Boolean") - ) + ), ] - ) + ), ] - ) + ), ] ) @@ -248,11 +270,11 @@ class SchemaParserTests : XCTestCase { nameNode("flag"), typeNode("Boolean"), BooleanValue(value: true) - ) + ), ] - ) + ), ] - ) + ), ] ) @@ -275,11 +297,11 @@ class SchemaParserTests : XCTestCase { inputValueNode( nameNode("things"), ListType(type: typeNode("String")) - ) + ), ] - ) + ), ] - ) + ), ] ) @@ -306,11 +328,11 @@ class SchemaParserTests : XCTestCase { inputValueNode( nameNode("argTwo"), typeNode("Int") - ) + ), ] - ) + ), ] - ) + ), ] ) @@ -328,7 +350,7 @@ class SchemaParserTests : XCTestCase { types: [ typeNode("World"), ] - ) + ), ] ) @@ -347,7 +369,7 @@ class SchemaParserTests : XCTestCase { typeNode("Wo"), typeNode("Rld"), ] - ) + ), ] ) @@ -362,7 +384,7 @@ class SchemaParserTests : XCTestCase { definitions: [ ScalarTypeDefinition( name: nameNode("Hello") - ) + ), ] ) @@ -381,9 +403,9 @@ class SchemaParserTests : XCTestCase { inputValueNode( nameNode("world"), typeNode("String") - ) + ), ] - ) + ), ] ) @@ -395,27 +417,27 @@ class SchemaParserTests : XCTestCase { let source = "input Hello { world(foo: Int): String }" XCTAssertThrowsError(try parse(source: source)) } - + func testSimpleSchema() throws { let source = "schema { query: Hello }" let expected = SchemaDefinition( - directives: [], - operationTypes: [ - OperationTypeDefinition( - operation: .query, - type: namedTypeNode("Hello") - ) - ] - ) + directives: [], + operationTypes: [ + OperationTypeDefinition( + operation: .query, + type: namedTypeNode("Hello") + ), + ] + ) let result = try parse(source: source) XCTAssert(result.definitions[0] == expected) } // Description tests - + func testTypeWithDescription() throws { let source = #""The Hello type" type Hello { world: String }"# - + let expected = ObjectTypeDefinition( description: StringValue(value: "The Hello type", block: false), name: nameNode("Hello"), @@ -423,102 +445,122 @@ class SchemaParserTests : XCTestCase { fieldNode( nameNode("world"), typeNode("String") - ) + ), ] ) - + let result = try parse(source: source) let firstDefinition = try XCTUnwrap(result.definitions[0] as? ObjectTypeDefinition) - XCTAssertEqual(firstDefinition, expected, "\n\(dump(firstDefinition))\n\(dump(expected))\n") + XCTAssertEqual( + firstDefinition, + expected, + """ + \(dump(firstDefinition)) + \(dump(expected)) + """ + ) } - + func testTypeWitMultilinehDescription() 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: [ ObjectTypeDefinition( - description: StringValue(value:"The Hello type.\nMulti-line description", block: true), + description: StringValue( + value: "The Hello type.\nMulti-line description", + block: true + ), name: nameNode("Hello"), fields: [ fieldNode( nameNode("world"), typeNode("String") - ) + ), ] - ) + ), ] ) - + let result = try parse(source: source) XCTAssert(result == expected) } - + func testDirectiveDesciption() throws { let source = #""directive description" directive @Test(a: String = "hello") on FIELD"# - - let expected: Document = Document( + + let expected = Document( definitions: [ - DirectiveDefinition(loc: nil, - description: StringValue(value: "directive description", block: false), - name: nameNode("Test"), - arguments: [ - inputValueNode( - nameNode("a"), - typeNode("String"), - StringValue(value: "hello", block: false) - ) - ], - locations: [ - nameNode("FIELD") - ]) + DirectiveDefinition( + loc: nil, + description: StringValue( + value: "directive description", + block: false + ), + name: nameNode("Test"), + arguments: [ + inputValueNode( + nameNode("a"), + typeNode("String"), + StringValue(value: "hello", block: false) + ), + ], + locations: [ + nameNode("FIELD"), + ] + ), ] ) - + let result = try parse(source: source) XCTAssert(result == expected) } - + func testDirectiveMultilineDesciption() throws { let source = #""" - """ - directive description - """ - directive @Test(a: String = "hello") on FIELD - """# - let expected: Document = Document( + """ + directive description + """ + directive @Test(a: String = "hello") on FIELD + """# + let expected = Document( definitions: [ - DirectiveDefinition(loc: nil, - description: StringValue(value: "directive description", block: true), - name: nameNode("Test"), - arguments: [ - inputValueNode( - nameNode("a"), - typeNode("String"), - StringValue(value: "hello", block: false) - ) - ], - locations: [ - nameNode("FIELD") - ]) + DirectiveDefinition( + loc: nil, + description: StringValue( + value: "directive description", + block: true + ), + name: nameNode("Test"), + arguments: [ + inputValueNode( + nameNode("a"), + typeNode("String"), + StringValue(value: "hello", block: false) + ), + ], + locations: [ + nameNode("FIELD"), + ] + ), ] ) - + let result = try parse(source: source) XCTAssert(result == expected) } - + func testSimpleSchemaWithDescription() throws { let source = #""Hello Schema" schema { query: Hello } "# - + let expected = SchemaDefinition( description: StringValue(value: "Hello Schema", block: false), directives: [], @@ -526,32 +568,32 @@ class SchemaParserTests : XCTestCase { OperationTypeDefinition( operation: .query, type: namedTypeNode("Hello") - ) + ), ] ) let result = try parse(source: source) XCTAssert(result.definitions[0] == expected) } - + func testScalarWithDescription() throws { let source = #""Hello Scaler Test" scalar Hello"# - + let expected = Document( definitions: [ ScalarTypeDefinition( description: StringValue(value: "Hello Scaler Test", block: false), name: nameNode("Hello") - ) + ), ] ) - + let result = try parse(source: source) XCTAssert(result == expected) } - + func testSimpleInterfaceWithDescription() throws { let source = #""Hello World Interface" interface Hello { world: String } "# - + let expected = Document( definitions: [ InterfaceTypeDefinition( @@ -561,19 +603,19 @@ class SchemaParserTests : XCTestCase { fieldNode( nameNode("world"), typeNode("String") - ) + ), ] - ) + ), ] ) - + let result = try parse(source: source) XCTAssert(result == expected) } - + func testSimpleUnionWithDescription() throws { let source = #""Hello World Union!" union Hello = World "# - + let expected = Document( definitions: [ UnionTypeDefinition( @@ -582,17 +624,17 @@ class SchemaParserTests : XCTestCase { types: [ typeNode("World"), ] - ) + ), ] ) - + let result = try parse(source: source) XCTAssert(result == expected) } - + func testSingleValueEnumDescription() throws { let source = #""Hello World Enum..." enum Hello { WORLD } "# - + let expected = Document( definitions: [ EnumTypeDefinition( @@ -601,17 +643,17 @@ class SchemaParserTests : XCTestCase { values: [ enumValueNode("WORLD"), ] - ) + ), ] ) - + let result = try parse(source: source) XCTAssert(result == expected) } - + func testSimpleInputObjectWithDescription() throws { let source = #""Hello Input Object" input Hello { world: String }"# - + let expected = Document( definitions: [ InputObjectTypeDefinition( @@ -621,47 +663,53 @@ class SchemaParserTests : XCTestCase { inputValueNode( nameNode("world"), typeNode("String") - ) + ), ] - ) + ), ] ) - + let result = try parse(source: source) XCTAssert(result == expected) } - + // Test Fields and values with optional descriptions - + func testSingleValueEnumWithDescription() throws { let source = """ - enum Hello { - "world description" - WORLD - "Hello there" - HELLO - } - """ - + enum Hello { + "world description" + WORLD + "Hello there" + HELLO + } + """ + let expected = Document( definitions: [ EnumTypeDefinition( name: nameNode("Hello"), values: [ - enumValueWithDescriptionNode(StringValue(value: "world description", block: false), "WORLD"), - enumValueWithDescriptionNode(StringValue(value: "Hello there", block: false), "HELLO") + enumValueWithDescriptionNode( + StringValue(value: "world description", block: false), + "WORLD" + ), + enumValueWithDescriptionNode( + StringValue(value: "Hello there", block: false), + "HELLO" + ), ] - ) + ), ] ) - + let result = try parse(source: source) XCTAssert(result == expected) } - + func testTypeFieldWithDescription() throws { let source = #"type Hello { "The world field." world: String } "# - + let expected = Document( definitions: [ ObjectTypeDefinition( @@ -671,27 +719,27 @@ class SchemaParserTests : XCTestCase { StringValue(value: "The world field.", block: false), nameNode("world"), typeNode("String") - ) + ), ] - ) + ), ] ) - + let result = try parse(source: source) XCTAssert(result == expected) } func testTypeFieldWithMultilineDescription() throws { let source = #""" - type Hello { - """ - The world - field. - """ - world: String - } - """# - + type Hello { + """ + The world + field. + """ + world: String + } + """# + let expected = Document( definitions: [ ObjectTypeDefinition( @@ -701,20 +749,19 @@ class SchemaParserTests : XCTestCase { StringValue(value: "The world\nfield.", block: true), nameNode("world"), typeNode("String") - ) + ), ] - ) + ), ] ) - + let result = try parse(source: source) XCTAssert(result == expected, "\(dump(result)) \n\n\(dump(expected))") } - func testSimpleInputObjectFieldWithDescription() throws { let source = #"input Hello { "World field" world: String }"# - + let expected = Document( definitions: [ InputObjectTypeDefinition( @@ -724,14 +771,13 @@ class SchemaParserTests : XCTestCase { StringValue(value: "World field", block: false), nameNode("world"), typeNode("String") - ) + ), ] - ) + ), ] ) - + let result = try parse(source: source) XCTAssert(result == expected) } - } diff --git a/Tests/GraphQLTests/LanguageTests/VisitorTests.swift b/Tests/GraphQLTests/LanguageTests/VisitorTests.swift index 198d11d9..858748d6 100644 --- a/Tests/GraphQLTests/LanguageTests/VisitorTests.swift +++ b/Tests/GraphQLTests/LanguageTests/VisitorTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import GraphQL +import XCTest -class VisitorTests : XCTestCase { - func test() throws { - } +class VisitorTests: XCTestCase { + func test() throws {} } diff --git a/Tests/GraphQLTests/MapTests/MapTests.swift b/Tests/GraphQLTests/MapTests/MapTests.swift index f78c31e4..a2b8431e 100644 --- a/Tests/GraphQLTests/MapTests/MapTests.swift +++ b/Tests/GraphQLTests/MapTests/MapTests.swift @@ -37,7 +37,7 @@ class MapTests: XCTestCase { "second": .number(4), "third": .number(9), "fourth": .null, - "fifth": .undefined + "fifth": .undefined, ] ) XCTAssertEqual(map.dictionary?.count, 5) @@ -51,42 +51,42 @@ class MapTests: XCTestCase { XCTAssertEqual(dictionary["fourth"]?.isNull, true) XCTAssertEqual(dictionary["fifth"]?.isUndefined, true) } - + // Ensure that default decoding preserves undefined becoming nil func testNilAndUndefinedDecodeToNilByDefault() throws { - struct DecodableTest : Codable { + struct DecodableTest: Codable { let first: Int? let second: Int? let third: Int? let fourth: Int? } - + let map = Map.dictionary( [ "first": .number(1), "second": .null, - "third": .undefined + "third": .undefined, // fourth not included ] ) - + let decodable = try MapDecoder().decode(DecodableTest.self, from: map) XCTAssertEqual(decodable.first, 1) XCTAssertEqual(decodable.second, nil) XCTAssertEqual(decodable.third, nil) XCTAssertEqual(decodable.fourth, nil) } - + // Ensure that, if custom decoding is defined, provided nulls and unset values can be differentiated. // This should match JSON in that values set to `null` should be 'contained' by the container, but // values expected by the result that are undefined or not present should not be. func testNilAndUndefinedDecoding() throws { - struct DecodableTest : Codable { + struct DecodableTest: Codable { let first: Int? let second: Int? let third: Int? let fourth: Int? - + init( first: Int?, second: Int?, @@ -98,10 +98,10 @@ class MapTests: XCTestCase { self.third = third self.fourth = fourth } - + init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - + XCTAssertTrue(container.contains(.first)) // Null value should be contained, but decode to nil XCTAssertTrue(container.contains(.second)) @@ -109,36 +109,36 @@ class MapTests: XCTestCase { XCTAssertFalse(container.contains(.third)) // Missing value should operate the same as undefined XCTAssertFalse(container.contains(.fourth)) - + first = try container.decodeIfPresent(Int.self, forKey: .first) second = try container.decodeIfPresent(Int.self, forKey: .second) third = try container.decodeIfPresent(Int.self, forKey: .third) fourth = try container.decodeIfPresent(Int.self, forKey: .fourth) } } - + let map = Map.dictionary( [ "first": .number(1), "second": .null, - "third": .undefined + "third": .undefined, // fourth not included ] ) - + _ = try MapDecoder().decode(DecodableTest.self, from: map) } - + // Ensure that map encoding includes defined nulls, but skips undefined values func testMapEncodingNilAndUndefined() throws { let map = Map.dictionary( [ "first": .number(1), "second": .null, - "third": .undefined + "third": .undefined, ] ) - + let data = try GraphQLJSONEncoder().encode(map) let json = String(data: data, encoding: .utf8) XCTAssertEqual( @@ -148,7 +148,7 @@ class MapTests: XCTestCase { """ ) } - + // Ensure that GraphQLJSONEncoder preserves map dictionary order in output func testMapEncodingOrderPreserved() throws { // Test top level @@ -172,7 +172,7 @@ class MapTests: XCTestCase { {"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8} """ ) - + // Test embedded XCTAssertEqual( String( @@ -187,7 +187,7 @@ class MapTests: XCTestCase { "6": .number(6), "7": .number(7), "8": .number(8), - ]) + ]), ]) ), encoding: .utf8 diff --git a/Tests/GraphQLTests/PersistedQueriesTests/PersistedQueriesTests.swift b/Tests/GraphQLTests/PersistedQueriesTests/PersistedQueriesTests.swift index 562a1ea6..884631cb 100644 --- a/Tests/GraphQLTests/PersistedQueriesTests/PersistedQueriesTests.swift +++ b/Tests/GraphQLTests/PersistedQueriesTests/PersistedQueriesTests.swift @@ -2,7 +2,6 @@ import GraphQL import XCTest class PersistedQueriesTests: XCTestCase { - // let schema = try! GraphQLSchema( // query: GraphQLObjectType( // name: "RootQueryType", @@ -106,9 +105,9 @@ class PersistedQueriesTests: XCTestCase { // XCTAssertEqual(result, expected) // } // -//} + // } // -//extension PersistedQueriesTests: PersistedQueryRetrieval { + // extension PersistedQueriesTests: PersistedQueryRetrieval { // typealias Id = String // // func lookup(_ id: Id) throws -> PersistedQueryRetrievalResult { @@ -136,5 +135,4 @@ class PersistedQueriesTests: XCTestCase { // throw error // } // } - } diff --git a/Tests/GraphQLTests/StarWarsTests/StarWarsData.swift b/Tests/GraphQLTests/StarWarsTests/StarWarsData.swift index e7684243..dce0c18d 100644 --- a/Tests/GraphQLTests/StarWarsTests/StarWarsData.swift +++ b/Tests/GraphQLTests/StarWarsTests/StarWarsData.swift @@ -8,7 +8,7 @@ import GraphQL * values in a more complex demo. */ -enum Episode : String, Encodable { +enum Episode: String, Encodable { case newHope = "NEWHOPE" case empire = "EMPIRE" case jedi = "JEDI" @@ -22,14 +22,14 @@ enum Episode : String, Encodable { } } -protocol Character : Encodable { +protocol Character: Encodable { var id: String { get } var name: String { get } var friends: [String] { get } var appearsIn: [Episode] { get } } -struct Human : Character { +struct Human: Character { let id: String let name: String let friends: [String] @@ -51,7 +51,7 @@ struct Human : Character { } } -struct Droid : Character { +struct Droid: Character { let id: String let name: String let friends: [String] @@ -70,7 +70,7 @@ let luke = Human( let vader = Human( id: "1001", name: "Darth Vader", - friends: [ "1004" ], + friends: ["1004"], appearsIn: [.newHope, .empire, .jedi], homePlanet: "Tatooine" ) @@ -116,7 +116,7 @@ let c3po = Droid( let r2d2 = Droid( id: "2001", name: "R2-D2", - friends: [ "1000", "1002", "1003" ], + friends: ["1000", "1002", "1003"], appearsIn: [.newHope, .empire, .jedi], primaryFunction: "Astromech" ) diff --git a/Tests/GraphQLTests/StarWarsTests/StarWarsIntrospectionTests.swift b/Tests/GraphQLTests/StarWarsTests/StarWarsIntrospectionTests.swift index e48b2d04..ff8b4b5b 100644 --- a/Tests/GraphQLTests/StarWarsTests/StarWarsIntrospectionTests.swift +++ b/Tests/GraphQLTests/StarWarsTests/StarWarsIntrospectionTests.swift @@ -1,9 +1,9 @@ -import XCTest import NIO +import XCTest @testable import GraphQL -class StarWarsIntrospectionTests : XCTestCase { +class StarWarsIntrospectionTests: XCTestCase { func testIntrospectionTypeQuery() throws { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) defer { @@ -11,69 +11,73 @@ class StarWarsIntrospectionTests : XCTestCase { } do { - let query = "query IntrospectionTypeQuery {" + - " __schema {" + - " types {" + - " name" + - " }" + - " }" + - "}" - - let expected = GraphQLResult( - data: [ - "__schema": [ - "types": [ - [ - "name": "Boolean", - ], - [ - "name": "Character", - ], - [ - "name": "Droid", - ], - [ - "name": "Episode", - ], - [ - "name": "Human", - ], - [ - "name": "Query", - ], - [ - "name": "String", - ], - [ - "name": "__Directive", - ], - [ - "name": "__DirectiveLocation", - ], - [ - "name": "__EnumValue", - ], - [ - "name": "__Field", - ], - [ - "name": "__InputValue", - ], - [ - "name": "__Schema", - ], - [ - "name": "__Type", - ], - [ - "name": "__TypeKind", + let query = "query IntrospectionTypeQuery {" + + " __schema {" + + " types {" + + " name" + + " }" + + " }" + + "}" + + let expected = GraphQLResult( + data: [ + "__schema": [ + "types": [ + [ + "name": "Boolean", + ], + [ + "name": "Character", + ], + [ + "name": "Droid", + ], + [ + "name": "Episode", + ], + [ + "name": "Human", + ], + [ + "name": "Query", + ], + [ + "name": "String", + ], + [ + "name": "__Directive", + ], + [ + "name": "__DirectiveLocation", + ], + [ + "name": "__EnumValue", + ], + [ + "name": "__Field", + ], + [ + "name": "__InputValue", + ], + [ + "name": "__Schema", + ], + [ + "name": "__Type", + ], + [ + "name": "__TypeKind", + ], ], ], - ], - ] - ) - - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + ] + ) + + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } catch { print(error) @@ -87,12 +91,12 @@ class StarWarsIntrospectionTests : XCTestCase { } let query = "query IntrospectionQueryTypeQuery {" + - " __schema {" + - " queryType {" + - " name" + - " }" + - " }" + - "}" + " __schema {" + + " queryType {" + + " name" + + " }" + + " }" + + "}" let expected = GraphQLResult( data: [ @@ -104,7 +108,11 @@ class StarWarsIntrospectionTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -115,10 +123,10 @@ class StarWarsIntrospectionTests : XCTestCase { } let query = "query IntrospectionDroidTypeQuery {" + - " __type(name: \"Droid\") {" + - " name" + - " }" + - "}" + " __type(name: \"Droid\") {" + + " name" + + " }" + + "}" let expected = GraphQLResult( data: [ @@ -128,7 +136,11 @@ class StarWarsIntrospectionTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -139,11 +151,11 @@ class StarWarsIntrospectionTests : XCTestCase { } let query = "query IntrospectionDroidKindQuery {" + - " __type(name: \"Droid\") {" + - " name" + - " kind" + - " }" + - "}" + " __type(name: \"Droid\") {" + + " name" + + " kind" + + " }" + + "}" let expected = GraphQLResult( data: [ @@ -154,7 +166,11 @@ class StarWarsIntrospectionTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -165,11 +181,11 @@ class StarWarsIntrospectionTests : XCTestCase { } let query = "query IntrospectionCharacterKindQuery {" + - " __type(name: \"Character\") {" + - " name" + - " kind" + - " }" + - "}" + " __type(name: \"Character\") {" + + " name" + + " kind" + + " }" + + "}" let expected = GraphQLResult( data: [ @@ -180,7 +196,11 @@ class StarWarsIntrospectionTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -191,17 +211,17 @@ class StarWarsIntrospectionTests : XCTestCase { } let query = "query IntrospectionDroidFieldsQuery {" + - " __type(name: \"Droid\") {" + - " name" + - " fields {" + - " name" + - " type {" + - " name" + - " kind" + - " }" + - " }" + - " }" + - "}" + " __type(name: \"Droid\") {" + + " name" + + " fields {" + + " name" + + " type {" + + " name" + + " kind" + + " }" + + " }" + + " }" + + "}" let expected = GraphQLResult( data: [ @@ -255,7 +275,11 @@ class StarWarsIntrospectionTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -266,21 +290,21 @@ class StarWarsIntrospectionTests : XCTestCase { } let query = "query IntrospectionDroidNestedFieldsQuery {" + - " __type(name: \"Droid\") {" + - " name" + - " fields {" + - " name" + - " type {" + - " name" + - " kind" + - " ofType {" + - " name" + - " kind" + - " }" + - " }" + - " }" + - " }" + - "}" + " __type(name: \"Droid\") {" + + " name" + + " fields {" + + " name" + + " type {" + + " name" + + " kind" + + " ofType {" + + " name" + + " kind" + + " }" + + " }" + + " }" + + " }" + + "}" let expected = GraphQLResult( data: [ @@ -349,7 +373,11 @@ class StarWarsIntrospectionTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -360,27 +388,27 @@ class StarWarsIntrospectionTests : XCTestCase { } let query = "query IntrospectionFieldArgsQuery {" + - " __schema {" + - " queryType {" + - " fields {" + - " name" + - " args {" + - " name" + - " description" + - " type {" + - " name" + - " kind" + - " ofType {" + - " name" + - " kind" + - " }" + - " }" + - " defaultValue" + - " }" + - " }" + - " }" + - " }" + - "}" + " __schema {" + + " queryType {" + + " fields {" + + " name" + + " args {" + + " name" + + " description" + + " type {" + + " name" + + " kind" + + " ofType {" + + " name" + + " kind" + + " }" + + " }" + + " defaultValue" + + " }" + + " }" + + " }" + + " }" + + "}" let expected = GraphQLResult( data: [ @@ -399,10 +427,10 @@ class StarWarsIntrospectionTests : XCTestCase { "ofType": [ "name": "String", "kind": "SCALAR", - ] + ], ], "defaultValue": nil, - ], + ], ], ], [ @@ -414,7 +442,7 @@ class StarWarsIntrospectionTests : XCTestCase { "type": [ "name": "Episode", "kind": "ENUM", - "ofType": nil + "ofType": nil, ], "defaultValue": nil, ], @@ -432,7 +460,7 @@ class StarWarsIntrospectionTests : XCTestCase { "ofType": [ "name": "String", "kind": "SCALAR", - ] + ], ], "defaultValue": nil, ], @@ -444,7 +472,11 @@ class StarWarsIntrospectionTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -455,11 +487,11 @@ class StarWarsIntrospectionTests : XCTestCase { } let query = "query IntrospectionDroidDescriptionQuery {" + - " __type(name: \"Droid\") {" + - " name" + - " description" + - " }" + - "}" + " __type(name: \"Droid\") {" + + " name" + + " description" + + " }" + + "}" let expected = GraphQLResult( data: [ @@ -470,7 +502,11 @@ class StarWarsIntrospectionTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } } diff --git a/Tests/GraphQLTests/StarWarsTests/StarWarsQueryTests.swift b/Tests/GraphQLTests/StarWarsTests/StarWarsQueryTests.swift index 5ce678fd..5e56da32 100644 --- a/Tests/GraphQLTests/StarWarsTests/StarWarsQueryTests.swift +++ b/Tests/GraphQLTests/StarWarsTests/StarWarsQueryTests.swift @@ -1,12 +1,12 @@ -import XCTest import NIO +import XCTest @testable import GraphQL -class StarWarsQueryTests : XCTestCase { +class StarWarsQueryTests: XCTestCase { func testHeroNameQuery() throws { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) - + defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } @@ -18,7 +18,7 @@ class StarWarsQueryTests : XCTestCase { } } """ - + let expected = GraphQLResult( data: [ "hero": [ @@ -32,13 +32,13 @@ class StarWarsQueryTests : XCTestCase { request: query, eventLoopGroup: eventLoopGroup ).wait() - + XCTAssertEqual(result, expected) } func testHeroNameAndFriendsQuery() throws { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) - + defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } @@ -74,13 +74,13 @@ class StarWarsQueryTests : XCTestCase { request: query, eventLoopGroup: eventLoopGroup ).wait() - + XCTAssertEqual(result, expected) } func testNestedQuery() throws { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) - + defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } @@ -139,7 +139,11 @@ class StarWarsQueryTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -149,11 +153,14 @@ class StarWarsQueryTests : XCTestCase { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - let query = "query FetchLukeQuery {" + - " human(id: \"1000\") {" + - " name" + - " }" + - "}" + let query = + """ + query FetchLukeQuery { + human(id: "1000") { + name + } + } + """ let expected = GraphQLResult( data: [ @@ -163,21 +170,28 @@ class StarWarsQueryTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } - func testOptionalVariable() throws{ + func testOptionalVariable() throws { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - let query = "query FetchHeroByEpisodeQuery($episode: String) {" + - " hero(episode: $episode) {" + - " name" + - " }" + - "}" + let query = + """ + query FetchHeroByEpisodeQuery($episode: String) { + hero(episode: $episode) { + name + } + } + """ var params: [String: Map] var expected: GraphQLResult @@ -194,7 +208,12 @@ class StarWarsQueryTests : XCTestCase { ] ) - result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup, variableValues: params).wait() + result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup, + variableValues: params + ).wait() XCTAssertEqual(result, expected) // or we can pass "EMPIRE" and expect Luke @@ -210,7 +229,12 @@ class StarWarsQueryTests : XCTestCase { ] ) - result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup, variableValues: params).wait() + result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup, + variableValues: params + ).wait() XCTAssertEqual(result, expected) } @@ -220,11 +244,14 @@ class StarWarsQueryTests : XCTestCase { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - let query = "query FetchSomeIDQuery($someId: String!) {" + - " human(id: $someId) {" + - " name" + - " }" + - "}" + let query = + """ + query FetchSomeIDQuery($someId: String!) { + human(id: $someId) { + name + } + } + """ var params: [String: Map] var expected: GraphQLResult @@ -242,7 +269,12 @@ class StarWarsQueryTests : XCTestCase { ] ) - result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup, variableValues: params).wait() + result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup, + variableValues: params + ).wait() XCTAssertEqual(result, expected) params = [ @@ -257,10 +289,14 @@ class StarWarsQueryTests : XCTestCase { ] ) - result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup, variableValues: params).wait() + result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup, + variableValues: params + ).wait() XCTAssertEqual(result, expected) - params = [ "someId": "not a valid id", ] @@ -271,7 +307,12 @@ class StarWarsQueryTests : XCTestCase { ] ) - result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup, variableValues: params).wait() + result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup, + variableValues: params + ).wait() XCTAssertEqual(result, expected) } @@ -281,11 +322,14 @@ class StarWarsQueryTests : XCTestCase { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - let query = "query FetchLukeAliasedQuery {" + - " luke: human(id: \"1000\") {" + - " name" + - " }" + - "}" + let query = + """ + query FetchLukeAliasedQuery { + luke: human(id: "1000") { + name + } + } + """ let expected = GraphQLResult( data: [ @@ -295,7 +339,11 @@ class StarWarsQueryTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -305,14 +353,17 @@ class StarWarsQueryTests : XCTestCase { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - let query = "query FetchLukeAndLeiaAliasedQuery {" + - " luke: human(id: \"1000\") {" + - " name" + - " }" + - " leia: human(id: \"1003\") {" + - " name" + - " }" + - "}" + let query = + """ + query FetchLukeAndLeiaAliasedQuery { + luke: human(id: "1000") { + name + } + leia: human(id: "1003") { + name + } + } + """ let expected = GraphQLResult( data: [ @@ -325,7 +376,11 @@ class StarWarsQueryTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -335,16 +390,19 @@ class StarWarsQueryTests : XCTestCase { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - let query = "query DuplicateFieldsQuery {" + - " luke: human(id: \"1000\") {" + - " name" + - " homePlanet" + - " }" + - " leia: human(id: \"1003\") {" + - " name" + - " homePlanet" + - " }" + - "}" + let query = + """ + query DuplicateFieldsQuery { + luke: human(id: "1000") { + name + homePlanet + } + leia: human(id: "1003") { + name + homePlanet + } + } + """ let expected = GraphQLResult( data: [ @@ -359,7 +417,11 @@ class StarWarsQueryTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -369,18 +431,21 @@ class StarWarsQueryTests : XCTestCase { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - let query = "query UseFragmentQuery {" + - " luke: human(id: \"1000\") {" + - " ...HumanFragment" + - " }" + - " leia: human(id: \"1003\") {" + - " ...HumanFragment" + - " }" + - "}" + - "fragment HumanFragment on Human {" + - " name" + - " homePlanet" + - "}" + let query = + """ + query UseFragmentQuery { + luke: human(id: "1000") { + ...HumanFragment + } + leia: human(id: "1003") { + ...HumanFragment + } + } + fragment HumanFragment on Human { + name + homePlanet + } + """ let expected = GraphQLResult( data: [ @@ -395,7 +460,11 @@ class StarWarsQueryTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -405,12 +474,15 @@ class StarWarsQueryTests : XCTestCase { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - let query = "query CheckTypeOfR2Query {" + - " hero {" + - " __typename" + - " name" + - " }" + - "}" + let query = + """ + query CheckTypeOfR2Query { + hero { + __typename + name + } + } + """ let expected = GraphQLResult( data: [ @@ -426,7 +498,7 @@ class StarWarsQueryTests : XCTestCase { request: query, eventLoopGroup: eventLoopGroup ).wait() - + XCTAssertEqual(result, expected) } @@ -436,12 +508,15 @@ class StarWarsQueryTests : XCTestCase { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - let query = "query CheckTypeOfLukeQuery {" + - " hero(episode: EMPIRE) {" + - " __typename" + - " name" + - " }" + - "}" + let query = + """ + query CheckTypeOfLukeQuery { + hero(episode: EMPIRE) { + __typename + name + } + } + """ let expected = GraphQLResult( data: [ @@ -452,7 +527,11 @@ class StarWarsQueryTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -462,12 +541,15 @@ class StarWarsQueryTests : XCTestCase { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - let query = "query SecretBackstoryQuery {\n" + - " hero {\n" + - " name\n" + - " secretBackstory\n" + - " }\n" + - "}\n" + let query = + """ + query SecretBackstoryQuery { + hero { + name + secretBackstory + } + } + """ let expected = GraphQLResult( data: [ @@ -481,11 +563,15 @@ class StarWarsQueryTests : XCTestCase { message: "secretBackstory is secret.", locations: [SourceLocation(line: 4, column: 9)], path: ["hero", "secretBackstory"] - ) + ), ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -495,15 +581,18 @@ class StarWarsQueryTests : XCTestCase { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - let query = "query SecretBackstoryListQuery {\n" + - " hero {\n" + - " name\n" + - " friends {\n" + - " name\n" + - " secretBackstory\n" + - " }\n" + - " }\n" + - "}\n" + let query = + """ + query SecretBackstoryListQuery { + hero { + name + friends { + name + secretBackstory + } + } + } + """ let expected = GraphQLResult( data: [ @@ -544,7 +633,11 @@ class StarWarsQueryTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -554,12 +647,15 @@ class StarWarsQueryTests : XCTestCase { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - let query = "query SecretBackstoryAliasQuery {\n" + - " mainHero: hero {\n" + - " name\n" + - " story: secretBackstory\n" + - " }\n" + - "}\n" + let query = + """ + query SecretBackstoryAliasQuery { + mainHero: hero { + name + story: secretBackstory + } + } + """ let expected = GraphQLResult( data: [ @@ -577,7 +673,11 @@ class StarWarsQueryTests : XCTestCase { ] ) - let result = try graphql(schema: starWarsSchema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql( + schema: starWarsSchema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() XCTAssertEqual(result, expected) } @@ -605,7 +705,7 @@ class StarWarsQueryTests : XCTestCase { "throws": GraphQLField( type: GraphQLNonNull(GraphQLString), resolve: { _, _, _, _ -> [String: String]? in - struct 🏃 : Error, CustomStringConvertible { + struct 🏃: Error, CustomStringConvertible { let description: String } @@ -623,25 +723,28 @@ class StarWarsQueryTests : XCTestCase { resolve: { _, _, _, _ -> [String: String]? in [:] as [String: String] } - ) + ), ] ) - let schema = try GraphQLSchema( + let schema = try GraphQLSchema( query: queryType - ) - - let query = "query {\n" + - " nullableA {\n" + - " nullableA {\n" + - " nonNullA {\n" + - " nonNullA {\n" + - " throws\n" + - " }\n" + - " }\n" + - " }\n" + - " }\n" + - "}\n" + ) + + let query = + """ + query { + nullableA { + nullableA { + nonNullA { + nonNullA { + throws + } + } + } + } + } + """ let expected = GraphQLResult( data: [ @@ -658,53 +761,54 @@ class StarWarsQueryTests : XCTestCase { ] ) - let result = try graphql(schema: schema, request: query, eventLoopGroup: eventLoopGroup).wait() + let result = try graphql(schema: schema, request: query, eventLoopGroup: eventLoopGroup) + .wait() XCTAssertEqual(result, expected) } - + func testFieldOrderQuery() throws { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) - + defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } - + XCTAssertEqual(try graphql( schema: starWarsSchema, request: """ - query HeroNameQuery { - hero { - id - name - } + query HeroNameQuery { + hero { + id + name } - """, + } + """, eventLoopGroup: eventLoopGroup ).wait(), GraphQLResult( data: [ "hero": [ "id": "2001", - "name": "R2-D2" + "name": "R2-D2", ], ] )) - + XCTAssertNotEqual(try graphql( schema: starWarsSchema, request: """ - query HeroNameQuery { - hero { - id - name - } + query HeroNameQuery { + hero { + id + name } - """, + } + """, eventLoopGroup: eventLoopGroup ).wait(), GraphQLResult( data: [ "hero": [ "name": "R2-D2", - "id": "2001" + "id": "2001", ], ] )) diff --git a/Tests/GraphQLTests/StarWarsTests/StarWarsSchema.swift b/Tests/GraphQLTests/StarWarsTests/StarWarsSchema.swift index ffbdbf30..09202e43 100644 --- a/Tests/GraphQLTests/StarWarsTests/StarWarsSchema.swift +++ b/Tests/GraphQLTests/StarWarsTests/StarWarsSchema.swift @@ -121,7 +121,6 @@ let CharacterInterface = try! GraphQLInterfaceType( } ) - /** * We define our human type, which implements the character interface. * @@ -149,7 +148,7 @@ let HumanType = try! GraphQLObjectType( "friends": GraphQLField( type: GraphQLList(CharacterInterface), description: "The friends of the human, or an empty list if they " + - "have none.", + "have none.", resolve: { human, _, _, _ in getFriends(character: human as! Human) } @@ -166,7 +165,7 @@ let HumanType = try! GraphQLObjectType( type: GraphQLString, description: "Where are they from and how they came to be who they are.", resolve: { _, _, _, _ in - struct Secret : Error, CustomStringConvertible { + struct Secret: Error, CustomStringConvertible { let description: String } @@ -180,7 +179,6 @@ let HumanType = try! GraphQLObjectType( } ) - /** * The other type of character in Star Wars is a droid. * @@ -221,7 +219,7 @@ let DroidType = try! GraphQLObjectType( type: GraphQLString, description: "Construction date and the name of the designer.", resolve: { _, _, _, _ in - struct SecretError : Error, CustomStringConvertible { + struct SecretError: Error, CustomStringConvertible { let description: String } @@ -239,7 +237,6 @@ 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 @@ -264,8 +261,8 @@ let QueryType = try! GraphQLObjectType( type: EpisodeEnum, description: "If omitted, returns the hero of the whole saga. If " + - "provided, returns the hero of that particular episode." - ) + "provided, returns the hero of that particular episode." + ), ], resolve: { _, arguments, _, _ in let episode = Episode(arguments["episode"].string) @@ -278,10 +275,10 @@ let QueryType = try! GraphQLObjectType( "id": GraphQLArgument( type: GraphQLNonNull(GraphQLString), description: "id of the human" - ) + ), ], resolve: { _, arguments, _, _ in - return getHuman(id: arguments["id"].string!) + getHuman(id: arguments["id"].string!) } ), "droid": GraphQLField( @@ -290,10 +287,10 @@ let QueryType = try! GraphQLObjectType( "id": GraphQLArgument( type: GraphQLNonNull(GraphQLString), description: "id of the droid" - ) + ), ], resolve: { _, arguments, _, _ in - return getDroid(id: arguments["id"].string!) + getDroid(id: arguments["id"].string!) } ), ] diff --git a/Tests/GraphQLTests/StarWarsTests/StarWarsValidationTests.swift b/Tests/GraphQLTests/StarWarsTests/StarWarsValidationTests.swift index 4d6a7cb9..0c8555ff 100644 --- a/Tests/GraphQLTests/StarWarsTests/StarWarsValidationTests.swift +++ b/Tests/GraphQLTests/StarWarsTests/StarWarsValidationTests.swift @@ -1,5 +1,5 @@ -import XCTest @testable import GraphQL +import XCTest /** * Helper function to test a query and the expected response. @@ -10,95 +10,95 @@ func validationErrors(query: String) throws -> [GraphQLError] { return validate(schema: starWarsSchema, ast: ast) } -class StarWarsValidationTests : XCTestCase { +class StarWarsValidationTests: XCTestCase { func testNestedQueryWithFragment() throws { let query = "query NestedQueryWithFragment {" + - " hero {" + - " ...NameAndAppearances" + - " friends {" + - " ...NameAndAppearances" + - " friends {" + - " ...NameAndAppearances" + - " }" + - " }" + - " }" + - "}" + - "fragment NameAndAppearances on Character {" + - " name" + - " appearsIn" + - "}" + " hero {" + + " ...NameAndAppearances" + + " friends {" + + " ...NameAndAppearances" + + " friends {" + + " ...NameAndAppearances" + + " }" + + " }" + + " }" + + "}" + + "fragment NameAndAppearances on Character {" + + " name" + + " appearsIn" + + "}" XCTAssert(try validationErrors(query: query).isEmpty) } func testHeroSpaceshipQuery() throws { let query = "query HeroSpaceshipQuery {" + - " hero {" + - " favoriteSpaceship" + - " }" + - "}" + - "fragment NameAndAppearances on Character {" + - " name" + - " appearsIn" + - "}" + " hero {" + + " favoriteSpaceship" + + " }" + + "}" + + "fragment NameAndAppearances on Character {" + + " name" + + " appearsIn" + + "}" XCTAssertFalse(try validationErrors(query: query).isEmpty) } func testHeroNoFieldsQuery() throws { let query = "query HeroNoFieldsQuery {" + - " hero" + - "}" + " hero" + + "}" XCTAssertFalse(try validationErrors(query: query).isEmpty) } func testHeroFieldsOnScalarQuery() throws { let query = "query HeroFieldsOnScalarQuery {" + - " hero {" + - " name {" + - " firstCharacterOfName" + - " }" + - " }" + - "}" + " hero {" + + " name {" + + " firstCharacterOfName" + + " }" + + " }" + + "}" XCTAssertFalse(try validationErrors(query: query).isEmpty) } func testDroidFieldOnCharacter() throws { let query = "query DroidFieldOnCharacter {" + - " hero {" + - " name" + - " primaryFunction" + - " }" + - "}" + " hero {" + + " name" + + " primaryFunction" + + " }" + + "}" XCTAssertFalse(try validationErrors(query: query).isEmpty) } func testDroidFieldInFragment() throws { let query = "query DroidFieldInFragment {" + - " hero {" + - " name" + - " ...DroidFields" + - " }" + - "}" + - "fragment DroidFields on Droid {" + - " primaryFunction" + - "}" + " hero {" + + " name" + + " ...DroidFields" + + " }" + + "}" + + "fragment DroidFields on Droid {" + + " primaryFunction" + + "}" XCTAssert(try validationErrors(query: query).isEmpty) } func testDroidFieldInInlineFragment() throws { let query = "query DroidFieldInInlineFragment {" + - " hero {" + - " name" + - " ... on Droid {" + - " primaryFunction" + - " }" + - " }" + - "}" + " hero {" + + " name" + + " ... on Droid {" + + " primaryFunction" + + " }" + + " }" + + "}" XCTAssert(try validationErrors(query: query).isEmpty) } diff --git a/Tests/GraphQLTests/SubscriptionTests/SimplePubSub.swift b/Tests/GraphQLTests/SubscriptionTests/SimplePubSub.swift index 52a77605..31532f79 100644 --- a/Tests/GraphQLTests/SubscriptionTests/SimplePubSub.swift +++ b/Tests/GraphQLTests/SubscriptionTests/SimplePubSub.swift @@ -1,49 +1,47 @@ import GraphQL - #if compiler(>=5.5) && canImport(_Concurrency) -@available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) -/// A very simple publish/subscriber used for testing -class SimplePubSub { - private var subscribers: [Subscriber] - - init() { - subscribers = [] - } - - func emit(event: T) { - for subscriber in subscribers { - subscriber.callback(event) + @available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) + /// A very simple publish/subscriber used for testing + class SimplePubSub { + private var subscribers: [Subscriber] + + init() { + subscribers = [] } - } - - func cancel() { - for subscriber in subscribers { - subscriber.cancel() + + func emit(event: T) { + for subscriber in subscribers { + subscriber.callback(event) + } } - } - - func subscribe() -> ConcurrentEventStream { - let asyncStream = AsyncThrowingStream { continuation in - let subscriber = Subscriber( - callback: { newValue in - continuation.yield(newValue) - }, - cancel: { - continuation.finish() - } - ) - subscribers.append(subscriber) - return + + func cancel() { + for subscriber in subscribers { + subscriber.cancel() + } + } + + func subscribe() -> ConcurrentEventStream { + let asyncStream = AsyncThrowingStream { continuation in + let subscriber = Subscriber( + callback: { newValue in + continuation.yield(newValue) + }, + cancel: { + continuation.finish() + } + ) + subscribers.append(subscriber) + } + return ConcurrentEventStream.init(asyncStream) } - return ConcurrentEventStream.init(asyncStream) } -} -struct Subscriber { - let callback: (T) -> Void - let cancel: () -> Void -} + struct Subscriber { + let callback: (T) -> Void + let cancel: () -> Void + } #endif diff --git a/Tests/GraphQLTests/SubscriptionTests/SubscriptionSchema.swift b/Tests/GraphQLTests/SubscriptionTests/SubscriptionSchema.swift index 0b2eef67..41e296bb 100644 --- a/Tests/GraphQLTests/SubscriptionTests/SubscriptionSchema.swift +++ b/Tests/GraphQLTests/SubscriptionTests/SubscriptionSchema.swift @@ -1,206 +1,217 @@ -import NIO @testable import GraphQL +import NIO #if compiler(>=5.5) && canImport(_Concurrency) -// MARK: Types -struct Email : Encodable { - let from:String - let subject:String - let message:String - let unread:Bool - let priority:Int - - init(from:String, subject:String, message:String, unread:Bool, priority:Int = 0) { - self.from = from - self.subject = subject - self.message = message - self.unread = unread - self.priority = priority - } -} - -struct Inbox : Encodable { - let emails:[Email] -} - -struct EmailEvent : Encodable { - let email:Email - let inbox:Inbox -} - -// MARK: Schema -let EmailType = try! GraphQLObjectType( - name: "Email", - fields: [ - "from": GraphQLField( - type: GraphQLString - ), - "subject": GraphQLField( - type: GraphQLString - ), - "message": GraphQLField( - type: GraphQLString - ), - "unread": GraphQLField( - type: GraphQLBoolean - ), - ] -) -let InboxType = try! GraphQLObjectType( - name: "Inbox", - fields: [ - "emails": GraphQLField( - type: GraphQLList(EmailType) - ), - "total": GraphQLField( - type: GraphQLInt, - resolve: { inbox, _, _, _ in - (inbox as! Inbox).emails.count - } - ), - "unread": GraphQLField( - type: GraphQLInt, - resolve: { inbox, _, _, _ in - (inbox as! Inbox).emails.filter({$0.unread}).count - } - ), - ] -) -let EmailEventType = try! GraphQLObjectType( - name: "EmailEvent", - fields: [ - "email": GraphQLField( - type: EmailType - ), - "inbox": GraphQLField( - type: InboxType - ) - ] -) -let EmailQueryType = try! GraphQLObjectType( - name: "Query", - fields: [ - "inbox": GraphQLField( - type: InboxType - ) - ] -) - -// MARK: Test Helpers - -let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) - -@available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) -class EmailDb { - var emails: [Email] - let publisher: SimplePubSub - - init() { - emails = [ - Email( - from: "joe@graphql.org", - subject: "Hello", - message: "Hello World", - unread: false - ) - ] - publisher = SimplePubSub() + // MARK: Types + + struct Email: Encodable { + let from: String + let subject: String + let message: String + let unread: Bool + let priority: Int + + init(from: String, subject: String, message: String, unread: Bool, priority: Int = 0) { + self.from = from + self.subject = subject + self.message = message + self.unread = unread + self.priority = priority + } } - - /// Adds a new email to the database and triggers all observers - func trigger(email:Email) { - emails.append(email) - publisher.emit(event: email) + + struct Inbox: Encodable { + let emails: [Email] } - - func stop() { - publisher.cancel() + + struct EmailEvent: Encodable { + let email: Email + let inbox: Inbox } - - /// Returns the default email schema, with standard resolvers. - func defaultSchema() throws -> GraphQLSchema { - return try emailSchemaWithResolvers( - resolve: {emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - if let email = emailAny as? Email { - return eventLoopGroup.next().makeSucceededFuture(EmailEvent( - email: email, - inbox: Inbox(emails: self.emails) - )) - } else { - throw GraphQLError(message: "\(type(of:emailAny)) is not Email") + + // MARK: Schema + + let EmailType = try! GraphQLObjectType( + name: "Email", + fields: [ + "from": GraphQLField( + type: GraphQLString + ), + "subject": GraphQLField( + type: GraphQLString + ), + "message": GraphQLField( + type: GraphQLString + ), + "unread": GraphQLField( + type: GraphQLBoolean + ), + ] + ) + let InboxType = try! GraphQLObjectType( + name: "Inbox", + fields: [ + "emails": GraphQLField( + type: GraphQLList(EmailType) + ), + "total": GraphQLField( + type: GraphQLInt, + resolve: { inbox, _, _, _ in + (inbox as! Inbox).emails.count + } + ), + "unread": GraphQLField( + type: GraphQLInt, + resolve: { inbox, _, _, _ in + (inbox as! Inbox).emails.filter { $0.unread }.count } - }, - subscribe: {_, args, _, eventLoopGroup, _ throws -> EventLoopFuture in - let priority = args["priority"].int ?? 0 - let filtered = self.publisher.subscribe().stream.filterStream { emailAny throws in + ), + ] + ) + let EmailEventType = try! GraphQLObjectType( + name: "EmailEvent", + fields: [ + "email": GraphQLField( + type: EmailType + ), + "inbox": GraphQLField( + type: InboxType + ), + ] + ) + let EmailQueryType = try! GraphQLObjectType( + name: "Query", + fields: [ + "inbox": GraphQLField( + type: InboxType + ), + ] + ) + + // MARK: Test Helpers + + let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) + + @available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) + class EmailDb { + var emails: [Email] + let publisher: SimplePubSub + + init() { + emails = [ + Email( + from: "joe@graphql.org", + subject: "Hello", + message: "Hello World", + unread: false + ), + ] + publisher = SimplePubSub() + } + + /// Adds a new email to the database and triggers all observers + func trigger(email: Email) { + emails.append(email) + publisher.emit(event: email) + } + + func stop() { + publisher.cancel() + } + + /// Returns the default email schema, with standard resolvers. + func defaultSchema() throws -> GraphQLSchema { + return try emailSchemaWithResolvers( + resolve: { emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture in if let email = emailAny as? Email { - return email.priority >= priority + return eventLoopGroup.next().makeSucceededFuture(EmailEvent( + email: email, + inbox: Inbox(emails: self.emails) + )) } else { - return true + throw GraphQLError(message: "\(type(of: emailAny)) is not Email") } + }, + subscribe: { _, args, _, eventLoopGroup, _ throws -> EventLoopFuture in + let priority = args["priority"].int ?? 0 + let filtered = self.publisher.subscribe().stream + .filterStream { emailAny throws in + if let email = emailAny as? Email { + return email.priority >= priority + } else { + return true + } + } + return eventLoopGroup.next() + .makeSucceededFuture(ConcurrentEventStream(filtered)) } - return eventLoopGroup.next().makeSucceededFuture(ConcurrentEventStream(filtered)) - } + ) + } + + /// Generates a subscription to the database using the default schema and resolvers + func subscription( + query: String, + variableValues: [String: Map] = [:] + ) throws -> SubscriptionEventStream { + return try createSubscription( + schema: defaultSchema(), + query: query, + variableValues: variableValues + ) + } + } + + /// Generates an email schema with the specified resolve and subscribe methods + func emailSchemaWithResolvers( + resolve: GraphQLFieldResolve? = nil, + subscribe: GraphQLFieldResolve? = nil + ) throws -> GraphQLSchema { + return try GraphQLSchema( + query: EmailQueryType, + subscription: try! GraphQLObjectType( + name: "Subscription", + fields: [ + "importantEmail": GraphQLField( + type: EmailEventType, + args: [ + "priority": GraphQLArgument( + type: GraphQLInt + ), + ], + resolve: resolve, + subscribe: subscribe + ), + ] + ) ) } - - /// Generates a subscription to the database using the default schema and resolvers - func subscription ( - query:String, + + /// Generates a subscription from the given schema and query. It's expected that the resolver/database interactions are configured by the caller. + func createSubscription( + schema: GraphQLSchema, + query: String, variableValues: [String: Map] = [:] ) throws -> SubscriptionEventStream { - return try createSubscription(schema: defaultSchema(), query: query, variableValues: variableValues) - } -} - -/// Generates an email schema with the specified resolve and subscribe methods -func emailSchemaWithResolvers(resolve: GraphQLFieldResolve? = nil, subscribe: GraphQLFieldResolve? = nil) throws -> GraphQLSchema { - return try GraphQLSchema( - query: EmailQueryType, - subscription: try! GraphQLObjectType( - name: "Subscription", - fields: [ - "importantEmail": GraphQLField( - type: EmailEventType, - args: [ - "priority": GraphQLArgument( - type: GraphQLInt - ) - ], - resolve: resolve, - subscribe: subscribe - ) - ] - ) - ) -} - -/// Generates a subscription from the given schema and query. It's expected that the resolver/database interactions are configured by the caller. -func createSubscription( - schema: GraphQLSchema, - query: String, - variableValues: [String: Map] = [:] -) throws -> SubscriptionEventStream { - let result = try graphqlSubscribe( - queryStrategy: SerialFieldExecutionStrategy(), - mutationStrategy: SerialFieldExecutionStrategy(), - subscriptionStrategy: SerialFieldExecutionStrategy(), - instrumentation: NoOpInstrumentation, - schema: schema, - request: query, - rootValue: Void(), - context: Void(), - eventLoopGroup: eventLoopGroup, - variableValues: variableValues, - operationName: nil - ).wait() - - if let stream = result.stream { - return stream - } else { - throw result.errors.first! // We may have more than one... + let result = try graphqlSubscribe( + queryStrategy: SerialFieldExecutionStrategy(), + mutationStrategy: SerialFieldExecutionStrategy(), + subscriptionStrategy: SerialFieldExecutionStrategy(), + instrumentation: NoOpInstrumentation, + schema: schema, + request: query, + rootValue: (), + context: (), + eventLoopGroup: eventLoopGroup, + variableValues: variableValues, + operationName: nil + ).wait() + + if let stream = result.stream { + return stream + } else { + throw result.errors.first! // We may have more than one... + } } -} #endif diff --git a/Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift b/Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift index 44db10b9..ac8c65b0 100644 --- a/Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift +++ b/Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift @@ -2,307 +2,288 @@ import GraphQL import NIO import XCTest - #if compiler(>=5.5) && canImport(_Concurrency) -@available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) -/// This follows the graphql-js testing, with deviations where noted. -class SubscriptionTests : XCTestCase { - let timeoutDuration = 0.5 // in seconds - - // MARK: Test primary graphqlSubscribe function - - /// This test is not present in graphql-js, but just tests basic functionality. - func testGraphqlSubscribe() async throws { - let db = EmailDb() - let schema = try db.defaultSchema() - let query = """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total + @available(macOS 12, iOS 15, watchOS 8, tvOS 15, *) + /// This follows the graphql-js testing, with deviations where noted. + class SubscriptionTests: XCTestCase { + let timeoutDuration = 0.5 // in seconds + + // MARK: Test primary graphqlSubscribe function + + /// This test is not present in graphql-js, but just tests basic functionality. + func testGraphqlSubscribe() async throws { + let db = EmailDb() + let schema = try db.defaultSchema() + let query = """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } } - } - } - """ - - let subscriptionResult = try graphqlSubscribe( - schema: schema, - request: query, - eventLoopGroup: eventLoopGroup - ).wait() - guard let subscription = subscriptionResult.stream else { - XCTFail(subscriptionResult.errors.description) - return - } - guard let stream = subscription as? ConcurrentEventStream else { - XCTFail("stream isn't ConcurrentEventStream") - return - } - var iterator = stream.stream.makeAsyncIterator() - - db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) - db.stop() - let result = try await iterator.next()?.get() - XCTAssertEqual( - result, - GraphQLResult( - data: ["importantEmail": [ - "email":[ - "from": "yuzhi@graphql.org", - "subject": "Alright" - ], - "inbox":[ - "unread": 1, - "total": 2 - ] - ]] - ) - ) - } - - // MARK: Subscription Initialization Phase - - /// accepts multiple subscription fields defined in schema - func testAcceptsMultipleSubscriptionFields() async throws { - let db = EmailDb() - let schema = try GraphQLSchema( - query: EmailQueryType, - subscription: GraphQLObjectType( - name: "Subscription", - fields: [ - "importantEmail": GraphQLField( - type: EmailEventType, - args: [ - "priority": GraphQLArgument( - type: GraphQLInt - ) + """ + + let subscriptionResult = try graphqlSubscribe( + schema: schema, + request: query, + eventLoopGroup: eventLoopGroup + ).wait() + guard let subscription = subscriptionResult.stream else { + XCTFail(subscriptionResult.errors.description) + return + } + guard let stream = subscription as? ConcurrentEventStream else { + XCTFail("stream isn't ConcurrentEventStream") + return + } + var iterator = stream.stream.makeAsyncIterator() + + db.trigger(email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + )) + db.stop() + let result = try await iterator.next()?.get() + XCTAssertEqual( + result, + GraphQLResult( + data: ["importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Alright", ], - resolve: {emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - guard let email = emailAny as? Email else { - throw GraphQLError(message:"Source is not Email type: \(type(of: emailAny))") - } - return eventLoopGroup.next().makeSucceededFuture(EmailEvent( - email: email, - inbox: Inbox(emails: db.emails) - )) - }, - subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - return eventLoopGroup.next().makeSucceededFuture(db.publisher.subscribe()) - } - ), - "notImportantEmail": GraphQLField( - type: EmailEventType, - args: [ - "priority": GraphQLArgument( - type: GraphQLInt - ) + "inbox": [ + "unread": 1, + "total": 2, ], - resolve: {emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - guard let email = emailAny as? Email else { - throw GraphQLError(message:"Source is not Email type: \(type(of: emailAny))") - } - return eventLoopGroup.next().makeSucceededFuture(EmailEvent( - email: email, - inbox: Inbox(emails: db.emails) - )) - }, - subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - return eventLoopGroup.next().makeSucceededFuture(db.publisher.subscribe()) - } - ) - ] + ]] + ) ) - ) - let subscription = try createSubscription(schema: schema, query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total - } - } - } - """) - guard let stream = subscription as? ConcurrentEventStream else { - XCTFail("stream isn't ConcurrentEventStream") - return } - var iterator = stream.stream.makeAsyncIterator() - - db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) - - let result = try await iterator.next()?.get() - XCTAssertEqual( - result, - GraphQLResult( - data: ["importantEmail": [ - "email":[ - "from": "yuzhi@graphql.org", - "subject": "Alright" - ], - "inbox":[ - "unread": 1, - "total": 2 - ] - ]] - ) - ) - } - /// 'should only resolve the first field of invalid multi-field' - /// - /// Note that due to implementation details in Swift, this will not resolve the "first" one, but rather a random one of the two - func testInvalidMultiField() async throws { - let db = EmailDb() - - var didResolveImportantEmail = false - var didResolveNonImportantEmail = false - - let schema = try GraphQLSchema( - query: EmailQueryType, - subscription: GraphQLObjectType( - name: "Subscription", - fields: [ - "importantEmail": GraphQLField( - type: EmailEventType, - resolve: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - return eventLoopGroup.next().makeSucceededFuture(nil) - }, - subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - didResolveImportantEmail = true - return eventLoopGroup.next().makeSucceededFuture(db.publisher.subscribe()) - } - ), - "notImportantEmail": GraphQLField( - type: EmailEventType, - resolve: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - return eventLoopGroup.next().makeSucceededFuture(nil) - }, - subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - didResolveNonImportantEmail = true - return eventLoopGroup.next().makeSucceededFuture(db.publisher.subscribe()) - } - ) - ] + // MARK: Subscription Initialization Phase + + /// accepts multiple subscription fields defined in schema + func testAcceptsMultipleSubscriptionFields() async throws { + let db = EmailDb() + let schema = try GraphQLSchema( + query: EmailQueryType, + subscription: GraphQLObjectType( + name: "Subscription", + fields: [ + "importantEmail": GraphQLField( + type: EmailEventType, + args: [ + "priority": GraphQLArgument( + type: GraphQLInt + ), + ], + resolve: { emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + guard let email = emailAny as? Email else { + throw GraphQLError( + message: "Source is not Email type: \(type(of: emailAny))" + ) + } + return eventLoopGroup.next().makeSucceededFuture(EmailEvent( + email: email, + inbox: Inbox(emails: db.emails) + )) + }, + subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + eventLoopGroup.next().makeSucceededFuture(db.publisher.subscribe()) + } + ), + "notImportantEmail": GraphQLField( + type: EmailEventType, + args: [ + "priority": GraphQLArgument( + type: GraphQLInt + ), + ], + resolve: { emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + guard let email = emailAny as? Email else { + throw GraphQLError( + message: "Source is not Email type: \(type(of: emailAny))" + ) + } + return eventLoopGroup.next().makeSucceededFuture(EmailEvent( + email: email, + inbox: Inbox(emails: db.emails) + )) + }, + subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + eventLoopGroup.next().makeSucceededFuture(db.publisher.subscribe()) + } + ), + ] + ) ) - ) - let _ = try createSubscription(schema: schema, query: """ - subscription { - importantEmail { - email { - from - } - } - notImportantEmail { - email { + let subscription = try createSubscription(schema: schema, query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { from + subject + } + inbox { + unread + total + } } - } + } + """) + guard let stream = subscription as? ConcurrentEventStream else { + XCTFail("stream isn't ConcurrentEventStream") + return } - """) - - db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) - - - // One and only one should be true - XCTAssertTrue(didResolveImportantEmail || didResolveNonImportantEmail) - XCTAssertFalse(didResolveImportantEmail && didResolveNonImportantEmail) - } + var iterator = stream.stream.makeAsyncIterator() - // 'throws an error if schema is missing' - // Not implemented because this is taken care of by Swift optional types + db.trigger(email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + )) - // 'throws an error if document is missing' - // Not implemented because this is taken care of by Swift optional types - - /// 'resolves to an error for unknown subscription field' - func testErrorUnknownSubscriptionField() throws { - let db = EmailDb() - XCTAssertThrowsError( - try db.subscription(query: """ - subscription { - unknownField - } - """ + let result = try await iterator.next()?.get() + XCTAssertEqual( + result, + GraphQLResult( + data: ["importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Alright", + ], + "inbox": [ + "unread": 1, + "total": 2, + ], + ]] + ) ) - ) { error in - guard let graphQLError = error as? GraphQLError else { - XCTFail("Error was not of type GraphQLError") - return - } - XCTAssertEqual(graphQLError.message, "Cannot query field \"unknownField\" on type \"Subscription\".") - XCTAssertEqual(graphQLError.locations, [SourceLocation(line: 2, column: 5)]) } - } - /// 'should pass through unexpected errors thrown in subscribe' - func testPassUnexpectedSubscribeErrors() throws { - let db = EmailDb() - XCTAssertThrowsError( - try db.subscription(query: "") - ) - } - - /// 'throws an error if subscribe does not return an iterator' - func testErrorIfSubscribeIsntIterator() throws { - let schema = try emailSchemaWithResolvers( - resolve: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - return eventLoopGroup.next().makeSucceededFuture(nil) - }, - subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - return eventLoopGroup.next().makeSucceededFuture("test") - } - ) - XCTAssertThrowsError( - try createSubscription(schema: schema, query: """ + /// 'should only resolve the first field of invalid multi-field' + /// + /// Note that due to implementation details in Swift, this will not resolve the "first" one, but rather a random one of the two + func testInvalidMultiField() async throws { + let db = EmailDb() + + var didResolveImportantEmail = false + var didResolveNonImportantEmail = false + + let schema = try GraphQLSchema( + query: EmailQueryType, + subscription: GraphQLObjectType( + name: "Subscription", + fields: [ + "importantEmail": GraphQLField( + type: EmailEventType, + resolve: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + eventLoopGroup.next().makeSucceededFuture(nil) + }, + subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + didResolveImportantEmail = true + return eventLoopGroup.next() + .makeSucceededFuture(db.publisher.subscribe()) + } + ), + "notImportantEmail": GraphQLField( + type: EmailEventType, + resolve: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + eventLoopGroup.next().makeSucceededFuture(nil) + }, + subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + didResolveNonImportantEmail = true + return eventLoopGroup.next() + .makeSucceededFuture(db.publisher.subscribe()) + } + ), + ] + ) + ) + let _ = try createSubscription(schema: schema, query: """ subscription { importantEmail { email { from } } + notImportantEmail { + email { + from + } + } } """) - ) { error in - guard let graphQLError = error as? GraphQLError else { - XCTFail("Error was not of type GraphQLError") - return + + db.trigger(email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + )) + + // One and only one should be true + XCTAssertTrue(didResolveImportantEmail || didResolveNonImportantEmail) + XCTAssertFalse(didResolveImportantEmail && didResolveNonImportantEmail) + } + + // 'throws an error if schema is missing' + // Not implemented because this is taken care of by Swift optional types + + // 'throws an error if document is missing' + // Not implemented because this is taken care of by Swift optional types + + /// 'resolves to an error for unknown subscription field' + func testErrorUnknownSubscriptionField() throws { + let db = EmailDb() + XCTAssertThrowsError( + try db.subscription(query: """ + subscription { + unknownField + } + """) + ) { error in + guard let graphQLError = error as? GraphQLError else { + XCTFail("Error was not of type GraphQLError") + return + } + XCTAssertEqual( + graphQLError.message, + "Cannot query field \"unknownField\" on type \"Subscription\"." + ) + XCTAssertEqual(graphQLError.locations, [SourceLocation(line: 2, column: 5)]) } - XCTAssertEqual( - graphQLError.message, - "Subscription field resolver must return EventStream. Received: 'test'" + } + + /// 'should pass through unexpected errors thrown in subscribe' + func testPassUnexpectedSubscribeErrors() throws { + let db = EmailDb() + XCTAssertThrowsError( + try db.subscription(query: "") ) } - } - /// 'resolves to an error for subscription resolver errors' - func testErrorForSubscriptionResolverErrors() throws { - func verifyError(schema: GraphQLSchema) { + /// 'throws an error if subscribe does not return an iterator' + func testErrorIfSubscribeIsntIterator() throws { + let schema = try emailSchemaWithResolvers( + resolve: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + eventLoopGroup.next().makeSucceededFuture(nil) + }, + subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + eventLoopGroup.next().makeSucceededFuture("test") + } + ) XCTAssertThrowsError( try createSubscription(schema: schema, query: """ subscription { @@ -318,667 +299,692 @@ class SubscriptionTests : XCTestCase { XCTFail("Error was not of type GraphQLError") return } - XCTAssertEqual(graphQLError.message, "test error") + XCTAssertEqual( + graphQLError.message, + "Subscription field resolver must return EventStream. Received: 'test'" + ) } } - // Throwing an error - try verifyError(schema: emailSchemaWithResolvers( - subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - throw GraphQLError(message: "test error") + /// 'resolves to an error for subscription resolver errors' + func testErrorForSubscriptionResolverErrors() throws { + func verifyError(schema: GraphQLSchema) { + XCTAssertThrowsError( + try createSubscription(schema: schema, query: """ + subscription { + importantEmail { + email { + from + } + } + } + """) + ) { error in + guard let graphQLError = error as? GraphQLError else { + XCTFail("Error was not of type GraphQLError") + return + } + XCTAssertEqual(graphQLError.message, "test error") + } } - )) - // Resolving to an error - try verifyError(schema: emailSchemaWithResolvers( - subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - return eventLoopGroup.next().makeSucceededFuture(GraphQLError(message: "test error")) - } - )) + // Throwing an error + try verifyError(schema: emailSchemaWithResolvers( + subscribe: { _, _, _, _, _ throws -> EventLoopFuture in + throw GraphQLError(message: "test error") + } + )) - // Rejecting with an error - try verifyError(schema: emailSchemaWithResolvers( - subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - return eventLoopGroup.next().makeFailedFuture(GraphQLError(message: "test error")) - } - )) - } + // Resolving to an error + try verifyError(schema: emailSchemaWithResolvers( + subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + eventLoopGroup.next().makeSucceededFuture(GraphQLError(message: "test error")) + } + )) + // Rejecting with an error + try verifyError(schema: emailSchemaWithResolvers( + subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + eventLoopGroup.next().makeFailedFuture(GraphQLError(message: "test error")) + } + )) + } - /// 'resolves to an error for source event stream resolver errors' - // Tests above cover this + /// 'resolves to an error for source event stream resolver errors' + // Tests above cover this - /// 'resolves to an error if variables were wrong type' - func testErrorVariablesWrongType() throws { - let db = EmailDb() - let query = """ - subscription ($priority: Int) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total + /// 'resolves to an error if variables were wrong type' + func testErrorVariablesWrongType() throws { + let db = EmailDb() + let query = """ + subscription ($priority: Int) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } } + """ + + XCTAssertThrowsError( + try db.subscription( + query: query, + variableValues: [ + "priority": "meow", + ] + ) + ) { error in + guard let graphQLError = error as? GraphQLError else { + XCTFail("Error was not of type GraphQLError") + return } - } - """ - - XCTAssertThrowsError( - try db.subscription( - query: query, - variableValues: [ - "priority": "meow" - ] - ) - ) { error in - guard let graphQLError = error as? GraphQLError else { - XCTFail("Error was not of type GraphQLError") + XCTAssertEqual( + graphQLError.message, + "Variable \"$priority\" got invalid value \"\"meow\"\".\nExpected type \"Int\", found \"meow\"." + ) + } + } + + // MARK: Subscription Publish Phase + + /// 'produces a payload for a single subscriber' + func testSingleSubscriber() async throws { + let db = EmailDb() + let subscription = try db.subscription(query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } + } + """) + guard let stream = subscription as? ConcurrentEventStream else { + XCTFail("stream isn't ConcurrentEventStream") return } + var iterator = stream.stream.makeAsyncIterator() + + db.trigger(email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + )) + db.stop() + + let result = try await iterator.next()?.get() XCTAssertEqual( - graphQLError.message, - "Variable \"$priority\" got invalid value \"\"meow\"\".\nExpected type \"Int\", found \"meow\"." + result, + GraphQLResult( + data: ["importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Alright", + ], + "inbox": [ + "unread": 1, + "total": 2, + ], + ]] + ) ) } - } - - // MARK: Subscription Publish Phase - - /// 'produces a payload for a single subscriber' - func testSingleSubscriber() async throws { - let db = EmailDb() - let subscription = try db.subscription(query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject + /// 'produces a payload for multiple subscribe in same subscription' + func testMultipleSubscribers() async throws { + let db = EmailDb() + let subscription1 = try db.subscription(query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } } - inbox { - unread - total + """) + guard let stream1 = subscription1 as? ConcurrentEventStream else { + XCTFail("stream isn't ConcurrentEventStream") + return + } + + let subscription2 = try db.subscription(query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } } - } - } - """) - guard let stream = subscription as? ConcurrentEventStream else { - XCTFail("stream isn't ConcurrentEventStream") - return - } - var iterator = stream.stream.makeAsyncIterator() - - db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) - db.stop() - - let result = try await iterator.next()?.get() - XCTAssertEqual( - result, - GraphQLResult( + """) + guard let stream2 = subscription2 as? ConcurrentEventStream else { + XCTFail("stream isn't ConcurrentEventStream") + return + } + + var iterator1 = stream1.stream.makeAsyncIterator() + var iterator2 = stream2.stream.makeAsyncIterator() + + db.trigger(email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + )) + + let result1 = try await iterator1.next()?.get() + let result2 = try await iterator2.next()?.get() + + let expected = GraphQLResult( data: ["importantEmail": [ - "email":[ + "email": [ "from": "yuzhi@graphql.org", - "subject": "Alright" + "subject": "Alright", ], - "inbox":[ + "inbox": [ "unread": 1, - "total": 2 - ] + "total": 2, + ], ]] ) - ) - } - /// 'produces a payload for multiple subscribe in same subscription' - func testMultipleSubscribers() async throws { - let db = EmailDb() - let subscription1 = try db.subscription(query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total - } - } - } - """) - guard let stream1 = subscription1 as? ConcurrentEventStream else { - XCTFail("stream isn't ConcurrentEventStream") - return - } - - let subscription2 = try db.subscription(query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total - } - } - } - """) - guard let stream2 = subscription2 as? ConcurrentEventStream else { - XCTFail("stream isn't ConcurrentEventStream") - return + XCTAssertEqual(result1, expected) + XCTAssertEqual(result2, expected) } - - var iterator1 = stream1.stream.makeAsyncIterator() - var iterator2 = stream2.stream.makeAsyncIterator() - - db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) - - let result1 = try await iterator1.next()?.get() - let result2 = try await iterator2.next()?.get() - - let expected = GraphQLResult( - data: ["importantEmail": [ - "email":[ - "from": "yuzhi@graphql.org", - "subject": "Alright" - ], - "inbox":[ - "unread": 1, - "total": 2 - ] - ]] - ) - - XCTAssertEqual(result1, expected) - XCTAssertEqual(result2, expected) - } - - /// 'produces a payload per subscription event' - func testPayloadPerEvent() async throws { - let db = EmailDb() - let subscription = try db.subscription(query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total + + /// 'produces a payload per subscription event' + func testPayloadPerEvent() async throws { + let db = EmailDb() + let subscription = try db.subscription(query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } } - } - } - """) - guard let stream = subscription as? ConcurrentEventStream else { - XCTFail("stream isn't ConcurrentEventStream") - return - } - var iterator = stream.stream.makeAsyncIterator() - - // A new email arrives! - db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) - let result1 = try await iterator.next()?.get() - XCTAssertEqual( - result1, - GraphQLResult( - data: ["importantEmail": [ - "email":[ - "from": "yuzhi@graphql.org", - "subject": "Alright" - ], - "inbox":[ - "unread": 1, - "total": 2 - ] - ]] + """) + guard let stream = subscription as? ConcurrentEventStream else { + XCTFail("stream isn't ConcurrentEventStream") + return + } + var iterator = stream.stream.makeAsyncIterator() + + // A new email arrives! + db.trigger(email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + )) + let result1 = try await iterator.next()?.get() + XCTAssertEqual( + result1, + GraphQLResult( + data: ["importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Alright", + ], + "inbox": [ + "unread": 1, + "total": 2, + ], + ]] + ) ) - ) - - // Another new email arrives - db.trigger(email: Email( - from: "hyo@graphql.org", - subject: "Tools", - message: "I <3 making things", - unread: true - )) - let result2 = try await iterator.next()?.get() - XCTAssertEqual( - result2, - GraphQLResult( - data: ["importantEmail": [ - "email":[ - "from": "hyo@graphql.org", - "subject": "Tools" - ], - "inbox":[ - "unread": 2, - "total": 3 - ] - ]] + + // Another new email arrives + db.trigger(email: Email( + from: "hyo@graphql.org", + subject: "Tools", + message: "I <3 making things", + unread: true + )) + let result2 = try await iterator.next()?.get() + XCTAssertEqual( + result2, + GraphQLResult( + data: ["importantEmail": [ + "email": [ + "from": "hyo@graphql.org", + "subject": "Tools", + ], + "inbox": [ + "unread": 2, + "total": 3, + ], + ]] + ) ) - ) - } - - /// Tests that subscriptions use arguments correctly. - /// This is not in the graphql-js tests. - func testArguments() async throws { - let db = EmailDb() - let subscription = try db.subscription(query: """ - subscription ($priority: Int = 5) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total + } + + /// Tests that subscriptions use arguments correctly. + /// This is not in the graphql-js tests. + func testArguments() async throws { + let db = EmailDb() + let subscription = try db.subscription(query: """ + subscription ($priority: Int = 5) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } } + """) + guard let stream = subscription as? ConcurrentEventStream else { + XCTFail("stream isn't ConcurrentEventStream") + return + } + + var results = [GraphQLResult]() + var expectation = XCTestExpectation() + + // So that the Task won't immediately be cancelled since the ConcurrentEventStream is discarded + let keepForNow = stream.map { event in + event.map { result in + results.append(result) + expectation.fulfill() } - } - """) - guard let stream = subscription as? ConcurrentEventStream else { - XCTFail("stream isn't ConcurrentEventStream") - return - } - - var results = [GraphQLResult]() - var expectation = XCTestExpectation() - - // So that the Task won't immediately be cancelled since the ConcurrentEventStream is discarded - let keepForNow = stream.map { event in - event.map { result in - results.append(result) - expectation.fulfill() } - } - var expected = [GraphQLResult]() - - 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 - ] - ]] + var expected = [GraphQLResult]() + + 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, + ], + ]] + ) ) - ) - wait(for: [expectation], timeout: timeoutDuration) - XCTAssertEqual(results, expected) - - // Low priority email shouldn't trigger an event - expectation = XCTestExpectation() - expectation.isInverted = true - db.trigger(email: Email( - from: "hyo@graphql.org", - subject: "Not Important", - message: "Ignore this email", - unread: true, - priority: 2 - )) - wait(for: [expectation], timeout: timeoutDuration) - XCTAssertEqual(results, expected) - - // Higher priority one should trigger again - expectation = XCTestExpectation() - 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 - ] - ]] + wait(for: [expectation], timeout: timeoutDuration) + XCTAssertEqual(results, expected) + + // Low priority email shouldn't trigger an event + expectation = XCTestExpectation() + expectation.isInverted = true + db.trigger(email: Email( + from: "hyo@graphql.org", + subject: "Not Important", + message: "Ignore this email", + unread: true, + priority: 2 + )) + wait(for: [expectation], timeout: timeoutDuration) + XCTAssertEqual(results, expected) + + // Higher priority one should trigger again + expectation = XCTestExpectation() + 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, + ], + ]] + ) ) - ) - wait(for: [expectation], timeout: timeoutDuration) - XCTAssertEqual(results, expected) + wait(for: [expectation], timeout: timeoutDuration) + XCTAssertEqual(results, expected) - // So that the Task won't immediately be cancelled since the ConcurrentEventStream is discarded - _ = keepForNow - } + // So that the Task won't immediately be cancelled since the ConcurrentEventStream is discarded + _ = keepForNow + } - /// 'should not trigger when subscription is already done' - func testNoTriggerAfterDone() async throws { - let db = EmailDb() - let subscription = try db.subscription(query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total + /// 'should not trigger when subscription is already done' + func testNoTriggerAfterDone() async throws { + let db = EmailDb() + let subscription = try db.subscription(query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } } + """) + guard let stream = subscription as? ConcurrentEventStream else { + XCTFail("stream isn't ConcurrentEventStream") + return + } + + var results = [GraphQLResult]() + var expectation = XCTestExpectation() + // So that the Task won't immediately be cancelled since the ConcurrentEventStream is discarded + let keepForNow = stream.map { event in + event.map { result in + results.append(result) + expectation.fulfill() } - } - """) - guard let stream = subscription as? ConcurrentEventStream else { - XCTFail("stream isn't ConcurrentEventStream") - return - } - - var results = [GraphQLResult]() - var expectation = XCTestExpectation() - // So that the Task won't immediately be cancelled since the ConcurrentEventStream is discarded - let keepForNow = stream.map { event in - event.map { result in - results.append(result) - expectation.fulfill() } - } - var expected = [GraphQLResult]() - - 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 - ], - ]] + var expected = [GraphQLResult]() + + 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, + ], + ]] + ) ) - ) - wait(for: [expectation], timeout: timeoutDuration) - XCTAssertEqual(results, expected) - - db.stop() - - // This should not trigger an event. - expectation = XCTestExpectation() - expectation.isInverted = true - 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 - wait(for: [expectation], timeout: timeoutDuration) - XCTAssertEqual(results, expected) - - // So that the Task won't immediately be cancelled since the ConcurrentEventStream is discarded - _ = keepForNow - } + wait(for: [expectation], timeout: timeoutDuration) + XCTAssertEqual(results, expected) + + db.stop() + + // This should not trigger an event. + expectation = XCTestExpectation() + expectation.isInverted = true + 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 + wait(for: [expectation], timeout: timeoutDuration) + XCTAssertEqual(results, expected) + + // So that the Task won't immediately be cancelled since the ConcurrentEventStream is discarded + _ = keepForNow + } - /// 'should not trigger when subscription is thrown' - // Not necessary - Swift async stream handles throwing errors - - /// 'event order is correct for multiple publishes' - func testOrderCorrectForMultiplePublishes() async throws { - let db = EmailDb() - let subscription = try db.subscription(query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total + /// 'should not trigger when subscription is thrown' + // Not necessary - Swift async stream handles throwing errors + + /// 'event order is correct for multiple publishes' + func testOrderCorrectForMultiplePublishes() async throws { + let db = EmailDb() + let subscription = try db.subscription(query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } } - } - } - """) - guard let stream = subscription as? ConcurrentEventStream else { - XCTFail("stream isn't ConcurrentEventStream") - return - } - var iterator = stream.stream.makeAsyncIterator() - - db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Alright", - message: "Tests are good", - unread: true - )) - db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Message 2", - message: "Tests are good 2", - unread: true - )) - - let result1 = try await iterator.next()?.get() - XCTAssertEqual( - result1, - GraphQLResult( - data: ["importantEmail": [ - "email":[ - "from": "yuzhi@graphql.org", - "subject": "Alright" - ], - "inbox":[ - "unread": 2, - "total": 3 - ] - ]] + """) + guard let stream = subscription as? ConcurrentEventStream else { + XCTFail("stream isn't ConcurrentEventStream") + return + } + var iterator = stream.stream.makeAsyncIterator() + + db.trigger(email: Email( + from: "yuzhi@graphql.org", + subject: "Alright", + message: "Tests are good", + unread: true + )) + db.trigger(email: Email( + from: "yuzhi@graphql.org", + subject: "Message 2", + message: "Tests are good 2", + unread: true + )) + + let result1 = try await iterator.next()?.get() + XCTAssertEqual( + result1, + GraphQLResult( + data: ["importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Alright", + ], + "inbox": [ + "unread": 2, + "total": 3, + ], + ]] + ) ) - ) - - let result2 = try await iterator.next()?.get() - XCTAssertEqual( - result2, - GraphQLResult( - data: ["importantEmail": [ - "email":[ - "from": "yuzhi@graphql.org", - "subject": "Message 2" - ], - "inbox":[ - "unread": 2, - "total": 3 - ] - ]] + + let result2 = try await iterator.next()?.get() + XCTAssertEqual( + result2, + GraphQLResult( + data: ["importantEmail": [ + "email": [ + "from": "yuzhi@graphql.org", + "subject": "Message 2", + ], + "inbox": [ + "unread": 2, + "total": 3, + ], + ]] + ) ) - ) - } + } - /// 'should handle error during execution of source event' - func testErrorDuringSubscription() async throws { - let db = EmailDb() + /// 'should handle error during execution of source event' + func testErrorDuringSubscription() async throws { + let db = EmailDb() - let schema = try emailSchemaWithResolvers( - resolve: {emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - guard let email = emailAny as? Email else { - throw GraphQLError(message:"Source is not Email type: \(type(of: emailAny))") - } - if email.subject == "Goodbye" { // Force the system to fail here. - throw GraphQLError(message:"Never leave.") + let schema = try emailSchemaWithResolvers( + resolve: { emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + guard let email = emailAny as? Email else { + throw GraphQLError( + message: "Source is not Email type: \(type(of: emailAny))" + ) + } + if email.subject == "Goodbye" { // Force the system to fail here. + throw GraphQLError(message: "Never leave.") + } + return eventLoopGroup.next().makeSucceededFuture(EmailEvent( + email: email, + inbox: Inbox(emails: db.emails) + )) + }, + subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture in + eventLoopGroup.next().makeSucceededFuture(db.publisher.subscribe()) } - return eventLoopGroup.next().makeSucceededFuture(EmailEvent( - email: email, - inbox: Inbox(emails: db.emails) - )) - }, - subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in - return eventLoopGroup.next().makeSucceededFuture(db.publisher.subscribe()) - } - ) + ) - let subscription = try createSubscription(schema: schema, query: """ - subscription { - importantEmail { - email { - subject + let subscription = try createSubscription(schema: schema, query: """ + subscription { + importantEmail { + email { + subject + } } } + """) + guard let stream = subscription as? ConcurrentEventStream else { + XCTFail("stream isn't ConcurrentEventStream") + return } - """) - guard let stream = subscription as? ConcurrentEventStream else { - XCTFail("stream isn't ConcurrentEventStream") - return - } - - var results = [GraphQLResult]() - var expectation = XCTestExpectation() - // So that the Task won't immediately be cancelled since the ConcurrentEventStream is discarded - let keepForNow = stream.map { event in - event.map { result in - results.append(result) - expectation.fulfill() + + var results = [GraphQLResult]() + var expectation = XCTestExpectation() + // So that the Task won't immediately be cancelled since the ConcurrentEventStream is discarded + let keepForNow = stream.map { event in + event.map { result in + results.append(result) + expectation.fulfill() + } } - } - var expected = [GraphQLResult]() - - db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Hello", - message: "Tests are good", - unread: true - )) - expected.append( - GraphQLResult( - data: ["importantEmail": [ - "email":[ - "subject": "Hello" - ] - ]] - ) - ) - wait(for: [expectation], timeout: timeoutDuration) - XCTAssertEqual(results, expected) - - expectation = XCTestExpectation() - // An error in execution is presented as such. - 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.") - ] + var expected = [GraphQLResult]() + + db.trigger(email: Email( + from: "yuzhi@graphql.org", + subject: "Hello", + message: "Tests are good", + unread: true + )) + expected.append( + GraphQLResult( + data: ["importantEmail": [ + "email": [ + "subject": "Hello", + ], + ]] + ) ) - ) - wait(for: [expectation], timeout: timeoutDuration) - XCTAssertEqual(results, expected) - - expectation = XCTestExpectation() - // However that does not close the response event stream. Subsequent events are still executed. - db.trigger(email: Email( - from: "yuzhi@graphql.org", - subject: "Bonjour", - message: "Tests are good", - unread: true - )) - expected.append( - GraphQLResult( - data: ["importantEmail": [ - "email":[ - "subject": "Bonjour" + wait(for: [expectation], timeout: timeoutDuration) + XCTAssertEqual(results, expected) + + expectation = XCTestExpectation() + // An error in execution is presented as such. + 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."), ] - ]] + ) ) - ) - wait(for: [expectation], timeout: timeoutDuration) - XCTAssertEqual(results, expected) + wait(for: [expectation], timeout: timeoutDuration) + XCTAssertEqual(results, expected) + + expectation = XCTestExpectation() + // However that does not close the response event stream. Subsequent events are still executed. + db.trigger(email: Email( + from: "yuzhi@graphql.org", + subject: "Bonjour", + message: "Tests are good", + unread: true + )) + expected.append( + GraphQLResult( + data: ["importantEmail": [ + "email": [ + "subject": "Bonjour", + ], + ]] + ) + ) + wait(for: [expectation], timeout: timeoutDuration) + XCTAssertEqual(results, expected) - // So that the Task won't immediately be cancelled since the ConcurrentEventStream is discarded - _ = keepForNow - } - - /// 'should pass through error thrown in source event stream' - // Handled by AsyncThrowingStream - - /// Test incorrect emitted type errors - func testErrorWrongEmitType() async throws { - let db = EmailDb() - let subscription = try db.subscription(query: """ - subscription ($priority: Int = 0) { - importantEmail(priority: $priority) { - email { - from - subject - } - inbox { - unread - total - } - } - } - """) - guard let stream = subscription as? ConcurrentEventStream else { - XCTFail("stream isn't ConcurrentEventStream") - return + // So that the Task won't immediately be cancelled since the ConcurrentEventStream is discarded + _ = keepForNow } - var iterator = stream.stream.makeAsyncIterator() - - db.publisher.emit(event: "String instead of email") - - let result = try await iterator.next()?.get() - XCTAssertEqual( - result, - GraphQLResult( - data: ["importantEmail": nil], - errors: [ - GraphQLError(message: "String is not Email") - ] + + /// 'should pass through error thrown in source event stream' + // Handled by AsyncThrowingStream + + /// Test incorrect emitted type errors + func testErrorWrongEmitType() async throws { + let db = EmailDb() + let subscription = try db.subscription(query: """ + subscription ($priority: Int = 0) { + importantEmail(priority: $priority) { + email { + from + subject + } + inbox { + unread + total + } + } + } + """) + guard let stream = subscription as? ConcurrentEventStream else { + XCTFail("stream isn't ConcurrentEventStream") + return + } + var iterator = stream.stream.makeAsyncIterator() + + db.publisher.emit(event: "String instead of email") + + let result = try await iterator.next()?.get() + XCTAssertEqual( + result, + GraphQLResult( + data: ["importantEmail": nil], + errors: [ + GraphQLError(message: "String is not Email"), + ] + ) ) - ) + } } -} #endif diff --git a/Tests/GraphQLTests/TypeTests/GraphQLArgumentDefinitionTests.swift b/Tests/GraphQLTests/TypeTests/GraphQLArgumentDefinitionTests.swift index 80f5c376..3f6ad542 100644 --- a/Tests/GraphQLTests/TypeTests/GraphQLArgumentDefinitionTests.swift +++ b/Tests/GraphQLTests/TypeTests/GraphQLArgumentDefinitionTests.swift @@ -2,7 +2,6 @@ import XCTest class GraphQLArgumentDefinitionTests: XCTestCase { - func testArgumentWithNullableTypeIsNotARequiredArgument() { let argument = GraphQLArgumentDefinition( name: "nullableString", diff --git a/Tests/GraphQLTests/TypeTests/GraphQLSchemaTests.swift b/Tests/GraphQLTests/TypeTests/GraphQLSchemaTests.swift index 7a77dcf2..bc7c8b49 100644 --- a/Tests/GraphQLTests/TypeTests/GraphQLSchemaTests.swift +++ b/Tests/GraphQLTests/TypeTests/GraphQLSchemaTests.swift @@ -2,8 +2,8 @@ import XCTest class GraphQLSchemaTests: XCTestCase { - - func testAssertObjectImplementsInterfacePassesWhenObjectFieldHasRequiredArgumentsFromInterface() throws { + func testAssertObjectImplementsInterfacePassesWhenObjectFieldHasRequiredArgumentsFromInterface( + ) throws { let interface = try GraphQLInterfaceType( name: "Interface", fields: [ @@ -20,7 +20,7 @@ class GraphQLSchemaTests: XCTestCase { args: [ "arg1": GraphQLArgument(type: GraphQLString), "arg2": GraphQLArgument(type: GraphQLNonNull(GraphQLInt)), - "arg3": GraphQLArgument(type: GraphQLNonNull(GraphQLBoolean)) + "arg3": GraphQLArgument(type: GraphQLNonNull(GraphQLBoolean)), ] ), ] @@ -42,12 +42,12 @@ class GraphQLSchemaTests: XCTestCase { args: [ "arg1": GraphQLArgument(type: GraphQLString), "arg2": GraphQLArgument(type: GraphQLNonNull(GraphQLInt)), - "arg3": GraphQLArgument(type: GraphQLNonNull(GraphQLBoolean)) + "arg3": GraphQLArgument(type: GraphQLNonNull(GraphQLBoolean)), ] ), ], interfaces: [interface], - isTypeOf: { (_, _, _) -> Bool in + isTypeOf: { _, _, _ -> Bool in preconditionFailure("Should not be called") } ) @@ -55,7 +55,8 @@ class GraphQLSchemaTests: XCTestCase { _ = try GraphQLSchema(query: object, types: [interface, object]) } - func testAssertObjectImplementsInterfacePassesWhenObjectFieldHasRequiredArgumentMissingInInterfaceButHasDefaultValue() throws { + func testAssertObjectImplementsInterfacePassesWhenObjectFieldHasRequiredArgumentMissingInInterfaceButHasDefaultValue( + ) throws { let interface = try GraphQLInterfaceType( name: "Interface", fields: [ @@ -75,12 +76,12 @@ class GraphQLSchemaTests: XCTestCase { "addedRequiredArgWithDefaultValue": GraphQLArgument( type: GraphQLNonNull(GraphQLInt), defaultValue: .int(5) - ) + ), ] ), ], interfaces: [interface], - isTypeOf: { (_, _, _) -> Bool in + isTypeOf: { _, _, _ -> Bool in preconditionFailure("Should not be called") } ) @@ -88,7 +89,8 @@ class GraphQLSchemaTests: XCTestCase { _ = try GraphQLSchema(query: object, types: [interface, object]) } - func testAssertObjectImplementsInterfacePassesWhenObjectFieldHasNullableArgumentMissingInInterface() throws { + func testAssertObjectImplementsInterfacePassesWhenObjectFieldHasNullableArgumentMissingInInterface( + ) throws { let interface = try GraphQLInterfaceType( name: "Interface", fields: [ @@ -108,7 +110,7 @@ class GraphQLSchemaTests: XCTestCase { ), ], interfaces: [interface], - isTypeOf: { (_, _, _) -> Bool in + isTypeOf: { _, _, _ -> Bool in preconditionFailure("Should not be called") } ) @@ -116,7 +118,8 @@ class GraphQLSchemaTests: XCTestCase { _ = try GraphQLSchema(query: object, types: [interface, object]) } - func testAssertObjectImplementsInterfaceFailsWhenObjectFieldHasRequiredArgumentMissingInInterface() throws { + func testAssertObjectImplementsInterfaceFailsWhenObjectFieldHasRequiredArgumentMissingInInterface( + ) throws { let interface = try GraphQLInterfaceType( name: "Interface", fields: [ @@ -133,12 +136,12 @@ class GraphQLSchemaTests: XCTestCase { "fieldWithoutArg": GraphQLField( type: GraphQLInt, args: [ - "addedRequiredArg": GraphQLArgument(type: GraphQLNonNull(GraphQLInt)) + "addedRequiredArg": GraphQLArgument(type: GraphQLNonNull(GraphQLInt)), ] ), ], interfaces: [interface], - isTypeOf: { (_, _, _) -> Bool in + isTypeOf: { _, _, _ -> Bool in preconditionFailure("Should not be called") } ) @@ -148,7 +151,10 @@ class GraphQLSchemaTests: XCTestCase { XCTFail("Expected errors when creating schema") } catch { let graphQLError = try XCTUnwrap(error as? GraphQLError) - XCTAssertEqual(graphQLError.message, "Object.fieldWithoutArg includes required argument (addedRequiredArg:) that is missing from the Interface field Interface.fieldWithoutArg.") + XCTAssertEqual( + graphQLError.message, + "Object.fieldWithoutArg includes required argument (addedRequiredArg:) that is missing from the Interface field Interface.fieldWithoutArg." + ) } } } diff --git a/Tests/GraphQLTests/ValidationTests/ExampleSchema.swift b/Tests/GraphQLTests/ValidationTests/ExampleSchema.swift index e507be6e..1defddde 100644 --- a/Tests/GraphQLTests/ValidationTests/ExampleSchema.swift +++ b/Tests/GraphQLTests/ValidationTests/ExampleSchema.swift @@ -1,8 +1,8 @@ @testable import GraphQL -//interface Being { +// interface Being { // name(surname: Boolean): String -//} +// } let ValidationExampleBeing = try! GraphQLInterfaceType( name: "Being", fields: [ @@ -15,29 +15,29 @@ let ValidationExampleBeing = try! GraphQLInterfaceType( } ), ], - resolveType: { _, _, info in - return "Unknown" + resolveType: { _, _, _ in + "Unknown" } ) -//interface Mammal { +// interface Mammal { // mother: Mammal // father: Mammal -//} +// } let ValidationExampleMammal = try! GraphQLInterfaceType( - name: "Mammal", - fields: [ - "mother": GraphQLField(type: GraphQLTypeReference("Mammal")), - "father": GraphQLField(type: GraphQLTypeReference("Mammal")), - ], - resolveType: { _, _, _ in - return "Unknown" - } + name: "Mammal", + fields: [ + "mother": GraphQLField(type: GraphQLTypeReference("Mammal")), + "father": GraphQLField(type: GraphQLTypeReference("Mammal")), + ], + resolveType: { _, _, _ in + "Unknown" + } ) -//interface Pet implements Being { +// interface Pet implements Being { // name(surname: Boolean): String -//} +// } let ValidationExamplePet = try! GraphQLInterfaceType( name: "Pet", interfaces: [ValidationExampleBeing], @@ -52,37 +52,36 @@ let ValidationExamplePet = try! GraphQLInterfaceType( ), ], resolveType: { _, _, _ in - return "Unknown" + "Unknown" } ) -//interface Canine implements Mammal & Being { +// interface Canine implements Mammal & Being { // name(surname: Boolean): String // mother: Canine // father: Canine -//} +// } let ValidationExampleCanine = try! GraphQLInterfaceType( - name: "Canine", - interfaces: [ValidationExampleMammal, ValidationExampleBeing], - fields: [ - "name": GraphQLField( - type: GraphQLString, - args: ["surname": GraphQLArgument(type: GraphQLBoolean)] - ), - "mother": GraphQLField( - type: GraphQLTypeReference("Mammal") - ), - "father": GraphQLField( - type: GraphQLTypeReference("Mammal") - ), - ], - resolveType: { _, _, info in - return "Unknown" - } - + name: "Canine", + interfaces: [ValidationExampleMammal, ValidationExampleBeing], + fields: [ + "name": GraphQLField( + type: GraphQLString, + args: ["surname": GraphQLArgument(type: GraphQLBoolean)] + ), + "mother": GraphQLField( + type: GraphQLTypeReference("Mammal") + ), + "father": GraphQLField( + type: GraphQLTypeReference("Mammal") + ), + ], + resolveType: { _, _, _ in + "Unknown" + } ) -//enum DogCommand { +// enum DogCommand { // SIT // HEEL // DOWN @@ -102,7 +101,7 @@ let ValidationExampleDogCommand = try! GraphQLEnumType( ] ) -//type Dog implements Being & Pet & Mammal & Canine { +// type Dog implements Being & Pet & Mammal & Canine { // name(surname: Boolean): String // nickname: String // barkVolume: Int @@ -112,7 +111,7 @@ let ValidationExampleDogCommand = try! GraphQLEnumType( // isAtLocation(x: Int, y: Int): Boolean // mother: Dog // father: Dog -//} +// } let ValidationExampleDog = try! GraphQLObjectType( name: "Dog", fields: [ @@ -139,7 +138,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)) @@ -152,7 +151,7 @@ let ValidationExampleDog = try! GraphQLObjectType( "atOtherHomes": GraphQLArgument( type: GraphQLBoolean, defaultValue: true - ) + ), ], resolve: { inputValue, _, _, _ -> String? in print(type(of: inputValue)) @@ -167,7 +166,7 @@ let ValidationExampleDog = try! GraphQLObjectType( ), "y": GraphQLArgument( type: GraphQLInt - ) + ), ], resolve: { inputValue, _, _, _ -> String? in print(type(of: inputValue)) @@ -201,33 +200,33 @@ let ValidationExampleDog = try! GraphQLObjectType( ] ) -//enum FurColor { +// enum FurColor { // BROWN // BLACK // TAN // SPOTTED // NO_FUR // UNKNOWN -//} +// } let ValidationExampleFurColor = try! GraphQLEnumType( - name: "FurColor", - values: [ - "BROWN": GraphQLEnumValue(value: ["value": 0]), - "BLACK": GraphQLEnumValue(value: ["value": 1]), - "TAN": GraphQLEnumValue(value: ["value": 2]), - "SPOTTED": GraphQLEnumValue(value: ["value": 3]), - "NO_FUR": GraphQLEnumValue(value: ["value": .null]), - "UNKNOWN": GraphQLEnumValue(value: ["value": .null]), - ] + name: "FurColor", + values: [ + "BROWN": GraphQLEnumValue(value: ["value": 0]), + "BLACK": GraphQLEnumValue(value: ["value": 1]), + "TAN": GraphQLEnumValue(value: ["value": 2]), + "SPOTTED": GraphQLEnumValue(value: ["value": 3]), + "NO_FUR": GraphQLEnumValue(value: ["value": .null]), + "UNKNOWN": GraphQLEnumValue(value: ["value": .null]), + ] ) -//type Cat implements Being & Pet { +// type Cat implements Being & Pet { // name(surname: Boolean): String // nickname: String // meows: Boolean // meowsVolume: Int // furColor: FurColor -//} +// } let ValidationExampleCat = try! GraphQLObjectType( name: "Cat", fields: [ @@ -263,21 +262,21 @@ let ValidationExampleCat = try! GraphQLObjectType( let ValidationExampleCatOrDog = try! GraphQLUnionType( name: "CatOrDog", resolveType: { _, _, _ in - return "Unknown" + "Unknown" }, types: [ValidationExampleCat, ValidationExampleDog] ) -//interface Intelligent { +// interface Intelligent { // iq: Int -//} +// } let ValidationExampleIntelligent = try! GraphQLInterfaceType( name: "Intelligent", fields: [ "iq": GraphQLField(type: GraphQLInt), ], - resolveType: { _, _, info in - return "Unknown" + resolveType: { _, _, _ in + "Unknown" } ) @@ -292,8 +291,8 @@ let ValidationExampleSentient = try! GraphQLInterfaceType( return nil }, ], - resolveType: { _, _, info in - return "Unknown" + resolveType: { _, _, _ in + "Unknown" } ) @@ -362,8 +361,8 @@ let ValidationExampleCatCommand = try! GraphQLEnumType( // union DogOrHuman = Dog | Human let ValidationExampleDogOrHuman = try! GraphQLUnionType( name: "DogOrHuman", - resolveType: { _, _, info in - return "Unknown" + resolveType: { _, _, _ in + "Unknown" }, types: [ValidationExampleDog, ValidationExampleHuman] ) @@ -371,8 +370,8 @@ let ValidationExampleDogOrHuman = try! GraphQLUnionType( // union HumanOrAlien = Human | Alien let ValidationExampleHumanOrAlien = try! GraphQLUnionType( name: "HumanOrAlien", - resolveType: { _, _, info in - return "Unknown" + resolveType: { _, _, _ in + "Unknown" }, types: [ValidationExampleHuman, ValidationExampleAlien] ) diff --git a/Tests/GraphQLTests/ValidationTests/FieldsOnCorrectTypeTests.swift b/Tests/GraphQLTests/ValidationTests/FieldsOnCorrectTypeTests.swift index 1ff35730..5d139094 100644 --- a/Tests/GraphQLTests/ValidationTests/FieldsOnCorrectTypeTests.swift +++ b/Tests/GraphQLTests/ValidationTests/FieldsOnCorrectTypeTests.swift @@ -1,7 +1,7 @@ @testable import GraphQL import XCTest -class FieldsOnCorrectTypeTests : ValidationTestCase { +class FieldsOnCorrectTypeTests: ValidationTestCase { override func setUp() { rule = FieldsOnCorrectTypeRule } @@ -67,12 +67,12 @@ class FieldsOnCorrectTypeTests : ValidationTestCase { } """ ) - + try assertValidationError( 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, message: "Cannot query field \"unknown_cat_field\" on type \"Cat\"." @@ -84,7 +84,7 @@ class FieldsOnCorrectTypeTests : ValidationTestCase { errorCount: 1, query: "fragment fieldNotDefined on Dog { meowVolume }" ) - + try assertValidationError( error: errors.first, line: 1, column: 35, message: "Cannot query field \"meowVolume\" on type \"Dog\". Did you mean \"barkVolume\"?" @@ -96,7 +96,7 @@ class FieldsOnCorrectTypeTests : ValidationTestCase { errorCount: 1, query: "fragment deepFieldNotDefined on Dog { unknown_field { deeper_unknown_field }}" ) - + try assertValidationError( error: errors.first, line: 1, column: 39, message: "Cannot query field \"unknown_field\" on type \"Dog\"." @@ -108,7 +108,7 @@ class FieldsOnCorrectTypeTests : ValidationTestCase { errorCount: 1, query: "fragment subFieldNotDefined on Human { pets { unknown_field } }" ) - + try assertValidationError( error: errors.first, line: 1, column: 47, message: "Cannot query field \"unknown_field\" on type \"Pet\"." @@ -120,7 +120,7 @@ class FieldsOnCorrectTypeTests : ValidationTestCase { errorCount: 1, query: "fragment fieldNotDefinedOnInlineFragment on Pet { ... on Dog { meowVolume } }" ) - + try assertValidationError( error: errors.first, line: 1, column: 64, message: "Cannot query field \"meowVolume\" on type \"Dog\". Did you mean \"barkVolume\"?" @@ -132,7 +132,7 @@ class FieldsOnCorrectTypeTests : ValidationTestCase { errorCount: 1, query: "fragment aliasedFieldTargetNotDefined on Dog { volume : mooVolume }" ) - + try assertValidationError( error: errors.first, line: 1, column: 48, message: "Cannot query field \"mooVolume\" on type \"Dog\". Did you mean \"barkVolume\"?" @@ -144,7 +144,7 @@ class FieldsOnCorrectTypeTests : ValidationTestCase { errorCount: 1, query: "fragment aliasedLyingFieldTargetNotDefined on Dog { barkVolume : kawVolume }" ) - + try assertValidationError( error: errors.first, line: 1, column: 53, message: "Cannot query field \"kawVolume\" on type \"Dog\". Did you mean \"barkVolume\"?" @@ -156,7 +156,7 @@ class FieldsOnCorrectTypeTests : ValidationTestCase { errorCount: 1, query: "fragment notDefinedOnInterface on Pet { tailLength }" ) - + try assertValidationError( error: errors.first, line: 1, column: 41, message: "Cannot query field \"tailLength\" on type \"Pet\"." @@ -168,13 +168,13 @@ class FieldsOnCorrectTypeTests : ValidationTestCase { errorCount: 1, query: "fragment definedOnImplementorsButNotInterface on Pet { nickname }" ) - + try assertValidationError( error: errors.first, line: 1, column: 56, message: "Cannot query field \"nickname\" on type \"Pet\". Did you mean \"name\"?" ) } - + // func testInvalidWhenDirectFieldSelectionOnUnion() throws { // let errors = try assertInvalid( // errorCount: 1, diff --git a/Tests/GraphQLTests/ValidationTests/KnownArgumentNamesTests.swift b/Tests/GraphQLTests/ValidationTests/KnownArgumentNamesTests.swift index 1120c373..8d118f9c 100644 --- a/Tests/GraphQLTests/ValidationTests/KnownArgumentNamesTests.swift +++ b/Tests/GraphQLTests/ValidationTests/KnownArgumentNamesTests.swift @@ -1,41 +1,41 @@ @testable import GraphQL import XCTest -class KnownArgumentNamesTests : ValidationTestCase { +class KnownArgumentNamesTests: ValidationTestCase { override func setUp() { rule = KnownArgumentNamesRule } - + func testValidWithObjectWithoutArguments() throws { try assertValid( "fragment objectFieldSelection on Dog { __typename name }" ) } - + func testValidWithCorrectArgumentNames() throws { try assertValid( "fragment objectFieldSelection on Dog { __typename isHousetrained(atOtherHomes: true) }" ) } - + func testInvalidWithSlightlyMisspelledArgument() throws { let errors = try assertInvalid( errorCount: 1, 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"?"# ) } - + func testInvalidWithUnrelatedArgument() throws { let errors = try assertInvalid( errorCount: 1, query: "fragment objectFieldSelection on Dog { __typename name(uppercased: true) }" ) - + try assertValidationError( error: errors.first, line: 1, column: 56, message: #"Field "name" on type "Dog" does not have argument "uppercased"."# diff --git a/Tests/GraphQLTests/ValidationTests/NoUnusedVariablesRuleTests.swift b/Tests/GraphQLTests/ValidationTests/NoUnusedVariablesRuleTests.swift index 27e62505..0f26f03f 100644 --- a/Tests/GraphQLTests/ValidationTests/NoUnusedVariablesRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/NoUnusedVariablesRuleTests.swift @@ -1,11 +1,11 @@ @testable import GraphQL import XCTest -class NoUnusedVariablesRuleTests : ValidationTestCase { +class NoUnusedVariablesRuleTests: ValidationTestCase { override func setUp() { rule = NoUnusedVariablesRule } - + func testUsesAllVariables() throws { try assertValid( """ @@ -29,7 +29,7 @@ class NoUnusedVariablesRuleTests : ValidationTestCase { """ ) } - + func testUsesAllVariablesDeeplyInInlineFragments() throws { try assertValid( """ @@ -47,7 +47,7 @@ class NoUnusedVariablesRuleTests : ValidationTestCase { """ ) } - + func testUsesAllVariablesInFragments() throws { try assertValid( """ @@ -89,7 +89,7 @@ class NoUnusedVariablesRuleTests : ValidationTestCase { """ ) } - + func testVariableUsedByRecursiveFragment() throws { try assertValid( """ @@ -104,7 +104,7 @@ class NoUnusedVariablesRuleTests : ValidationTestCase { """ ) } - + func testVariableNotUsed() throws { let errors = try assertInvalid( errorCount: 1, @@ -114,13 +114,13 @@ class NoUnusedVariablesRuleTests : ValidationTestCase { } """ ) - + try assertValidationError( error: errors.first, line: 1, column: 32, message: "Variable \"$c\" is never used." ) } - + func testMultipleVariablesNotUsed() throws { let errors = try assertInvalid( errorCount: 2, @@ -130,18 +130,18 @@ class NoUnusedVariablesRuleTests : ValidationTestCase { } """ ) - + try assertValidationError( 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, message: #"Variable "$c" is never used in operation "Foo"."# ) } - + func testVariableNotUsedInFragments() throws { let errors = try assertInvalid( errorCount: 1, @@ -164,13 +164,13 @@ class NoUnusedVariablesRuleTests : ValidationTestCase { } """ ) - + try assertValidationError( error: errors.first, line: 1, column: 35, message: #"Variable "$c" is never used in operation "Foo"."# ) } - + func testMultipleVariablesNotUsedInFragments() throws { let errors = try assertInvalid( errorCount: 2, @@ -193,12 +193,12 @@ class NoUnusedVariablesRuleTests : ValidationTestCase { } """ ) - + try assertValidationError( 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, message: #"Variable "$c" is never used in operation "Foo"."# @@ -220,13 +220,13 @@ class NoUnusedVariablesRuleTests : ValidationTestCase { } """ ) - + try assertValidationError( error: errors.first, line: 1, column: 11, message: #"Variable "$b" is never used in operation "Foo"."# ) } - + func testVariableNotUsedByFragmentUsedByOtherOperation() throws { let errors = try assertInvalid( errorCount: 2, @@ -245,12 +245,12 @@ class NoUnusedVariablesRuleTests : ValidationTestCase { } """ ) - + try assertValidationError( 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, message: #"Variable "$a" is never used in operation "Bar"."# diff --git a/Tests/GraphQLTests/ValidationTests/PossibleFragmentSpreadsRuleRuleTests.swift b/Tests/GraphQLTests/ValidationTests/PossibleFragmentSpreadsRuleRuleTests.swift index 8f998865..15e0ee3c 100644 --- a/Tests/GraphQLTests/ValidationTests/PossibleFragmentSpreadsRuleRuleTests.swift +++ b/Tests/GraphQLTests/ValidationTests/PossibleFragmentSpreadsRuleRuleTests.swift @@ -1,11 +1,11 @@ @testable import GraphQL import XCTest -class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { +class PossibleFragmentSpreadsRuleRuleTests: ValidationTestCase { override func setUp() { rule = PossibleFragmentSpreadsRule } - + func testUsesAllVariables() throws { try assertValid( """ @@ -15,7 +15,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { """ ) } - + func testOfTheSameObject() throws { try assertValid( """ @@ -28,7 +28,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { """ ) } - + func testOfTheSameObjectWithInlineFragment() throws { try assertValid( """ @@ -40,7 +40,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { """ ) } - + func testObjectIntoAnImplementedInterface() throws { try assertValid( """ @@ -66,7 +66,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { """ ) } - + func testUnionIntoContainedObject() throws { try assertValid( """ @@ -79,7 +79,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { """ ) } - + func testUnionIntoOverlappingInterface() throws { try assertValid( """ @@ -92,7 +92,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { """ ) } - + func testUnionIntoOverlappingUnion() throws { try assertValid( """ @@ -105,7 +105,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { """ ) } - + func testInterfaceIntoImplementedObject() throws { try assertValid( """ @@ -118,7 +118,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { """ ) } - + // func testInterfaceIntoOverlappingInterface() throws { // try assertValid( // """ @@ -143,7 +143,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { // """ // ) // } - + func testInterfaceIntoOverlappingUnion() throws { try assertValid( """ @@ -156,7 +156,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { """ ) } - + func testIgnoresIncorrectTypeCaughtByFragmentsOnCompositeTypesRule() throws { try assertValid( """ @@ -169,7 +169,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { """ ) } - + func testIgnoresUnknownFragmentsCaughtByKnownFragmentNamesRule() throws { try assertValid( """ @@ -192,13 +192,13 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { } """ ) - + 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"."# ) } - + func testDifferentObjectIntoObjectInInlineFragment() throws { let errors = try assertInvalid( errorCount: 1, @@ -208,7 +208,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { } """ ) - + 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"."# @@ -229,7 +229,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { } """ ) - + 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"."# @@ -250,13 +250,13 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { } """ ) - + 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"."# ) } - + func testUnionIntoNotContainedObject() throws { let errors = try assertInvalid( errorCount: 1, @@ -269,13 +269,13 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { } """ ) - + 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"."# ) } - + func testUnionIntoNonOverlappingInterface() throws { let errors = try assertInvalid( errorCount: 1, @@ -288,7 +288,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { } """ ) - + 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"."# @@ -307,13 +307,13 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { } """ ) - + 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"."# ) } - + func testInterfaceIntoNonImplementingObject() throws { let errors = try assertInvalid( errorCount: 1, @@ -326,13 +326,13 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { } """ ) - + 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"."# ) } - + func testInterfaceIntNonOverlappingInterface() throws { let errors = try assertInvalid( errorCount: 1, @@ -345,13 +345,13 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { } """ ) - + 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"."# ) } - + func testInterfaceIntoNonOverlappingInterfaceInInlineFragment() throws { let errors = try assertInvalid( errorCount: 1, @@ -361,13 +361,13 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { } """ ) - + 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"."# ) } - + func testInterfaceIntoNonOverlappingUnion() throws { let errors = try assertInvalid( errorCount: 1, @@ -380,7 +380,7 @@ class PossibleFragmentSpreadsRuleRuleTests : ValidationTestCase { } """ ) - + 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"."# diff --git a/Tests/GraphQLTests/ValidationTests/ProvidedNonNullArgumentsTests.swift b/Tests/GraphQLTests/ValidationTests/ProvidedNonNullArgumentsTests.swift index 35521a88..9e0fb336 100644 --- a/Tests/GraphQLTests/ValidationTests/ProvidedNonNullArgumentsTests.swift +++ b/Tests/GraphQLTests/ValidationTests/ProvidedNonNullArgumentsTests.swift @@ -1,17 +1,17 @@ @testable import GraphQL import XCTest -class ProvidedNonNullArgumentsTests : ValidationTestCase { +class ProvidedNonNullArgumentsTests: ValidationTestCase { override func setUp() { rule = ProvidedNonNullArgumentsRule } - + func testValidWithObjectWithoutArguments() throws { try assertValid( "fragment objectFieldSelection on Dog { __typename name }" ) } - + func testValidWithCorrectArgumentNames() throws { try assertValid( "fragment objectFieldSelection on Dog { __typename doesKnowCommand(dogCommand: SIT) }" diff --git a/Tests/GraphQLTests/ValidationTests/ValidationTests.swift b/Tests/GraphQLTests/ValidationTests/ValidationTests.swift index c319e17b..89ff46f1 100644 --- a/Tests/GraphQLTests/ValidationTests/ValidationTests.swift +++ b/Tests/GraphQLTests/ValidationTests/ValidationTests.swift @@ -1,12 +1,12 @@ @testable import GraphQL import XCTest -class ValidationTestCase : XCTestCase { +class ValidationTestCase: XCTestCase { typealias Rule = (ValidationContext) -> Visitor var rule: Rule! - private func validate(body request: String ) throws -> [GraphQLError] { + private func validate(body request: String) throws -> [GraphQLError] { return GraphQL.validate( schema: ValidationExampleSchema, ast: try parse(source: Source(body: request, name: "GraphQL request")), @@ -16,7 +16,13 @@ class ValidationTestCase : XCTestCase { func assertValid(_ query: String, file: StaticString = #file, line: UInt = #line) throws { let errors = try validate(body: query) - XCTAssertEqual(errors.count, 0, "Expecting to pass validation without any errors", file: file, line: line) + XCTAssertEqual( + errors.count, + 0, + "Expecting to pass validation without any errors", + file: file, + line: line + ) } @discardableResult func assertInvalid( @@ -26,7 +32,13 @@ class ValidationTestCase : XCTestCase { line: UInt = #line ) throws -> [GraphQLError] { let errors = try validate(body: query) - XCTAssertEqual(errors.count, errorCount, "Expecting to fail validation with at least 1 error", file: file, line: line) + XCTAssertEqual( + errors.count, + errorCount, + "Expecting to fail validation with at least 1 error", + file: file, + line: line + ) return errors } @@ -42,14 +54,29 @@ class ValidationTestCase : XCTestCase { guard let error = error else { return XCTFail("Error was not provided") } - - XCTAssertEqual(error.message, message, "Unexpected error message", file: testFile, line: testLine) - XCTAssertEqual(error.locations[0].line, line, "Unexpected line location", file: testFile, line: testLine) - XCTAssertEqual(error.locations[0].column, column, "Unexpected column location", file: testFile, line: testLine) - let errorPath = error.path.elements.map({ $0.description }).joined(separator: " ") + + XCTAssertEqual( + error.message, + message, + "Unexpected error message", + file: testFile, + line: testLine + ) + XCTAssertEqual( + error.locations[0].line, + line, + "Unexpected line location", + file: testFile, + line: testLine + ) + XCTAssertEqual( + error.locations[0].column, + column, + "Unexpected column location", + file: testFile, + line: testLine + ) + let errorPath = error.path.elements.map { $0.description }.joined(separator: " ") XCTAssertEqual(errorPath, path, "Unexpected error path", file: testFile, line: testLine) } - } - -