├── .gitignore ├── Gemfile ├── Gemfile.lock ├── GraphQL.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── GraphQL.xcscheme ├── GraphQL.xcworkspace └── contents.xcworkspacedata ├── GraphQL ├── Execution │ └── Executor.swift ├── GraphQL.h ├── GraphQL.swift ├── Info.plist ├── Introspection │ └── Introspection.swift ├── Language │ ├── AbstractSyntaxTree.swift │ ├── Lexer.swift │ ├── Parser.swift │ ├── Source.swift │ ├── Token.swift │ └── Visitor.swift ├── Type system │ ├── Directives.swift │ ├── NonNull.swift │ ├── Schema.swift │ ├── SchemaDirective.swift │ ├── SchemaEnum.swift │ ├── SchemaInputObject.swift │ ├── SchemaInterface.swift │ ├── SchemaList.swift │ ├── SchemaObject.swift │ ├── SchemaScalar.swift │ ├── SchemaUnion.swift │ └── ValidName.swift ├── Utils │ ├── IdentityKit.swift │ ├── MultilineStringOperator.swift │ ├── TypeInfo.swift │ └── Undefined.swift └── Validation │ ├── Rule.swift │ ├── Rules │ ├── ArgumentsOfCorrectType.swift │ ├── DefaultValuesOfCorrectType.swift │ ├── FieldsOnCorrectType.swift │ ├── FragmentsOnCompositeTypes.swift │ ├── KnownArgumentNames.swift │ ├── KnownDirectives.swift │ ├── KnownFragmentNames.swift │ ├── KnownTypeNames.swift │ ├── LoneAnonymousOperation.swift │ ├── NoFragmentCycles.swift │ ├── NoUndefinedVariables.swift │ ├── NoUnusedFragments.swift │ ├── NoUnusedVariables.swift │ ├── OverlappingFieldsCanBeMerged.swift │ ├── PossibleFragmentSpreads.swift │ ├── ProvidedNonNullArguments.swift │ ├── ScalarLeafs.swift │ ├── UniqueArgumentNames.swift │ ├── UniqueFragmentNames.swift │ ├── UniqueInputFieldNames.swift │ ├── UniqueOperationNames.swift │ ├── VariableAreInputTypes.swift │ └── VariablesInAllowedPosition.swift │ └── Validator.swift ├── GraphQLTests ├── Info.plist ├── Language │ ├── LexerSpec.swift │ ├── ParserSpec.swift │ └── kitchen-sink.graphql ├── Type system │ ├── StarWarsData.swift │ ├── StarWarsModels.swift │ └── StarWarsSchema.swift └── Validation │ ├── Rules │ ├── UniqueArgumentNamesSpec.swift │ └── UniqueOperationNamesSpec.swift │ └── ValidatorHarness.swift ├── Podfile ├── Podfile.lock └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | Pods 2 | *.xcuserdatad 3 | *.xccheckout 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | gem 'cocoapods' 2 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | specs: 3 | activesupport (4.2.4) 4 | i18n (~> 0.7) 5 | json (~> 1.7, >= 1.7.7) 6 | minitest (~> 5.1) 7 | thread_safe (~> 0.3, >= 0.3.4) 8 | tzinfo (~> 1.1) 9 | claide (0.9.1) 10 | cocoapods (0.39.0) 11 | activesupport (>= 4.0.2) 12 | claide (~> 0.9.1) 13 | cocoapods-core (= 0.39.0) 14 | cocoapods-downloader (~> 0.9.3) 15 | cocoapods-plugins (~> 0.4.2) 16 | cocoapods-search (~> 0.1.0) 17 | cocoapods-stats (~> 0.6.2) 18 | cocoapods-trunk (~> 0.6.4) 19 | cocoapods-try (~> 0.5.1) 20 | colored (~> 1.2) 21 | escape (~> 0.0.4) 22 | molinillo (~> 0.4.0) 23 | nap (~> 1.0) 24 | xcodeproj (~> 0.28.2) 25 | cocoapods-core (0.39.0) 26 | activesupport (>= 4.0.2) 27 | fuzzy_match (~> 2.0.4) 28 | nap (~> 1.0) 29 | cocoapods-downloader (0.9.3) 30 | cocoapods-plugins (0.4.2) 31 | nap 32 | cocoapods-search (0.1.0) 33 | cocoapods-stats (0.6.2) 34 | cocoapods-trunk (0.6.4) 35 | nap (>= 0.8, < 2.0) 36 | netrc (= 0.7.8) 37 | cocoapods-try (0.5.1) 38 | colored (1.2) 39 | escape (0.0.4) 40 | fuzzy_match (2.0.4) 41 | i18n (0.7.0) 42 | json (1.8.3) 43 | minitest (5.8.1) 44 | molinillo (0.4.0) 45 | nap (1.0.0) 46 | netrc (0.7.8) 47 | thread_safe (0.3.5) 48 | tzinfo (1.2.2) 49 | thread_safe (~> 0.1) 50 | xcodeproj (0.28.2) 51 | activesupport (>= 3) 52 | claide (~> 0.9.1) 53 | colored (~> 1.2) 54 | 55 | PLATFORMS 56 | ruby 57 | 58 | DEPENDENCIES 59 | cocoapods 60 | 61 | BUNDLED WITH 62 | 1.10.6 63 | -------------------------------------------------------------------------------- /GraphQL.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 570340DA3A7928020D4AB3CA /* Pods_GraphQL_GraphQLTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA3F8DE2497765C3B20492F2 /* Pods_GraphQL_GraphQLTests.framework */; }; 11 | C003DB871B462D2B00A90329 /* GraphQL.h in Headers */ = {isa = PBXBuildFile; fileRef = C003DB861B462D2B00A90329 /* GraphQL.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | C003DB8E1B462D2B00A90329 /* GraphQL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C003DB831B462D2B00A90329 /* GraphQL.framework */; }; 13 | C003DBA11B462D3900A90329 /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = C003DB9E1B462D3900A90329 /* Token.swift */; }; 14 | C003DBAA1B4636DB00A90329 /* GraphQL.swift in Sources */ = {isa = PBXBuildFile; fileRef = C003DBA91B4636DB00A90329 /* GraphQL.swift */; }; 15 | C00CA1541C07DCC3004DF73F /* StarWarsData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C00CA1531C07DCC3004DF73F /* StarWarsData.swift */; }; 16 | C00CA1561C07DCEC004DF73F /* StarWarsModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C00CA1551C07DCEC004DF73F /* StarWarsModels.swift */; }; 17 | C06F7F791B856769006CF035 /* Visitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C06F7F781B856769006CF035 /* Visitor.swift */; }; 18 | C087DAC31C0B9FBB00EF4F91 /* Executor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAC21C0B9FBB00EF4F91 /* Executor.swift */; }; 19 | C087DAC51C0B9FBF00EF4F91 /* Introspection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAC41C0B9FBF00EF4F91 /* Introspection.swift */; }; 20 | C087DAE11C0B9FCB00EF4F91 /* Rule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAC71C0B9FCB00EF4F91 /* Rule.swift */; }; 21 | C087DAE21C0B9FCB00EF4F91 /* ArgumentsOfCorrectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAC91C0B9FCB00EF4F91 /* ArgumentsOfCorrectType.swift */; }; 22 | C087DAE31C0B9FCB00EF4F91 /* DefaultValuesOfCorrectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DACA1C0B9FCB00EF4F91 /* DefaultValuesOfCorrectType.swift */; }; 23 | C087DAE41C0B9FCB00EF4F91 /* FieldsOnCorrectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DACB1C0B9FCB00EF4F91 /* FieldsOnCorrectType.swift */; }; 24 | C087DAE51C0B9FCB00EF4F91 /* FragmentsOnCompositeTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DACC1C0B9FCB00EF4F91 /* FragmentsOnCompositeTypes.swift */; }; 25 | C087DAE61C0B9FCB00EF4F91 /* KnownArgumentNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DACD1C0B9FCB00EF4F91 /* KnownArgumentNames.swift */; }; 26 | C087DAE71C0B9FCB00EF4F91 /* KnownDirectives.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DACE1C0B9FCB00EF4F91 /* KnownDirectives.swift */; }; 27 | C087DAE81C0B9FCB00EF4F91 /* KnownFragmentNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DACF1C0B9FCB00EF4F91 /* KnownFragmentNames.swift */; }; 28 | C087DAE91C0B9FCB00EF4F91 /* KnownTypeNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAD01C0B9FCB00EF4F91 /* KnownTypeNames.swift */; }; 29 | C087DAEA1C0B9FCB00EF4F91 /* LoneAnonymousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAD11C0B9FCB00EF4F91 /* LoneAnonymousOperation.swift */; }; 30 | C087DAEB1C0B9FCB00EF4F91 /* NoFragmentCycles.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAD21C0B9FCB00EF4F91 /* NoFragmentCycles.swift */; }; 31 | C087DAEC1C0B9FCB00EF4F91 /* NoUndefinedVariables.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAD31C0B9FCB00EF4F91 /* NoUndefinedVariables.swift */; }; 32 | C087DAED1C0B9FCB00EF4F91 /* NoUnusedFragments.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAD41C0B9FCB00EF4F91 /* NoUnusedFragments.swift */; }; 33 | C087DAEE1C0B9FCB00EF4F91 /* NoUnusedVariables.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAD51C0B9FCB00EF4F91 /* NoUnusedVariables.swift */; }; 34 | C087DAEF1C0B9FCB00EF4F91 /* OverlappingFieldsCanBeMerged.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAD61C0B9FCB00EF4F91 /* OverlappingFieldsCanBeMerged.swift */; }; 35 | C087DAF01C0B9FCB00EF4F91 /* PossibleFragmentSpreads.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAD71C0B9FCB00EF4F91 /* PossibleFragmentSpreads.swift */; }; 36 | C087DAF11C0B9FCB00EF4F91 /* ProvidedNonNullArguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAD81C0B9FCB00EF4F91 /* ProvidedNonNullArguments.swift */; }; 37 | C087DAF21C0B9FCB00EF4F91 /* ScalarLeafs.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAD91C0B9FCB00EF4F91 /* ScalarLeafs.swift */; }; 38 | C087DAF31C0B9FCB00EF4F91 /* UniqueArgumentNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DADA1C0B9FCB00EF4F91 /* UniqueArgumentNames.swift */; }; 39 | C087DAF41C0B9FCB00EF4F91 /* UniqueFragmentNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DADB1C0B9FCB00EF4F91 /* UniqueFragmentNames.swift */; }; 40 | C087DAF51C0B9FCB00EF4F91 /* UniqueInputFieldNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DADC1C0B9FCB00EF4F91 /* UniqueInputFieldNames.swift */; }; 41 | C087DAF61C0B9FCB00EF4F91 /* UniqueOperationNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DADD1C0B9FCB00EF4F91 /* UniqueOperationNames.swift */; }; 42 | C087DAF71C0B9FCB00EF4F91 /* VariableAreInputTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DADE1C0B9FCB00EF4F91 /* VariableAreInputTypes.swift */; }; 43 | C087DAF81C0B9FCB00EF4F91 /* VariablesInAllowedPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DADF1C0B9FCB00EF4F91 /* VariablesInAllowedPosition.swift */; }; 44 | C087DAF91C0B9FCB00EF4F91 /* Validator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAE01C0B9FCB00EF4F91 /* Validator.swift */; }; 45 | C087DAFF1C0B9FE600EF4F91 /* UniqueArgumentNamesSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAFC1C0B9FE600EF4F91 /* UniqueArgumentNamesSpec.swift */; }; 46 | C087DB001C0B9FE600EF4F91 /* UniqueOperationNamesSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAFD1C0B9FE600EF4F91 /* UniqueOperationNamesSpec.swift */; }; 47 | C087DB011C0B9FE600EF4F91 /* ValidatorHarness.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DAFE1C0B9FE600EF4F91 /* ValidatorHarness.swift */; }; 48 | C087DB041C0BA03C00EF4F91 /* IdentityKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DB021C0BA03C00EF4F91 /* IdentityKit.swift */; }; 49 | C087DB051C0BA03C00EF4F91 /* MultilineStringOperator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DB031C0BA03C00EF4F91 /* MultilineStringOperator.swift */; }; 50 | C087DB071C0BD47C00EF4F91 /* Directives.swift in Sources */ = {isa = PBXBuildFile; fileRef = C087DB061C0BD47C00EF4F91 /* Directives.swift */; }; 51 | C0B2A1CB1C0796D500FFE199 /* kitchen-sink.graphql in Resources */ = {isa = PBXBuildFile; fileRef = C0B2A1C61C0796D500FFE199 /* kitchen-sink.graphql */; }; 52 | C0B2A1CC1C0796D500FFE199 /* LexerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B2A1C71C0796D500FFE199 /* LexerSpec.swift */; }; 53 | C0B2A1CD1C0796D500FFE199 /* ParserSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B2A1C81C0796D500FFE199 /* ParserSpec.swift */; }; 54 | C0B2A1D21C07B01E00FFE199 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B2A1D11C07B01E00FFE199 /* Schema.swift */; }; 55 | C0B2A1D51C07BF0700FFE199 /* StarWarsSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B2A1D41C07BF0700FFE199 /* StarWarsSchema.swift */; }; 56 | C0B3E2B61C09202E00421A72 /* SchemaDirective.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B3E2B51C09202E00421A72 /* SchemaDirective.swift */; }; 57 | C0B3E2B81C09378D00421A72 /* SchemaObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B3E2B71C09378D00421A72 /* SchemaObject.swift */; }; 58 | C0B3E2BA1C0937C200421A72 /* SchemaInputObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B3E2B91C0937C200421A72 /* SchemaInputObject.swift */; }; 59 | C0B3E2BC1C0937D800421A72 /* SchemaInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B3E2BB1C0937D800421A72 /* SchemaInterface.swift */; }; 60 | C0B3E2BE1C0937EB00421A72 /* SchemaEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B3E2BD1C0937EB00421A72 /* SchemaEnum.swift */; }; 61 | C0B3E2C01C0937FC00421A72 /* ValidName.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B3E2BF1C0937FC00421A72 /* ValidName.swift */; }; 62 | C0B3E2C21C0938C500421A72 /* SchemaUnion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B3E2C11C0938C500421A72 /* SchemaUnion.swift */; }; 63 | C0B3E2C41C0938DC00421A72 /* SchemaScalar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B3E2C31C0938DC00421A72 /* SchemaScalar.swift */; }; 64 | C0D4208E1C1358CC00A9EF85 /* NonNull.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D4208D1C1358CC00A9EF85 /* NonNull.swift */; }; 65 | C0D420901C13592700A9EF85 /* SchemaList.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D4208F1C13592700A9EF85 /* SchemaList.swift */; }; 66 | C0FE4CEE1B498178005217E2 /* AbstractSyntaxTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0FE4CEB1B498178005217E2 /* AbstractSyntaxTree.swift */; }; 67 | C0FE4CEF1B498178005217E2 /* Lexer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0FE4CEC1B498178005217E2 /* Lexer.swift */; }; 68 | C0FE4CF01B498178005217E2 /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0FE4CED1B498178005217E2 /* Parser.swift */; }; 69 | C0FE4CF71B4981D0005217E2 /* TypeInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0FE4CF51B4981D0005217E2 /* TypeInfo.swift */; }; 70 | C0FE4CF81B4981D0005217E2 /* Undefined.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0FE4CF61B4981D0005217E2 /* Undefined.swift */; }; 71 | C0FE4CFA1B498279005217E2 /* Source.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0FE4CF91B498279005217E2 /* Source.swift */; }; 72 | /* End PBXBuildFile section */ 73 | 74 | /* Begin PBXContainerItemProxy section */ 75 | C003DB8F1B462D2B00A90329 /* PBXContainerItemProxy */ = { 76 | isa = PBXContainerItemProxy; 77 | containerPortal = C003DB7A1B462D2B00A90329 /* Project object */; 78 | proxyType = 1; 79 | remoteGlobalIDString = C003DB821B462D2B00A90329; 80 | remoteInfo = GraphQL; 81 | }; 82 | /* End PBXContainerItemProxy section */ 83 | 84 | /* Begin PBXFileReference section */ 85 | BA3F8DE2497765C3B20492F2 /* Pods_GraphQL_GraphQLTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GraphQL_GraphQLTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 86 | C003DB831B462D2B00A90329 /* GraphQL.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GraphQL.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 87 | C003DB861B462D2B00A90329 /* GraphQL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GraphQL.h; sourceTree = ""; }; 88 | C003DB881B462D2B00A90329 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 89 | C003DB8D1B462D2B00A90329 /* GraphQLTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GraphQLTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 90 | C003DB941B462D2B00A90329 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 91 | C003DB9E1B462D3900A90329 /* Token.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Token.swift; sourceTree = ""; }; 92 | C003DBA91B4636DB00A90329 /* GraphQL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQL.swift; sourceTree = ""; }; 93 | C00CA1531C07DCC3004DF73F /* StarWarsData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarWarsData.swift; sourceTree = ""; }; 94 | C00CA1551C07DCEC004DF73F /* StarWarsModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarWarsModels.swift; sourceTree = ""; }; 95 | C06F7F781B856769006CF035 /* Visitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Visitor.swift; sourceTree = ""; }; 96 | C087DAC21C0B9FBB00EF4F91 /* Executor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Executor.swift; sourceTree = ""; }; 97 | C087DAC41C0B9FBF00EF4F91 /* Introspection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Introspection.swift; sourceTree = ""; }; 98 | C087DAC71C0B9FCB00EF4F91 /* Rule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Rule.swift; sourceTree = ""; }; 99 | C087DAC91C0B9FCB00EF4F91 /* ArgumentsOfCorrectType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArgumentsOfCorrectType.swift; sourceTree = ""; }; 100 | C087DACA1C0B9FCB00EF4F91 /* DefaultValuesOfCorrectType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultValuesOfCorrectType.swift; sourceTree = ""; }; 101 | C087DACB1C0B9FCB00EF4F91 /* FieldsOnCorrectType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FieldsOnCorrectType.swift; sourceTree = ""; }; 102 | C087DACC1C0B9FCB00EF4F91 /* FragmentsOnCompositeTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FragmentsOnCompositeTypes.swift; sourceTree = ""; }; 103 | C087DACD1C0B9FCB00EF4F91 /* KnownArgumentNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KnownArgumentNames.swift; sourceTree = ""; }; 104 | C087DACE1C0B9FCB00EF4F91 /* KnownDirectives.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KnownDirectives.swift; sourceTree = ""; }; 105 | C087DACF1C0B9FCB00EF4F91 /* KnownFragmentNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KnownFragmentNames.swift; sourceTree = ""; }; 106 | C087DAD01C0B9FCB00EF4F91 /* KnownTypeNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KnownTypeNames.swift; sourceTree = ""; }; 107 | C087DAD11C0B9FCB00EF4F91 /* LoneAnonymousOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoneAnonymousOperation.swift; sourceTree = ""; }; 108 | C087DAD21C0B9FCB00EF4F91 /* NoFragmentCycles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoFragmentCycles.swift; sourceTree = ""; }; 109 | C087DAD31C0B9FCB00EF4F91 /* NoUndefinedVariables.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoUndefinedVariables.swift; sourceTree = ""; }; 110 | C087DAD41C0B9FCB00EF4F91 /* NoUnusedFragments.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoUnusedFragments.swift; sourceTree = ""; }; 111 | C087DAD51C0B9FCB00EF4F91 /* NoUnusedVariables.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoUnusedVariables.swift; sourceTree = ""; }; 112 | C087DAD61C0B9FCB00EF4F91 /* OverlappingFieldsCanBeMerged.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverlappingFieldsCanBeMerged.swift; sourceTree = ""; }; 113 | C087DAD71C0B9FCB00EF4F91 /* PossibleFragmentSpreads.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PossibleFragmentSpreads.swift; sourceTree = ""; }; 114 | C087DAD81C0B9FCB00EF4F91 /* ProvidedNonNullArguments.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProvidedNonNullArguments.swift; sourceTree = ""; }; 115 | C087DAD91C0B9FCB00EF4F91 /* ScalarLeafs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScalarLeafs.swift; sourceTree = ""; }; 116 | C087DADA1C0B9FCB00EF4F91 /* UniqueArgumentNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniqueArgumentNames.swift; sourceTree = ""; }; 117 | C087DADB1C0B9FCB00EF4F91 /* UniqueFragmentNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniqueFragmentNames.swift; sourceTree = ""; }; 118 | C087DADC1C0B9FCB00EF4F91 /* UniqueInputFieldNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniqueInputFieldNames.swift; sourceTree = ""; }; 119 | C087DADD1C0B9FCB00EF4F91 /* UniqueOperationNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniqueOperationNames.swift; sourceTree = ""; }; 120 | C087DADE1C0B9FCB00EF4F91 /* VariableAreInputTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VariableAreInputTypes.swift; sourceTree = ""; }; 121 | C087DADF1C0B9FCB00EF4F91 /* VariablesInAllowedPosition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VariablesInAllowedPosition.swift; sourceTree = ""; }; 122 | C087DAE01C0B9FCB00EF4F91 /* Validator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Validator.swift; sourceTree = ""; }; 123 | C087DAFC1C0B9FE600EF4F91 /* UniqueArgumentNamesSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniqueArgumentNamesSpec.swift; sourceTree = ""; }; 124 | C087DAFD1C0B9FE600EF4F91 /* UniqueOperationNamesSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniqueOperationNamesSpec.swift; sourceTree = ""; }; 125 | C087DAFE1C0B9FE600EF4F91 /* ValidatorHarness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidatorHarness.swift; sourceTree = ""; }; 126 | C087DB021C0BA03C00EF4F91 /* IdentityKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentityKit.swift; sourceTree = ""; }; 127 | C087DB031C0BA03C00EF4F91 /* MultilineStringOperator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilineStringOperator.swift; sourceTree = ""; }; 128 | C087DB061C0BD47C00EF4F91 /* Directives.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Directives.swift; sourceTree = ""; }; 129 | C0B2A1C61C0796D500FFE199 /* kitchen-sink.graphql */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "kitchen-sink.graphql"; sourceTree = ""; }; 130 | C0B2A1C71C0796D500FFE199 /* LexerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LexerSpec.swift; sourceTree = ""; }; 131 | C0B2A1C81C0796D500FFE199 /* ParserSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParserSpec.swift; sourceTree = ""; }; 132 | C0B2A1D11C07B01E00FFE199 /* Schema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Schema.swift; sourceTree = ""; }; 133 | C0B2A1D41C07BF0700FFE199 /* StarWarsSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarWarsSchema.swift; sourceTree = ""; }; 134 | C0B3E2B51C09202E00421A72 /* SchemaDirective.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaDirective.swift; sourceTree = ""; }; 135 | C0B3E2B71C09378D00421A72 /* SchemaObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaObject.swift; sourceTree = ""; }; 136 | C0B3E2B91C0937C200421A72 /* SchemaInputObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaInputObject.swift; sourceTree = ""; }; 137 | C0B3E2BB1C0937D800421A72 /* SchemaInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaInterface.swift; sourceTree = ""; }; 138 | C0B3E2BD1C0937EB00421A72 /* SchemaEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaEnum.swift; sourceTree = ""; }; 139 | C0B3E2BF1C0937FC00421A72 /* ValidName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidName.swift; sourceTree = ""; }; 140 | C0B3E2C11C0938C500421A72 /* SchemaUnion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaUnion.swift; sourceTree = ""; }; 141 | C0B3E2C31C0938DC00421A72 /* SchemaScalar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaScalar.swift; sourceTree = ""; }; 142 | C0D4208D1C1358CC00A9EF85 /* NonNull.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NonNull.swift; sourceTree = ""; }; 143 | C0D4208F1C13592700A9EF85 /* SchemaList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaList.swift; sourceTree = ""; }; 144 | C0FE4CEB1B498178005217E2 /* AbstractSyntaxTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AbstractSyntaxTree.swift; sourceTree = ""; }; 145 | C0FE4CEC1B498178005217E2 /* Lexer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lexer.swift; sourceTree = ""; }; 146 | C0FE4CED1B498178005217E2 /* Parser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Parser.swift; sourceTree = ""; }; 147 | C0FE4CF51B4981D0005217E2 /* TypeInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeInfo.swift; sourceTree = ""; }; 148 | C0FE4CF61B4981D0005217E2 /* Undefined.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Undefined.swift; sourceTree = ""; }; 149 | C0FE4CF91B498279005217E2 /* Source.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Source.swift; sourceTree = ""; }; 150 | C3D129EDC86D227E763190F7 /* Pods-GraphQL-GraphQLTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GraphQL-GraphQLTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-GraphQL-GraphQLTests/Pods-GraphQL-GraphQLTests.release.xcconfig"; sourceTree = ""; }; 151 | E159DB1464CFB67365B6705D /* Pods-GraphQL-GraphQLTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GraphQL-GraphQLTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GraphQL-GraphQLTests/Pods-GraphQL-GraphQLTests.debug.xcconfig"; sourceTree = ""; }; 152 | /* End PBXFileReference section */ 153 | 154 | /* Begin PBXFrameworksBuildPhase section */ 155 | C003DB7F1B462D2B00A90329 /* Frameworks */ = { 156 | isa = PBXFrameworksBuildPhase; 157 | buildActionMask = 2147483647; 158 | files = ( 159 | ); 160 | runOnlyForDeploymentPostprocessing = 0; 161 | }; 162 | C003DB8A1B462D2B00A90329 /* Frameworks */ = { 163 | isa = PBXFrameworksBuildPhase; 164 | buildActionMask = 2147483647; 165 | files = ( 166 | C003DB8E1B462D2B00A90329 /* GraphQL.framework in Frameworks */, 167 | 570340DA3A7928020D4AB3CA /* Pods_GraphQL_GraphQLTests.framework in Frameworks */, 168 | ); 169 | runOnlyForDeploymentPostprocessing = 0; 170 | }; 171 | /* End PBXFrameworksBuildPhase section */ 172 | 173 | /* Begin PBXGroup section */ 174 | 728587A83F4CF1E3A4EDC412 /* Pods */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | E159DB1464CFB67365B6705D /* Pods-GraphQL-GraphQLTests.debug.xcconfig */, 178 | C3D129EDC86D227E763190F7 /* Pods-GraphQL-GraphQLTests.release.xcconfig */, 179 | ); 180 | name = Pods; 181 | sourceTree = ""; 182 | }; 183 | 98E5DE221EE1444B8CE05147 /* Frameworks */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | BA3F8DE2497765C3B20492F2 /* Pods_GraphQL_GraphQLTests.framework */, 187 | ); 188 | name = Frameworks; 189 | sourceTree = ""; 190 | }; 191 | C003DB791B462D2B00A90329 = { 192 | isa = PBXGroup; 193 | children = ( 194 | C003DB851B462D2B00A90329 /* GraphQL */, 195 | C003DB911B462D2B00A90329 /* GraphQLTests */, 196 | C003DB841B462D2B00A90329 /* Products */, 197 | 728587A83F4CF1E3A4EDC412 /* Pods */, 198 | 98E5DE221EE1444B8CE05147 /* Frameworks */, 199 | ); 200 | sourceTree = ""; 201 | }; 202 | C003DB841B462D2B00A90329 /* Products */ = { 203 | isa = PBXGroup; 204 | children = ( 205 | C003DB831B462D2B00A90329 /* GraphQL.framework */, 206 | C003DB8D1B462D2B00A90329 /* GraphQLTests.xctest */, 207 | ); 208 | name = Products; 209 | sourceTree = ""; 210 | }; 211 | C003DB851B462D2B00A90329 /* GraphQL */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | C087DAC11C0B9FBB00EF4F91 /* Execution */, 215 | C087DAC01C0B9F9500EF4F91 /* Introspection */, 216 | C0FE4CEA1B498178005217E2 /* Language */, 217 | C0B2A1D01C07B01900FFE199 /* Type system */, 218 | C087DAC61C0B9FCB00EF4F91 /* Validation */, 219 | C0FE4CF41B4981D0005217E2 /* Utils */, 220 | C003DB861B462D2B00A90329 /* GraphQL.h */, 221 | C003DBA91B4636DB00A90329 /* GraphQL.swift */, 222 | C003DB881B462D2B00A90329 /* Info.plist */, 223 | ); 224 | path = GraphQL; 225 | sourceTree = ""; 226 | }; 227 | C003DB911B462D2B00A90329 /* GraphQLTests */ = { 228 | isa = PBXGroup; 229 | children = ( 230 | C0B2A1C51C0796D500FFE199 /* Language */, 231 | C0B2A1D31C07BEF300FFE199 /* Type system */, 232 | C087DAFA1C0B9FE600EF4F91 /* Validation */, 233 | C003DB941B462D2B00A90329 /* Info.plist */, 234 | ); 235 | path = GraphQLTests; 236 | sourceTree = ""; 237 | }; 238 | C087DAC01C0B9F9500EF4F91 /* Introspection */ = { 239 | isa = PBXGroup; 240 | children = ( 241 | C087DAC41C0B9FBF00EF4F91 /* Introspection.swift */, 242 | ); 243 | path = Introspection; 244 | sourceTree = ""; 245 | }; 246 | C087DAC11C0B9FBB00EF4F91 /* Execution */ = { 247 | isa = PBXGroup; 248 | children = ( 249 | C087DAC21C0B9FBB00EF4F91 /* Executor.swift */, 250 | ); 251 | path = Execution; 252 | sourceTree = ""; 253 | }; 254 | C087DAC61C0B9FCB00EF4F91 /* Validation */ = { 255 | isa = PBXGroup; 256 | children = ( 257 | C087DAC81C0B9FCB00EF4F91 /* Rules */, 258 | C087DAC71C0B9FCB00EF4F91 /* Rule.swift */, 259 | C087DAE01C0B9FCB00EF4F91 /* Validator.swift */, 260 | ); 261 | name = Validation; 262 | path = GraphQL/Validation; 263 | sourceTree = SOURCE_ROOT; 264 | }; 265 | C087DAC81C0B9FCB00EF4F91 /* Rules */ = { 266 | isa = PBXGroup; 267 | children = ( 268 | C087DAC91C0B9FCB00EF4F91 /* ArgumentsOfCorrectType.swift */, 269 | C087DACA1C0B9FCB00EF4F91 /* DefaultValuesOfCorrectType.swift */, 270 | C087DACB1C0B9FCB00EF4F91 /* FieldsOnCorrectType.swift */, 271 | C087DACC1C0B9FCB00EF4F91 /* FragmentsOnCompositeTypes.swift */, 272 | C087DACD1C0B9FCB00EF4F91 /* KnownArgumentNames.swift */, 273 | C087DACE1C0B9FCB00EF4F91 /* KnownDirectives.swift */, 274 | C087DACF1C0B9FCB00EF4F91 /* KnownFragmentNames.swift */, 275 | C087DAD01C0B9FCB00EF4F91 /* KnownTypeNames.swift */, 276 | C087DAD11C0B9FCB00EF4F91 /* LoneAnonymousOperation.swift */, 277 | C087DAD21C0B9FCB00EF4F91 /* NoFragmentCycles.swift */, 278 | C087DAD31C0B9FCB00EF4F91 /* NoUndefinedVariables.swift */, 279 | C087DAD41C0B9FCB00EF4F91 /* NoUnusedFragments.swift */, 280 | C087DAD51C0B9FCB00EF4F91 /* NoUnusedVariables.swift */, 281 | C087DAD61C0B9FCB00EF4F91 /* OverlappingFieldsCanBeMerged.swift */, 282 | C087DAD71C0B9FCB00EF4F91 /* PossibleFragmentSpreads.swift */, 283 | C087DAD81C0B9FCB00EF4F91 /* ProvidedNonNullArguments.swift */, 284 | C087DAD91C0B9FCB00EF4F91 /* ScalarLeafs.swift */, 285 | C087DADA1C0B9FCB00EF4F91 /* UniqueArgumentNames.swift */, 286 | C087DADB1C0B9FCB00EF4F91 /* UniqueFragmentNames.swift */, 287 | C087DADC1C0B9FCB00EF4F91 /* UniqueInputFieldNames.swift */, 288 | C087DADD1C0B9FCB00EF4F91 /* UniqueOperationNames.swift */, 289 | C087DADE1C0B9FCB00EF4F91 /* VariableAreInputTypes.swift */, 290 | C087DADF1C0B9FCB00EF4F91 /* VariablesInAllowedPosition.swift */, 291 | ); 292 | path = Rules; 293 | sourceTree = ""; 294 | }; 295 | C087DAFA1C0B9FE600EF4F91 /* Validation */ = { 296 | isa = PBXGroup; 297 | children = ( 298 | C087DAFB1C0B9FE600EF4F91 /* Rules */, 299 | C087DAFE1C0B9FE600EF4F91 /* ValidatorHarness.swift */, 300 | ); 301 | path = Validation; 302 | sourceTree = ""; 303 | }; 304 | C087DAFB1C0B9FE600EF4F91 /* Rules */ = { 305 | isa = PBXGroup; 306 | children = ( 307 | C087DAFC1C0B9FE600EF4F91 /* UniqueArgumentNamesSpec.swift */, 308 | C087DAFD1C0B9FE600EF4F91 /* UniqueOperationNamesSpec.swift */, 309 | ); 310 | path = Rules; 311 | sourceTree = ""; 312 | }; 313 | C0B2A1C51C0796D500FFE199 /* Language */ = { 314 | isa = PBXGroup; 315 | children = ( 316 | C0B2A1C61C0796D500FFE199 /* kitchen-sink.graphql */, 317 | C0B2A1C71C0796D500FFE199 /* LexerSpec.swift */, 318 | C0B2A1C81C0796D500FFE199 /* ParserSpec.swift */, 319 | ); 320 | path = Language; 321 | sourceTree = ""; 322 | }; 323 | C0B2A1D01C07B01900FFE199 /* Type system */ = { 324 | isa = PBXGroup; 325 | children = ( 326 | C087DB061C0BD47C00EF4F91 /* Directives.swift */, 327 | C0D4208D1C1358CC00A9EF85 /* NonNull.swift */, 328 | C0B2A1D11C07B01E00FFE199 /* Schema.swift */, 329 | C0B3E2B51C09202E00421A72 /* SchemaDirective.swift */, 330 | C0B3E2BD1C0937EB00421A72 /* SchemaEnum.swift */, 331 | C0B3E2B91C0937C200421A72 /* SchemaInputObject.swift */, 332 | C0B3E2BB1C0937D800421A72 /* SchemaInterface.swift */, 333 | C0D4208F1C13592700A9EF85 /* SchemaList.swift */, 334 | C0B3E2B71C09378D00421A72 /* SchemaObject.swift */, 335 | C0B3E2C31C0938DC00421A72 /* SchemaScalar.swift */, 336 | C0B3E2C11C0938C500421A72 /* SchemaUnion.swift */, 337 | C0B3E2BF1C0937FC00421A72 /* ValidName.swift */, 338 | ); 339 | path = "Type system"; 340 | sourceTree = ""; 341 | }; 342 | C0B2A1D31C07BEF300FFE199 /* Type system */ = { 343 | isa = PBXGroup; 344 | children = ( 345 | C00CA1531C07DCC3004DF73F /* StarWarsData.swift */, 346 | C00CA1551C07DCEC004DF73F /* StarWarsModels.swift */, 347 | C0B2A1D41C07BF0700FFE199 /* StarWarsSchema.swift */, 348 | ); 349 | path = "Type system"; 350 | sourceTree = ""; 351 | }; 352 | C0FE4CEA1B498178005217E2 /* Language */ = { 353 | isa = PBXGroup; 354 | children = ( 355 | C0FE4CEB1B498178005217E2 /* AbstractSyntaxTree.swift */, 356 | C0FE4CEC1B498178005217E2 /* Lexer.swift */, 357 | C0FE4CED1B498178005217E2 /* Parser.swift */, 358 | C0FE4CF91B498279005217E2 /* Source.swift */, 359 | C003DB9E1B462D3900A90329 /* Token.swift */, 360 | C06F7F781B856769006CF035 /* Visitor.swift */, 361 | ); 362 | path = Language; 363 | sourceTree = ""; 364 | }; 365 | C0FE4CF41B4981D0005217E2 /* Utils */ = { 366 | isa = PBXGroup; 367 | children = ( 368 | C087DB021C0BA03C00EF4F91 /* IdentityKit.swift */, 369 | C087DB031C0BA03C00EF4F91 /* MultilineStringOperator.swift */, 370 | C0FE4CF51B4981D0005217E2 /* TypeInfo.swift */, 371 | C0FE4CF61B4981D0005217E2 /* Undefined.swift */, 372 | ); 373 | path = Utils; 374 | sourceTree = ""; 375 | }; 376 | /* End PBXGroup section */ 377 | 378 | /* Begin PBXHeadersBuildPhase section */ 379 | C003DB801B462D2B00A90329 /* Headers */ = { 380 | isa = PBXHeadersBuildPhase; 381 | buildActionMask = 2147483647; 382 | files = ( 383 | C003DB871B462D2B00A90329 /* GraphQL.h in Headers */, 384 | ); 385 | runOnlyForDeploymentPostprocessing = 0; 386 | }; 387 | /* End PBXHeadersBuildPhase section */ 388 | 389 | /* Begin PBXNativeTarget section */ 390 | C003DB821B462D2B00A90329 /* GraphQL */ = { 391 | isa = PBXNativeTarget; 392 | buildConfigurationList = C003DB971B462D2B00A90329 /* Build configuration list for PBXNativeTarget "GraphQL" */; 393 | buildPhases = ( 394 | C003DB7E1B462D2B00A90329 /* Sources */, 395 | C003DB7F1B462D2B00A90329 /* Frameworks */, 396 | C003DB801B462D2B00A90329 /* Headers */, 397 | C003DB811B462D2B00A90329 /* Resources */, 398 | ); 399 | buildRules = ( 400 | ); 401 | dependencies = ( 402 | ); 403 | name = GraphQL; 404 | productName = GraphQL; 405 | productReference = C003DB831B462D2B00A90329 /* GraphQL.framework */; 406 | productType = "com.apple.product-type.framework"; 407 | }; 408 | C003DB8C1B462D2B00A90329 /* GraphQLTests */ = { 409 | isa = PBXNativeTarget; 410 | buildConfigurationList = C003DB9A1B462D2B00A90329 /* Build configuration list for PBXNativeTarget "GraphQLTests" */; 411 | buildPhases = ( 412 | 3BA57C7924B600F0E2772F30 /* Check Pods Manifest.lock */, 413 | C003DB891B462D2B00A90329 /* Sources */, 414 | C003DB8A1B462D2B00A90329 /* Frameworks */, 415 | C003DB8B1B462D2B00A90329 /* Resources */, 416 | A2FE96F097336F68F23F5322 /* Embed Pods Frameworks */, 417 | 6E5CABAE40DE84CECA5822CF /* Copy Pods Resources */, 418 | ); 419 | buildRules = ( 420 | ); 421 | dependencies = ( 422 | C003DB901B462D2B00A90329 /* PBXTargetDependency */, 423 | ); 424 | name = GraphQLTests; 425 | productName = GraphQLTests; 426 | productReference = C003DB8D1B462D2B00A90329 /* GraphQLTests.xctest */; 427 | productType = "com.apple.product-type.bundle.unit-test"; 428 | }; 429 | /* End PBXNativeTarget section */ 430 | 431 | /* Begin PBXProject section */ 432 | C003DB7A1B462D2B00A90329 /* Project object */ = { 433 | isa = PBXProject; 434 | attributes = { 435 | LastSwiftUpdateCheck = 0700; 436 | LastUpgradeCheck = 0700; 437 | ORGANIZATIONNAME = stepanhruda; 438 | TargetAttributes = { 439 | C003DB821B462D2B00A90329 = { 440 | CreatedOnToolsVersion = 7.0; 441 | }; 442 | C003DB8C1B462D2B00A90329 = { 443 | CreatedOnToolsVersion = 7.0; 444 | }; 445 | }; 446 | }; 447 | buildConfigurationList = C003DB7D1B462D2B00A90329 /* Build configuration list for PBXProject "GraphQL" */; 448 | compatibilityVersion = "Xcode 3.2"; 449 | developmentRegion = English; 450 | hasScannedForEncodings = 0; 451 | knownRegions = ( 452 | en, 453 | ); 454 | mainGroup = C003DB791B462D2B00A90329; 455 | productRefGroup = C003DB841B462D2B00A90329 /* Products */; 456 | projectDirPath = ""; 457 | projectRoot = ""; 458 | targets = ( 459 | C003DB821B462D2B00A90329 /* GraphQL */, 460 | C003DB8C1B462D2B00A90329 /* GraphQLTests */, 461 | ); 462 | }; 463 | /* End PBXProject section */ 464 | 465 | /* Begin PBXResourcesBuildPhase section */ 466 | C003DB811B462D2B00A90329 /* Resources */ = { 467 | isa = PBXResourcesBuildPhase; 468 | buildActionMask = 2147483647; 469 | files = ( 470 | ); 471 | runOnlyForDeploymentPostprocessing = 0; 472 | }; 473 | C003DB8B1B462D2B00A90329 /* Resources */ = { 474 | isa = PBXResourcesBuildPhase; 475 | buildActionMask = 2147483647; 476 | files = ( 477 | C0B2A1CB1C0796D500FFE199 /* kitchen-sink.graphql in Resources */, 478 | ); 479 | runOnlyForDeploymentPostprocessing = 0; 480 | }; 481 | /* End PBXResourcesBuildPhase section */ 482 | 483 | /* Begin PBXShellScriptBuildPhase section */ 484 | 3BA57C7924B600F0E2772F30 /* Check Pods Manifest.lock */ = { 485 | isa = PBXShellScriptBuildPhase; 486 | buildActionMask = 2147483647; 487 | files = ( 488 | ); 489 | inputPaths = ( 490 | ); 491 | name = "Check Pods Manifest.lock"; 492 | outputPaths = ( 493 | ); 494 | runOnlyForDeploymentPostprocessing = 0; 495 | shellPath = /bin/sh; 496 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 497 | showEnvVarsInLog = 0; 498 | }; 499 | 6E5CABAE40DE84CECA5822CF /* Copy Pods Resources */ = { 500 | isa = PBXShellScriptBuildPhase; 501 | buildActionMask = 2147483647; 502 | files = ( 503 | ); 504 | inputPaths = ( 505 | ); 506 | name = "Copy Pods Resources"; 507 | outputPaths = ( 508 | ); 509 | runOnlyForDeploymentPostprocessing = 0; 510 | shellPath = /bin/sh; 511 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-GraphQL-GraphQLTests/Pods-GraphQL-GraphQLTests-resources.sh\"\n"; 512 | showEnvVarsInLog = 0; 513 | }; 514 | A2FE96F097336F68F23F5322 /* Embed Pods Frameworks */ = { 515 | isa = PBXShellScriptBuildPhase; 516 | buildActionMask = 2147483647; 517 | files = ( 518 | ); 519 | inputPaths = ( 520 | ); 521 | name = "Embed Pods Frameworks"; 522 | outputPaths = ( 523 | ); 524 | runOnlyForDeploymentPostprocessing = 0; 525 | shellPath = /bin/sh; 526 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-GraphQL-GraphQLTests/Pods-GraphQL-GraphQLTests-frameworks.sh\"\n"; 527 | showEnvVarsInLog = 0; 528 | }; 529 | /* End PBXShellScriptBuildPhase section */ 530 | 531 | /* Begin PBXSourcesBuildPhase section */ 532 | C003DB7E1B462D2B00A90329 /* Sources */ = { 533 | isa = PBXSourcesBuildPhase; 534 | buildActionMask = 2147483647; 535 | files = ( 536 | C087DAEF1C0B9FCB00EF4F91 /* OverlappingFieldsCanBeMerged.swift in Sources */, 537 | C0B3E2BC1C0937D800421A72 /* SchemaInterface.swift in Sources */, 538 | C0D420901C13592700A9EF85 /* SchemaList.swift in Sources */, 539 | C087DAF31C0B9FCB00EF4F91 /* UniqueArgumentNames.swift in Sources */, 540 | C0FE4CF81B4981D0005217E2 /* Undefined.swift in Sources */, 541 | C0D4208E1C1358CC00A9EF85 /* NonNull.swift in Sources */, 542 | C087DAC31C0B9FBB00EF4F91 /* Executor.swift in Sources */, 543 | C087DAEC1C0B9FCB00EF4F91 /* NoUndefinedVariables.swift in Sources */, 544 | C087DB041C0BA03C00EF4F91 /* IdentityKit.swift in Sources */, 545 | C087DAE11C0B9FCB00EF4F91 /* Rule.swift in Sources */, 546 | C0B3E2B81C09378D00421A72 /* SchemaObject.swift in Sources */, 547 | C087DAEB1C0B9FCB00EF4F91 /* NoFragmentCycles.swift in Sources */, 548 | C087DAF51C0B9FCB00EF4F91 /* UniqueInputFieldNames.swift in Sources */, 549 | C0FE4CEE1B498178005217E2 /* AbstractSyntaxTree.swift in Sources */, 550 | C0B3E2BE1C0937EB00421A72 /* SchemaEnum.swift in Sources */, 551 | C003DBAA1B4636DB00A90329 /* GraphQL.swift in Sources */, 552 | C0FE4CFA1B498279005217E2 /* Source.swift in Sources */, 553 | C087DAF41C0B9FCB00EF4F91 /* UniqueFragmentNames.swift in Sources */, 554 | C087DAF61C0B9FCB00EF4F91 /* UniqueOperationNames.swift in Sources */, 555 | C0B3E2C21C0938C500421A72 /* SchemaUnion.swift in Sources */, 556 | C087DAF71C0B9FCB00EF4F91 /* VariableAreInputTypes.swift in Sources */, 557 | C087DAE91C0B9FCB00EF4F91 /* KnownTypeNames.swift in Sources */, 558 | C087DAF11C0B9FCB00EF4F91 /* ProvidedNonNullArguments.swift in Sources */, 559 | C087DAF81C0B9FCB00EF4F91 /* VariablesInAllowedPosition.swift in Sources */, 560 | C087DAE31C0B9FCB00EF4F91 /* DefaultValuesOfCorrectType.swift in Sources */, 561 | C087DAC51C0B9FBF00EF4F91 /* Introspection.swift in Sources */, 562 | C087DAEA1C0B9FCB00EF4F91 /* LoneAnonymousOperation.swift in Sources */, 563 | C087DAF01C0B9FCB00EF4F91 /* PossibleFragmentSpreads.swift in Sources */, 564 | C0FE4CF01B498178005217E2 /* Parser.swift in Sources */, 565 | C0B3E2BA1C0937C200421A72 /* SchemaInputObject.swift in Sources */, 566 | C087DAED1C0B9FCB00EF4F91 /* NoUnusedFragments.swift in Sources */, 567 | C087DB071C0BD47C00EF4F91 /* Directives.swift in Sources */, 568 | C087DAF91C0B9FCB00EF4F91 /* Validator.swift in Sources */, 569 | C003DBA11B462D3900A90329 /* Token.swift in Sources */, 570 | C087DAEE1C0B9FCB00EF4F91 /* NoUnusedVariables.swift in Sources */, 571 | C087DAF21C0B9FCB00EF4F91 /* ScalarLeafs.swift in Sources */, 572 | C0FE4CEF1B498178005217E2 /* Lexer.swift in Sources */, 573 | C0B2A1D21C07B01E00FFE199 /* Schema.swift in Sources */, 574 | C0FE4CF71B4981D0005217E2 /* TypeInfo.swift in Sources */, 575 | C087DAE51C0B9FCB00EF4F91 /* FragmentsOnCompositeTypes.swift in Sources */, 576 | C087DAE71C0B9FCB00EF4F91 /* KnownDirectives.swift in Sources */, 577 | C0B3E2C41C0938DC00421A72 /* SchemaScalar.swift in Sources */, 578 | C0B3E2C01C0937FC00421A72 /* ValidName.swift in Sources */, 579 | C087DAE41C0B9FCB00EF4F91 /* FieldsOnCorrectType.swift in Sources */, 580 | C087DB051C0BA03C00EF4F91 /* MultilineStringOperator.swift in Sources */, 581 | C0B3E2B61C09202E00421A72 /* SchemaDirective.swift in Sources */, 582 | C06F7F791B856769006CF035 /* Visitor.swift in Sources */, 583 | C087DAE21C0B9FCB00EF4F91 /* ArgumentsOfCorrectType.swift in Sources */, 584 | C087DAE61C0B9FCB00EF4F91 /* KnownArgumentNames.swift in Sources */, 585 | C087DAE81C0B9FCB00EF4F91 /* KnownFragmentNames.swift in Sources */, 586 | ); 587 | runOnlyForDeploymentPostprocessing = 0; 588 | }; 589 | C003DB891B462D2B00A90329 /* Sources */ = { 590 | isa = PBXSourcesBuildPhase; 591 | buildActionMask = 2147483647; 592 | files = ( 593 | C087DB001C0B9FE600EF4F91 /* UniqueOperationNamesSpec.swift in Sources */, 594 | C087DB011C0B9FE600EF4F91 /* ValidatorHarness.swift in Sources */, 595 | C00CA1561C07DCEC004DF73F /* StarWarsModels.swift in Sources */, 596 | C00CA1541C07DCC3004DF73F /* StarWarsData.swift in Sources */, 597 | C087DAFF1C0B9FE600EF4F91 /* UniqueArgumentNamesSpec.swift in Sources */, 598 | C0B2A1CC1C0796D500FFE199 /* LexerSpec.swift in Sources */, 599 | C0B2A1CD1C0796D500FFE199 /* ParserSpec.swift in Sources */, 600 | C0B2A1D51C07BF0700FFE199 /* StarWarsSchema.swift in Sources */, 601 | ); 602 | runOnlyForDeploymentPostprocessing = 0; 603 | }; 604 | /* End PBXSourcesBuildPhase section */ 605 | 606 | /* Begin PBXTargetDependency section */ 607 | C003DB901B462D2B00A90329 /* PBXTargetDependency */ = { 608 | isa = PBXTargetDependency; 609 | target = C003DB821B462D2B00A90329 /* GraphQL */; 610 | targetProxy = C003DB8F1B462D2B00A90329 /* PBXContainerItemProxy */; 611 | }; 612 | /* End PBXTargetDependency section */ 613 | 614 | /* Begin XCBuildConfiguration section */ 615 | C003DB951B462D2B00A90329 /* Debug */ = { 616 | isa = XCBuildConfiguration; 617 | buildSettings = { 618 | ALWAYS_SEARCH_USER_PATHS = NO; 619 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 620 | CLANG_CXX_LIBRARY = "libc++"; 621 | CLANG_ENABLE_MODULES = YES; 622 | CLANG_ENABLE_OBJC_ARC = YES; 623 | CLANG_WARN_BOOL_CONVERSION = YES; 624 | CLANG_WARN_CONSTANT_CONVERSION = YES; 625 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 626 | CLANG_WARN_EMPTY_BODY = YES; 627 | CLANG_WARN_ENUM_CONVERSION = YES; 628 | CLANG_WARN_INT_CONVERSION = YES; 629 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 630 | CLANG_WARN_UNREACHABLE_CODE = YES; 631 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 632 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 633 | COPY_PHASE_STRIP = NO; 634 | CURRENT_PROJECT_VERSION = 1; 635 | DEBUG_INFORMATION_FORMAT = dwarf; 636 | ENABLE_STRICT_OBJC_MSGSEND = YES; 637 | ENABLE_TESTABILITY = YES; 638 | GCC_C_LANGUAGE_STANDARD = gnu99; 639 | GCC_DYNAMIC_NO_PIC = NO; 640 | GCC_NO_COMMON_BLOCKS = YES; 641 | GCC_OPTIMIZATION_LEVEL = 0; 642 | GCC_PREPROCESSOR_DEFINITIONS = ( 643 | "DEBUG=1", 644 | "$(inherited)", 645 | ); 646 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 647 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 648 | GCC_WARN_UNDECLARED_SELECTOR = YES; 649 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 650 | GCC_WARN_UNUSED_FUNCTION = YES; 651 | GCC_WARN_UNUSED_VARIABLE = YES; 652 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 653 | MTL_ENABLE_DEBUG_INFO = YES; 654 | ONLY_ACTIVE_ARCH = YES; 655 | SDKROOT = iphoneos; 656 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 657 | TARGETED_DEVICE_FAMILY = "1,2"; 658 | VERSIONING_SYSTEM = "apple-generic"; 659 | VERSION_INFO_PREFIX = ""; 660 | }; 661 | name = Debug; 662 | }; 663 | C003DB961B462D2B00A90329 /* Release */ = { 664 | isa = XCBuildConfiguration; 665 | buildSettings = { 666 | ALWAYS_SEARCH_USER_PATHS = NO; 667 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 668 | CLANG_CXX_LIBRARY = "libc++"; 669 | CLANG_ENABLE_MODULES = YES; 670 | CLANG_ENABLE_OBJC_ARC = YES; 671 | CLANG_WARN_BOOL_CONVERSION = YES; 672 | CLANG_WARN_CONSTANT_CONVERSION = YES; 673 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 674 | CLANG_WARN_EMPTY_BODY = YES; 675 | CLANG_WARN_ENUM_CONVERSION = YES; 676 | CLANG_WARN_INT_CONVERSION = YES; 677 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 678 | CLANG_WARN_UNREACHABLE_CODE = YES; 679 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 680 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 681 | COPY_PHASE_STRIP = NO; 682 | CURRENT_PROJECT_VERSION = 1; 683 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 684 | ENABLE_NS_ASSERTIONS = NO; 685 | ENABLE_STRICT_OBJC_MSGSEND = YES; 686 | GCC_C_LANGUAGE_STANDARD = gnu99; 687 | GCC_NO_COMMON_BLOCKS = YES; 688 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 689 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 690 | GCC_WARN_UNDECLARED_SELECTOR = YES; 691 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 692 | GCC_WARN_UNUSED_FUNCTION = YES; 693 | GCC_WARN_UNUSED_VARIABLE = YES; 694 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 695 | MTL_ENABLE_DEBUG_INFO = NO; 696 | SDKROOT = iphoneos; 697 | TARGETED_DEVICE_FAMILY = "1,2"; 698 | VALIDATE_PRODUCT = YES; 699 | VERSIONING_SYSTEM = "apple-generic"; 700 | VERSION_INFO_PREFIX = ""; 701 | }; 702 | name = Release; 703 | }; 704 | C003DB981B462D2B00A90329 /* Debug */ = { 705 | isa = XCBuildConfiguration; 706 | buildSettings = { 707 | CLANG_ENABLE_MODULES = YES; 708 | DEFINES_MODULE = YES; 709 | DYLIB_COMPATIBILITY_VERSION = 1; 710 | DYLIB_CURRENT_VERSION = 1; 711 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 712 | INFOPLIST_FILE = GraphQL/Info.plist; 713 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 714 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 715 | PRODUCT_BUNDLE_IDENTIFIER = technology.stepanhruda.GraphQL; 716 | PRODUCT_NAME = "$(TARGET_NAME)"; 717 | SKIP_INSTALL = YES; 718 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 719 | }; 720 | name = Debug; 721 | }; 722 | C003DB991B462D2B00A90329 /* Release */ = { 723 | isa = XCBuildConfiguration; 724 | buildSettings = { 725 | CLANG_ENABLE_MODULES = YES; 726 | DEFINES_MODULE = YES; 727 | DYLIB_COMPATIBILITY_VERSION = 1; 728 | DYLIB_CURRENT_VERSION = 1; 729 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 730 | INFOPLIST_FILE = GraphQL/Info.plist; 731 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 732 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 733 | PRODUCT_BUNDLE_IDENTIFIER = technology.stepanhruda.GraphQL; 734 | PRODUCT_NAME = "$(TARGET_NAME)"; 735 | SKIP_INSTALL = YES; 736 | }; 737 | name = Release; 738 | }; 739 | C003DB9B1B462D2B00A90329 /* Debug */ = { 740 | isa = XCBuildConfiguration; 741 | baseConfigurationReference = E159DB1464CFB67365B6705D /* Pods-GraphQL-GraphQLTests.debug.xcconfig */; 742 | buildSettings = { 743 | INFOPLIST_FILE = GraphQLTests/Info.plist; 744 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 745 | PRODUCT_BUNDLE_IDENTIFIER = technology.stepanhruda.GraphQLTests; 746 | PRODUCT_NAME = "$(TARGET_NAME)"; 747 | }; 748 | name = Debug; 749 | }; 750 | C003DB9C1B462D2B00A90329 /* Release */ = { 751 | isa = XCBuildConfiguration; 752 | baseConfigurationReference = C3D129EDC86D227E763190F7 /* Pods-GraphQL-GraphQLTests.release.xcconfig */; 753 | buildSettings = { 754 | INFOPLIST_FILE = GraphQLTests/Info.plist; 755 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 756 | PRODUCT_BUNDLE_IDENTIFIER = technology.stepanhruda.GraphQLTests; 757 | PRODUCT_NAME = "$(TARGET_NAME)"; 758 | }; 759 | name = Release; 760 | }; 761 | /* End XCBuildConfiguration section */ 762 | 763 | /* Begin XCConfigurationList section */ 764 | C003DB7D1B462D2B00A90329 /* Build configuration list for PBXProject "GraphQL" */ = { 765 | isa = XCConfigurationList; 766 | buildConfigurations = ( 767 | C003DB951B462D2B00A90329 /* Debug */, 768 | C003DB961B462D2B00A90329 /* Release */, 769 | ); 770 | defaultConfigurationIsVisible = 0; 771 | defaultConfigurationName = Release; 772 | }; 773 | C003DB971B462D2B00A90329 /* Build configuration list for PBXNativeTarget "GraphQL" */ = { 774 | isa = XCConfigurationList; 775 | buildConfigurations = ( 776 | C003DB981B462D2B00A90329 /* Debug */, 777 | C003DB991B462D2B00A90329 /* Release */, 778 | ); 779 | defaultConfigurationIsVisible = 0; 780 | defaultConfigurationName = Release; 781 | }; 782 | C003DB9A1B462D2B00A90329 /* Build configuration list for PBXNativeTarget "GraphQLTests" */ = { 783 | isa = XCConfigurationList; 784 | buildConfigurations = ( 785 | C003DB9B1B462D2B00A90329 /* Debug */, 786 | C003DB9C1B462D2B00A90329 /* Release */, 787 | ); 788 | defaultConfigurationIsVisible = 0; 789 | defaultConfigurationName = Release; 790 | }; 791 | /* End XCConfigurationList section */ 792 | }; 793 | rootObject = C003DB7A1B462D2B00A90329 /* Project object */; 794 | } 795 | -------------------------------------------------------------------------------- /GraphQL.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /GraphQL.xcodeproj/xcshareddata/xcschemes/GraphQL.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /GraphQL.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /GraphQL/Execution/Executor.swift: -------------------------------------------------------------------------------- 1 | func execute(schema schema: Schema, rootValue: Any?, request: AbstractSyntaxTree, operationName: Any?, variableValues: Any?) { 2 | 3 | } -------------------------------------------------------------------------------- /GraphQL/GraphQL.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepanhruda/GraphQL-Swift/9b135a365d15f50107e83bf768f9715ac31a9079/GraphQL/GraphQL.h -------------------------------------------------------------------------------- /GraphQL/GraphQL.swift: -------------------------------------------------------------------------------- 1 | enum GraphQLFormattedError: ErrorType { 2 | case Unknown 3 | } 4 | 5 | struct GraphQLResult { 6 | let data: Any? 7 | let errors: [GraphQLFormattedError]? 8 | } 9 | 10 | enum GraphQLComposedError: ErrorType { 11 | case MultipleErrors([ErrorType]) 12 | } 13 | 14 | 15 | func graphql(schema: Schema, requestString: String = "", rootValue: Any?, variableValues: [String: Any]?, operationName: String?, completion: (GraphQLResult -> Void)?) throws { 16 | do { 17 | let source = Source(body: requestString, name: "GraphQL request") 18 | let request = try Parser.parse(source) 19 | try request.validateForSchema(schema) 20 | execute(schema: schema, rootValue: rootValue, request: request, operationName: operationName, variableValues: variableValues) 21 | } catch let error { 22 | // TODO: Error processing 23 | throw error 24 | } 25 | 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /GraphQL/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /GraphQL/Introspection/Introspection.swift: -------------------------------------------------------------------------------- 1 | final class Introspection { 2 | 3 | static let schema = SchemaObject( 4 | name: "__Schema", 5 | 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.", 6 | fields: { [ 7 | SchemaObjectField( 8 | name: "types", 9 | type: NonNull(List(NonNull(type))), 10 | description: "A list of all types supported by this server.", 11 | resolve: { toResolve in 12 | let schema = toResolve as! Schema 13 | return schema.types }), 14 | SchemaObjectField( 15 | name: "queryType", 16 | type: NonNull(type), 17 | description: "The type that query operations will be rooted at.", 18 | resolve: { toResolve in 19 | let schema = toResolve as! Schema 20 | return schema.queryType }), 21 | SchemaObjectField( 22 | name: "mutationType", 23 | type: type, 24 | description: "If this server support mutation, the type that subscription operations will be rooted at.", 25 | resolve: { toResolve in 26 | let schema = toResolve as! Schema 27 | return schema.mutationType }), 28 | SchemaObjectField( 29 | name: "subscriptionType", 30 | type: type, 31 | description: "If this server support subscription, the type that subscription operations will be rooted at.", 32 | resolve: { toResolve in 33 | let schema = toResolve as! Schema 34 | return schema.subscriptionType }), 35 | SchemaObjectField( 36 | name: "directives", 37 | type: NonNull(List(NonNull(directive))), 38 | description: "A list of all directives supported by this server.", 39 | resolve: { toResolve in 40 | let schema = toResolve as! Schema 41 | return schema.directives }), 42 | ] } 43 | ) 44 | 45 | static let directive = SchemaObject( 46 | name: "__Directive", 47 | 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.", 48 | fields: { [ 49 | SchemaObjectField(name: "name", type: NonNull(StringType())), 50 | SchemaObjectField(name: "description", type: StringType()), 51 | SchemaObjectField( 52 | name: "arguments", 53 | type: NonNull(List(NonNull(inputValue))), 54 | resolve: { toResolve in 55 | let directive = toResolve as! SchemaDirective 56 | return directive.arguments }), 57 | SchemaObjectField(name: "onOperation", type: Boolean()), 58 | SchemaObjectField(name: "onFragment", type: Boolean()), 59 | SchemaObjectField(name: "onField", type: Boolean()), 60 | ] }) 61 | 62 | // Defined twice for recursive purposes 63 | static let type: SchemaObject = typeDefinition 64 | static let typeDefinition = SchemaObject( 65 | name: "__Type", 66 | 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.", 67 | fields: { [ 68 | SchemaObjectField( 69 | name: "kind", 70 | type: NonNull(typeKind), 71 | resolve: { toResolve -> TypeKind in 72 | switch toResolve { 73 | case is SchemaScalar: return .Scalar 74 | case is SchemaObject: return .Object 75 | case is SchemaInterface: return .Interface 76 | case is SchemaUnion: return .Union 77 | case is AnySchemaEnum: return .Enum 78 | case is SchemaInputObject: return .InputObject 79 | case is List: return .List 80 | case is NonNull: return .NonNull 81 | default: fatalError("type of unknown kind") 82 | } }), 83 | SchemaObjectField(name: "name", type: NonNull(StringType())), 84 | SchemaObjectField(name: "description", type: StringType()), 85 | SchemaObjectField( 86 | name: "fields", 87 | type: List(NonNull(field)), 88 | arguments: [ 89 | SchemaInputValue( 90 | name: "includeDeprecated", 91 | type: Boolean(), 92 | defaultValue: false) 93 | ], 94 | resolve: { toResolve in 95 | let arguments = toResolve as! (type: SchemaType, includeDeprecated: Bool) 96 | let fields: IdentitySet 97 | switch arguments.type { 98 | case let object as SchemaObject: fields = object.fields 99 | case let interface as SchemaInterface: fields = interface.fields 100 | default: return nil 101 | } 102 | switch arguments.includeDeprecated { 103 | case true: return fields 104 | case false: return fields.filter { $0.deprecationReason == nil } 105 | } }), 106 | SchemaObjectField( 107 | name: "interfaces", 108 | type: List(NonNull(type)), 109 | resolve: { toResolve in 110 | let object = toResolve as? SchemaObject 111 | return object?.interfaces 112 | }), 113 | SchemaObjectField( 114 | name: "possibleTypes", 115 | type: List(NonNull(type)), 116 | resolve: { toResolve in 117 | switch toResolve { 118 | case let interface as SchemaInterface: return interface.possibleTypes 119 | case let union as SchemaUnion: return union.possibleTypes 120 | default: return nil 121 | } 122 | }), 123 | SchemaObjectField( 124 | name: "enumValues", 125 | type: List(NonNull(enumValue)), 126 | arguments: [ 127 | SchemaInputValue( 128 | name: "includeDeprecated", 129 | type: Boolean(), 130 | defaultValue: false) 131 | ], 132 | resolve: { toResolve in 133 | let arguments = toResolve as! (type: SchemaType, includeDeprecated: Bool) 134 | guard let schemaEnum = arguments.type as? AnySchemaEnum else { return nil } 135 | switch arguments.includeDeprecated { 136 | case true: return schemaEnum.allValues 137 | case false: return schemaEnum.nonDeprecatedValues 138 | } }), 139 | SchemaObjectField( 140 | name: "inputFields", 141 | type: List(NonNull(inputValue)), 142 | resolve: { toResolve in 143 | let inputObject = toResolve as? SchemaInputObject 144 | return inputObject?.fields 145 | }), 146 | SchemaObjectField(name: "ofType", type: type), 147 | ] }) 148 | 149 | static let field = SchemaObject( 150 | name: "__Field", 151 | 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.", 152 | fields: { [ 153 | SchemaObjectField(name: "name", type: NonNull(StringType())), 154 | SchemaObjectField(name: "description", type: StringType()), 155 | SchemaObjectField( 156 | name: "arguments", 157 | type: NonNull(List(NonNull(inputValue))), 158 | resolve: { toResolve in 159 | let field = toResolve as! SchemaObjectField 160 | return field.arguments } ), 161 | SchemaObjectField(name: "type", type: NonNull(type)), 162 | SchemaObjectField( 163 | name: "isDeprecated", 164 | type: NonNull(Boolean()), 165 | resolve: { toResolve in 166 | let field = toResolve as! SchemaObjectField 167 | return field.deprecationReason != nil } ), 168 | SchemaObjectField(name: "deprecationReason", type: StringType()), 169 | ] }) 170 | 171 | 172 | static let inputValue = SchemaObject( 173 | name: "__InputValue", 174 | description: "Arguments provided to Fields or Directives and the input fields of an input object are represented as input values which describe their type and optionally a default value.", 175 | fields: { [ 176 | SchemaObjectField(name: "name", type: NonNull(StringType())), 177 | SchemaObjectField(name: "description", type: StringType()), 178 | SchemaObjectField(name: "type", type: NonNull(type)), 179 | SchemaObjectField( 180 | name: "defaultValue", 181 | type: StringType(), // Why is this a string? 182 | description: "A GraphQL-formatted string representing the default value for this input value.", 183 | resolve: { toResolve in 184 | let inputValue = toResolve as! SchemaInputValue 185 | // TODO: Reference implementation converts this to a GraphQL valid object 186 | return inputValue.defaultValue } ), 187 | ] }) 188 | 189 | static let enumValue = SchemaObject( 190 | name: "__EnumValue", 191 | 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.", 192 | fields: { [ 193 | SchemaObjectField(name: "name", type: NonNull(StringType())), 194 | SchemaObjectField(name: "description", type: StringType()), 195 | SchemaObjectField( 196 | name: "isDeprecated", 197 | type: NonNull(Boolean()), 198 | resolve: { toResolve in 199 | let enumValue = toResolve as! AnySchemaEnumValue 200 | return enumValue.deprecationReason != nil } ), 201 | SchemaObjectField(name: "deprecationReason", type: StringType()), 202 | ] }) 203 | 204 | enum TypeKind: String { 205 | case Scalar = "SCALAR" 206 | case Object = "OBJECT" 207 | case Interface = "INTERFACE" 208 | case Union = "UNION" 209 | case Enum = "ENUM" 210 | case InputObject = "INPUT_OBJECT" 211 | case List = "LIST" 212 | case NonNull = "NON_NULL" 213 | } 214 | 215 | static let typeKind = SchemaEnum( 216 | name: "__TypeKind", 217 | description: "An enum describing what kind of type a given `__Type` is.", 218 | values: [ 219 | SchemaEnumValue( 220 | value: .Scalar, 221 | description: "Indicates this type is a scalar."), 222 | SchemaEnumValue( 223 | value: .Object, 224 | description: "Indicates this type is an object. `fields` and `interfaces` are valid fields."), 225 | SchemaEnumValue( 226 | value: .Interface, 227 | description: "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields."), 228 | SchemaEnumValue( 229 | value: .Union, 230 | description: "Indicates this type is a union. `possibleTypes` is a valid field."), 231 | SchemaEnumValue( 232 | value: .Enum, 233 | description: "Indicates this type is an enum. `enumValues` is a valid field."), 234 | SchemaEnumValue( 235 | value: .InputObject, 236 | description: "Indicates this type is an input object. `inputFields` is a valid field."), 237 | SchemaEnumValue( 238 | value: .List, 239 | description: "Indicates this type is a list. `ofType` is a valid field."), 240 | SchemaEnumValue( 241 | value: .NonNull, 242 | description: "Indicates this type is a non-null. `ofType` is a valid field."), 243 | ]) 244 | 245 | static let schemaMetaField = SchemaObjectField( 246 | name: "__schema", 247 | type: NonNull(schema), 248 | description: "Access the current type schema of this server.", 249 | arguments: [], 250 | resolve: { toResolve in 251 | let input = toResolve as! (source: Source, arguments: IdentitySet, userSchema: Schema) 252 | return input.userSchema } ) 253 | 254 | static let typeMetaField = SchemaObjectField( 255 | name: "__type", 256 | type: type, 257 | description: "Request the type information of a single type.", 258 | arguments: [ 259 | SchemaInputValue(name: "name", type: NonNull(StringType())), 260 | ], 261 | resolve: { toResolve in 262 | let input = toResolve as! (source: Source, arguments: IdentitySet, userSchema: Schema) 263 | let name = input.arguments["name"]!.value as! String 264 | return input.userSchema.types[name] } ) 265 | 266 | static let typeNameMetaField = SchemaObjectField( 267 | name: "__typename", 268 | type: NonNull(StringType()), 269 | description: "The name of the current Object type at runtime.", 270 | arguments: [], 271 | resolve: { toResolve in 272 | let input = toResolve as! (source: Source, arguments: IdentitySet, parentType: SchemaObject) 273 | return input.parentType.name } ) 274 | } 275 | -------------------------------------------------------------------------------- /GraphQL/Language/AbstractSyntaxTree.swift: -------------------------------------------------------------------------------- 1 | protocol Node { 2 | var type: NodeType { get } 3 | var location: Location? { get } 4 | } 5 | 6 | protocol HasSubtree: Node { 7 | var children: [Node] { get } 8 | 9 | // Possibly remove this if we don't allow editing the AST through a visitor 10 | mutating func removeChildAtIndex(index: Int) 11 | mutating func replaceChildAtIndex(index: Int, newValue: Node) 12 | } 13 | 14 | struct AbstractSyntaxTree: HasSubtree { 15 | var definitions: [Definition] 16 | let location: Location? 17 | 18 | var type: NodeType { return .Document } 19 | 20 | var children: [Node] { return definitions.map { $0 as Node } } 21 | 22 | mutating func removeChildAtIndex(index: Int) { 23 | definitions.removeAtIndex(index) 24 | } 25 | mutating func replaceChildAtIndex(index: Int, newValue: Node) { 26 | definitions[index] = newValue as! Definition 27 | } 28 | } 29 | 30 | protocol Definition: Node {} 31 | 32 | struct OperationDefinition: Definition, HasSubtree { 33 | let operationType: OperationType 34 | let name: ValidName? 35 | let variableDefinitions: [VariableDefinition] 36 | let directives: [Directive] 37 | let selectionSet: SelectionSet 38 | let location: Location? 39 | 40 | var type: NodeType { return .OperationDefinition } 41 | 42 | var children: [Node] { return variableDefinitions.map { $0 as Node } + directives.map { $0 as Node } + [selectionSet] } 43 | } 44 | 45 | enum OperationType { 46 | case Query 47 | case Mutation 48 | } 49 | 50 | protocol Selection: Node {} 51 | 52 | struct SelectionSet: HasSubtree { 53 | let selections: [Selection] 54 | let location: Location? 55 | 56 | var type: NodeType { return .SelectionSet } 57 | 58 | var children: [Node] { return selections.map { $0 as Node } } 59 | } 60 | 61 | struct Field: Selection, HasSubtree, Named { 62 | let alias: ValidName? 63 | let name: ValidName 64 | // Arguments are unordered, so this could be IdentitySet if we enforce the language rule during parsing. 65 | let arguments: [Argument] 66 | let directives: [Directive] 67 | let selectionSet: SelectionSet? 68 | let location: Location? 69 | 70 | var children: [Node] { 71 | var children = arguments.map { $0 as Node } + directives.map { $0 as Node } 72 | if let selectionSet = selectionSet { 73 | children.append(selectionSet) 74 | } 75 | return children 76 | } 77 | 78 | var type: NodeType { return .Field } 79 | } 80 | 81 | struct Argument: Node, Named { 82 | let name: ValidName 83 | let value: Value 84 | let location: Location? 85 | 86 | var type: NodeType { return .Argument } 87 | } 88 | 89 | struct FragmentDefinition: Definition, HasSubtree, Named { 90 | let name: ValidName 91 | let typeCondition: NamedType 92 | let directives: [Directive] 93 | let selectionSet: SelectionSet 94 | let location: Location? 95 | 96 | var type: NodeType { return .FragmentDefinition } 97 | 98 | var children: [Node] { return directives.map { $0 as Node } + [selectionSet] } 99 | } 100 | 101 | protocol Fragment: Selection {} 102 | 103 | struct FragmentSpread: Fragment, HasSubtree, Named { 104 | let name: ValidName 105 | let directives: [Directive] 106 | let location: Location? 107 | 108 | var type: NodeType { return .FragmentSpread } 109 | 110 | var children: [Node] { return directives.map { $0 as Node } } 111 | } 112 | 113 | struct InlineFragment: Fragment, HasSubtree { 114 | let typeCondition: NamedType? 115 | let directives: [Directive] 116 | let selectionSet: SelectionSet 117 | let location: Location? 118 | 119 | var type: NodeType { return .InlineFragment } 120 | 121 | var children: [Node] { return directives.map { $0 as Node } + [selectionSet] } 122 | } 123 | 124 | protocol Value: Node { 125 | } 126 | 127 | struct IntValue: Value { 128 | let value: Int 129 | let location: Location? 130 | 131 | var type: NodeType { return .IntValue } 132 | } 133 | 134 | struct FloatValue: Value { 135 | let value: Float 136 | let location: Location? 137 | 138 | var type: NodeType { return .FloatValue } 139 | } 140 | 141 | struct StringValue: Value { 142 | let value: String 143 | let location: Location? 144 | 145 | var type: NodeType { return .StringValue } 146 | } 147 | 148 | struct BoolValue: Value { 149 | let value: Bool 150 | let location: Location? 151 | 152 | var type: NodeType { return .BoolValue } 153 | } 154 | 155 | struct EnumValue: Value { 156 | let value: String 157 | let location: Location? 158 | 159 | var type: NodeType { return .EnumValue } 160 | } 161 | 162 | struct ListValue: Value, HasSubtree { 163 | let values: [Value] 164 | let location: Location? 165 | 166 | var type: NodeType { return .ListValue } 167 | 168 | var children: [Node] { return values.map { $0 as Node } } 169 | } 170 | 171 | struct InputObjectValue: Value { 172 | // Arguments are unordered, so this could be IdentitySet if we enforce the language rule during parsing. 173 | let fields: [InputObjectField] 174 | let location: Location? 175 | 176 | var type: NodeType { return .InputObjectValue } 177 | 178 | var children: [Node] { return fields.map { $0 as Node } } 179 | } 180 | 181 | struct InputObjectField: Value, Named { 182 | let name: ValidName 183 | let value: Value 184 | let location: Location? 185 | 186 | var type: NodeType { return .InputObjectField } 187 | } 188 | 189 | struct VariableDefinition: Definition { 190 | let variable: Variable 191 | let inputType: InputType 192 | let defaultValue: Value? 193 | let location: Location? 194 | 195 | var type: NodeType { return .VariableDefinition } 196 | } 197 | 198 | struct Variable: Value, Named { 199 | let name: ValidName 200 | let location: Location? 201 | 202 | var type: NodeType { return .Variable } 203 | } 204 | 205 | protocol InputType: Node { } 206 | 207 | struct NamedType: InputType { 208 | let value: String 209 | let location: Location? 210 | 211 | var type: NodeType { return .NamedType } 212 | } 213 | 214 | struct NonNullType: InputType { 215 | let inputType: InputType 216 | let location: Location? 217 | 218 | var type: NodeType { return .NonNullType } 219 | } 220 | 221 | struct ListType: InputType { 222 | let inputType: InputType 223 | let location: Location? 224 | 225 | var type: NodeType { return .ListType } 226 | } 227 | 228 | struct Directive: Node, Named { 229 | let name: ValidName 230 | let arguments: [Argument] 231 | let location: Location? 232 | 233 | var type: NodeType { return .Directive } 234 | } 235 | 236 | extension HasSubtree { 237 | mutating func removeChildAtIndex(index: Int) {} 238 | mutating func replaceChildAtIndex(index: Int, newValue: Node) {} 239 | } 240 | 241 | public struct Location { 242 | let start: String.Index 243 | let end: String.Index 244 | let source: Source? 245 | } 246 | -------------------------------------------------------------------------------- /GraphQL/Language/Lexer.swift: -------------------------------------------------------------------------------- 1 | enum LexerErrorCode: Int { 2 | case UnexpectedCharacter 3 | case InvalidNumber 4 | case UnterminatedString 5 | case BadCharacterEscapeSequence 6 | } 7 | 8 | struct LexerError: ErrorType { 9 | let code: LexerErrorCode 10 | let source: Source 11 | let position: String.Index 12 | } 13 | 14 | struct Lexer { 15 | static func functionForSource(source: Source) -> ((position: String.Index?) throws -> Token) { 16 | var previousPosition = source.body.startIndex 17 | return { position in 18 | let token = try readSource(source, position: position ?? previousPosition) 19 | previousPosition = token.end 20 | return token 21 | } 22 | } 23 | 24 | static func readSource(source: Source, position: String.Index) throws -> Token { 25 | let characters = source.body.characters 26 | 27 | let position = positionAfterWhitespace(body: source.body, position: position) 28 | 29 | if position >= characters.endIndex { 30 | return Token(kind: .EndOfFile, start: position, end: position) 31 | } 32 | 33 | switch characters[position] { 34 | 35 | case "!": return Token(kind: .Bang, start: position, end: position + 1) 36 | case "$": return Token(kind: .Dollar, start: position, end: position + 1) 37 | case "(": return Token(kind: .ParenLeft, start: position, end: position + 1) 38 | case ")": return Token(kind: .ParenRight, start: position, end: position + 1) 39 | 40 | case "." where characters[position + 1] == "." && characters[position + 2] == ".": 41 | return Token(kind: .Spread, start: position, end: position + 3) 42 | 43 | case ":": return Token(kind: .Colon, start: position, end: position + 1) 44 | case "=": return Token(kind: .Equals, start: position, end: position + 1) 45 | case "@": return Token(kind: .At, start: position, end: position + 1) 46 | case "[": return Token(kind: .BracketLeft, start: position, end: position + 1) 47 | case "]": return Token(kind: .BracketRight, start: position, end: position + 1) 48 | case "{": return Token(kind: .BraceLeft, start: position, end: position + 1) 49 | case "|": return Token(kind: .Pipe, start: position, end: position + 1) 50 | case "}": return Token(kind: .BraceRight, start: position, end: position + 1) 51 | 52 | case "A"..."Z", "_", "a"..."z": return readName(source: source, position: position) 53 | case "-", "0"..."9": 54 | return try readNumber(source: source, position: position) 55 | 56 | case "\"": 57 | return try readString(source: source, position: position) 58 | 59 | default: throw LexerError(code: .UnexpectedCharacter, source: source, position: position) 60 | 61 | } 62 | } 63 | 64 | static func readName(source source: Source, position start: String.Index) -> Token { 65 | let body = source.body 66 | var end = start 67 | 68 | for character in body[start.. Token { 77 | let body = source.body 78 | var end = start 79 | var generator = body[start.. Character? = { 83 | let next = generator.next() 84 | guard let _ = next else { return next } 85 | end = end.successor() 86 | return next 87 | } 88 | 89 | var character = nextCharacter() 90 | 91 | let readDigits: Void -> Void = { 92 | repeat { 93 | character = nextCharacter() 94 | guard let tested = character, case "0"..."9" = tested else { 95 | if end < body.endIndex { 96 | lastCharacterInvalid = true 97 | } 98 | break 99 | } 100 | } while true 101 | } 102 | 103 | if character == "-" { 104 | character = nextCharacter() 105 | } 106 | 107 | if character == "0" { 108 | character = nextCharacter() 109 | } else if let tested = character, case "1"..."9" = tested { 110 | readDigits() 111 | } else { 112 | throw LexerError(code: .InvalidNumber, source: source, position: end) 113 | } 114 | 115 | if character == "." { 116 | isFloat = true 117 | lastCharacterInvalid = false 118 | character = nextCharacter() 119 | 120 | if let tested = character, case "0"..."9" = tested { 121 | readDigits() 122 | } else { 123 | throw LexerError(code: .InvalidNumber, source: source, position: end) 124 | } 125 | 126 | if character == "e" { 127 | lastCharacterInvalid = false 128 | character = nextCharacter() 129 | 130 | if character == "-" { 131 | character = nextCharacter() 132 | } 133 | if let tested = character, case "0"..."9" = tested { 134 | readDigits() 135 | } else { 136 | throw LexerError(code: .InvalidNumber, source: source, position: end) 137 | } 138 | } 139 | } 140 | 141 | if lastCharacterInvalid { end = end.predecessor() } 142 | 143 | let value = body[start.. Token { 150 | let body = source.body 151 | var alreadyProcessed = start 152 | var end = start 153 | var value = "" 154 | var escapingCharacters = false 155 | var charactersToSkip = 0 156 | 157 | lexing: for character in body[(start + 1).. 0) { 161 | charactersToSkip -= 1 162 | continue 163 | } 164 | 165 | if (!escapingCharacters) { 166 | 167 | switch character { 168 | case "\"", "\n", "\r", "\u{2028}", "\u{2029}": break lexing 169 | case "\\": 170 | value += body[(alreadyProcessed + 1).. end + 3 else { 191 | throw LexerError(code: .BadCharacterEscapeSequence, source: source, position: end) 192 | } 193 | 194 | let characterCode = Int(body[(end + 1)...(end + 4)], radix: 16) 195 | 196 | if let characterCode = characterCode { 197 | var unicodeCharacter = "" 198 | UnicodeScalar(characterCode).writeTo(&unicodeCharacter) 199 | value += unicodeCharacter 200 | 201 | alreadyProcessed = alreadyProcessed + 4 202 | } else { 203 | throw LexerError(code: .BadCharacterEscapeSequence, source: source, position: end) 204 | } 205 | 206 | default: 207 | throw LexerError(code: .BadCharacterEscapeSequence, source: source, position: end) 208 | } 209 | 210 | alreadyProcessed = alreadyProcessed + 2 211 | escapingCharacters = false 212 | } 213 | } 214 | 215 | guard body[end] == "\"" && end > start else { 216 | throw LexerError(code: .UnterminatedString, source: source, position: end) 217 | } 218 | 219 | value += body[(alreadyProcessed + 1).. String.Index { 224 | var position = start 225 | var insideComment = false 226 | 227 | search: for character in body[start.. String.CharacterView.Index { 250 | return left.advancedBy(right) 251 | } 252 | 253 | func - (left: String.CharacterView.Index, right: Int) -> String.CharacterView.Index { 254 | return left.advancedBy(-right) 255 | } 256 | 257 | extension Character { 258 | var isValidNameCharacter: Bool { 259 | get { 260 | switch self { 261 | case "A"..."Z", "_", "a"..."z", "0"..."9": return true 262 | default: return false 263 | } 264 | } 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /GraphQL/Language/Parser.swift: -------------------------------------------------------------------------------- 1 | final class Parser { 2 | let lexer: String.Index? throws -> Token 3 | let source: Source 4 | let options: ParserOptions 5 | var previousEnd: String.Index 6 | var currentToken: Token 7 | 8 | static func parse(source: Source, options: ParserOptions = []) throws -> AbstractSyntaxTree { 9 | let lexer = Lexer.functionForSource(source) 10 | let parser = Parser(lexer: lexer, source: source, options: options, previousEnd: source.body.startIndex, token: try lexer(position: nil)) 11 | return try parser.parse() 12 | } 13 | 14 | init(lexer: String.Index? throws -> Token, 15 | source: Source, 16 | options: ParserOptions, 17 | previousEnd: String.Index, 18 | token: Token) { 19 | self.lexer = lexer 20 | self.source = source 21 | self.options = options 22 | self.previousEnd = previousEnd 23 | self.currentToken = token 24 | } 25 | 26 | func parse() throws -> AbstractSyntaxTree { 27 | let start = currentToken.start 28 | var definitions: [Definition] = [] 29 | 30 | repeat { 31 | 32 | switch currentToken.kind { 33 | case .BraceLeft: 34 | definitions.append(try parseShorthandQueryDefinition()) 35 | case .Name: 36 | let name = try peekAtValueOfNameToken(currentToken) 37 | switch name { 38 | case query: 39 | definitions.append(try parseOperationDefinitionOfType(.Query)) 40 | case mutation: 41 | definitions.append(try parseOperationDefinitionOfType(.Mutation)) 42 | case fragment: 43 | definitions.append(try parseFragmentDefinition()) 44 | default: 45 | throw unexpectedTokenError 46 | } 47 | default: 48 | throw unexpectedTokenError 49 | } 50 | 51 | } while try !skipping(.EndOfFile) 52 | 53 | return AbstractSyntaxTree(definitions: definitions, location: locateWithStart(start)) 54 | } 55 | 56 | /// If the next token is of the given kind, `skipping` skips over it and returns `true`. 57 | /// If the next token is different, `skipping` doesn't move the parser and returns `false`. 58 | /// 59 | /// The naming is in favor of readability: `try skipping(.Foo)` conveys the behavior well. 60 | func skipping(kind: TokenKind) throws -> Bool { 61 | let match = currentToken.kind == kind 62 | if (match) { 63 | try advance() 64 | } 65 | return match 66 | } 67 | 68 | func advance() throws { 69 | previousEnd = currentToken.end 70 | currentToken = try lexer(previousEnd) 71 | } 72 | 73 | func currentTokenIs(kind: TokenKind) -> Bool { 74 | return currentToken.kind == kind 75 | } 76 | 77 | func parseShorthandQueryDefinition() throws -> OperationDefinition { 78 | let start = currentToken.start 79 | 80 | return OperationDefinition( 81 | operationType: .Query, 82 | name: nil, 83 | variableDefinitions: [], 84 | directives: [], 85 | selectionSet: try parseSelectionSet(), 86 | location: locateWithStart(start)) 87 | } 88 | 89 | func parseOperationDefinitionOfType(type: OperationType) throws -> OperationDefinition { 90 | let start = currentToken.start 91 | 92 | try advance() 93 | return OperationDefinition( 94 | operationType: type, 95 | name: try parseValidName(), 96 | variableDefinitions: try parseVariableDefinitions(), 97 | directives: try parseDirectives(), 98 | selectionSet: try parseSelectionSet(), 99 | location: locateWithStart(start)) 100 | } 101 | 102 | func parseVariableDefinitions() throws -> [VariableDefinition] { 103 | return currentTokenIs(.ParenLeft) 104 | ? try parseOneOrMoreBetweenDelimiters(left: .ParenLeft, function: parseVariableDefinition, right: .ParenRight) 105 | : [] 106 | } 107 | 108 | func parseVariableDefinition() throws -> VariableDefinition { 109 | let start = currentToken.start 110 | 111 | return VariableDefinition( 112 | variable: try parseVariable(), 113 | inputType: try { try expect(.Colon); return try parseType() }(), 114 | defaultValue: try skipping(.Equals) ? try parseValue(isConst: true) : nil, 115 | location: locateWithStart(start)) 116 | } 117 | 118 | func parseType() throws -> InputType { 119 | let start = currentToken.start 120 | 121 | var type: InputType 122 | if try skipping(.BracketLeft) { 123 | type = try parseType() 124 | try expect(.BracketRight) 125 | type = ListType(inputType: type, location: locateWithStart(start)) 126 | } else { 127 | type = try parseNamedType() 128 | } 129 | if try skipping(.Bang) { 130 | return NonNullType(inputType: type, location: locateWithStart(start)) 131 | } else { 132 | return type 133 | } 134 | } 135 | 136 | func parseNamedType() throws -> NamedType { 137 | let start = currentToken.start 138 | let token = try expect(.Name) 139 | return NamedType(value: try peekAtValueOfNameToken(token), location: locateWithStart(start)) 140 | } 141 | 142 | func parseFragmentDefinition() throws -> FragmentDefinition { 143 | let start = currentToken.start 144 | try expectKeyword(fragment) 145 | return FragmentDefinition( 146 | name: try parseFragmentName(), 147 | typeCondition: try parseTypeCondition(), 148 | directives: try parseDirectives(), 149 | selectionSet: try parseSelectionSet(), 150 | location: locateWithStart(start)) 151 | } 152 | 153 | func parseFragmentName() throws -> ValidName { 154 | let name = try parseValidName() 155 | guard name.string != on else { throw unexpectedTokenError } 156 | return name 157 | } 158 | 159 | func parseTypeCondition() throws -> NamedType { 160 | try expectKeyword(on) 161 | return try parseNamedType() 162 | } 163 | 164 | func expectKeyword(keyword: String) throws -> Token { 165 | guard currentToken.kind == .Name, 166 | let value = currentToken.value as? String where value == keyword else { 167 | throw ParserError.UnexpectedToken(source: source, position: previousEnd, description: "Expected \(keyword), found \(currentToken)") 168 | } 169 | let token = currentToken 170 | try advance() 171 | return token 172 | } 173 | 174 | func parseValidName() throws -> ValidName { 175 | let start = currentToken.start 176 | let token = try expect(.Name) 177 | return ValidName(string: try peekAtValueOfNameToken(token), location: locateWithStart(start)) 178 | } 179 | 180 | func expect(kind: TokenKind) throws -> Token { 181 | if currentToken.kind == kind { 182 | let token = currentToken 183 | try advance() 184 | return token 185 | } else { 186 | throw ParserError.UnexpectedToken(source: source, position: previousEnd, description: "Expected \(kind), found \(currentToken.kind)") 187 | } 188 | } 189 | 190 | func parseSelectionSet() throws -> SelectionSet { 191 | let start = currentToken.start 192 | return SelectionSet( 193 | selections: try parseOneOrMoreBetweenDelimiters(left: .BraceLeft, function: parseSelection, right: .BraceRight), 194 | location: locateWithStart(start)) 195 | } 196 | 197 | func parseSelection() throws -> Selection { 198 | return currentTokenIs(.Spread) ? try parseFragment() : try parseField() 199 | } 200 | 201 | func parseFragment() throws -> Fragment { 202 | let start = currentToken.start 203 | try expect(.Spread) 204 | 205 | if currentTokenIs(.Name) { 206 | 207 | switch try peekAtValueOfNameToken(currentToken) { 208 | case on: 209 | return InlineFragment( 210 | typeCondition: try parseTypeCondition(), 211 | directives: try parseDirectives(), 212 | selectionSet: try parseSelectionSet(), 213 | location: locateWithStart(start)) 214 | default: 215 | return FragmentSpread( 216 | name: try parseFragmentName(), 217 | directives: try parseDirectives(), 218 | location: locateWithStart(start)) 219 | } 220 | 221 | } else { 222 | return InlineFragment( 223 | typeCondition: nil, 224 | directives: try parseDirectives(), 225 | selectionSet: try parseSelectionSet(), 226 | location: locateWithStart(start)) 227 | } 228 | } 229 | 230 | func parseField() throws -> Field { 231 | let start = currentToken.start 232 | 233 | let nameOrAlias = try parseValidName() 234 | 235 | var alias: ValidName? 236 | var name: ValidName 237 | if try skipping(.Colon) { 238 | alias = nameOrAlias 239 | name = try parseValidName() 240 | } else { 241 | alias = nil 242 | name = nameOrAlias 243 | } 244 | 245 | return Field( 246 | alias: alias, 247 | name: name, 248 | arguments: try parseArguments(), 249 | directives: try parseDirectives(), 250 | selectionSet: currentTokenIs(.BraceLeft) ? try parseSelectionSet() : nil, 251 | location: locateWithStart(start)) 252 | } 253 | 254 | func parseArguments() throws -> [Argument] { 255 | return currentTokenIs(.ParenLeft) 256 | ? try parseOneOrMoreBetweenDelimiters(left: .ParenLeft, function: parseArgument, right: .ParenRight) 257 | : [] 258 | } 259 | 260 | func parseArgument() throws -> Argument { 261 | let start = currentToken.start 262 | return Argument( 263 | name: try parseValidName(), 264 | value: try parseArgumentValue(), 265 | location: locateWithStart(start)) 266 | } 267 | 268 | func parseArgumentValue() throws -> Value { 269 | try expect(.Colon) 270 | return try parseValue(isConst: false) 271 | } 272 | 273 | func parseDirectives() throws -> [Directive] { 274 | var directives: [Directive] = [] 275 | while currentTokenIs(.At) { 276 | directives.append(try parseDirective()) 277 | } 278 | return directives 279 | } 280 | 281 | func parseDirective() throws -> Directive { 282 | let start = currentToken.start 283 | try expect(.At) 284 | return Directive( 285 | name: try parseValidName(), 286 | arguments: try parseArguments(), 287 | location: locateWithStart(start)) 288 | } 289 | 290 | func parseValue(isConst isConst: Bool) throws -> Value { 291 | switch currentToken.kind { 292 | case .BracketLeft: 293 | return try parseArray(isConst: isConst) 294 | case .BraceLeft: 295 | return try parseInputObject(isConst: isConst) 296 | case .Int: 297 | return try parseIntValue() 298 | case .Float: 299 | return try parseFloatValue() 300 | case .String: 301 | return try parseStringValue() 302 | case .Name: 303 | return try parseBoolOrEnumValue() 304 | case .Dollar: 305 | if (!isConst) { 306 | return try parseVariable() 307 | } 308 | default: break 309 | } 310 | throw unexpectedTokenError 311 | } 312 | 313 | func parseArray(isConst isConst: Bool) throws -> ListValue { 314 | let start = currentToken.start 315 | let parseFunction = isConst ? parseConstValue : parseVariableValue 316 | return ListValue( 317 | values: try parseZeroOrMoreBetweenDelimiters(left: .BracketLeft, function: parseFunction, right: .BracketRight), 318 | location: locateWithStart(start)) 319 | } 320 | 321 | func parseIntValue() throws -> IntValue { 322 | let token = currentToken 323 | guard let value = token.value as? Int else { throw unexpectedTokenError } 324 | try advance() 325 | return IntValue(value: value, location: locateWithStart(token.start)) 326 | } 327 | 328 | func parseFloatValue() throws -> FloatValue { 329 | let token = currentToken 330 | guard let value = token.value as? Float else { throw unexpectedTokenError } 331 | try advance() 332 | return FloatValue(value: value, location: locateWithStart(token.start)) 333 | } 334 | 335 | func parseStringValue() throws -> StringValue { 336 | let token = currentToken 337 | guard let value = token.value as? String else { throw unexpectedTokenError } 338 | try advance() 339 | return StringValue(value: value, location: locateWithStart(token.start)) 340 | } 341 | 342 | func parseVariable() throws -> Variable { 343 | let start = currentToken.start 344 | try expect(.Dollar) 345 | return Variable(name: try parseValidName(), location: locateWithStart(start)) 346 | } 347 | 348 | func parseBoolOrEnumValue() throws -> Value { 349 | let start = currentToken.start 350 | switch try parseValueOfNameToken() { 351 | case "true": return BoolValue(value: true, location: locateWithStart(start)) 352 | case "false": return BoolValue(value: false, location: locateWithStart(start)) 353 | case let string: return EnumValue(value: string, location: locateWithStart(start)) 354 | } 355 | } 356 | 357 | func parseInputObject(isConst isConst: Bool) throws -> InputObjectValue { 358 | let start = currentToken.start 359 | try expect(.BraceLeft) 360 | var fields: [InputObjectField] = [] 361 | // This should be IdentitySet 362 | var fieldNames: [ValidName] = [] 363 | while try !skipping(.BraceRight) { 364 | fields.append(try parseInputObjectField(isConst: isConst, existingFieldNames: &fieldNames)) 365 | } 366 | return InputObjectValue(fields: fields, location: locateWithStart(start)) 367 | } 368 | 369 | func parseInputObjectField(isConst isConst: Bool, inout existingFieldNames: [ValidName]) throws -> InputObjectField { 370 | let start = currentToken.start 371 | let name = try parseValidName() 372 | guard !(existingFieldNames.contains { $0.string == name.string }) else { 373 | throw ParserError.DuplicateInputObjectField(source: source, position: previousEnd, description: "Duplicate input object field \(name.string)") 374 | } 375 | existingFieldNames.append(name) 376 | 377 | return InputObjectField( 378 | name: name, 379 | value: try parseObjectFieldValue(isConst: isConst), 380 | location: locateWithStart(start)) 381 | } 382 | 383 | func parseObjectFieldValue(isConst isConst: Bool) throws -> Value { 384 | try expect(.Colon) 385 | return try parseValue(isConst: isConst) 386 | } 387 | 388 | func parseConstValue() throws -> Value { 389 | return try parseValue(isConst: true) 390 | } 391 | 392 | func parseVariableValue() throws -> Value { 393 | return try parseValue(isConst: false) 394 | } 395 | 396 | func parseValueOfNameToken() throws -> String { 397 | let name = try peekAtValueOfNameToken(currentToken) 398 | try advance() 399 | return name 400 | } 401 | 402 | func peekAtValueOfNameToken(token: Token) throws -> String { 403 | guard token.kind == .Name else { throw unexpectedTokenError } 404 | guard let name = token.value as? String else { throw unexpectedTokenError } 405 | return name 406 | } 407 | 408 | var unexpectedTokenError: ParserError { 409 | return ParserError.UnexpectedToken(source: source, position: previousEnd, description: "Unexpected \(currentToken)") 410 | } 411 | 412 | func parseZeroOrMoreBetweenDelimiters(left left: TokenKind, function: () throws -> T, right: TokenKind) throws -> [T] { 413 | try expect(left) 414 | var nodes: [T] = [] 415 | while try !skipping(right) { 416 | nodes.append(try function()) 417 | } 418 | return nodes 419 | } 420 | 421 | func parseOneOrMoreBetweenDelimiters(left left: TokenKind, function: () throws -> T, right: TokenKind) throws -> [T] { 422 | try expect(left) 423 | var nodes: [T] = [try function()] 424 | while try !skipping(right) { 425 | nodes.append(try function()) 426 | } 427 | return nodes 428 | } 429 | 430 | func locateWithStart(start: String.Index) -> Location? { 431 | guard !options.contains(ParserOptions.NoLocation) else { return nil } 432 | 433 | let source: Source? = options.contains(ParserOptions.NoLocation) ? nil : self.source 434 | return Location(start: start, end: previousEnd, source: source) 435 | } 436 | } 437 | 438 | enum ParserError: ErrorType { 439 | case UnexpectedToken(source: Source, position: String.Index, description: String) 440 | // This has been moved to a rule 441 | case DuplicateInputObjectField(source: Source, position: String.Index, description: String) 442 | } 443 | 444 | struct ParserOptions: OptionSetType { 445 | let rawValue: UInt 446 | static let NoLocation = ParserOptions(rawValue: 1 << 0) 447 | static let NoSource = ParserOptions(rawValue: 1 << 1) 448 | } 449 | 450 | private let query = "query" 451 | private let mutation = "mutation" 452 | private let fragment = "fragment" 453 | private let on = "on" 454 | -------------------------------------------------------------------------------- /GraphQL/Language/Source.swift: -------------------------------------------------------------------------------- 1 | public struct Source { 2 | public let body: String 3 | public let name: String 4 | 5 | public init(body: String, name: String = "GraphQL") { 6 | self.body = body 7 | self.name = name 8 | } 9 | } 10 | 11 | extension Source: StringLiteralConvertible { 12 | public typealias ExtendedGraphemeClusterLiteralType = String 13 | public typealias UnicodeScalarLiteralType = String 14 | 15 | public init(unicodeScalarLiteral value: UnicodeScalarLiteralType) { 16 | self.init(body: value) 17 | } 18 | 19 | public init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) { 20 | self.init(body: value) 21 | } 22 | 23 | public init(stringLiteral value: StringLiteralType) { 24 | self.init(body: value) 25 | } 26 | } -------------------------------------------------------------------------------- /GraphQL/Language/Token.swift: -------------------------------------------------------------------------------- 1 | enum TokenKind { 2 | case EndOfFile 3 | case Bang 4 | case Dollar 5 | case ParenLeft 6 | case ParenRight 7 | case Spread 8 | case Colon 9 | case Equals 10 | case At 11 | case BracketLeft 12 | case BracketRight 13 | case BraceLeft 14 | case Pipe 15 | case BraceRight 16 | case Name 17 | case Variable 18 | case Int 19 | case Float 20 | case String 21 | } 22 | 23 | struct Token { 24 | let kind: TokenKind 25 | let start: String.Index 26 | let end: String.Index 27 | let value: Any? 28 | 29 | init(kind: TokenKind, start: String.Index, end: String.Index, value: Any? = nil) { 30 | self.kind = kind 31 | self.start = start 32 | self.end = end 33 | self.value = value 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /GraphQL/Language/Visitor.swift: -------------------------------------------------------------------------------- 1 | 2 | enum VisitAction { 3 | case Continue 4 | case Stop 5 | /// Skip doesn't make sense when returned from a "leave" closure and causes a fatal error. 6 | case SkipHasSubtree 7 | case ReplaceValue(Node) 8 | case RemoveValue 9 | } 10 | 11 | enum NodeType: String { 12 | case Any 13 | case Document 14 | case OperationDefinition 15 | case FragmentDefinition 16 | case FragmentSpread 17 | case Field 18 | case Directive 19 | case Argument 20 | case VariableDefinition 21 | case SelectionSet 22 | case InlineFragment 23 | case IntValue 24 | case FloatValue 25 | case StringValue 26 | case BoolValue 27 | case EnumValue 28 | case ListValue 29 | case InputObjectValue 30 | case InputObjectField 31 | case Variable 32 | case NamedType 33 | case NonNullType 34 | case ListType 35 | 36 | 37 | var identifier: String { return rawValue } 38 | } 39 | 40 | enum VisitError: ErrorType { 41 | case SkipHasSubtree 42 | case Stop 43 | } 44 | 45 | struct Visitor: Identifiable { 46 | let nodeType: NodeType 47 | let enter: (Node throws -> VisitAction)? 48 | let leave: (Node throws -> VisitAction)? 49 | 50 | init(nodeType: NodeType, enter: (Node throws -> VisitAction)? = nil, leave: (Node throws -> VisitAction)? = nil) { 51 | self.nodeType = nodeType 52 | self.enter = enter 53 | self.leave = leave 54 | } 55 | 56 | var identifier: String { 57 | return nodeType.identifier 58 | } 59 | } 60 | 61 | extension Node { 62 | func visit(visitor: Visitor) throws -> Node? { 63 | 64 | guard var afterEntering = try enter(visitor) else { return nil } 65 | 66 | if var tree = afterEntering as? HasSubtree { 67 | try tree.visitChildren(visitor) 68 | afterEntering = tree 69 | } 70 | 71 | guard let afterLeaving = try afterEntering.leave(visitor) else { return nil } 72 | 73 | return afterLeaving 74 | } 75 | 76 | private func enter(visitor: Visitor) throws -> Node? { 77 | guard let enter = visitor.enter else { return self } 78 | 79 | switch try enter(self) { 80 | case .Continue: return self 81 | case .Stop: throw VisitError.Stop 82 | case .SkipHasSubtree: throw VisitError.SkipHasSubtree 83 | case .ReplaceValue(let newValue): return newValue 84 | case .RemoveValue: return nil 85 | } 86 | } 87 | 88 | private func leave(visitor: Visitor) throws -> Node? { 89 | guard let leave = visitor.leave else { return self } 90 | 91 | switch try leave(self) { 92 | case .Continue: return self 93 | case .Stop: throw VisitError.Stop 94 | case .SkipHasSubtree: fatalError("Developer error: there is no point in skipping a subtree after it has been visited") 95 | case .ReplaceValue(let newValue): return newValue 96 | case .RemoveValue: return nil 97 | } 98 | } 99 | } 100 | 101 | extension HasSubtree { 102 | 103 | private mutating func visitChildren(visitor: Visitor) throws { 104 | var currentIndex = 0 105 | while currentIndex < children.count { 106 | let child = children[currentIndex] 107 | let childModifiedByVisit = try child.visit(visitor) 108 | 109 | if let childModifiedByVisit = childModifiedByVisit { 110 | replaceChildAtIndex(currentIndex, newValue: childModifiedByVisit) 111 | currentIndex += 1 112 | } else { 113 | removeChildAtIndex(currentIndex) 114 | // Do not increase current index, everything has shifted down by one because the child was removed. 115 | // Keeping the same index will in fact visit the next child (or break the loop if it was the last child). 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /GraphQL/Type system/Directives.swift: -------------------------------------------------------------------------------- 1 | public let includeDirective = SchemaDirective( 2 | name: "include", 3 | description: "Directs the executor to include this field or fragment only when the `if` argument is true.", 4 | arguments: [ 5 | SchemaInputValue( 6 | name: "if", 7 | type: NonNull(Boolean()), 8 | description: "Included when true."), 9 | ], 10 | onFragment: true, 11 | onField: true) 12 | 13 | public let skipDirective = SchemaDirective( 14 | name: "skip", 15 | description: "Directs the executor to skip this field or fragment when the `if` argument is true.", 16 | arguments: [ 17 | SchemaInputValue( 18 | name: "if", 19 | type: NonNull(Boolean()), 20 | description: "Skipped when true."), 21 | ], 22 | onFragment: true, 23 | onField: true) 24 | -------------------------------------------------------------------------------- /GraphQL/Type system/NonNull.swift: -------------------------------------------------------------------------------- 1 | public struct NonNull: AllowedAsInputValue, AllowedAsObjectField { 2 | let value: AllowedAsNonNull 3 | 4 | public init(_ value: AllowedAsNonNull) { 5 | self.value = value 6 | } 7 | } 8 | 9 | public protocol AllowedAsNonNull {} 10 | -------------------------------------------------------------------------------- /GraphQL/Type system/Schema.swift: -------------------------------------------------------------------------------- 1 | public protocol SchemaType: Named { 2 | } 3 | 4 | public final class AnySchemaType: SchemaType { 5 | public let wrappedType: SchemaType 6 | 7 | public var name: ValidName { 8 | return wrappedType.name 9 | } 10 | 11 | init(_ type: SchemaType) { 12 | self.wrappedType = type 13 | } 14 | } 15 | 16 | public struct Schema { 17 | let queryType: SchemaObject 18 | let mutationType: SchemaObject? 19 | let subscriptionType: SchemaObject? 20 | let directives: [SchemaDirective] 21 | let types: IdentitySet 22 | 23 | public init( 24 | queryType: SchemaObject, 25 | mutationType: SchemaObject? = nil, 26 | subscriptionType: SchemaObject? = nil, 27 | directives: [SchemaDirective] = [includeDirective, skipDirective] 28 | ) { 29 | self.queryType = queryType 30 | self.mutationType = mutationType 31 | self.subscriptionType = subscriptionType 32 | self.directives = directives 33 | 34 | let optionalArray: [SchemaObject?] = [queryType, mutationType, subscriptionType]//, Introspection.schema] 35 | let topLevelTypes = IdentitySet(values: optionalArray.flatMap { $0 }.map { AnySchemaType($0) }) 36 | self.types = Schema.collectAllTypesFrom(topLevelTypes) 37 | 38 | assertTypesConformToTheirInterfaces() 39 | } 40 | 41 | static func collectAllTypesFrom(types: IdentitySet) -> IdentitySet { 42 | return [] 43 | } 44 | 45 | func assertTypesConformToTheirInterfaces() { 46 | for type in types { 47 | guard let objectType = type.wrappedType as? SchemaObject else { continue } 48 | for interface in objectType.interfaces { 49 | objectType.assertConformanceToInterface(interface) 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /GraphQL/Type system/SchemaDirective.swift: -------------------------------------------------------------------------------- 1 | public struct SchemaDirective: Named { 2 | public let name: ValidName 3 | let description: String? 4 | let arguments: IdentitySet 5 | let onOperation: Bool 6 | let onFragment: Bool 7 | let onField: Bool 8 | 9 | public init( 10 | name: ValidName, 11 | description: String? = nil, 12 | arguments: IdentitySet, 13 | onOperation: Bool = false, 14 | onFragment: Bool = false, 15 | onField: Bool = false) { 16 | self.name = name 17 | self.description = description 18 | self.arguments = arguments 19 | self.onOperation = onOperation 20 | self.onFragment = onFragment 21 | self.onField = onField 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /GraphQL/Type system/SchemaEnum.swift: -------------------------------------------------------------------------------- 1 | public final class SchemaEnum: SchemaType, AllowedAsObjectField, AllowedAsInputValue, AllowedAsNonNull, AnySchemaEnum { 2 | public let name: ValidName 3 | let description: String? 4 | let values: IdentitySet> 5 | 6 | public init( 7 | name: ValidName, 8 | description: String? = nil, 9 | values: IdentitySet>) { 10 | self.name = name 11 | self.description = description 12 | self.values = values 13 | } 14 | 15 | public var allValues: [AnySchemaEnumValue] { 16 | return values.map { $0 as AnySchemaEnumValue } 17 | } 18 | 19 | public var nonDeprecatedValues: [AnySchemaEnumValue] { 20 | return allValues.filter { $0.deprecationReason == nil } 21 | } 22 | } 23 | 24 | public protocol AnySchemaEnum { 25 | var allValues: [AnySchemaEnumValue] { get } 26 | var nonDeprecatedValues: [AnySchemaEnumValue] { get } 27 | } 28 | 29 | public protocol AnySchemaEnumValue { 30 | var deprecationReason: String? { get } 31 | } 32 | 33 | public struct SchemaEnumValue: Identifiable, AnySchemaEnumValue { 34 | public let value: Enum 35 | public let description: String? 36 | public let deprecationReason: String? 37 | 38 | public init( 39 | value: Enum, 40 | description: String? = nil, 41 | deprecationReason: String? = nil) { 42 | self.value = value 43 | self.description = description 44 | self.deprecationReason = deprecationReason 45 | } 46 | 47 | public var identifier: String { return value.rawValue } 48 | } 49 | 50 | public protocol StringRepresentable { 51 | 52 | } 53 | 54 | 55 | -------------------------------------------------------------------------------- /GraphQL/Type system/SchemaInputObject.swift: -------------------------------------------------------------------------------- 1 | public struct SchemaInputValue: Named { 2 | public let name: ValidName 3 | public let description: String? 4 | public let type: AllowedAsInputValue 5 | /// Perhaps it's possible to restrict the default based on type above? 6 | public let defaultValue: Any? 7 | public var value: Any? 8 | 9 | public init( 10 | name: ValidName, 11 | type: AllowedAsInputValue, 12 | description: String? = nil, 13 | defaultValue: Any? = nil) { 14 | self.name = name 15 | self.type = type 16 | self.description = description 17 | self.defaultValue = defaultValue 18 | } 19 | } 20 | 21 | public protocol AllowedAsInputValue { 22 | func isEqualToType(otherType: AllowedAsInputValue) -> Bool 23 | } 24 | 25 | extension AllowedAsInputValue { 26 | public func isEqualToType(otherType: AllowedAsInputValue) -> Bool { return false } 27 | } 28 | 29 | public struct SchemaInputObject: AllowedAsInputValue, AllowedAsNonNull { 30 | var fields: IdentitySet! 31 | } 32 | -------------------------------------------------------------------------------- /GraphQL/Type system/SchemaInterface.swift: -------------------------------------------------------------------------------- 1 | public final class SchemaInterface: SchemaType { 2 | 3 | var possibleTypes: IdentitySet { 4 | return undefined() 5 | } 6 | 7 | public let name: ValidName 8 | let description: String? 9 | lazy var fields: IdentitySet = self.lazyFields() 10 | 11 | let resolveType: Any -> SchemaObject 12 | private let lazyFields: () -> IdentitySet 13 | 14 | public init( 15 | name: ValidName, 16 | description: String? = nil, 17 | fields: () -> IdentitySet, 18 | resolveType: Any -> SchemaObject) { 19 | self.name = name 20 | self.description = description 21 | self.lazyFields = fields 22 | self.resolveType = resolveType 23 | } 24 | } 25 | 26 | extension SchemaInterface: AllowedAsObjectField { 27 | 28 | } 29 | 30 | extension SchemaObject { 31 | // TODO: This method needs to throw rather than abort so it can be tested 32 | func assertConformanceToInterface(interface: SchemaInterface) { 33 | for interfaceField in interface.fields { 34 | guard let objectField = fields.memberMatching(interfaceField) else { 35 | fatalError("\(interface.name) expects field \(interfaceField.name) but \(name) does not provide it.") 36 | } 37 | 38 | guard interfaceField.type.isSubtypeOf(objectField.type) else { 39 | fatalError("\(interface.name).\(interfaceField.name) expects type \(interfaceField.type) but \(name).\(objectField.name) provides type \(objectField.type)") 40 | } 41 | 42 | for interfaceArgument in interfaceField.arguments { 43 | 44 | guard let objectArgument = objectField.arguments.memberMatching(interfaceArgument) else { 45 | fatalError("\(interface.name).\(interfaceField.name) expects argument \(interfaceArgument.name) but \(name).\(objectField.name) does not provide it.") 46 | } 47 | 48 | guard interfaceArgument.type.isEqualToType(objectArgument.type) else { fatalError("\(interface.name).\(interfaceField.name).(\(interfaceArgument.name):) expects type \(interfaceArgument.type) but \(name).\(objectField.name)(\(objectArgument.name):) provides type \(objectArgument.type)") } 49 | } 50 | 51 | for objectArgument in objectField.arguments 52 | where !interfaceField.arguments.contains(objectArgument) 53 | && objectArgument.type is NonNull { 54 | fatalError("\(name).\(objectField.name)(\(objectArgument.name):) is of required type \(objectArgument.type) but is also not provided by the interface \(interface.name).\(interfaceField.name)") 55 | } 56 | } 57 | } 58 | } 59 | 60 | //extension SchemaObjectFieldType { 61 | // func isEqualToType(hopefullyEqualType: SchemaObjectFieldType) -> Bool { 62 | // switch (self, hopefullyEqualType) { 63 | // case (.Scalar(let a), .Scalar(let b)): return a == b 64 | // case (.Object(let a), .Object(let b)): return a === b 65 | // case (.Interface(let a), .Interface(let b)): return a === b 66 | // case (.Union (let a), .Union(let b)): return a === b 67 | // case (.Enum(let a), .Enum(let b)): return a === b 68 | // case (.List(let a), .List(let b)): return a.isEqualToType(b) 69 | // case (.NonNull(let a), .NonNull(let b)): return a.isEqualToType(b) 70 | // default: return false 71 | // } 72 | // } 73 | // 74 | // func isSubtypeOf(hopefullySupertype: SchemaObjectFieldType) -> Bool { 75 | // if self.isEqualToType(hopefullySupertype) { return true } 76 | // 77 | // switch (self, hopefullySupertype) { 78 | // case (.NonNull(let a), .NonNull(let b)): return a.isSubtypeOf(b) 79 | // case (.List(let a), .List(let b)): return a.isSubtypeOf(b) 80 | // case (.Object(let implementation), .Interface(let interface)): return interface.possibleTypes.contains(implementation) 81 | // case (.Object(let implementation), .Union(let union)): return union.possibleTypes.contains(implementation) 82 | // default: return false 83 | // } 84 | // } 85 | //} -------------------------------------------------------------------------------- /GraphQL/Type system/SchemaList.swift: -------------------------------------------------------------------------------- 1 | public final class List: AllowedAsObjectField, AllowedAsNonNull { 2 | let objectFieldType: AllowedAsObjectField 3 | 4 | public init(_ objectFieldType: AllowedAsObjectField) { 5 | self.objectFieldType = objectFieldType 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /GraphQL/Type system/SchemaObject.swift: -------------------------------------------------------------------------------- 1 | public final class SchemaObject: SchemaType, AllowedAsObjectField, AllowedAsNonNull { 2 | public let name: ValidName 3 | let description: String? 4 | 5 | lazy var fields: IdentitySet = self.lazyFields() 6 | let interfaces: [SchemaInterface] 7 | 8 | private let lazyFields: () -> IdentitySet 9 | 10 | public init( 11 | name: ValidName, 12 | description: String? = nil, 13 | fields: () -> IdentitySet, 14 | interfaces: [SchemaInterface] = []) { 15 | self.name = name 16 | self.description = description 17 | self.lazyFields = fields 18 | self.interfaces = interfaces 19 | } 20 | } 21 | 22 | public protocol AllowedAsObjectField { 23 | func isEqualToType(otherType: AllowedAsObjectField) -> Bool 24 | func isSubtypeOf(hopefullySupertype: AllowedAsObjectField) -> Bool 25 | } 26 | 27 | extension AllowedAsObjectField { 28 | public func isEqualToType(otherType: AllowedAsObjectField) -> Bool { return false } 29 | public func isSubtypeOf(hopefullySupertype: AllowedAsObjectField) -> Bool { return false } 30 | } 31 | 32 | public struct SchemaObjectField: Named { 33 | public let name: ValidName 34 | let type: AllowedAsObjectField 35 | let description: String? 36 | let arguments: IdentitySet 37 | let resolve: (Any -> Any?)? 38 | let deprecationReason: String? 39 | 40 | public init( 41 | name: ValidName, 42 | type: AllowedAsObjectField, 43 | description: String? = nil, 44 | arguments: IdentitySet = [], 45 | resolve: (Any -> Any?)? = nil, 46 | deprecationReason: String? = nil) { 47 | self.name = name 48 | self.type = type 49 | self.description = description 50 | self.arguments = arguments 51 | self.resolve = resolve 52 | self.deprecationReason = deprecationReason 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /GraphQL/Type system/SchemaScalar.swift: -------------------------------------------------------------------------------- 1 | public protocol SchemaScalar: AllowedAsInputValue, AllowedAsNonNull, AllowedAsObjectField { 2 | 3 | } 4 | 5 | public struct Boolean: SchemaScalar { 6 | 7 | } 8 | 9 | public struct StringType: SchemaScalar { 10 | public init() {} 11 | } 12 | -------------------------------------------------------------------------------- /GraphQL/Type system/SchemaUnion.swift: -------------------------------------------------------------------------------- 1 | public final class SchemaUnion: SchemaType { 2 | public let name: ValidName 3 | let description: String? 4 | let possibleTypes: IdentitySet 5 | let resolve: Any -> SchemaObject 6 | 7 | public init( 8 | name: ValidName, 9 | description: String? = nil, 10 | possibleTypes: IdentitySet, 11 | resolve: Any -> SchemaObject 12 | ) { 13 | self.name = name 14 | self.description = description 15 | self.possibleTypes = possibleTypes 16 | self.resolve = resolve 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /GraphQL/Type system/ValidName.swift: -------------------------------------------------------------------------------- 1 | public struct ValidName: StringLiteralConvertible { 2 | public let string: String 3 | public let location: Location? 4 | 5 | public init(string: String, location: Location? = nil) { 6 | self.string = string 7 | self.location = location 8 | } 9 | 10 | public typealias ExtendedGraphemeClusterLiteralType = String 11 | public typealias UnicodeScalarLiteralType = String 12 | 13 | public init(unicodeScalarLiteral value: UnicodeScalarLiteralType) { 14 | self.init(string: value) 15 | } 16 | 17 | public init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) { 18 | self.init(string: value) 19 | } 20 | 21 | public init(stringLiteral value: StringLiteralType) { 22 | self.init(string: value) 23 | } 24 | 25 | } 26 | 27 | extension ValidName: Hashable { 28 | public var hashValue: Int { return string.hashValue } 29 | } 30 | 31 | public func == (left: ValidName, right: ValidName) -> Bool { 32 | return left.string == right.string 33 | } 34 | 35 | extension ValidName: CustomStringConvertible { 36 | public var description: String { 37 | return string 38 | } 39 | } 40 | 41 | public protocol Named: Identifiable { 42 | var name: ValidName { get } 43 | } 44 | 45 | extension Named { 46 | public var identifier: String { return name.string } 47 | } 48 | -------------------------------------------------------------------------------- /GraphQL/Utils/IdentityKit.swift: -------------------------------------------------------------------------------- 1 | public protocol Identifiable { 2 | var identifier: String { get } 3 | } 4 | 5 | public struct IdentitySet { 6 | private var storage: [String: Member] 7 | 8 | public init(values: [Member] = []) { 9 | var storage = [String: Member](minimumCapacity: values.count) 10 | for value in values { 11 | storage[value.identifier] = value 12 | } 13 | self.storage = storage 14 | } 15 | 16 | public mutating func insert(member: Member) { 17 | storage[member.identifier] = member 18 | } 19 | 20 | public mutating func remove(member: Member) { 21 | removeForIdentifier(member.identifier) 22 | } 23 | 24 | public mutating func removeForIdentifier(identifier: String) { 25 | storage[identifier] = nil 26 | } 27 | 28 | public func memberMatching(member: Member) -> Member? { 29 | return memberForIdentifier(member.identifier) 30 | } 31 | 32 | public func memberForIdentifier(identifier: String) -> Member? { 33 | return storage[identifier] 34 | } 35 | 36 | public func contains(member: Member) -> Bool { 37 | return memberMatching(member) != nil 38 | } 39 | 40 | subscript(identifier: String) -> Member? { 41 | get { return memberForIdentifier(identifier) } 42 | // set subscript doesn't make sense, you use `add` instead 43 | } 44 | } 45 | 46 | extension IdentitySet: ArrayLiteralConvertible { 47 | public typealias Element = Member 48 | 49 | public init(arrayLiteral elements: IdentitySet.Element...) { 50 | self.init(values: elements) 51 | } 52 | } 53 | 54 | extension IdentitySet: SequenceType { 55 | public typealias Generator = IdentitySetGenerator 56 | 57 | public func generate() -> Generator { 58 | return IdentitySetGenerator(dictionaryGenerator: storage.generate()) 59 | } 60 | } 61 | 62 | public struct IdentitySetGenerator: GeneratorType { 63 | public typealias Element = GeneratedType 64 | 65 | private var dictionaryGenerator: DictionaryGenerator 66 | 67 | init(dictionaryGenerator: DictionaryGenerator) { 68 | self.dictionaryGenerator = dictionaryGenerator 69 | } 70 | 71 | public mutating func next() -> Element? { 72 | return dictionaryGenerator.next()?.1 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /GraphQL/Utils/MultilineStringOperator.swift: -------------------------------------------------------------------------------- 1 | infix operator ¶ { associativity left } 2 | 3 | /// Concatenates and adds a new line. Insert using `⌥ + 7`. 4 | func ¶ (left: String, right: String) -> String { 5 | return left + "\n" + right 6 | } 7 | -------------------------------------------------------------------------------- /GraphQL/Utils/TypeInfo.swift: -------------------------------------------------------------------------------- 1 | struct GraphQLOutputType { 2 | 3 | } 4 | 5 | struct GraphQLCompositeType { 6 | 7 | } 8 | 9 | struct GraphQLInputType { 10 | 11 | } 12 | 13 | struct SchemaObjectFieldDefinition { 14 | 15 | } 16 | 17 | /// TypeInfo is a utility class which, given a GraphQL schema, can keep track 18 | /// of the current field and type definitions at any point in a GraphQL document 19 | /// AST during a recursive descent by calling `enter` and `leave`. 20 | final class TypeInfo { 21 | let schema: Schema 22 | private var typeStack: [GraphQLOutputType] = [] 23 | private var parentTypeStack: [GraphQLCompositeType] = [] 24 | private var inputTypeStack: [GraphQLInputType] = [] 25 | private var fieldDefinitionStack: [SchemaObjectFieldDefinition] = [] 26 | 27 | init(schema: Schema) { 28 | self.schema = schema 29 | } 30 | 31 | func enter(node: Node) { 32 | 33 | } 34 | 35 | func leave(node: Node) { 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /GraphQL/Utils/Undefined.swift: -------------------------------------------------------------------------------- 1 | func undefined(hint:String="", file:StaticString=#file, line:UInt=#line) -> T { 2 | let message = hint == "" ? "" : ": \(hint)" 3 | fatalError("undefined \(T.self)\(message)", file:file, line:line) 4 | } 5 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rule.swift: -------------------------------------------------------------------------------- 1 | let allRules: [ValidationContext -> Rule] = [ 2 | UniqueOperationNames.init, 3 | LoneAnonymousOperation.init, 4 | KnownTypeNames.init, 5 | FragmentsOnCompositeType.init, 6 | VariablesAreInputTypes.init, 7 | ScalarLeafs.init, 8 | FieldsOnCorrectType.init, 9 | UniqueFragmentNames.init, 10 | KnownFragmentNames.init, 11 | NoUnusedFragments.init, 12 | PossibleFragmentSpreads.init, 13 | NoFragmentCycles.init, 14 | NoUndefinedVariables.init, 15 | NoUnusedVariables.init, 16 | KnownDirectives.init, 17 | KnownArgumentNames.init, 18 | UniqueArgumentNames.init, 19 | ArgumentsOfCorrectType.init, 20 | ProvidedNonNullArguments.init, 21 | DefaultValuesOfCorrectType.init, 22 | VariablesInAllowedPosition.init, 23 | OverlappingFieldsCanBeMerged.init, 24 | UniqueInputFieldNames.init, 25 | ] 26 | 27 | protocol Rule { 28 | var context: ValidationContext { get } 29 | init(context: ValidationContext) 30 | 31 | /// An identity set of visitors to be used when a node is entered. 32 | /// Only a single visitor closure is executed per node, specific visitors are preferred over .Any visitors. 33 | func visitors() -> IdentitySet 34 | } 35 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/ArgumentsOfCorrectType.swift: -------------------------------------------------------------------------------- 1 | final class ArgumentsOfCorrectType: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/DefaultValuesOfCorrectType.swift: -------------------------------------------------------------------------------- 1 | final class DefaultValuesOfCorrectType: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/FieldsOnCorrectType.swift: -------------------------------------------------------------------------------- 1 | final class FieldsOnCorrectType: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/FragmentsOnCompositeTypes.swift: -------------------------------------------------------------------------------- 1 | final class FragmentsOnCompositeType: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/KnownArgumentNames.swift: -------------------------------------------------------------------------------- 1 | final class KnownArgumentNames: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/KnownDirectives.swift: -------------------------------------------------------------------------------- 1 | final class KnownDirectives: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/KnownFragmentNames.swift: -------------------------------------------------------------------------------- 1 | final class KnownFragmentNames: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/KnownTypeNames.swift: -------------------------------------------------------------------------------- 1 | final class KnownTypeNames: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/LoneAnonymousOperation.swift: -------------------------------------------------------------------------------- 1 | final class LoneAnonymousOperation: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/NoFragmentCycles.swift: -------------------------------------------------------------------------------- 1 | final class NoFragmentCycles: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/NoUndefinedVariables.swift: -------------------------------------------------------------------------------- 1 | final class NoUndefinedVariables: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/NoUnusedFragments.swift: -------------------------------------------------------------------------------- 1 | final class NoUnusedFragments: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/NoUnusedVariables.swift: -------------------------------------------------------------------------------- 1 | final class NoUnusedVariables: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/OverlappingFieldsCanBeMerged.swift: -------------------------------------------------------------------------------- 1 | final class OverlappingFieldsCanBeMerged: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/PossibleFragmentSpreads.swift: -------------------------------------------------------------------------------- 1 | final class PossibleFragmentSpreads: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/ProvidedNonNullArguments.swift: -------------------------------------------------------------------------------- 1 | final class ProvidedNonNullArguments: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/ScalarLeafs.swift: -------------------------------------------------------------------------------- 1 | final class ScalarLeafs: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/UniqueArgumentNames.swift: -------------------------------------------------------------------------------- 1 | final class UniqueArgumentNames: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | var knownArgumentNames: Set = [] 8 | 9 | func visitors() -> IdentitySet { 10 | return [ 11 | Visitor(nodeType: .Field, 12 | enter: { field in 13 | self.knownArgumentNames = [] 14 | return .Continue 15 | }), 16 | Visitor(nodeType: .Directive, 17 | enter: { directive in 18 | self.knownArgumentNames = [] 19 | return .Continue 20 | }), 21 | Visitor(nodeType: .Argument, 22 | enter: { argument in 23 | let argument = argument as! Argument 24 | guard !self.knownArgumentNames.contains(argument.name) else { 25 | throw DocumentValidationError.DuplicateArgumentNames(name: argument.name.string) 26 | } 27 | 28 | self.knownArgumentNames.insert(argument.name) 29 | 30 | return .Continue 31 | }), 32 | ] 33 | } 34 | } 35 | 36 | 37 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/UniqueFragmentNames.swift: -------------------------------------------------------------------------------- 1 | final class UniqueFragmentNames: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/UniqueInputFieldNames.swift: -------------------------------------------------------------------------------- 1 | final class UniqueInputFieldNames: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/UniqueOperationNames.swift: -------------------------------------------------------------------------------- 1 | final class UniqueOperationNames: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | var knownOperationNames: Set = [] 8 | 9 | func visitors() -> IdentitySet { 10 | return [Visitor( 11 | nodeType: .OperationDefinition, 12 | enter: { operation in 13 | let operation = operation as! OperationDefinition 14 | guard let name = operation.name else { return .Continue } 15 | 16 | guard !self.knownOperationNames.contains(name) else { 17 | throw DocumentValidationError.DuplicateOperationNames(name: name.string) 18 | } 19 | 20 | self.knownOperationNames.insert(name) 21 | 22 | return .Continue 23 | })] 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/VariableAreInputTypes.swift: -------------------------------------------------------------------------------- 1 | final class VariablesAreInputTypes: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [Visitor(nodeType: .VariableDefinition, enter: { variableDefinition in 9 | let _ = variableDefinition as! VariableDefinition 10 | 11 | // TODO: throw DocumentValidationError.VariableIsNonInputType 12 | 13 | return .Continue 14 | })] 15 | } 16 | } -------------------------------------------------------------------------------- /GraphQL/Validation/Rules/VariablesInAllowedPosition.swift: -------------------------------------------------------------------------------- 1 | final class VariablesInAllowedPosition: Rule { 2 | let context: ValidationContext 3 | required init(context: ValidationContext) { 4 | self.context = context 5 | } 6 | 7 | func visitors() -> IdentitySet { 8 | return [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GraphQL/Validation/Validator.swift: -------------------------------------------------------------------------------- 1 | struct ValidationContext { 2 | let schema: Schema 3 | let document: AbstractSyntaxTree 4 | let typeInfo: TypeInfo 5 | } 6 | 7 | // TODO: Location reporting 8 | public enum DocumentValidationError: ErrorType { 9 | case DuplicateOperationNames(name: String) 10 | case DuplicateArgumentNames(name: String) 11 | case VariableIsNonInputType 12 | } 13 | 14 | extension AbstractSyntaxTree { 15 | func validateForSchema(schema: Schema, ruleInitializers: [ValidationContext -> Rule] = allRules) throws { 16 | let typeInfo = TypeInfo(schema: schema) 17 | let context = ValidationContext(schema: schema, document: self, typeInfo: typeInfo) 18 | let rules = ruleInitializers.map { $0(context) } 19 | var errors: [ErrorType] = [] 20 | 21 | for rule in rules { 22 | do { 23 | try visitUsingRule(rule, typeInfo: typeInfo) 24 | } catch let error { 25 | errors.append(error) 26 | } 27 | } 28 | 29 | switch errors.count { 30 | case 1: throw errors.first! 31 | case _ where errors.count > 1: throw GraphQLComposedError.MultipleErrors(errors) 32 | default: break 33 | } 34 | 35 | } 36 | 37 | func visitUsingRule(rule: Rule, typeInfo: TypeInfo) throws { 38 | 39 | try visit(Visitor(nodeType: .Any, 40 | 41 | enter: { node in 42 | print("Entering \(node.type.rawValue)") 43 | typeInfo.enter(node) 44 | 45 | guard let visitor = rule.findVisitorForNode(node), 46 | let enter = visitor.enter else { return .Continue } 47 | 48 | let action = try enter(node) 49 | 50 | if case .SkipHasSubtree = action { 51 | typeInfo.leave(node) 52 | } 53 | 54 | return action }, 55 | 56 | leave: { node in 57 | print("Leaving \(node.type.rawValue)") 58 | 59 | guard let visitor = rule.findVisitorForNode(node), 60 | let leave = visitor.leave else { return .Continue } 61 | 62 | let action = try leave(node) 63 | 64 | typeInfo.leave(node) 65 | 66 | return action })) 67 | } 68 | } 69 | 70 | extension Rule { 71 | 72 | private func findVisitorForNode(node: Node) -> Visitor? { 73 | let cachedVisitors = visitors() 74 | let specificVisitor = cachedVisitors.memberForIdentifier(node.type.identifier) 75 | let anyVisitor = cachedVisitors.memberForIdentifier(NodeType.Any.identifier) 76 | return specificVisitor ?? anyVisitor 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /GraphQLTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /GraphQLTests/Language/LexerSpec.swift: -------------------------------------------------------------------------------- 1 | @testable import GraphQL 2 | import Nimble 3 | import Quick 4 | 5 | final class LexerSpec: QuickSpec { 6 | 7 | override func spec() { 8 | 9 | describe("functionForSource") { 10 | func lex(string: String) throws -> (Token, String.Index) { 11 | let source = Source(body: string) 12 | let lexer = Lexer.functionForSource(source) 13 | return (try lexer(position: nil), source.body.startIndex) 14 | } 15 | 16 | it("skips whitespace") { 17 | let (token, startIndex) = try! lex(" \n \t foo \n \t ") 18 | expect(token.kind) == TokenKind.Name 19 | expect(token.start) == startIndex + 10 20 | expect(token.end) == startIndex + 13 21 | expect(token.value as? String) == "foo" 22 | } 23 | 24 | it("skips comments") { 25 | let (token, startIndex) = try! lex(" \n#comment\nfoo#comment\n\n") 26 | expect(token.kind) == TokenKind.Name 27 | expect(token.start) == startIndex + 12 28 | expect(token.end) == startIndex + 15 29 | expect(token.value as? String) == "foo" 30 | } 31 | 32 | it("skips commas") { 33 | let (token, startIndex) = try! lex(",,,foo,,,") 34 | expect(token.kind) == TokenKind.Name 35 | expect(token.start) == startIndex + 3 36 | expect(token.end) == startIndex + 6 37 | expect(token.value as? String) == "foo" 38 | } 39 | 40 | it("throws errors in correct position") { 41 | var (_, _): (Token, String.Index) 42 | var error: ErrorType? = nil 43 | do { (_, _) = try lex(" ? ") } 44 | catch let thrownError { 45 | error = thrownError 46 | } 47 | // TODO: Add tighter expectations for errors 48 | expect(error).toNot(beNil()) 49 | } 50 | 51 | it("lexes strings") { 52 | let (token, startIndex) = try! lex("\"simple\"") 53 | expect(token.kind) == TokenKind.String 54 | expect(token.start) == startIndex 55 | expect(token.end) == startIndex + 8 56 | expect(token.value as? String) == "simple" 57 | } 58 | 59 | it("lexes spreads") { 60 | let (token, startIndex) = try! lex("...") 61 | expect(token.kind) == TokenKind.Spread 62 | expect(token.start) == startIndex 63 | expect(token.end) == startIndex + 3 64 | } 65 | 66 | it("lexes two tokens") { 67 | let source = Source(body: "foo bar") 68 | let lexer = Lexer.functionForSource(source) 69 | var token = try! lexer(position: nil) 70 | token = try! lexer(position: token.end) 71 | expect(token.kind) == TokenKind.Name 72 | expect(token.start) == source.body.startIndex + 4 73 | expect(token.end) == source.body.endIndex 74 | } 75 | } 76 | 77 | describe("readName") { 78 | 79 | it("reads a single-character name") { 80 | let source = Source(body: "h") 81 | let token = Lexer.readName(source: source, position: source.body.startIndex) 82 | 83 | expect(token.kind) == TokenKind.Name 84 | expect(token.value as? String) == "h" 85 | } 86 | 87 | it("reads a single-character name terminated by a space") { 88 | let source = Source(body: "h ") 89 | let token = Lexer.readName(source: source, position: source.body.startIndex) 90 | 91 | expect(token.kind) == TokenKind.Name 92 | expect(token.value as? String) == "h" 93 | } 94 | 95 | it("reads a multi-character name") { 96 | let source = Source(body: "hello") 97 | let token = Lexer.readName(source: source, position: source.body.startIndex) 98 | 99 | expect(token.kind) == TokenKind.Name 100 | expect(token.value as? String) == "hello" 101 | } 102 | 103 | it("reads a multi-character name terminated by a space") { 104 | let source = Source(body: "hello dolly") 105 | let token = Lexer.readName(source: source, position: source.body.startIndex) 106 | 107 | expect(token.kind) == TokenKind.Name 108 | expect(token.value as? String) == "hello" 109 | } 110 | } 111 | 112 | describe("readNumber") { 113 | 114 | it("reads a short integer") { 115 | let source = Source(body: "5") 116 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 117 | 118 | expect(token.kind) == TokenKind.Int 119 | expect(token.value as? Int) == 5 120 | } 121 | 122 | it("reads a longer integer") { 123 | let source = Source(body: "535056544") 124 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 125 | 126 | expect(token.kind) == TokenKind.Int 127 | expect(token.value as? Int) == 535056544 128 | } 129 | 130 | it("reads a short negative integer") { 131 | let source = Source(body: "-5") 132 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 133 | 134 | expect(token.kind) == TokenKind.Int 135 | expect(token.value as? Int) == -5 136 | } 137 | 138 | it("reads a longer negative integer") { 139 | let source = Source(body: "-535056544") 140 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 141 | 142 | expect(token.kind) == TokenKind.Int 143 | expect(token.value as? Int) == -535056544 144 | } 145 | 146 | it("reads a short float") { 147 | let source = Source(body: "5.2") 148 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 149 | 150 | expect(token.kind) == TokenKind.Float 151 | expect(token.value as? Float) == 5.2 152 | } 153 | 154 | it("reads a longer float") { 155 | let source = Source(body: "5534653.22463") 156 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 157 | 158 | expect(token.kind) == TokenKind.Float 159 | expect(token.value as? Float) == 5534653.22463 160 | } 161 | 162 | it("reads a short negative float") { 163 | let source = Source(body: "-5.2") 164 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 165 | 166 | expect(token.kind) == TokenKind.Float 167 | expect(token.value as? Float) == -5.2 168 | } 169 | 170 | it("reads a longer negative float") { 171 | let source = Source(body: "-5534653.22463") 172 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 173 | 174 | expect(token.kind) == TokenKind.Float 175 | expect(token.value as? Float) == -5534653.22463 176 | } 177 | 178 | it("reads numbers with short exponent notation") { 179 | let source = Source(body: "-1.123e4") 180 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 181 | 182 | expect(token.kind) == TokenKind.Float 183 | expect(token.value as? Float) == -1.123e4 184 | } 185 | 186 | it("reads numbers with short negative exponent notation") { 187 | let source = Source(body: "-1.123e-4") 188 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 189 | 190 | expect(token.kind) == TokenKind.Float 191 | expect(token.value as? Float) == -1.123e-4 192 | } 193 | 194 | 195 | it("reads numbers with longer exponent notation") { 196 | let source = Source(body: "-1.123e23") 197 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 198 | 199 | expect(token.kind) == TokenKind.Float 200 | expect(token.value as? Float) == -1.123e23 201 | } 202 | 203 | it("reads numbers with longer negative exponent notation") { 204 | let source = Source(body: "-1.123e-23") 205 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 206 | 207 | expect(token.kind) == TokenKind.Float 208 | expect(token.value as? Float) == -1.123e-23 209 | } 210 | 211 | it("reads an integer followed by non-numbers") { 212 | let source = Source(body: "5andwemoveon") 213 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 214 | 215 | expect(token.kind) == TokenKind.Int 216 | expect(token.value as? Int) == 5 217 | } 218 | 219 | it("reads a float followed by non-numbers") { 220 | let source = Source(body: "5.3andwemoveon") 221 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 222 | 223 | expect(token.kind) == TokenKind.Float 224 | expect(token.value as? Float) == 5.3 225 | } 226 | 227 | it ("reads 00 as 0") { 228 | let source = Source(body: "00") 229 | let token = try! Lexer.readNumber(source: source, position: source.body.startIndex) 230 | 231 | expect(token.kind) == TokenKind.Int 232 | expect(token.value as? Int) == 0 233 | expect(token.end) == source.body.startIndex + 2 234 | } 235 | } 236 | 237 | describe("readString") { 238 | it("reads a simple string") { 239 | let string = "\"hello dolly\"" 240 | let source = Source(body: string) 241 | let token = try! Lexer.readString(source: source, position: source.body.startIndex) 242 | 243 | expect(token.kind) == TokenKind.String 244 | expect(token.value as? String) == "hello dolly" 245 | expect(token.start) == string.startIndex 246 | expect(token.end) == string.endIndex 247 | } 248 | 249 | it("reads escaped characters such as newline") { 250 | let string = "\"hello\\ndolly\"" 251 | let source = Source(body: string) 252 | let token = try! Lexer.readString(source: source, position: source.body.startIndex) 253 | 254 | expect(token.kind) == TokenKind.String 255 | expect(token.value as? String) == "hello\\ndolly" 256 | expect(token.start) == string.startIndex 257 | expect(token.end) == string.endIndex 258 | } 259 | 260 | it("reads unicode characters in \\u1234 format") { 261 | let string = "\"hello \\u0064olly\"" 262 | let source = Source(body: string) 263 | let token = try! Lexer.readString(source: source, position: source.body.startIndex) 264 | 265 | expect(token.kind) == TokenKind.String 266 | expect(token.value as? String) == "hello dolly" 267 | expect(token.start) == string.startIndex 268 | expect(token.end) == string.endIndex 269 | } 270 | 271 | // TODO: Add string error handling 272 | } 273 | 274 | describe("positionAfterWhitespace") { 275 | it("ignores spaces, commas, U+2028, U+2029, U+0008 through U+000E") { 276 | let string = " ,\u{2028}\u{2029}\u{9}\u{A}\u{B}\u{C}\u{D}h" 277 | let position = Lexer.positionAfterWhitespace(body: string, position: string.startIndex) 278 | 279 | expect(string[position]) == "h" 280 | } 281 | 282 | it("ignores comments started by #") { 283 | let string = "# whatever you wanna say\ng" 284 | let position = Lexer.positionAfterWhitespace(body: string, position: string.startIndex) 285 | 286 | expect(string[position]) == "g" 287 | } 288 | } 289 | } 290 | } -------------------------------------------------------------------------------- /GraphQLTests/Language/ParserSpec.swift: -------------------------------------------------------------------------------- 1 | @testable import GraphQL 2 | import Nimble 3 | import Quick 4 | 5 | final class ParserSpec: QuickSpec { 6 | 7 | override func spec() { 8 | 9 | describe("parse") { 10 | it("parses a basic document") { 11 | let string = 12 | "{" ¶ 13 | " node(id: 4) {" ¶ 14 | " id," ¶ 15 | " name" ¶ 16 | " }" ¶ 17 | "}" 18 | expect { 19 | let document = try Parser.parse(Source(body: string)) 20 | 21 | expect(document.definitions.count) == 1 22 | expect(document.definitions.first is OperationDefinition) == true 23 | let operationDefinition = document.definitions.first as! OperationDefinition 24 | expect(operationDefinition.selectionSet.selections.count) == 1 25 | 26 | expect(operationDefinition.selectionSet.selections.first is Field) == true 27 | let nodeSelectionField = operationDefinition.selectionSet.selections.first as! Field 28 | expect(nodeSelectionField.name.string) == "node" 29 | expect(nodeSelectionField.selectionSet?.selections.count) == 2 30 | expect(nodeSelectionField.arguments.count) == 1 31 | 32 | let idArgument = nodeSelectionField.arguments.first! 33 | expect(idArgument.name.string) == "id" 34 | expect(idArgument.value is IntValue) == true 35 | let idArgumentValue = idArgument.value as! IntValue 36 | expect(idArgumentValue.value) == 4 37 | 38 | expect(nodeSelectionField.selectionSet?.selections.first is Field) == true 39 | let idSelectionField = nodeSelectionField.selectionSet?.selections.first as! Field 40 | expect(idSelectionField.name.string) == "id" 41 | 42 | expect(nodeSelectionField.selectionSet?.selections.last is Field) == true 43 | let nameSelectionField = nodeSelectionField.selectionSet?.selections.last as! Field 44 | expect(nameSelectionField.name.string) == "name" 45 | 46 | return nil 47 | }.toNot(throwError()) 48 | } 49 | 50 | it("parses the kitchen-sink example") { 51 | let path = NSBundle(forClass: self.dynamicType).pathForResource("kitchen-sink", ofType: "graphql") 52 | let kitchenSink = try! NSString(contentsOfFile: path!, encoding: NSUTF8StringEncoding) 53 | expect { 54 | let document = try Parser.parse(Source(body: kitchenSink as String)) 55 | expect(document).toNot(beNil()) 56 | return nil 57 | }.toNot(throwError()) 58 | } 59 | } 60 | 61 | } 62 | } -------------------------------------------------------------------------------- /GraphQLTests/Language/kitchen-sink.graphql: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | 8 | query queryName($foo: ComplexType, $site: Site = MOBILE) { 9 | whoever123is: node(id: [123, 456]) { 10 | id , 11 | ... on User @defer { 12 | field2 { 13 | id , 14 | alias: field1(first:10, after:$foo,) @include(if: $foo) { 15 | id, 16 | ...frag 17 | } 18 | } 19 | } 20 | ... @skip(unless: $foo) { 21 | id 22 | } 23 | ... { 24 | id 25 | } 26 | } 27 | } 28 | 29 | mutation likeStory { 30 | like(story: 123) @defer { 31 | story { 32 | id 33 | } 34 | } 35 | } 36 | 37 | fragment frag on Friend { 38 | foo(size: $size, bar: $b, obj: {key: "value"}) 39 | } 40 | 41 | { 42 | unnamed(truthy: true, falsey: false), 43 | query 44 | } 45 | -------------------------------------------------------------------------------- /GraphQLTests/Type system/StarWarsData.swift: -------------------------------------------------------------------------------- 1 | enum Movie: String { 2 | case NewHope = "NEWHOPE" 3 | case EmpireStrikesBack = "EMPIRE" 4 | case ReturnOfTheJedi = "JEDI" 5 | } 6 | 7 | let luke = Human( 8 | id: "1000", 9 | name: "Luke Skywalker", 10 | friends: ["1002", "1003", "2000", "2001"], 11 | appearsIn: [.NewHope, .EmpireStrikesBack, .ReturnOfTheJedi], 12 | homePlanet: "Tatooine" 13 | ) 14 | 15 | let vader = Human( 16 | id: "1001", 17 | name: "Darth Vader", 18 | friends: ["1004"], 19 | appearsIn: [.NewHope, .EmpireStrikesBack, .ReturnOfTheJedi], 20 | homePlanet: "Tatooine" 21 | ) 22 | 23 | let han = Human( 24 | id: "1002", 25 | name: "Han Solo", 26 | friends: ["1000", "1003", "2001"], 27 | appearsIn: [.NewHope, .EmpireStrikesBack, .ReturnOfTheJedi] 28 | ) 29 | 30 | let leia = Human( 31 | id: "1003", 32 | name: "Leia Organa", 33 | friends: ["1000", "1002", "2000", "2001"], 34 | appearsIn: [.NewHope, .EmpireStrikesBack, .ReturnOfTheJedi], 35 | homePlanet: "Alderaan" 36 | ) 37 | 38 | let tarkin = Human( 39 | id: "1004", 40 | name: "Wilhuff Tarkin", 41 | friends: ["1001"], 42 | appearsIn: [.NewHope], 43 | homePlanet: "Tatooine" 44 | ) 45 | 46 | let humanTable = [ 47 | "1000": luke, 48 | "1001": vader, 49 | "1002": han, 50 | "1003": leia, 51 | "1004": tarkin, 52 | ] 53 | 54 | let threepio = Droid( 55 | id: "2000", 56 | name: "C-3PO", 57 | friends: ["1000", "1002", "1003", "2001"], 58 | appearsIn: [.NewHope, .EmpireStrikesBack, .ReturnOfTheJedi], 59 | primaryFunction: "Protocol" 60 | ) 61 | 62 | let artoo = Droid( 63 | id: "2001", 64 | name: "R2-D2", 65 | friends: ["1000", "1002", "1003"], 66 | appearsIn: [.NewHope, .EmpireStrikesBack, .ReturnOfTheJedi], 67 | primaryFunction: "Astromech" 68 | ) 69 | 70 | let droidTable = [ 71 | "2000": threepio, 72 | "2001": artoo, 73 | ] -------------------------------------------------------------------------------- /GraphQLTests/Type system/StarWarsModels.swift: -------------------------------------------------------------------------------- 1 | protocol Character { 2 | var id: String { get } 3 | var name: String { get } 4 | var friends: [String] { get } 5 | var appearsIn: Set { get } 6 | } 7 | 8 | enum Episode: Int { 9 | case NewHope = 4 10 | case EmpireStrikesBack = 5 11 | case ReturnOfTheJedi = 6 12 | 13 | func getHero() -> Character { 14 | switch self { 15 | case .EmpireStrikesBack: return luke 16 | case .NewHope, .ReturnOfTheJedi: return artoo 17 | } 18 | } 19 | } 20 | 21 | extension Character { 22 | func getFriends() -> [Character] { 23 | return friends.map { id in 24 | if let humanFriend = humanTable[id] { 25 | return humanFriend 26 | } else if let droidFriend = droidTable[id] { 27 | return droidFriend 28 | } 29 | fatalError("Invalid relationship") 30 | } 31 | } 32 | } 33 | 34 | struct Human: Character { 35 | let id: String 36 | let name: String 37 | let friends: [String] 38 | let appearsIn: Set 39 | let homePlanet: String? 40 | 41 | static func getById(id: String) -> Human? { 42 | return humanTable[id] 43 | } 44 | 45 | init(id: String, name: String, friends: [String], appearsIn: Set, homePlanet: String? = nil) { 46 | self.id = id 47 | self.name = name 48 | self.friends = friends 49 | self.appearsIn = appearsIn 50 | self.homePlanet = homePlanet 51 | } 52 | } 53 | 54 | struct Droid: Character { 55 | let id: String 56 | let name: String 57 | let friends: [String] 58 | let appearsIn: Set 59 | let primaryFunction: String 60 | 61 | static func getById(id: String) -> Droid? { 62 | return droidTable[id] 63 | } 64 | 65 | init(id: String, name: String, friends: [String], appearsIn: Set, primaryFunction: String) { 66 | self.id = id 67 | self.name = name 68 | self.friends = friends 69 | self.appearsIn = appearsIn 70 | self.primaryFunction = primaryFunction 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /GraphQLTests/Type system/StarWarsSchema.swift: -------------------------------------------------------------------------------- 1 | import GraphQL 2 | 3 | let starWarsSchema = { () -> Schema in 4 | var characterInterface: SchemaInterface! 5 | var droidType: SchemaObject! 6 | var humanType: SchemaObject! 7 | 8 | let episodeEnum = SchemaEnum( 9 | name: "Episode", 10 | description: "One of the films in the Star Wars Trilogy", 11 | values: [ 12 | SchemaEnumValue( 13 | value: .NewHope, 14 | description: "Released in 1977."), 15 | SchemaEnumValue( 16 | value: .EmpireStrikesBack, 17 | description: "Released in 1980."), 18 | SchemaEnumValue( 19 | value: .ReturnOfTheJedi, 20 | description: "Released in 1983."), 21 | ]) 22 | 23 | let characterInterfaceDefinition = SchemaInterface( 24 | name: "Character", 25 | description: "A character in the Star Wars Trilogy", 26 | fields: { [ 27 | SchemaObjectField( 28 | name: "id", 29 | type: NonNull(StringType()), 30 | description: "The id of the character."), 31 | SchemaObjectField( 32 | name: "name", 33 | type: StringType(), 34 | description: "The name of the character."), 35 | SchemaObjectField( 36 | name: "friends", 37 | type: List(characterInterface), 38 | description: "The friends of the character, or an empty list if they have none."), 39 | SchemaObjectField( 40 | name: "appearsIn", 41 | type: episodeEnum, 42 | description: "Which movies they appear in."), 43 | ] }, 44 | resolveType: { toResolve in 45 | let character = toResolve as! Character 46 | return Human.getById(character.id) != nil ? humanType : droidType }) 47 | characterInterface = characterInterfaceDefinition 48 | 49 | let humanTypeDefinition = SchemaObject( 50 | name: "Human", 51 | description: "A humanoid creature in the Star Wars universe.", 52 | fields: { [ 53 | SchemaObjectField( 54 | name: "id", 55 | type: NonNull(StringType()), 56 | description: "The id of the human."), 57 | SchemaObjectField( 58 | name: "name", 59 | type: StringType(), 60 | description: "The name of the human."), 61 | SchemaObjectField( 62 | name: "friends", 63 | type: List(characterInterface), 64 | description: "The friends of the human, or an empty list if they have none.", 65 | resolve: { toResolve in 66 | let human = toResolve as! Human 67 | return human.getFriends() }), 68 | SchemaObjectField( 69 | name: "appearsIn", 70 | type: List(episodeEnum), 71 | description: "Which movies they appear in."), 72 | SchemaObjectField( 73 | name: "homePlanet", 74 | type: StringType(), 75 | description: "The home planet of the human, or null if unknown.") 76 | ] }, 77 | interfaces: [characterInterface]) 78 | humanType = humanTypeDefinition 79 | 80 | let droidTypeDefinition = SchemaObject( 81 | name: "Droid", 82 | description: "A mechanical creature in the Star Wars universe.", 83 | fields: { [ 84 | SchemaObjectField( 85 | name: "id", 86 | type: NonNull(StringType()), 87 | description: "The id of the droid."), 88 | SchemaObjectField( 89 | name: "name", 90 | type: StringType(), 91 | description: "The name of the droid."), 92 | SchemaObjectField( 93 | name: "friends", 94 | type: List(characterInterface), 95 | description: "The friends of the droid, or an empty list if they have none.", 96 | resolve: { toResolve in 97 | let droid = toResolve as! Droid 98 | return droid.getFriends() 99 | }), 100 | SchemaObjectField( 101 | name: "appearsIn", 102 | type: List(episodeEnum), 103 | description: "Which movies they appear in."), 104 | SchemaObjectField( 105 | name: "primaryFunction", 106 | type: StringType(), 107 | description: "The primary function of the droid."), 108 | ] }, 109 | 110 | interfaces: [characterInterface]) 111 | droidType = droidTypeDefinition 112 | 113 | let queryType = SchemaObject( 114 | name: "Query", 115 | fields: { [ 116 | SchemaObjectField( 117 | name: "hero", 118 | type: characterInterface, 119 | arguments: [ 120 | SchemaInputValue( 121 | name: "episode", 122 | type: episodeEnum, 123 | description: "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode." 124 | ), 125 | ], 126 | resolve: { toResolve in 127 | let episode = toResolve as! Episode 128 | return episode.getHero() 129 | } 130 | ), 131 | SchemaObjectField( 132 | name: "human", 133 | type: humanType, 134 | arguments: [ 135 | SchemaInputValue( 136 | name: "id", 137 | type: NonNull(StringType()), 138 | description: "id of the human"), 139 | ], 140 | resolve: { toResolve in 141 | let id = toResolve as! String 142 | return Human.getById(id) 143 | } 144 | ), 145 | SchemaObjectField( 146 | name: "droid", 147 | type: droidType, 148 | arguments: [ 149 | SchemaInputValue( 150 | name: "id", 151 | type: NonNull(StringType()), 152 | description: "id of the droid"), 153 | ], 154 | resolve: { toResolve in 155 | let id = toResolve as! String 156 | return Droid.getById(id) 157 | } 158 | ), 159 | ] }) 160 | 161 | return Schema(queryType: queryType) 162 | }() 163 | -------------------------------------------------------------------------------- /GraphQLTests/Validation/Rules/UniqueArgumentNamesSpec.swift: -------------------------------------------------------------------------------- 1 | //@testable import GraphQL 2 | //import Nimble 3 | //import Quick 4 | // 5 | //final class UniqueArgumentNamesSpec: QuickSpec { 6 | // 7 | // override func spec() { 8 | // let rule: [ValidationContext -> Rule] = [UniqueArgumentNames.init] 9 | // let schema = starWarsSchema 10 | // 11 | // context("no arguments on field") { 12 | // let string = 13 | // "{" ¶ 14 | // " field" ¶ 15 | // "}" 16 | // 17 | // it("passes validation") { 18 | // expect(string).to(passValidationForSchema(schema, ruleInitializers: rule)) 19 | // } 20 | // } 21 | // 22 | // context("an argument on field") { 23 | // let string = 24 | // "{" ¶ 25 | // " field(arg: \"value\")" ¶ 26 | // "}" 27 | // 28 | // it("passes validation") { 29 | // expect(string).to(passValidationForSchema(schema, ruleInitializers: rule)) 30 | // } 31 | // } 32 | // 33 | // context("same argument on two fields") { 34 | // let string = 35 | // "{" ¶ 36 | // " one: field(arg: \"value\")" ¶ 37 | // " two: field(arg: \"value\")" ¶ 38 | // "}" 39 | // 40 | // it("passes validation") { 41 | // expect(string).to(passValidationForSchema(schema, ruleInitializers: rule)) 42 | // } 43 | // } 44 | // 45 | // context("multiple field arguments") { 46 | // let string = 47 | // "{" ¶ 48 | // " field(arg1: \"value\", arg2: \"value\", arg3: \"value\")" ¶ 49 | // "}" 50 | // 51 | // it("passes validation") { 52 | // expect(string).to(passValidationForSchema(schema, ruleInitializers: rule)) 53 | // } 54 | // } 55 | // 56 | // context("duplicate field arguments") { 57 | // let string = 58 | // "{" ¶ 59 | // " field(arg1: \"value\", arg1: \"value\")" ¶ 60 | // "}" 61 | // 62 | // it("fails validation") { 63 | // expect(string).to(failValidationForSchema(schema, ruleInitializers: rule) { error in 64 | // switch error { 65 | // case .DuplicateArgumentNames(let name): 66 | // return name == "arg1" 67 | // default: return false 68 | // } 69 | // }) 70 | // } 71 | // } 72 | // 73 | // context("many duplicate field arguments") { 74 | // let string = 75 | // "{" ¶ 76 | // " field(arg1: \"value\", arg1: \"value\", arg1: \"value\")" ¶ 77 | // "}" 78 | // 79 | // it("fails validation") { 80 | // expect(string).to(failValidationForSchema(schema, ruleInitializers: rule) { error in 81 | // switch error { 82 | // case .DuplicateArgumentNames(let name): 83 | // return name == "arg1" 84 | // default: return false 85 | // } 86 | // }) 87 | // } 88 | // } 89 | // } 90 | //} -------------------------------------------------------------------------------- /GraphQLTests/Validation/Rules/UniqueOperationNamesSpec.swift: -------------------------------------------------------------------------------- 1 | //@testable import GraphQL 2 | //import Nimble 3 | //import Quick 4 | // 5 | //final class UniqueOperationNamesSpec: QuickSpec { 6 | // 7 | // override func spec() { 8 | // let rule: [ValidationContext -> Rule] = [UniqueOperationNames.init] 9 | // let schema = starWarsSchema 10 | // 11 | // context("no operations in a request") { 12 | // let string = 13 | // "fragment fragA on Type {" ¶ 14 | // " field" ¶ 15 | // "}" 16 | // 17 | // it("passes validation") { 18 | // expect(string).to(passValidationForSchema(schema, ruleInitializers: rule)) 19 | // } 20 | // } 21 | // 22 | // context("one anonymous operation in a request") { 23 | // let string = 24 | // "{" ¶ 25 | // " field" ¶ 26 | // "}" 27 | // 28 | // it("passes validation") { 29 | // expect(string).to(passValidationForSchema(schema, ruleInitializers: rule)) 30 | // 31 | // } 32 | // } 33 | // 34 | // context("one named operation in a request") { 35 | // let string = 36 | // "query Foo {" ¶ 37 | // " field" ¶ 38 | // "}" 39 | // 40 | // it("passes validation") { 41 | // expect(string).to(passValidationForSchema(schema, ruleInitializers: rule)) 42 | // } 43 | // } 44 | // 45 | // context("multiple differently named operations of the same type in a request") { 46 | // let string = 47 | // "query Foo {" ¶ 48 | // " field" ¶ 49 | // "}" ¶ 50 | // "" ¶ 51 | // "query Bar {" ¶ 52 | // " field" ¶ 53 | // "}" 54 | // 55 | // it("passes validation") { 56 | // expect(string).to(passValidationForSchema(schema, ruleInitializers: rule)) 57 | // } 58 | // } 59 | // 60 | // context("multiple differently named operations of different types in a request") { 61 | // let string = 62 | // "query Foo {" ¶ 63 | // " field" ¶ 64 | // "}" ¶ 65 | // "" ¶ 66 | // "mutation Bar {" ¶ 67 | // " field" ¶ 68 | // "}" 69 | // 70 | // it("passes validation") { 71 | // expect(string).to(passValidationForSchema(schema, ruleInitializers: rule)) 72 | // } 73 | // } 74 | // 75 | // context("a fragment and an operation named the same in a request") { 76 | // let string = 77 | // "query Foo {" ¶ 78 | // " ...Foo" ¶ 79 | // "}" ¶ 80 | // "" ¶ 81 | // "fragment Foo on Type {" ¶ 82 | // " field" ¶ 83 | // "}" 84 | // 85 | // it("passes validation") { 86 | // expect(string).to(passValidationForSchema(schema, ruleInitializers: rule)) 87 | // } 88 | // } 89 | // 90 | // context("multiple same named operations of the same type in a request") { 91 | // let string = 92 | // "query Foo {" ¶ 93 | // " fieldA" ¶ 94 | // "}" ¶ 95 | // "" ¶ 96 | // "query Foo {" ¶ 97 | // " fieldB" ¶ 98 | // "}" 99 | // 100 | // it("fails validation") { 101 | // expect(string).to(failValidationForSchema(schema, ruleInitializers: rule) { error in 102 | // switch error { 103 | // case .DuplicateOperationNames(let name): 104 | // return name == "Foo" 105 | // default: return false 106 | // } 107 | // }) 108 | // } 109 | // } 110 | // 111 | // context("multiple same named operations of different types in a request") { 112 | // let string = 113 | // "query Foo {" ¶ 114 | // " fieldA" ¶ 115 | // "}" ¶ 116 | // "" ¶ 117 | // "mutation Foo {" ¶ 118 | // " fieldB" ¶ 119 | // "}" 120 | // 121 | // it("fails validation") { 122 | // expect(string).to(failValidationForSchema(schema, ruleInitializers: rule) { error in 123 | // switch error { 124 | // case .DuplicateOperationNames(let name): 125 | // return name == "Foo" 126 | // default: return false 127 | // } 128 | // }) 129 | // } 130 | // } 131 | // } 132 | //} -------------------------------------------------------------------------------- /GraphQLTests/Validation/ValidatorHarness.swift: -------------------------------------------------------------------------------- 1 | import Nimble 2 | import Quick 3 | @testable import GraphQL 4 | 5 | func passValidationForSchema(schema: Schema, ruleInitializers: [ValidationContext -> Rule]) -> NonNilMatcherFunc { 6 | return NonNilMatcherFunc { actualExpression, failureMessage in 7 | guard let source = try actualExpression.evaluate() else { 8 | failureMessage.actualValue = nil 9 | failureMessage.postfixMessage = "receive string" 10 | return false 11 | } 12 | 13 | failureMessage.actualValue = nil 14 | failureMessage.postfixMessage = "pass validation" 15 | let document = try Parser.parse(Source(body: source)) 16 | try document.validateForSchema(schema, ruleInitializers: ruleInitializers) 17 | 18 | return true 19 | } 20 | } 21 | 22 | func failValidationForSchema(schema: Schema, ruleInitializers: [ValidationContext -> Rule], withExpectedError: DocumentValidationError -> Bool) -> NonNilMatcherFunc { 23 | return NonNilMatcherFunc { actualExpression, failureMessage in 24 | guard let source = try actualExpression.evaluate() else { 25 | failureMessage.actualValue = nil 26 | failureMessage.postfixMessage = "receive string" 27 | return false 28 | } 29 | 30 | let document = try Parser.parse(Source(body: source)) 31 | do { 32 | failureMessage.actualValue = nil 33 | failureMessage.postfixMessage = "fail during validation" 34 | try document.validateForSchema(schema, ruleInitializers: ruleInitializers) 35 | } catch let error as DocumentValidationError { 36 | return withExpectedError(error) 37 | } 38 | 39 | return false 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target :GraphQL do 4 | 5 | target :GraphQLTests do 6 | pod 'Quick' 7 | pod 'Nimble' 8 | end 9 | 10 | end 11 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Nimble (4.0.1) 3 | - Quick (0.9.2) 4 | 5 | DEPENDENCIES: 6 | - Nimble 7 | - Quick 8 | 9 | SPEC CHECKSUMS: 10 | Nimble: 0f3c8b8b084cda391209c3c5efbb48bedeeb920a 11 | Quick: 18d057bc66451eedd5d1c8dc99ba2a5db6e60226 12 | 13 | COCOAPODS: 0.39.0 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is currently under development, [get in touch](twitter.com/stepanhruda) on Twitter if you have any questions. 2 | --------------------------------------------------------------------------------